diff options
author | Piotr Dziwinski <piotrdz@gmail.com> | 2012-06-25 19:59:17 +0200 |
---|---|---|
committer | Piotr Dziwinski <piotrdz@gmail.com> | 2012-06-25 19:59:17 +0200 |
commit | b08a63790c0fbeacb3f96a74e3eb15abe8c70dab (patch) | |
tree | 7260140ae1ea308bd256370c6fcbbc57dbd13441 | |
parent | f58918031c001a0159eaf8f18d4e451e70089d30 (diff) | |
download | colobot-b08a63790c0fbeacb3f96a74e3eb15abe8c70dab.tar.gz colobot-b08a63790c0fbeacb3f96a74e3eb15abe8c70dab.tar.bz2 colobot-b08a63790c0fbeacb3f96a74e3eb15abe8c70dab.zip |
SDL project
- added (very basic) SDL template in CApplication and CEngine
- split project into two targets: colobot_old (dependent on DirectX and WinAPI)
and colobot_new (dependent on SDL and OpenGL)
- moved sound.h/cpp to old/ and created new template in Snd namespace
- added platform-independent dialog boxes in app/system.h/cpp
44 files changed, 3283 insertions, 2030 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 02016af..ae0231d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,15 @@ -# CMake project file for compiling with MinGW +# CMake project file for compiling with GCC/MinGW cmake_minimum_required(VERSION 2.8) -project(colobot CXX) +project(colobot C CXX) +# Required packages +find_package(OpenGL REQUIRED) +find_package(SDL REQUIRED) +find_package(SDL_image REQUIRED) + +# Build with debugging symbols set(CMAKE_BUILD_TYPE debug) # Currently compiles only with -fpermissive @@ -11,4 +17,5 @@ set(CMAKE_BUILD_TYPE debug) set(CMAKE_CXX_FLAGS_RELEASE "-fpermissive -O2") set(CMAKE_CXX_FLAGS_DEBUG "-fpermissive -w -g -O0") +# Subdirectory with sources add_subdirectory(src bin) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 024489d..3f5e238 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,9 @@ -# CBot shared library +# CBot shared library is built separately add_subdirectory(CBot) -set(SOURCES + +# Source files for old target (dependent on WinAPI & DirectX) +set(OLD_SOURCES old/d3dapp.cpp old/joystick.cpp old/blitz.cpp @@ -23,29 +25,13 @@ old/d3dutil.cpp old/d3dmath.cpp old/math3d.cpp old/modfile.cpp -app/app.cpp +old/sound.cpp common/event.cpp common/iman.cpp common/metafile.cpp common/misc.cpp common/profile.cpp common/restext.cpp -graphics/common/camera.cpp -graphics/common/cloud.cpp -graphics/common/color.cpp -graphics/common/engine.cpp -graphics/common/light.cpp -graphics/common/lightning.cpp -graphics/common/model.cpp -graphics/common/modfile.cpp -graphics/common/particle.cpp -graphics/common/planet.cpp -graphics/common/pyro.cpp -graphics/common/terrain.cpp -graphics/common/text.cpp -graphics/common/water.cpp -graphics/opengl/gldevice.cpp -graphics/opengl/glengine.cpp object/auto/auto.cpp object/auto/autobase.cpp object/auto/autoconvert.cpp @@ -110,7 +96,6 @@ physics/physics.cpp script/cbottoken.cpp script/cmdtoken.cpp script/script.cpp -sound/sound.cpp ui/button.cpp ui/check.cpp ui/color.cpp @@ -139,25 +124,174 @@ ui/target.cpp ui/window.cpp ) -add_definitions(-DSTRICT -DD3D_OVERLOADS) +# Source files for new target (dependent on SDL & OpenGL) +# Commented out files are still dependent on DirectX or WinAPI +set(NEW_SOURCES +app/app.cpp +app/main.cpp +app/system.cpp +common/event.cpp +common/iman.cpp +# common/metafile.cpp +# common/misc.cpp +# common/modfile.cpp +# common/profile.cpp +# common/restext.cpp +graphics/common/camera.cpp +graphics/common/cloud.cpp +graphics/common/color.cpp +graphics/common/device.cpp +graphics/common/engine.cpp +graphics/common/light.cpp +graphics/common/lightning.cpp +graphics/common/model.cpp +graphics/common/modfile.cpp +graphics/common/particle.cpp +graphics/common/planet.cpp +graphics/common/pyro.cpp +graphics/common/terrain.cpp +graphics/common/text.cpp +graphics/common/water.cpp +graphics/opengl/gldevice.cpp +graphics/opengl/glengine.cpp +# object/auto/auto.cpp +# object/auto/autobase.cpp +# object/auto/autoconvert.cpp +# object/auto/autoderrick.cpp +# object/auto/autodestroyer.cpp +# object/auto/autoegg.cpp +# object/auto/autoenergy.cpp +# object/auto/autofactory.cpp +# object/auto/autoflag.cpp +# object/auto/autohuston.cpp +# object/auto/autoinfo.cpp +# object/auto/autojostle.cpp +# object/auto/autokid.cpp +# object/auto/autolabo.cpp +# object/auto/automush.cpp +# object/auto/autonest.cpp +# object/auto/autonuclear.cpp +# object/auto/autopara.cpp +# object/auto/autoportico.cpp +# object/auto/autoradar.cpp +# object/auto/autorepair.cpp +# object/auto/autoresearch.cpp +# object/auto/autoroot.cpp +# object/auto/autosafe.cpp +# object/auto/autostation.cpp +# object/auto/autotower.cpp +# object/brain.cpp +# object/mainmovie.cpp +# object/motion/motion.cpp +# object/motion/motionant.cpp +# object/motion/motionbee.cpp +# object/motion/motionhuman.cpp +# object/motion/motionmother.cpp +# object/motion/motionspider.cpp +# object/motion/motiontoto.cpp +# object/motion/motionvehicle.cpp +# object/motion/motionworm.cpp +# object/object.cpp +# object/robotmain.cpp +# object/task/task.cpp +# object/task/taskadvance.cpp +# object/task/taskbuild.cpp +# object/task/taskfire.cpp +# object/task/taskfireant.cpp +# object/task/taskflag.cpp +# object/task/taskgoto.cpp +# object/task/taskgungoal.cpp +# object/task/taskinfo.cpp +# object/task/taskmanager.cpp +# object/task/taskmanip.cpp +# object/task/taskpen.cpp +# object/task/taskrecover.cpp +# object/task/taskreset.cpp +# object/task/tasksearch.cpp +# object/task/taskshield.cpp +# object/task/taskspiderexplo.cpp +# object/task/tasktake.cpp +# object/task/taskterraform.cpp +# object/task/taskturn.cpp +# object/task/taskwait.cpp +# physics/physics.cpp +# script/cbottoken.cpp +# script/cmdtoken.cpp +# script/script.cpp +sound/sound.cpp +# ui/button.cpp +# ui/check.cpp +# ui/color.cpp +# ui/compass.cpp +# ui/control.cpp +# ui/displayinfo.cpp +# ui/displaytext.cpp +# ui/edit.cpp +# ui/editvalue.cpp +# ui/gauge.cpp +# ui/group.cpp +# ui/image.cpp +# ui/interface.cpp +# ui/key.cpp +# ui/label.cpp +# ui/list.cpp +# ui/maindialog.cpp +# ui/mainmap.cpp +# ui/mainshort.cpp +# ui/map.cpp +# ui/scroll.cpp +# ui/shortcut.cpp +# ui/slider.cpp +# ui/studio.cpp +# ui/target.cpp +# ui/window.cpp +) # Change to DirectX SDK directory set(DXSDK_DIR "c:/dxsdk") -include_directories(${DXSDK_DIR}/include .) +# Configure options +option(DEBUG "Enable debug output" ON) + +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(PLATFORM_WINDOWS 1) + set(PLATFORM_LINUX 0) + set(PLATFORM_OTHER 0) +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(PLATFORM_WINDOWS 0) + set(PLATFORM_LINUX 1) + set(PLATFORM_OTHER 0) +else() + set(PLATFORM_WINDOWS 0) + set(PLATFORM_LINUX 0) + set(PLATFORM_OTHER 1) +endif() + +# Configure file +configure_file(common/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/common/config.h) + +# #defines needed for old target +add_definitions(-DSTRICT -DD3D_OVERLOADS) + +include_directories(${DXSDK_DIR}/include . ${CMAKE_CURRENT_BINARY_DIR}) link_directories(${CMAKE_CURRENT_SOURCE_DIR}/CBot ${DXSDK_DIR}/lib) -set( LIBS -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 + +# Old target +set(OLD_LIBS -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lwinmm - ${DXSDK_DIR}/lib/ddraw.lib ${DXSDK_DIR}/lib/dinput.lib ${DXSDK_DIR}/lib/dxguid.lib ${DXSDK_DIR}/lib/d3d8.lib ${DXSDK_DIR}/lib/dsound.lib ) + ${DXSDK_DIR}/lib/ddraw.lib ${DXSDK_DIR}/lib/dinput.lib ${DXSDK_DIR}/lib/dxguid.lib ${DXSDK_DIR}/lib/d3d8.lib ${DXSDK_DIR}/lib/dsound.lib) + +add_executable(colobot_old ${OLD_SOURCES}) + +target_link_libraries(colobot_old CBot ${OLD_LIBS}) -# To build with libwine: -# include_directories(/usr/include/wine/windows /usr/include/wine/msvcrt) -# set(LIBS -lwine) -add_executable(colobot ${SOURCES}) +# New target +set(NEW_LIBS ${SDL_LIBRARY} ${SDLIMAGE_LIBRARY} ${OPENGL_LIBRARY}) -target_link_libraries(colobot CBot ${LIBS}) +add_executable(colobot_new ${NEW_SOURCES}) +target_link_libraries(colobot_new ${NEW_LIBS}) diff --git a/src/app/app.cpp b/src/app/app.cpp index 0938f2a..726d32d 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -19,5 +19,507 @@ #include "app/app.h" +#include "app/system.h" +#include "common/iman.h" -// TODO implementation + +#include <SDL/SDL.h> +#include <SDL/SDL_image.h> + + +/** + * \struct ApplicationPrivate Private data of CApplication class + * + * Contains SDL-specific variables that should not be visible outside application module. + */ +struct ApplicationPrivate +{ + //! Display surface + SDL_Surface *surface; + //! Currently handled event + SDL_Event currentEvent; + //! Joystick + SDL_Joystick *joystick; + //! Index of joystick device + int joystickDevice; + + ApplicationPrivate() + { + memset(¤tEvent, 0, sizeof(SDL_Event)); + surface = NULL; + joystick = NULL; + joystickDevice = 0; + } +}; + + +CApplication::CApplication() +{ + m_private = new ApplicationPrivate(); + m_exitCode = 0; + + m_iMan = new CInstanceManager(); + m_event = new CEvent(m_iMan); + + m_engine = 0; + m_robotMain = 0; + m_sound = 0; + + m_keyState = 0; + m_axeKey = Math::Vector(0.0f, 0.0f, 0.0f); + m_axeJoy = Math::Vector(0.0f, 0.0f, 0.0f); + + m_vidMemTotal = 0; + m_active = false; + m_activateApp = false; + m_ready = false; + m_joystick = false; + m_time = 0.0f; + + for (int i = 0; i < 32; i++) + { + m_joyButton[i] = false; + } + + m_windowTitle = "COLOBOT"; + + m_appUseZBuffer = true; + m_appUseStereo = true; + m_showStats = false; + m_debugMode = false; + m_audioState = true; + m_audioTrack = true; + m_niceMouse = false; + m_setupMode = true; + + ResetKey(); +} + +CApplication::~CApplication() +{ + delete m_private; + m_private = NULL; + + delete m_iMan; + m_iMan = NULL; +} + +Error CApplication::ParseArguments(int argc, char *argv[]) +{ + for (int i = 1; i < argc; ++i) + { + std::string arg = argv[i]; + + if (arg == "-debug") + { + m_showStats = true; + SetDebugMode(true); + } + else if (arg == "-audiostate") + { + m_audioState = false; + } + else if (arg == "-audiotrack") + { + m_audioTrack = false; + } + // TODO else {} report invalid argument + } + + return ERR_OK; +} + +bool CApplication::Create() +{ +/* +TODO + Full screen by default unless in debug mode + if (! m_debugMode) + m_deviceConfig.fullScreen = true; + + int full = 0; + if (GetProfileInt("Device", "FullScreen", full)) + m_deviceConfig.fullScreen = full == 1; +*/ + + // Temporarily -- only in windowed mode + m_deviceConfig.fullScreen = false; + +/* +TODO + // Create the 3D engine. + m_engine = new CEngine(m_iMan, this); + + // Initialize the app's custom scene stuff + if (! m_engine->OneTimeSceneInit()) + { + SystemDialog(SDT_ERROR, "COLOBOT - Error", m_engine->RetError()); + return false; + } + + // Create the sound instance. + m_sound = new CSound(m_iMan); + + // Create the robot application. + m_robotMain = new CRobotMain(m_iMan); +*/ + + + Uint32 initFlags = SDL_INIT_VIDEO; + if (m_joystick) + initFlags |= SDL_INIT_JOYSTICK; + + if (SDL_Init(initFlags) < 0) + { + SystemDialog( SDT_ERROR, "COLOBOT - Error", "SDL initialization error:\n" + std::string(SDL_GetError()) ); + return false; + } + + const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo(); + if (! videoInfo) + { + SystemDialog( SDT_ERROR, "COLOBOT - Error", "SDL error while getting video info:\n " + std::string(SDL_GetError()) ); + return false; + } + + Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE; + + if (m_deviceConfig.resizeable) + videoFlags |= SDL_RESIZABLE; + + // Use hardware surface if available + if (videoInfo->hw_available) + videoFlags |= SDL_HWSURFACE; + else + videoFlags |= SDL_SWSURFACE; + + // Enable hardware blit if available + if (videoInfo->blit_hw) + videoFlags |= SDL_HWACCEL; + + if (m_deviceConfig.fullScreen) + videoFlags |= SDL_FULLSCREEN; + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) == 0) + { + SystemDialog( SDT_ERROR, "COLOBOT - Error", std::string("SDL_Image initialization error:\n") + + std::string(IMG_GetError()) ); + return false; + } + + m_private->surface = SDL_SetVideoMode(m_deviceConfig.width, m_deviceConfig.height, + m_deviceConfig.bpp, videoFlags); + + if (! m_private->surface) + { + SystemDialog( SDT_ERROR, "COLOBT - Error", std::string("SDL error while setting video mode:\n") + + std::string(SDL_GetError()) ); + return false; + } + + SDL_WM_SetCaption(m_windowTitle.c_str(), m_windowTitle.c_str()); + + SDL_EnableUNICODE(1); + + +/* +TODO + + InitJoystick(); + + if ( !GetProfileInt("Setup", "Sound3D", b3D) ) + { + b3D = true; + } + m_pSound->SetDebugMode(m_bDebugMode); + m_pSound->Create(m_hWnd, b3D); + m_pSound->CacheAll(); + m_pSound->SetState(m_bAudioState); + m_pSound->SetAudioTrack(m_bAudioTrack); + m_pSound->SetCDpath(m_CDpath); + + // First execution? + if ( !GetProfileInt("Setup", "ObjectDirty", iValue) ) + { + m_pD3DEngine->FirstExecuteAdapt(true); + } + + // Creates the file colobot.ini at the first execution. + m_pRobotMain->CreateIni(); + + m_pRobotMain->ChangePhase(PHASE_WELCOME2); + + m_engine->TimeInit(); +*/ + + // The app is ready to go + m_ready = true; + + return true; +} + +void CApplication::Destroy() +{ + if (m_private->joystick != NULL) + { + SDL_JoystickClose(m_private->joystick); + m_private->joystick = NULL; + } + + SDL_FreeSurface(m_private->surface); + m_private->surface = NULL; + + IMG_Quit(); + + SDL_Quit(); +} + +int CApplication::Run() +{ + m_active = true; + + while (m_private->currentEvent.type != SDL_QUIT) + { + // Use SDL_PeepEvents() if the app is active, so we can use idle time to + // render the scene. Else, use SDL_PollEvent() to avoid eating CPU time. + int count = 0; + if (m_active) + { + SDL_PumpEvents(); + count = SDL_PeepEvents(&m_private->currentEvent, 1, SDL_GETEVENT, SDL_ALLEVENTS); + } + else + { + SDL_PollEvent(&m_private->currentEvent); + } + + // If received an event + if ((m_active && count > 0) || (!m_active)) + { + ParseEvent(); + } + + // Render a frame during idle time (no messages are waiting) + if (m_active && m_ready) + { + Event event; + while (m_event->GetEvent(event)) + { + if (event.event == EVENT_QUIT) + { + goto end; // exit both loops + } + + //m_robotMain->EventProcess(event); + } + + //if ( !RetNiceMouse()) + //{ + // SetMouseType(m_engine->RetMouseType()); + //} + + // If an error occurs, push quit event to the queue + if (! Render()) + { + SDL_Event quitEvent; + memset(&quitEvent, 0, sizeof(SDL_Event)); + quitEvent.type = SDL_QUIT; + SDL_PushEvent(&quitEvent); + } + } + } + +end: + //m_sound->StopMusic(); + Destroy(); + + return m_exitCode; +} + +void CApplication::ParseEvent() +{ +/* Event event; + + if (m_private->currentEvent.type == SDL_MOUSEBUTTONDOWN) + { + if (m_private->currentEvent.button.button == SDL_BUTTON_LEFT) + event.event = EVENT_LBUTTONDOWN; + else if (m_private->currentEvent.button.button == SDL_BUTTON_RIGHT) + event.event = EVENT_RBUTTONDOWN; + } + else if (m_private->currentEvent.type == SDL_MOUSEBUTTONUP) + { + if (m_private->currentEvent.button.button == SDL_BUTTON_LEFT) + event.event = EVENT_LBUTTONUP; + else if (m_private->currentEvent.button.button == SDL_BUTTON_RIGHT) + event.event = EVENT_RBUTTONUP; + } + else if (m_private->currentEvent.type == SDL_MOUSEMOTION) + { + event.event = EVENT_MOUSEMOVE; + } + else if (m_private->currentEvent.type == SDL_KEYDOWN) + { + event.event = EVENT_KEYDOWN; + } + else if (m_private->currentEvent.type == SDL_KEYUP) + { + event.event = EVENT_KEYUP; + } + + if (m_robotMain != NULL && event.event != EVENT_NULL) + { + m_robotMain->EventProcess(event); + } + if (m_engine != NULL) + { + m_engine->MsgProc( hWnd, uMsg, wParam, lParam ); + } + + ProcessEvent(event);*/ +} + +void CApplication::ProcessEvent(Event event) +{ + +} + +bool CApplication::Render() +{ + bool result = m_engine->Render(); + if (! result) + return false; + + if (m_deviceConfig.doubleBuf) + SDL_GL_SwapBuffers(); + + return true; +} + +void CApplication::Pause(bool pause) +{ + // TODO +} + +void CApplication::SetMousePos(Math::Point pos) +{ + // TODO +} + +void CApplication::StepSimulation(float rTime) +{ + // TODO +} + +void SetShowStat(bool show) +{ + // TODO +} + +bool CApplication::RetShowStat() +{ + // TODO + return false; +} + +void CApplication::SetDebugMode(bool mode) +{ + // TODO +} + +bool CApplication::RetDebugMode() +{ + // TODO + return false; +} + +bool CApplication::RetSetupMode() +{ + // TODO + return false; +} + +void CApplication::FlushPressKey() +{ + // TODO +} + +void CApplication::ResetKey() +{ + // TODO +} + +void CApplication::SetKey(int keyRank, int option, int key) +{ + // TODO +} + +int CApplication::RetKey(int keyRank, int option) +{ + // TODO + return 0; +} + +void CApplication::SetJoystick(bool enable) +{ + // TODO +} + +bool CApplication::RetJoystick() +{ + // TODO + return false; +} + +void SetMouseType(Gfx::MouseType type) +{ + // TODO +} + +void SetNiceMouse(bool nice) +{ + // TODO +} + +bool CApplication::RetNiceMouse() +{ + return false; +} + +bool CApplication::RetNiceMouseCap() +{ + return false; +} + +bool CApplication::WriteScreenShot(char *filename, int width, int height) +{ + // TODO +} + +void CApplication::InitText() +{ + // TODO +} + +void CApplication::DrawSuppl() +{ + // TODO +} + +void CApplication::ShowStats() +{ + // TODO +} + +void CApplication::OutputText(long x, long y, char* str) +{ + // TODO +} diff --git a/src/app/app.h b/src/app/app.h index ee4965d..ee6184f 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -21,40 +21,59 @@ #include "common/misc.h" +#include "graphics/common/device.h" #include "graphics/common/engine.h" +#include <string> + class CInstanceManager; class CEvent; class CRobotMain; class CSound; +struct ApplicationPrivate; + +/** + * \class CApplication Main application + * + * This class is responsible for creating and handling main application window, + * receiving events, etc. + * + * ... + */ class CApplication { public: + //! Constructor (can only be called once!) CApplication(); + //! Destructor ~CApplication(); +public: + //! Parses commandline arguments + Error ParseArguments(int argc, char *argv[]); + //! Initializes the application + bool Create(); + //! Main event loop + int Run(); + protected: - //LRESULT OnQuerySuspend( DWORD dwFlags ); - //LRESULT OnResumeSuspend( DWORD dwData ); + //! Cleans up before exit + void Destroy(); + //! Processes an SDL event to Event struct + void ParseEvent(); + //! Handles some incoming events + void ProcessEvent(Event event); + //! Renders the image in window + bool Render(); public: - Error RegQuery(); - Error AudioQuery(); - Error CheckMistery(char *strCmdLine); - int GetVidMemTotal(); - bool IsVideo8MB(); - bool IsVideo32MB(); - //HRESULT Create( HINSTANCE, TCHAR* ); - int Run(); - //LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); void Pause(bool pause); - //Math::Point ConvPosToInterface(HWND hWnd, LPARAM lParam); + void StepSimulation(float rTime); + void SetMousePos(Math::Point pos); - void StepSimul(float rTime); - char* RetCDpath(); void SetShowStat(bool show); bool RetShowStat(); @@ -62,30 +81,21 @@ public: bool RetDebugMode(); bool RetSetupMode(); - bool EnumDevices(char *bufDevices, int lenDevices, char *bufModes, int lenModes, int &totalDevices, int &selectDevices, int &totalModes, int &selectModes); - bool RetFullScreen(); - bool ChangeDevice(char *device, char *mode, bool bFull); - void FlushPressKey(); void ResetKey(); void SetKey(int keyRank, int option, int key); int RetKey(int keyRank, int option); - void SetJoystick(bool bEnable); + void SetJoystick(bool enable); bool RetJoystick(); void SetMouseType(Gfx::MouseType type); - void SetNiceMouse(bool bNice); + void SetNiceMouse(bool nice); bool RetNiceMouse(); bool RetNiceMouseCap(); bool WriteScreenShot(char *filename, int width, int height); - //bool GetRenderDC(HDC &hDC); - //bool ReleaseRenderDC(HDC &hDC); - //PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp); - //bool CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC); - protected: //HRESULT ConfirmDevice( DDCAPS* pddDriverCaps, D3DDEVICEDESC7* pd3dDeviceDesc ); //HRESULT Initialize3DEnvironment(); @@ -102,55 +112,42 @@ protected: void OutputText(long x, long y, char* str); protected: + //! Private (SDL-dependent data) + ApplicationPrivate* m_private; CInstanceManager* m_iMan; + Gfx::DeviceConfig m_deviceConfig; + Gfx::CEngine* m_engine; CEvent* m_event; + CRobotMain* m_robotMain; + CSound* m_sound; - //HINSTANCE m_instance; - //HWND m_hWnd; - //D3DEnum_DeviceInfo* m_pDeviceInfo; - //LPDIRECTDRAW7 m_pDD; - //LPDIRECT3D7 m_pD3D; - //LPDIRECT3DDEVICE7 m_pD3DDevice; - //LPDIRECTDRAWSURFACE7 m_pddsRenderTarget; - //DDSURFACEDESC2 m_ddsdRenderTarget; - //LPDIRECTDRAWSURFACE7 m_pddsDepthBuffer; - - //HANDLE m_thread; - //DWORD m_threadId; + //! Code to return at exit + int m_exitCode; - char m_CDpath[100]; - - //CD3DFramework7* m_pFramework; bool m_active; bool m_activateApp; bool m_ready; bool m_joystick; + std::string m_windowTitle; long m_vidMemTotal; - char* m_strWindowTitle; - bool m_bAppUseZBuffer; - bool m_bAppUseStereo; - bool m_bShowStats; - bool m_bDebugMode; - bool m_bAudioState; - bool m_bAudioTrack; - bool m_bNiceMouse; - bool m_bSetupMode; - //HRESULT (*m_fnConfirmDevice)(DDCAPS*, D3DDEVICEDESC7*); - -public: - Gfx::CEngine* m_pD3DEngine; - CRobotMain* m_pRobotMain; - CSound* m_pSound; + bool m_appUseZBuffer; + bool m_appUseStereo; + bool m_showStats; + bool m_debugMode; + bool m_audioState; + bool m_audioTrack; + bool m_niceMouse; + bool m_setupMode; int m_keyState; Math::Vector m_axeKey; Math::Vector m_axeJoy; bool m_joyButton[32]; Math::Point m_mousePos; - long m_mshMouseWheel; + long m_mouseWheel; - float m_aTime; + float m_time; long m_key[50][2]; }; diff --git a/src/app/main.cpp b/src/app/main.cpp new file mode 100644 index 0000000..28d21ee --- /dev/null +++ b/src/app/main.cpp @@ -0,0 +1,41 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +// main.cpp + +#include "app/app.h" +#include "app/system.h" +#include "common/misc.h" +#include "common/restext.h" + + +//! Entry point to the program +int main(int argc, char *argv[]) +{ + CApplication app; // single instance of the application + + Error err = app.ParseArguments(argc, argv); + if (err != ERR_OK) + { + SystemDialog(SDT_ERROR, "COLOBOT", "Invalid commandline arguments!\n"); + } + + if (! app.Create()) + return 0; + + return app.Run(); +} diff --git a/src/app/system.cpp b/src/app/system.cpp new file mode 100644 index 0000000..4f7cd26 --- /dev/null +++ b/src/app/system.cpp @@ -0,0 +1,253 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +// system.cpp + +#include "app/system.h" + +#include "common/config.h" + +#if defined(PLATFORM_WINDOWS) +#include <windows.h> +#elif defined(PLATFORM_LINUX) +#include <cstdlib> +#else +#include <iostream> +#endif + + + +SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message); +SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message); +SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message); + +/** + * Displays a system dialog with info, error, question etc. message. + * + * \param type type of dialog + * \param message text of message (in UTF-8) + * \param title dialog title (in UTF-8) + * \returns result (which button was clicked) + */ +SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) +{ + #if defined(PLATFORM_WINDOWS) + return SystemDialog_Windows(type, title, message); + #elif defined(PLATFORM_LINUX) + return SystemDialog_Linux(type, title, message); + #else + return SystemDialog_Other(type, title, message); + #endif +} + + + +#if defined(PLATFORM_WINDOWS) + +// Convert a wide Unicode string to an UTF8 string +std::string UTF8_Encode_Windows(const std::wstring &wstr) +{ + int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL); + std::string strTo(size_needed, 0); + WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL); + return strTo; +} + +// Convert an UTF8 string to a wide Unicode String +std::wstring UTF8_Decode_Windows(const std::string &str) +{ + int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0); + std::wstring wstrTo(size_needed, 0); + MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed); + return wstrTo; +} + +SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message) +{ + unsigned int windowsType = 0; + std::wstring windowsMessage = UTF8_Decode_Windows(message); + std::wstring windowsTitle = UTF8_Decode_Windows(title); + + switch (type) + { + case SDT_INFO: + default: + windowsType = MB_ICONINFORMATION|MB_OK; + break; + case SDT_WARNING: + windowsType = MB_ICONWARNING|MB_OK; + break; + case SDT_ERROR: + windowsType = MB_ICONERROR|MB_OK; + break; + case SDT_YES_NO: + windowsType = MB_ICONQUESTION|MB_YESNO; + break; + case SDT_OK_CANCEL: + windowsType = MB_ICONWARNING|MB_OKCANCEL; + break; + } + + switch (MessageBoxW(NULL, windowsMessage.c_str(), windowsTitle.c_str(), windowsType)) + { + case IDOK: + return SDR_OK; + case IDCANCEL: + return SDR_CANCEL; + case IDYES: + return SDR_YES; + case IDNO: + return SDR_NO; + default: + break; + } + + return SDR_OK; +} + +#elif defined(PLATFORM_LINUX) + +SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message) +{ + std::string options = ""; + switch (type) + { + case SDT_INFO: + default: + options = "--info"; + break; + case SDT_WARNING: + options = "--warning"; + break; + case SDT_ERROR: + options = "--error"; + break; + case SDT_YES_NO: + options = "--question --ok-label=\"Yes\" --cancel-label=\"No\""; + break; + case SDT_OK_CANCEL: + options = "--question --ok-label=\"OK\" --cancel-label=\"Cancel\""; + break; + } + + std::string command = "zenity " + options + " --text=\"" + message + "\" --title=\"" + title + "\""; + int code = system(command.c_str()); + + SystemDialogResult result = SDR_OK; + switch (type) + { + case SDT_YES_NO: + result = code ? SDR_NO : SDR_YES; + break; + case SDT_OK_CANCEL: + result = code ? SDR_CANCEL : SDR_OK; + break; + default: + break; + } + + return result; +} + +#else + +SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message) +{ + switch (type) + { + case SDT_INFO: + std::cout << "INFO: "; + break; + case SDT_WARNING: + std::cout << "WARNING:"; + break; + case SDT_ERROR: + std::cout << "ERROR: "; + break; + case SDT_YES_NO: + case SDT_OK_CANCEL: + std::cout << "QUESTION: "; + break; + } + + std::cout << message << std::endl; + + std::string line; + + SystemDialogResult result = SDR_OK; + + bool done = false; + while (!done) + { + switch (type) + { + case SDT_INFO: + case SDT_WARNING: + case SDT_ERROR: + std::cout << "Press ENTER to continue"; + break; + + case SDT_YES_NO: + std::cout << "Type 'Y' for Yes or 'N' for No"; + break; + + case SDT_OK_CANCEL: + std::cout << "Type 'O' for OK or 'C' for Cancel"; + break; + } + + std::getline(std::cin, line); + + switch (type) + { + case SDT_INFO: + case SDT_WARNING: + case SDT_ERROR: + done = true; + break; + + case SDT_YES_NO: + if (line == "Y" || line == "y") + { + result = SDR_YES; + done = true; + } + else if (line == "N" || line == "n") + { + result = SDR_NO; + done = true; + } + break; + + case SDT_OK_CANCEL: + if (line == "O" || line == "o") + { + done = true; + result = SDR_OK; + } + else if (line == "C" || line == "c") + { + done = true; + result = SDR_CANCEL; + } + break; + } + } + + return result; +} +#endif // if defined(PLATFORM_WINDOWS) diff --git a/src/app/system.h b/src/app/system.h new file mode 100644 index 0000000..fd1c051 --- /dev/null +++ b/src/app/system.h @@ -0,0 +1,57 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +// system.h + +#pragma once + + +#include <string> + + +/** + * \enum SysDialogType Type of system dialog + */ +enum SystemDialogType +{ + //! Information message + SDT_INFO, + //! Warning message + SDT_WARNING, + //! Error message + SDT_ERROR, + //! Yes/No question + SDT_YES_NO, + //! Ok/Cancel question + SDT_OK_CANCEL +}; + +/** + * \enum SysDialogResult Result of system dialog + * + * Means which button was pressed. + */ +enum SystemDialogResult +{ + SDR_OK, + SDR_CANCEL, + SDR_YES, + SDR_NO +}; + +//! Displays a system dialog +SystemDialogResult SystemDialog(SystemDialogType, const std::string &title, const std::string &message); diff --git a/src/common/config.h.cmake b/src/common/config.h.cmake new file mode 100644 index 0000000..b066387 --- /dev/null +++ b/src/common/config.h.cmake @@ -0,0 +1,8 @@ +#pragma once
+
+// Macros set by CMake
+#cmakedefine DEBUG
+#cmakedefine PLATFORM_WINDOWS @PLATFORM_WINDOWS@
+#cmakedefine PLATFORM_LINUX @PLATFORM_LINUX@
+#cmakedefine PLATFORM_OTHER @PLATFORM_OTHER@
+
diff --git a/src/common/event.cpp b/src/common/event.cpp index b323e43..0a56fb9 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -16,15 +16,22 @@ // event.cpp
-
-#include <windows.h>
-#include <stdio.h>
-
-#include "common/struct.h"
#include "common/iman.h"
#include "common/event.h"
+#include <string.h>
+
+Event::Event()
+{
+ event = EVENT_NULL;
+ param = 0;
+ axeX = 0.0f;
+ axeY = 0.0f;
+ axeZ = 0.0f;
+ keyState = 0;
+ rTime = 0.0f;
+}
// Object's constructor.
@@ -57,7 +64,7 @@ void CEvent::Flush() void CEvent::MakeEvent(Event &event, EventMsg msg)
{
- ZeroMemory(&event, sizeof(Event));
+ memset(&event, 0, sizeof(Event));
event.event = msg;
}
diff --git a/src/common/event.h b/src/common/event.h index 0dc6ced..95e303c 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -538,6 +538,8 @@ struct Event float axeZ; // control the Z axis (-1 .. 1)
short keyState; // state of the keyboard (KS_ *)
float rTime; // relative time
+
+ Event();
};
@@ -620,8 +622,6 @@ public: bool GetEvent(Event &event);
protected:
-
-protected:
CInstanceManager* m_iMan;
Event m_fifo[MAXEVENT];
diff --git a/src/common/iman.cpp b/src/common/iman.cpp index 139f56a..53735a4 100644 --- a/src/common/iman.cpp +++ b/src/common/iman.cpp @@ -17,7 +17,6 @@ // iman.cpp
-#include <windows.h>
#include <stdio.h>
#include "common/struct.h"
diff --git a/src/common/restext.h b/src/common/restext.h index 019f67a..241951a 100644 --- a/src/common/restext.h +++ b/src/common/restext.h @@ -19,10 +19,10 @@ #pragma once
+#include "common/event.h"
-#include "old/d3dengine.h"
-#include "common/event.h"
+class CD3DEngine;
diff --git a/src/common/struct.h b/src/common/struct.h index eb0078b..b143334 100644 --- a/src/common/struct.h +++ b/src/common/struct.h @@ -19,8 +19,6 @@ #pragma once
-#include <d3d.h>
-
#include <math/vector.h>
diff --git a/src/graphics/common/camera.h b/src/graphics/common/camera.h index 59e7609..28397b9 100644 --- a/src/graphics/common/camera.h +++ b/src/graphics/common/camera.h @@ -20,7 +20,6 @@ #pragma once #include "engine.h" -#include "common/struct.h" #include "common/event.h" diff --git a/src/graphics/common/cloud.h b/src/graphics/common/cloud.h index 579eb9a..9ca8c11 100644 --- a/src/graphics/common/cloud.h +++ b/src/graphics/common/cloud.h @@ -19,10 +19,10 @@ #pragma once -#include "common/struct.h" #include "common/event.h" #include "graphics/common/color.h" #include "math/point.h" +#include "math/vector.h" diff --git a/src/graphics/common/device.cpp b/src/graphics/common/device.cpp new file mode 100644 index 0000000..2e3db61 --- /dev/null +++ b/src/graphics/common/device.cpp @@ -0,0 +1,14 @@ +#include "graphics/common/device.h" + +//! Sets the default values +Gfx::DeviceConfig::DeviceConfig() +{ + width = 800; + height = 600; + bpp = 16; + fullScreen = false; + resizeable = false; + hardwareAccel = true; + doubleBuf = true; + noFrame = false; +}
\ No newline at end of file diff --git a/src/graphics/common/device.h b/src/graphics/common/device.h index a8bf32c..cd52fa5 100644 --- a/src/graphics/common/device.h +++ b/src/graphics/common/device.h @@ -22,6 +22,28 @@ namespace Gfx { +struct DeviceConfig +{ + //! Screen width + int width; + //! Screen height + int height; + //! Bits per pixel + int bpp; + //! Full screen + bool fullScreen; + //! Resizeable window + bool resizeable; + //! Hardware acceleration + bool hardwareAccel; + //! Double buffering + bool doubleBuf; + //! No window frame (also set with full screen) + bool noFrame; + + DeviceConfig(); +}; + class CDevice { // TODO diff --git a/src/graphics/common/engine.cpp b/src/graphics/common/engine.cpp index acd0995..29857ce 100644 --- a/src/graphics/common/engine.cpp +++ b/src/graphics/common/engine.cpp @@ -19,5 +19,55 @@ #include "graphics/common/engine.h" +#include <GL/gl.h> +#include <GL/glu.h> + // TODO implementation + +Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app) +{ + // TODO +} + +Gfx::CEngine::~CEngine() +{ + // TODO +} + +int Gfx::CEngine::Render() +{ + /* Just a hello world for now */ + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glShadeModel(GL_SMOOTH); + glDisable(GL_DEPTH_TEST); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(-10.0f, 10.0f, -10.0f, 10.0f); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + //glTranslatef(0.0f, 0.0f, -6.0f); + + glBegin(GL_TRIANGLES); + { + glColor3f(1.0f, 0.0f, 0.0f); + glVertex2f(-2.0f, -1.0f); + glColor3f(0.0f, 1.0f, 0.0f); + glVertex2f(2.0f, -1.0f); + glColor3f(0.0f, 0.0f, 1.0f); + glVertex2f(0.0f, 1.5f); + } + glEnd(); + + glFlush(); + + return 1; +} diff --git a/src/graphics/common/lightning.h b/src/graphics/common/lightning.h index 2077954..8edf9e5 100644 --- a/src/graphics/common/lightning.h +++ b/src/graphics/common/lightning.h @@ -20,11 +20,11 @@ #pragma once #include "common/misc.h" -#include "common/struct.h" -#include "object/object.h" +#include "math/vector.h" class CInstanceManager; +class CObject; class CSound; diff --git a/src/graphics/common/model.h b/src/graphics/common/model.h index d67c71a..349c15c 100644 --- a/src/graphics/common/model.h +++ b/src/graphics/common/model.h @@ -20,7 +20,6 @@ #pragma once #include "engine.h" -#include "common/struct.h" #include "common/event.h" #include "modfile.h" #include "vertex.h" diff --git a/src/graphics/common/particle.h b/src/graphics/common/particle.h index 9e9fd36..4047cb5 100644 --- a/src/graphics/common/particle.h +++ b/src/graphics/common/particle.h @@ -305,7 +305,7 @@ protected: void DrawParticuleWheel(int i); CObject* SearchObjectGun(Math::Vector old, Math::Vector pos, ParticuleType type, CObject *father); CObject* SearchObjectRay(Math::Vector pos, Math::Vector goal, ParticuleType type, CObject *father); - void Play(Sound sound, Math::Vector pos, float amplitude); + void Play(Snd::Sound sound, Math::Vector pos, float amplitude); bool TrackMove(int i, Math::Vector pos, float progress); void TrackDraw(int i, ParticuleType type); diff --git a/src/graphics/common/planet.h b/src/graphics/common/planet.h index 2bf4d99..4ffccfc 100644 --- a/src/graphics/common/planet.h +++ b/src/graphics/common/planet.h @@ -19,7 +19,6 @@ #pragma once -#include "common/struct.h" #include "common/event.h" #include "math/point.h" diff --git a/src/graphics/common/pyro.h b/src/graphics/common/pyro.h index 704febf..e6b5844 100644 --- a/src/graphics/common/pyro.h +++ b/src/graphics/common/pyro.h @@ -19,9 +19,11 @@ #pragma once -#include "graphics/common/engine.h" -#include "object/object.h" #include "common/misc.h" +#include "graphics/common/engine.h" +//#include "object/object.h" +// TEMPORARILY! +enum ObjectType {}; class CInstanceManager; @@ -93,7 +95,7 @@ public: CPyro(CInstanceManager* iMan); ~CPyro(); - void DeleteObject(bool bAll=FALSE); + void DeleteObject(bool bAll=false); bool Create(PyroType type, CObject* pObj, float force=1.0f); bool EventProcess(const Event &event); Error IsEnded(); diff --git a/src/object/brain.cpp b/src/object/brain.cpp index 1ffe1b5..afc9903 100644 --- a/src/object/brain.cpp +++ b/src/object/brain.cpp @@ -62,7 +62,7 @@ #include "ui/window.h"
#include "ui/displaytext.h"
#include "old/text.h"
-#include "sound/sound.h"
+#include "old/sound.h"
#include "old/particule.h"
#include "script/cmdtoken.h"
diff --git a/src/object/object.cpp b/src/object/object.cpp index 10cc190..6931bd2 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -85,7 +85,7 @@ #include "ui/displaytext.h"
#include "script/cmdtoken.h"
#include "script/cbottoken.h"
-#include "sound/sound.h"
+#include "old/sound.h"
#include "object/object.h"
diff --git a/src/object/object.h b/src/object/object.h index 9d77ae1..735da8a 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -21,7 +21,7 @@ #include "old/d3dengine.h"
#include "old/camera.h"
-#include "sound/sound.h"
+#include "old/sound.h"
class CInstanceManager;
diff --git a/src/object/robotmain.cpp b/src/object/robotmain.cpp index a897349..902c1cb 100644 --- a/src/object/robotmain.cpp +++ b/src/object/robotmain.cpp @@ -69,7 +69,7 @@ #include "ui/edit.h"
#include "ui/displaytext.h"
#include "old/text.h"
-#include "sound/sound.h"
+#include "old/sound.h"
#include "script/cbottoken.h"
#include "script/cmdtoken.h"
#include "object/mainmovie.h"
diff --git a/src/old/blitz.cpp b/src/old/blitz.cpp index b73bd3e..15488d2 100644 --- a/src/old/blitz.cpp +++ b/src/old/blitz.cpp @@ -35,7 +35,7 @@ #include "old/camera.h"
#include "object/auto/auto.h"
#include "object/auto/autopara.h"
-#include "sound/sound.h"
+#include "old/sound.h"
#include "old/blitz.h"
diff --git a/src/old/d3dapp.cpp b/src/old/d3dapp.cpp index 0614fc3..7f04279 100644 --- a/src/old/d3dapp.cpp +++ b/src/old/d3dapp.cpp @@ -35,7 +35,7 @@ #include "old/math3d.h"
#include "old/joystick.h"
#include "object/robotmain.h"
-#include "sound/sound.h"
+#include "old/sound.h"
#include "old/d3dapp.h"
// fix for "MSH_MOUSEWHEEL undefined" error
diff --git a/src/old/d3dengine.cpp b/src/old/d3dengine.cpp index 305adc2..e28483d 100644 --- a/src/old/d3dengine.cpp +++ b/src/old/d3dengine.cpp @@ -44,7 +44,7 @@ #include "old/cloud.h"
#include "old/blitz.h"
#include "old/planet.h"
-#include "sound/sound.h"
+#include "old/sound.h"
diff --git a/src/old/particule.cpp b/src/old/particule.cpp index 3fb7791..8c8a162 100644 --- a/src/old/particule.cpp +++ b/src/old/particule.cpp @@ -38,7 +38,7 @@ #include "object/auto/auto.h"
#include "object/robotmain.h"
#include "old/terrain.h"
-#include "sound/sound.h"
+#include "old/sound.h"
#include "old/water.h"
#include "old/particule.h"
diff --git a/src/old/particule.h b/src/old/particule.h index 004dece..23d0899 100644 --- a/src/old/particule.h +++ b/src/old/particule.h @@ -21,7 +21,7 @@ #include "math/point.h"
#include "old/d3dengine.h"
-#include "sound/sound.h"
+#include "old/sound.h"
class CInstanceManager;
diff --git a/src/old/pyro.cpp b/src/old/pyro.cpp index 72f370e..fc61e62 100644 --- a/src/old/pyro.cpp +++ b/src/old/pyro.cpp @@ -39,7 +39,7 @@ #include "object/motion/motion.h"
#include "object/motion/motionhuman.h"
#include "ui/displaytext.h"
-#include "sound/sound.h"
+#include "old/sound.h"
#include "old/pyro.h"
diff --git a/src/old/sound.cpp b/src/old/sound.cpp new file mode 100644 index 0000000..8b4089a --- /dev/null +++ b/src/old/sound.cpp @@ -0,0 +1,1659 @@ +// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+// sound.cpp
+
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <d3dtypes.h>
+#include <dsound.h>
+#include <stdio.h>
+
+#include "common/language.h"
+#include "common/struct.h"
+#include "common/iman.h"
+#include "math/geometry.h"
+#include "math/conv.h"
+#include "old/math3d.h"
+#include "old/sound.h"
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+const int LXIMAGE = 640;
+const int LYIMAGE = 480;
+
+
+
+// Header .WAV file.
+
+struct WaveHeader
+{
+ BYTE RIFF[4]; // "RIFF"
+ DWORD dwSize; // size of data to follow
+ BYTE WAVE[4]; // "WAVE"
+ BYTE fmt_[4]; // "fmt "
+ DWORD dw16; // 16
+ WORD wOne_0; // 1
+ WORD wChnls; // number of Channels
+ DWORD dwSRate; // sample Rate
+ DWORD BytesPerSec; // sample Rate
+ WORD wBlkAlign; // 1
+ WORD BitsPerSample; // sample size
+ BYTE DATA[4]; // "DATA"
+ DWORD dwDSize; // number of Samples
+};
+
+
+
+
+// Displays an error DirectSound.
+
+void DisplayError(char *name, Sound sound, HRESULT err)
+{
+ char s[100];
+ unsigned int i = err;
+ if ( err == DS_OK ) return;
+ sprintf(s, "SoundError in %s, sound=%d err=%d\n", name, sound, i);
+ OutputDebugString(s);
+
+ if ( err == DSERR_ALLOCATED ) OutputDebugString("DSERR_ALLOCATED\n");
+ if ( err == DSERR_CONTROLUNAVAIL ) OutputDebugString("DSERR_CONTROLUNAVAIL\n");
+ if ( err == DSERR_INVALIDPARAM ) OutputDebugString("DSERR_INVALIDPARAM\n");
+ if ( err == DSERR_INVALIDCALL ) OutputDebugString("DSERR_INVALIDCALL\n");
+ if ( err == DSERR_GENERIC ) OutputDebugString("DSERR_GENERIC\n");
+ if ( err == DSERR_PRIOLEVELNEEDED ) OutputDebugString("DSERR_PRIOLEVELNEEDED\n");
+ if ( err == DSERR_OUTOFMEMORY ) OutputDebugString("DSERR_OUTOFMEMORY\n");
+ if ( err == DSERR_BADFORMAT ) OutputDebugString("DSERR_BADFORMAT\n");
+ if ( err == DSERR_UNSUPPORTED ) OutputDebugString("DSERR_UNSUPPORTED\n");
+ if ( err == DSERR_NODRIVER ) OutputDebugString("DSERR_NODRIVER\n");
+ if ( err == DSERR_ALREADYINITIALIZED ) OutputDebugString("DSERR_ALREADYINITIALIZED\n");
+ if ( err == DSERR_NOAGGREGATION ) OutputDebugString("DSERR_NOAGGREGATION\n");
+ if ( err == DSERR_BUFFERLOST ) OutputDebugString("DSERR_BUFFERLOST\n");
+ if ( err == DSERR_OTHERAPPHASPRIO ) OutputDebugString("DSERR_OTHERAPPHASPRIO\n");
+ if ( err == DSERR_UNINITIALIZED ) OutputDebugString("DSERR_UNINITIALIZED\n");
+ if ( err == DSERR_NOINTERFACE ) OutputDebugString("DSERR_NOINTERFACE\n");
+ if ( err == DSERR_ACCESSDENIED ) OutputDebugString("DSERR_ACCESSDENIED\n");
+}
+
+// Returns the name of the current folder.
+
+void GetCurrentDir(char *pName, int lg)
+{
+ int i;
+
+ strncpy(pName, _pgmptr, lg-1);
+ pName[lg-1] = 0;
+
+ lg = strlen(pName);
+ if ( lg == 0 ) return;
+
+ for ( i=0 ; i<lg ; i++ )
+ {
+ pName[i] = tolower(pName[i]);
+ }
+
+ while ( lg > 0 )
+ {
+ lg --;
+ if ( pName[lg] == '\\' )
+ {
+ pName[lg+1] = 0;
+ break;
+ }
+ }
+
+ if ( lg > 6 && strcmp(pName+lg-6, "\\debug\\") == 0 )
+ {
+ pName[lg-5] = 0; // ignores the folder \debug!
+ }
+
+ if ( lg > 6 && strcmp(pName+lg-6, "\\release\\") == 0 )
+ {
+ pName[lg-7] = 0; // ignores the folder \release !
+ }
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+// Changes the volume of midi.
+// The volume is between 0 and 20!
+
+void InitMidiVolume(int volume)
+{
+ int nb, i, n;
+ MMRESULT result;
+ HMIDIOUT hmo = 0;
+
+ static int table[21] =
+ {
+ 0x00000000,
+ 0x11111111,
+ 0x22222222,
+ 0x33333333,
+ 0x44444444,
+ 0x55555555,
+ 0x66666666,
+ 0x77777777,
+ 0x88888888,
+ 0x99999999,
+ 0xAAAAAAAA,
+ 0xBBBBBBBB,
+ 0xCCCCCCCC,
+ 0xDDDDDDDD,
+ 0xEEEEEEEE,
+ 0xF222F222,
+ 0xF555F555,
+ 0xF777F777,
+ 0xFAAAFAAA,
+ 0xFDDDFDDD,
+ 0xFFFFFFFF,
+ };
+
+ if ( volume < 0 ) volume = 0;
+ if ( volume > MAXVOLUME ) volume = MAXVOLUME;
+
+ nb = midiOutGetNumDevs();
+ for ( i=0 ; i<nb ; i++ )
+ {
+ result = midiOutOpen((LPHMIDIOUT)&hmo, i, 0L, 0L, 0L);
+ if ( result != MMSYSERR_NOERROR )
+ {
+ continue;
+ }
+
+ result = midiOutSetVolume(hmo, table[volume]);
+ if ( result != MMSYSERR_NOERROR )
+ {
+ n = 1;
+ }
+ midiOutClose(hmo);
+ hmo = 0;
+ }
+}
+
+// Changes the volume of audio CD.
+// The volume is between 0 and 20!
+// Crashing in Vista. The current craft (if _SOUNDTRACKS = true) no longer crashes,
+// but this is not the correct volume which is modified!
+
+bool InitAudioTrackVolume(int volume)
+{
+#if _SOUNDTRACKS
+ MMRESULT rc; // Return code.
+ HMIXER hMixer; // Mixer handle used in mixer API calls.
+ MIXERCONTROL mxc; // Holds the mixer control data.
+ MIXERLINE mxl; // Holds the mixer line data.
+ MIXERLINECONTROLS mxlc; // Obtains the mixer control.
+
+ if ( volume < 0 ) volume = 0;
+ if ( volume > MAXVOLUME ) volume = MAXVOLUME;
+
+ // Open the mixer. This opens the mixer with a deviceID of 0. If you
+ // have a single sound card/mixer, then this will open it. If you have
+ // multiple sound cards/mixers, the deviceIDs will be 0, 1, 2, and
+ // so on.
+ rc = mixerOpen(&hMixer, 0,0,0,0);
+ if ( rc != MMSYSERR_NOERROR )
+ {
+ return false; // Couldn't open the mixer.
+ }
+
+ // Initialize MIXERLINE structure.
+ ZeroMemory(&mxl,sizeof(mxl));
+ mxl.cbStruct = sizeof(mxl);
+
+ // Specify the line you want to get. You are getting the input line
+ // here. If you want to get the output line, you need to use
+ // MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT.
+ mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
+
+ rc = mixerGetLineInfo((HMIXEROBJ)hMixer, &mxl,
+ MIXER_GETLINEINFOF_COMPONENTTYPE);
+ if ( rc != MMSYSERR_NOERROR )
+ {
+ return false; // Couldn't get the mixer line.
+ }
+
+ // Get the control.
+ ZeroMemory(&mxlc, sizeof(mxlc));
+ mxlc.cbStruct = sizeof(mxlc);
+ mxlc.dwLineID = mxl.dwLineID;
+//? mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_PEAKMETER;
+//? mxlc.dwControlType = MIXERCONTROL_CONTROLF_UNIFORM;
+ mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
+ mxlc.cControls = 1;
+ mxlc.cbmxctrl = sizeof(mxc);
+ mxlc.pamxctrl = &mxc;
+ ZeroMemory(&mxc, sizeof(mxc));
+ mxc.cbStruct = sizeof(mxc);
+ rc = mixerGetLineControls((HMIXEROBJ)hMixer,&mxlc,
+ MIXER_GETLINECONTROLSF_ONEBYTYPE);
+//? MIXER_GETLINECONTROLSF_ALL);
+ if ( rc != MMSYSERR_NOERROR )
+ {
+ return false; // Couldn't get the control.
+ }
+
+ // After successfully getting the peakmeter control, the volume range
+ // will be specified by mxc.Bounds.lMinimum to mxc.Bounds.lMaximum.
+
+ MIXERCONTROLDETAILS mxcd; // Gets the control values.
+ MIXERCONTROLDETAILS_SIGNED volStruct; // Gets the control values.
+
+ volStruct.lValue = volume*(mxc.Bounds.lMaximum-mxc.Bounds.lMinimum);
+ volStruct.lValue /= MAXVOLUME;
+ volStruct.lValue += mxc.Bounds.lMinimum;
+
+ // Initialize the MIXERCONTROLDETAILS structure
+ ZeroMemory(&mxcd, sizeof(mxcd));
+ mxcd.cbStruct = sizeof(mxcd);
+ mxcd.cbDetails = sizeof(volStruct);
+ mxcd.dwControlID = mxc.dwControlID;
+ mxcd.paDetails = &volStruct;
+ mxcd.cChannels = 1;
+
+ // Get the current value of the peakmeter control. Typically, you
+ // would set a timer in your program to query the volume every 10th
+ // of a second or so.
+ rc = mixerSetControlDetails((HMIXEROBJ)hMixer, &mxcd,
+ MIXER_SETCONTROLDETAILSF_VALUE);
+ if ( rc != MMSYSERR_NOERROR )
+ {
+ return false; // Couldn't get the current volume.
+ }
+#endif
+
+ return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+// Constructor.
+
+CSound::CSound(CInstanceManager* iMan)
+{
+ int i;
+
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_SOUND, this);
+
+ m_bEnable = false;
+ m_bState = false;
+ m_bAudioTrack = true;
+ m_ctrl3D = true;
+ m_bDebugMode = false;
+ m_MidiDeviceID = 0;
+ m_MIDIMusic = 0;
+ m_audioVolume = 20;
+ m_midiVolume = 15;
+ m_lastMidiVolume = 0;
+ m_listener = 0;
+ m_lastTime = 0.0f;
+ m_playTime = 0.0f;
+ m_uniqueStamp = 0;
+ m_maxSound = MAXSOUND;
+ m_eye = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_hWnd = 0;
+
+ m_lpDS = NULL;
+
+ ZeroMemory(m_channel, sizeof(SoundChannel)*MAXSOUND);
+ for ( i=0 ; i<MAXSOUND ; i++ )
+ {
+ m_channel[i].bUsed = false;
+ }
+
+ for ( i=0 ; i<MAXFILES ; i++ )
+ {
+ m_files[i] = 0;
+ }
+}
+
+// Destructor.
+
+CSound::~CSound()
+{
+ int i;
+
+ if ( m_bEnable )
+ {
+ InitMidiVolume(15); // gives an average volume!
+ InitAudioTrackVolume(15); // gives an average volume!
+ }
+
+ for ( i=0 ; i<MAXSOUND ; i++ )
+ {
+ if ( m_channel[i].bUsed )
+ {
+ m_channel[i].soundBuffer->Stop();
+ m_channel[i].soundBuffer->Release();
+ m_channel[i].soundBuffer = 0;
+ m_channel[i].bUsed = false;
+ }
+ }
+
+ if ( m_listener != NULL )
+ {
+ m_listener->Release();
+ m_listener = NULL;
+ }
+
+ if ( m_lpDS != NULL )
+ {
+ m_lpDS->Release();
+ m_lpDS = NULL;
+ }
+}
+
+
+// Specifies whether you are in debug mode.
+
+void CSound::SetDebugMode(bool bMode)
+{
+ m_bDebugMode = bMode;
+}
+
+
+// Initializes DirectSound.
+
+bool CSound::Create(HWND hWnd, bool b3D)
+{
+ LPDIRECTSOUNDBUFFER primary;
+ DSBUFFERDESC dsbdesc;
+ DSCAPS dscaps;
+ WAVEFORMATEX wfx;
+ HRESULT hr;
+
+ if ( !DirectSoundCreate(NULL, &m_lpDS, NULL) == DS_OK )
+ {
+ OutputDebugString("Fatal error: DirectSoundCreate\n");
+ m_bEnable = false;
+ return false;
+ }
+
+//? m_lpDS->SetCooperativeLevel(hWnd, DSSCL_NORMAL);
+ m_lpDS->SetCooperativeLevel(hWnd, DSSCL_PRIORITY);
+
+ if ( !RetSound3DCap() ) b3D = false;
+
+ m_ctrl3D = false;
+ if ( b3D )
+ {
+ // Obtain primary buffer, asking it for 3D control.
+ ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
+ hr = m_lpDS->CreateSoundBuffer( &dsbdesc, &primary, NULL );
+ if ( hr == S_OK )
+ {
+ m_ctrl3D = true;
+ }
+ }
+
+ if ( !m_ctrl3D )
+ {
+ // Obtain primary buffer, without 3D control.
+ ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
+ hr = m_lpDS->CreateSoundBuffer( &dsbdesc, &primary, NULL );
+ if ( hr != S_OK )
+ {
+ return false;
+ }
+ m_ctrl3D = false;
+ }
+
+ if ( m_ctrl3D )
+ {
+ hr = primary->QueryInterface( IID_IDirectSound3DListener,
+ (VOID**)&m_listener );
+ if ( hr != S_OK )
+ {
+ primary->Release();
+ return false;
+ }
+ }
+
+ // Set primary buffer format to 44kHz and 16-bit output.
+ ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = 2;
+ wfx.nSamplesPerSec = 22050;
+//? wfx.nSamplesPerSec = 44100;
+ wfx.wBitsPerSample = 16;
+ wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+ hr = primary->SetFormat(&wfx);
+ if ( hr != S_OK )
+ {
+ DisplayError("SetFormat", SOUND_CLICK, hr);
+ }
+
+ // Release the primary buffer, since it is not need anymore.
+ primary->Release();
+
+ // Search the maximum possible voices.
+ if ( m_ctrl3D )
+ {
+ ZeroMemory( &dscaps, sizeof(DSCAPS) );
+ dscaps.dwSize = sizeof(DSCAPS);
+ hr = m_lpDS->GetCaps(&dscaps);
+ if ( hr == DS_OK )
+ {
+ m_maxSound = dscaps.dwMaxHwMixingAllBuffers;
+ if ( dscaps.dwMaxHw3DAllBuffers > 0 &&
+ m_maxSound > (int)dscaps.dwMaxHw3DAllBuffers )
+ {
+ m_maxSound = dscaps.dwMaxHw3DAllBuffers;
+ }
+ if ( m_maxSound > MAXSOUND ) m_maxSound = MAXSOUND;
+ }
+ }
+
+ m_bEnable = true;
+ m_hWnd = hWnd;
+ return true;
+}
+
+
+// Indicates whether to play sounds in 3D or not.
+
+void CSound::SetSound3D(bool bMode)
+{
+ StopAll();
+
+ if ( m_listener != NULL )
+ {
+ m_listener->Release();
+ m_listener = NULL;
+ }
+
+ if ( m_lpDS != NULL )
+ {
+ m_lpDS->Release();
+ m_lpDS = NULL;
+ }
+
+ Create(m_hWnd, bMode);
+}
+
+bool CSound::RetSound3D()
+{
+ return m_ctrl3D;
+}
+
+// Indicates whether it is possible to play sounds in 3D.
+
+bool CSound::RetSound3DCap()
+{
+ DSCAPS dscaps;
+ HRESULT hr;
+
+ ZeroMemory( &dscaps, sizeof(DSCAPS) );
+ dscaps.dwSize = sizeof(DSCAPS);
+ hr = m_lpDS->GetCaps(&dscaps);
+ if ( hr != DS_OK ) return false;
+
+ return ( dscaps.dwMaxHw3DAllBuffers > 0 );
+}
+
+
+
+// Returns the state of DirectSound.
+
+bool CSound::RetEnable()
+{
+ return m_bEnable;
+}
+
+
+// Switches on or off the sound.
+
+void CSound::SetState(bool bState)
+{
+ m_bState = bState;
+}
+
+// Specifies the pathname to the CD.
+
+void CSound::SetCDpath(char *path)
+{
+ strcpy(m_CDpath, path);
+}
+
+// Switches on or off the CD-audio music.
+
+void CSound::SetAudioTrack(bool bAudio)
+{
+ m_bAudioTrack = bAudio;
+}
+
+
+// Manages volumes of audio (. Wav) and midi (. Mid).
+
+void CSound::SetAudioVolume(int volume)
+{
+ m_audioVolume = volume;
+}
+
+int CSound::RetAudioVolume()
+{
+ if ( !m_bEnable ) return 0;
+ return m_audioVolume;
+}
+
+void CSound::SetMidiVolume(int volume)
+{
+ m_midiVolume = volume;
+
+ if ( m_bAudioTrack )
+ {
+ InitAudioTrackVolume(m_midiVolume);
+ }
+}
+
+int CSound::RetMidiVolume()
+{
+ if ( !m_bEnable ) return 0;
+ return m_midiVolume;
+}
+
+
+// Reads a file.
+
+bool CSound::ReadFile(Sound sound, char *metaname, char *filename)
+{
+ WaveHeader wavHdr;
+ DWORD size;
+ int err;
+
+ // Open the wave file.
+ err = g_metafile.Open(metaname, filename);
+ if ( err != 0 ) return false;
+
+ // Read in the wave header.
+ g_metafile.Read(&wavHdr, sizeof(wavHdr));
+
+ // Figure out the size of the data region.
+ size = wavHdr.dwDSize;
+
+ if ( m_files[sound] != 0 )
+ {
+ free(m_files[sound]);
+ }
+ m_files[sound] = (char*)malloc(sizeof(WaveHeader)+size);
+
+ memcpy(m_files[sound], &wavHdr, sizeof(WaveHeader));
+ g_metafile.Read(m_files[sound]+sizeof(WaveHeader), size);
+
+ // Close out the wave file.
+ g_metafile.Close();
+ return true;
+}
+
+// Hides all sound files (. Wav).
+
+void CSound::CacheAll()
+{
+ int i;
+ char meta[50];
+ char name[50];
+
+ if ( !m_bEnable ) return;
+
+ if ( m_bDebugMode )
+ {
+ strcpy(meta, "");
+ }
+ else
+ {
+#if _SCHOOL
+ strcpy(meta, "ceebot3.dat");
+#else
+ strcpy(meta, "colobot3.dat");
+#endif
+ }
+
+ for ( i=0 ; i<MAXFILES ; i++ )
+ {
+ if ( m_bDebugMode )
+ {
+ sprintf(name, "sound\\sound%.3d.wav", i);
+ }
+ else
+ {
+ sprintf(name, "sound%.3d.wav", i);
+ }
+ if ( !ReadFile((Sound)i, meta, name) ) break;
+ }
+}
+
+
+// Return the priority of a sound.
+// The higher the value, the greater the sound is important.
+
+int CSound::RetPriority(Sound sound)
+{
+ if ( sound == SOUND_FLYh ||
+ sound == SOUND_FLY ||
+ sound == SOUND_MOTORw ||
+ sound == SOUND_MOTORt ||
+ sound == SOUND_MOTORr ||
+ sound == SOUND_MOTORs ||
+ sound == SOUND_SLIDE ||
+ sound == SOUND_ERROR )
+ {
+ return 30;
+ }
+
+ if ( sound == SOUND_CONVERT ||
+ sound == SOUND_ENERGY ||
+ sound == SOUND_DERRICK ||
+ sound == SOUND_STATION ||
+ sound == SOUND_REPAIR ||
+ sound == SOUND_RESEARCH ||
+ sound == SOUND_BURN ||
+ sound == SOUND_BUILD ||
+ sound == SOUND_TREMBLE ||
+ sound == SOUND_NUCLEAR ||
+ sound == SOUND_EXPLO ||
+ sound == SOUND_EXPLOl ||
+ sound == SOUND_EXPLOlp ||
+ sound == SOUND_EXPLOp ||
+ sound == SOUND_EXPLOi )
+ {
+ return 20;
+ }
+
+ if ( sound == SOUND_BLUP ||
+ sound == SOUND_INSECTs ||
+ sound == SOUND_INSECTa ||
+ sound == SOUND_INSECTb ||
+ sound == SOUND_INSECTw ||
+ sound == SOUND_INSECTm ||
+ sound == SOUND_PSHHH ||
+ sound == SOUND_EGG )
+ {
+ return 0;
+ }
+
+ return 10;
+}
+
+// Seeks a free buffer.
+
+bool CSound::SearchFreeBuffer(Sound sound, int &channel, bool &bAlreadyLoaded)
+{
+ DWORD status;
+ int i, priority;
+
+ priority = RetPriority(sound);
+
+#if 1
+ // Seeks a channel used which sound is stopped.
+ for ( i=0 ; i<m_maxSound ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+ if ( m_channel[i].type != sound ) continue;
+
+ m_channel[i].soundBuffer->GetStatus(&status);
+ if ( (status&DSBSTATUS_PLAYING) == 0 )
+ {
+ m_channel[i].priority = priority;
+ m_channel[i].uniqueStamp = m_uniqueStamp++;
+ channel = i;
+ bAlreadyLoaded = true;
+ return true;
+ }
+ }
+#endif
+
+ // Seeks a channel completely free.
+ for ( i=0 ; i<m_maxSound ; i++ )
+ {
+ if ( !m_channel[i].bUsed )
+ {
+ m_channel[i].priority = priority;
+ m_channel[i].uniqueStamp = m_uniqueStamp++;
+ channel = i;
+ bAlreadyLoaded = false;
+ return true;
+ }
+ }
+
+ // Seeks a channel used which sound is stopped.
+ for ( i=0 ; i<m_maxSound ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+
+ m_channel[i].soundBuffer->GetStatus(&status);
+ if ( (status&DSBSTATUS_PLAYING) == 0 )
+ {
+ m_channel[i].soundBuffer->Release();
+ m_channel[i].soundBuffer = 0;
+ m_channel[i].priority = priority;
+ m_channel[i].uniqueStamp = m_uniqueStamp++;
+
+ channel = i;
+ bAlreadyLoaded = false;
+ return true;
+ }
+ }
+
+ // Seeks a lower priority channel used.
+ for ( i=0 ; i<m_maxSound ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+ if ( m_channel[i].priority >= priority ) continue;
+
+ m_channel[i].soundBuffer->Stop();
+ m_channel[i].soundBuffer->Release();
+ m_channel[i].soundBuffer = 0;
+ m_channel[i].priority = priority;
+ m_channel[i].uniqueStamp = m_uniqueStamp++;
+
+ channel = i;
+ bAlreadyLoaded = false;
+ return true;
+ }
+
+ // Seeks a channel used the same or lower priority.
+ for ( i=0 ; i<m_maxSound ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+ if ( m_channel[i].priority > priority ) continue;
+
+ m_channel[i].soundBuffer->Stop();
+ m_channel[i].soundBuffer->Release();
+ m_channel[i].soundBuffer = 0;
+ m_channel[i].priority = priority;
+ m_channel[i].uniqueStamp = m_uniqueStamp++;
+
+ channel = i;
+ bAlreadyLoaded = false;
+ return true;
+ }
+
+ char s[100];
+ sprintf(s, "Sound %d forget (priority=%d)\n", sound, priority);
+ OutputDebugString(s);
+
+ return false;
+}
+
+// Reads in data from a wave file.
+
+bool CSound::ReadData(LPDIRECTSOUNDBUFFER lpDSB, Sound sound, DWORD size)
+{
+ LPVOID pData1;
+ DWORD dwData1Size;
+ LPVOID pData2;
+ DWORD dwData2Size;
+ HRESULT hr;
+
+ // Lock data in buffer for writing.
+ hr = lpDSB->Lock(0, size, &pData1, &dwData1Size, &pData2, &dwData2Size, DSBLOCK_FROMWRITECURSOR);
+ if ( hr != DS_OK )
+ {
+ return false;
+ }
+
+ // Read in first chunk of data.
+ if ( dwData1Size > 0 )
+ {
+ memcpy(pData1, m_files[sound]+sizeof(WaveHeader), dwData1Size);
+ }
+
+ // Read in second chunk if necessary.
+ if ( dwData2Size > 0 )
+ {
+ memcpy(pData2, m_files[sound]+sizeof(WaveHeader)+dwData1Size, dwData2Size);
+ }
+
+ // Unlock data in buffer.
+ hr = lpDSB->Unlock(pData1, dwData1Size, pData2, dwData2Size);
+ if ( hr != DS_OK )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Creates a DirectSound buffer.
+
+bool CSound::CreateSoundBuffer(int channel, DWORD size, DWORD freq,
+ DWORD bitsPerSample, DWORD blkAlign,
+ bool bStereo)
+{
+ PCMWAVEFORMAT pcmwf;
+ DSBUFFERDESC dsbdesc;
+ DS3DBUFFER bufferParams; // 3D buffer properties
+ HRESULT hr;
+
+ // Set up wave format structure.
+ memset( &pcmwf, 0, sizeof(PCMWAVEFORMAT) );
+ pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM;
+ pcmwf.wf.nChannels = bStereo ? 2 : 1;
+ pcmwf.wf.nSamplesPerSec = freq;
+ pcmwf.wf.nBlockAlign = (WORD)blkAlign;
+ pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign;
+ pcmwf.wBitsPerSample = (WORD)bitsPerSample;
+
+ // Set up DSBUFFERDESC structure.
+ memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ if ( m_ctrl3D )
+ {
+ dsbdesc.dwFlags = DSBCAPS_CTRL3D|DSBCAPS_MUTE3DATMAXDISTANCE|
+ DSBCAPS_LOCDEFER|
+ DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLFREQUENCY;
+ }
+ else
+ {
+ dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN|DSBCAPS_CTRLFREQUENCY;
+ }
+ dsbdesc.dwBufferBytes = size;
+ dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;
+
+ hr = m_lpDS->CreateSoundBuffer(&dsbdesc, &m_channel[channel].soundBuffer, NULL);
+ if ( hr != DS_OK ) return false;
+
+ if ( m_ctrl3D )
+ {
+ hr = m_channel[channel].soundBuffer->QueryInterface
+ (
+ IID_IDirectSound3DBuffer,
+ (VOID**)&m_channel[channel].soundBuffer3D
+ );
+ if ( hr != DS_OK ) return false;
+ }
+
+ m_channel[channel].bUsed = true;
+ m_channel[channel].bMute = false;
+ return true;
+}
+
+// Creates a DirectSound buffer from a wave file.
+
+bool CSound::CreateBuffer(int channel, Sound sound)
+{
+ WaveHeader* wavHdr;
+ DWORD size;
+ bool bStereo;
+
+ if ( m_files[sound] == 0 ) return false;
+
+ wavHdr = (WaveHeader*)m_files[sound];
+ size = wavHdr->dwDSize;
+ bStereo = wavHdr->wChnls > 1 ? true : false;
+
+ // Create the sound buffer for the wave file.
+ if ( !CreateSoundBuffer(channel, size, wavHdr->dwSRate,
+ wavHdr->BitsPerSample, wavHdr->wBlkAlign, bStereo) )
+ {
+ return false;
+ }
+
+ // Read the data for the wave file into the sound buffer.
+ if ( !ReadData(m_channel[channel].soundBuffer, sound, size) )
+ {
+ return false;
+ }
+
+ m_channel[channel].type = sound;
+
+ // Close out the wave file.
+ return true;
+}
+
+// Calculates the volume and pan of a sound, non-3D mode.
+
+void CSound::ComputeVolumePan2D(int channel, const Math::Vector &pos)
+{
+ float dist, a, g;
+
+ if ( pos.x == m_eye.x &&
+ pos.y == m_eye.y &&
+ pos.z == m_eye.z )
+ {
+ m_channel[channel].volume = 1.0f; // maximum volume
+ m_channel[channel].pan = 0.0f; // at the center
+ return;
+ }
+
+#if _TEEN
+ dist = Math::Distance(pos, m_eye);
+ if ( dist >= 210.0f ) // very far?
+ {
+ m_channel[channel].volume = 0.0f; // silence
+ m_channel[channel].pan = 0.0f; // at the center
+ return;
+ }
+ if ( dist <= 10.0f ) // very close?
+ {
+ m_channel[channel].volume = 1.0f; // maximum volume
+ m_channel[channel].pan = 0.0f; // at the center
+ return;
+ }
+ m_channel[channel].volume = 1.0f-((dist-10.0f)/200.0f);
+#else
+ dist = Math::Distance(pos, m_eye);
+ if ( dist >= 110.0f ) // very far?
+ {
+ m_channel[channel].volume = 0.0f; // silence
+ m_channel[channel].pan = 0.0f; // at the center
+ return;
+ }
+ if ( dist <= 10.0f ) // very close?
+ {
+ m_channel[channel].volume = 1.0f; // maximum volume
+ m_channel[channel].pan = 0.0f; // at the center
+ return;
+ }
+ m_channel[channel].volume = 1.0f-((dist-10.0f)/100.0f);
+#endif
+
+ a = Math::RotateAngle(m_lookat.x-m_eye.x, m_eye.z-m_lookat.z);
+ g = Math::RotateAngle(pos.x-m_eye.x, m_eye.z-pos.z);
+ m_channel[channel].pan = sinf(Math::Direction(a, g));
+}
+
+// Sounds in the middle.
+// Returns the associated channel or -1.
+
+int CSound::Play(Sound sound, float amplitude, float frequency, bool bLoop)
+{
+ return Play(sound, m_lookat, amplitude, frequency, bLoop);
+}
+
+// Sounds at a given position.
+// Returns the associated channel or -1.
+
+int CSound::Play(Sound sound, Math::Vector pos,
+ float amplitude, float frequency, bool bLoop)
+{
+ DS3DBUFFER sb;
+ int channel, iVolume, iPan, iFreq, uniqueStamp;
+ bool bAlreadyLoaded;
+ DWORD flag, freq;
+ HRESULT err;
+
+ if ( !m_bEnable ) return -1;
+ if ( !m_bState || m_audioVolume == 0 ) return -1;
+
+//? if ( Math::Distance(pos, m_eye) > 100.0f ) return -1;
+
+ if ( !SearchFreeBuffer(sound, channel, bAlreadyLoaded) ) return -1;
+
+ if ( !bAlreadyLoaded )
+ {
+ if ( !CreateBuffer(channel, sound) )
+ {
+ if ( m_channel[channel].bUsed &&
+ m_channel[channel].soundBuffer != 0 )
+ {
+ m_channel[channel].soundBuffer->Release();
+ m_channel[channel].soundBuffer = 0;
+ }
+ m_channel[channel].bUsed = false;
+ return -1;
+ }
+ }
+
+ m_channel[channel].pos = pos;
+
+ if ( m_ctrl3D )
+ {
+ m_channel[channel].volume = 1.0f;
+ m_channel[channel].pan = 0.0f;
+ }
+ else
+ {
+ ComputeVolumePan2D(channel, pos);
+ }
+
+#if 0
+ DWORD status;
+ m_channel[channel].soundBuffer->GetStatus(&status);
+ char s[100];
+ sprintf(s, "Play sound=%d status=%d channel=%d flag=%d\n", sound, status, channel, bAlreadyLoaded);
+ OutputDebugString(s);
+#endif
+
+ m_channel[channel].oper[0].bUsed = false;
+ m_channel[channel].startAmplitude = amplitude;
+ m_channel[channel].startFrequency = frequency;
+ m_channel[channel].changeFrequency = 1.0f;
+
+ if ( m_ctrl3D )
+ {
+ sb.dwSize = sizeof(DS3DBUFFER);
+ err = m_channel[channel].soundBuffer3D->GetAllParameters(&sb);
+ DisplayError("GetAllParameters", sound, err);
+
+ sb.vPosition = VEC_TO_D3DVEC(pos);
+//? sb.dwInsideConeAngle = 90;
+//? sb.dwOutsideConeAngle = 180;
+//? sb.vConeOrientation = Math::Vector(0.0f, 1.0f, 0.0f);
+ sb.lConeOutsideVolume = DSBVOLUME_MIN;
+#if _TEEN
+ sb.flMinDistance = 50.0f;
+#else
+ sb.flMinDistance = 20.0f;
+#endif
+ sb.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
+
+ err = m_channel[channel].soundBuffer3D->SetAllParameters(&sb, DS3D_IMMEDIATE);
+ DisplayError("SetAllParameters", sound, err);
+ }
+
+ amplitude *= m_channel[channel].volume;
+ amplitude *= (float)m_audioVolume/MAXVOLUME;
+ iVolume = (int)((powf(amplitude, 0.2f)-1.0f)*10000.0f);
+ if ( iVolume > 0 ) iVolume = 0;
+ err = m_channel[channel].soundBuffer->SetVolume(iVolume);
+ DisplayError("SetVolume", sound, err);
+
+ if ( !m_ctrl3D )
+ {
+ iPan = (int)(m_channel[channel].pan*10000.0f);
+ err = m_channel[channel].soundBuffer->SetPan(iPan);
+ DisplayError("SetPan", sound, err);
+ }
+
+ if ( !bAlreadyLoaded )
+ {
+ err = m_channel[channel].soundBuffer->GetFrequency(&freq);
+ DisplayError("GetFrequency", sound, err);
+ m_channel[channel].initFrequency = freq;
+ }
+ iFreq = (int)(frequency*m_channel[channel].initFrequency);
+ err = m_channel[channel].soundBuffer->SetFrequency(iFreq);
+ DisplayError("SetFrequency", sound, err);
+
+ err = m_channel[channel].soundBuffer->SetCurrentPosition(0);
+ DisplayError("SetCurrentPosition", sound, err);
+
+ flag = bLoop?DSBPLAY_LOOPING:0;
+//? flag |= DSBPLAY_LOCHARDWARE|DSBPLAY_TERMINATEBY_DISTANCE;
+//? flag |= DSBPLAY_TERMINATEBY_DISTANCE;
+ err = m_channel[channel].soundBuffer->Play(0, 0, flag);
+ DisplayError("Play", sound, err);
+ if ( err == DSERR_BADFORMAT )
+ {
+ iFreq = m_channel[channel].initFrequency;
+ err = m_channel[channel].soundBuffer->SetFrequency(iFreq);
+ DisplayError("SetFrequency (repeat)", sound, err);
+
+ err = m_channel[channel].soundBuffer->Play(0, 0, flag);
+ DisplayError("Play (repeat)", sound, err);
+ }
+
+ uniqueStamp = m_channel[channel].uniqueStamp;
+ return channel | ((uniqueStamp&0xffff)<<16);
+}
+
+// Check a channel number.
+// Adapts the channel, so it can be used as an offset in m_channel.
+
+bool CSound::CheckChannel(int &channel)
+{
+ int uniqueStamp;
+
+ uniqueStamp = (channel>>16)&0xffff;
+ channel &= 0xffff;
+
+ if ( !m_bEnable ) return false;
+ if ( !m_bState || m_audioVolume == 0 ) return false;
+
+ if ( channel < 0 || channel >= m_maxSound ) return false;
+ if ( !m_channel[channel].bUsed ) return false;
+
+ if ( m_channel[channel].uniqueStamp != uniqueStamp ) return false;
+
+ return true;
+}
+
+// Removes all envelopes.
+
+bool CSound::FlushEnvelope(int channel)
+{
+ if ( !CheckChannel(channel) ) return false;
+
+ m_channel[channel].oper[0].bUsed = false;
+ return true;
+}
+
+// Adds an operation envelope.
+
+bool CSound::AddEnvelope(int channel, float amplitude, float frequency,
+ float time, SoundNext oper)
+{
+ int i;
+
+ if ( !CheckChannel(channel) ) return false;
+
+ for ( i=0 ; i<MAXOPER ; i++ )
+ {
+ if ( m_channel[channel].oper[i].bUsed ) continue;
+
+ m_channel[channel].oper[i].bUsed = true;
+ m_channel[channel].oper[i].finalAmplitude = amplitude;
+ m_channel[channel].oper[i].finalFrequency = frequency;
+ m_channel[channel].oper[i].totalTime = time;
+ m_channel[channel].oper[i].currentTime = 0;
+ m_channel[channel].oper[i].nextOper = oper;
+
+ if ( i < MAXOPER-1 )
+ {
+ m_channel[channel].oper[i+1].bUsed = false;
+ }
+ return true;
+ }
+ return false;
+}
+
+// Changes the position of a sound.
+
+bool CSound::Position(int channel, Math::Vector pos)
+{
+ float amplitude, pan;
+ int iVolume, iPan;
+ HRESULT err;
+
+ if ( !CheckChannel(channel) ) return false;
+
+ m_channel[channel].pos = pos;
+
+ if ( m_ctrl3D )
+ {
+ m_channel[channel].soundBuffer3D->SetPosition(pos.x, pos.y, pos.z, DS3D_DEFERRED);
+ }
+ else
+ {
+ ComputeVolumePan2D(channel, pos);
+
+ if ( !m_channel[channel].oper[0].bUsed )
+ {
+ amplitude = m_channel[channel].startAmplitude;
+ amplitude *= m_channel[channel].volume;
+ amplitude *= (float)m_audioVolume/MAXVOLUME;
+ iVolume = (int)((powf(amplitude, 0.2f)-1.0f)*10000.0f);
+ if ( iVolume > 0 ) iVolume = 0;
+ err = m_channel[channel].soundBuffer->SetVolume(iVolume);
+ DisplayError("SetVolume", m_channel[channel].type, err);
+ }
+
+ pan = m_channel[channel].pan;
+ iPan = (int)(pan*10000.0f);
+ err = m_channel[channel].soundBuffer->SetPan(iPan);
+ DisplayError("SetPan", m_channel[channel].type, err);
+ }
+ return true;
+}
+
+// Changes the frequency of a sound.
+// 0.5 down of an octave and 2.0 up of an octave.
+
+bool CSound::Frequency(int channel, float frequency)
+{
+ HRESULT err;
+ int iFreq;
+
+ if ( !CheckChannel(channel) ) return false;
+
+ m_channel[channel].changeFrequency = frequency;
+
+ if ( !m_channel[channel].oper[0].bUsed )
+ {
+ iFreq = (int)(frequency*m_channel[channel].initFrequency);
+ err = m_channel[channel].soundBuffer->SetFrequency(iFreq);
+ DisplayError("Frequency", m_channel[channel].type, err);
+ }
+
+ return true;
+}
+
+// Stops sound.
+
+bool CSound::Stop(int channel)
+{
+ if ( !CheckChannel(channel) ) return false;
+
+ m_channel[channel].soundBuffer->Stop();
+ return true;
+}
+
+// Stops all sounds.
+
+bool CSound::StopAll()
+{
+ DWORD status;
+ int i;
+
+ for ( i=0 ; i<MAXSOUND ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+
+ m_channel[i].soundBuffer->GetStatus(&status);
+ if ( (status&DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING )
+ {
+ m_channel[i].soundBuffer->Stop();
+ }
+ m_channel[i].soundBuffer->Stop();
+ m_channel[i].soundBuffer->Release();
+ m_channel[i].soundBuffer = 0;
+
+ m_channel[i].bUsed = false;
+ }
+ return true;
+}
+
+// Silent all sounds.
+
+bool CSound::MuteAll(bool bMute)
+{
+ int i;
+
+ for ( i=0 ; i<MAXSOUND ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+
+ m_channel[i].bMute = bMute;
+ }
+ return true;
+}
+
+
+// Passes the following operation for a channel.
+
+void CSound::OperNext(int channel)
+{
+ int i;
+
+ m_channel[channel].startAmplitude = m_channel[channel].oper[0].finalAmplitude;
+ m_channel[channel].startFrequency = m_channel[channel].oper[0].finalFrequency;
+
+ for ( i=0 ; i<MAXOPER-1 ; i++ )
+ {
+ if ( !m_channel[channel].oper[i+1].bUsed ) break;
+
+ m_channel[channel].oper[i] = m_channel[channel].oper[i+1];
+ }
+
+ m_channel[channel].oper[i].bUsed = false;
+}
+
+// Updates the sound buffers.
+
+void CSound::FrameMove(float rTime)
+{
+ HRESULT err;
+ SoundNext next;
+ float progress, volume, freq;
+ int i, iVolume, iFreq;
+
+ m_playTime += rTime;
+
+ for ( i=0 ; i<m_maxSound ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+ if ( !m_channel[i].oper[0].bUsed ) continue;
+
+ if ( m_channel[i].bMute )
+ {
+ m_channel[i].soundBuffer->SetVolume(-10000); // silence
+ continue;
+ }
+
+ m_channel[i].oper[0].currentTime += rTime;
+
+ progress = m_channel[i].oper[0].currentTime / m_channel[i].oper[0].totalTime;
+ if ( progress > 1.0f ) progress = 1.0f;
+
+ volume = progress;
+ volume *= m_channel[i].oper[0].finalAmplitude-m_channel[i].startAmplitude;
+ volume += m_channel[i].startAmplitude;
+ volume *= m_channel[i].volume;
+ volume *= (float)m_audioVolume/MAXVOLUME;
+ iVolume = (int)((powf(volume, 0.2f)-1.0f)*10000.0f);
+ if ( iVolume > 0 ) iVolume = 0;
+ m_channel[i].soundBuffer->SetVolume(iVolume);
+
+ freq = progress;
+ freq *= m_channel[i].oper[0].finalFrequency-m_channel[i].startFrequency;
+ freq += m_channel[i].startFrequency;
+ freq *= m_channel[i].changeFrequency;
+ iFreq = (int)(freq*m_channel[i].initFrequency);
+ err = m_channel[i].soundBuffer->SetFrequency(iFreq);
+ DisplayError("FrameMove::Frequency", m_channel[i].type, err);
+
+ if ( m_channel[i].oper[0].currentTime >=
+ m_channel[i].oper[0].totalTime )
+ {
+ next = m_channel[i].oper[0].nextOper;
+
+ if ( next == SOPER_LOOP )
+ {
+ m_channel[i].oper[0].currentTime = 0.0f;
+ }
+ else
+ {
+ OperNext(i);
+
+ if ( next == SOPER_STOP )
+ {
+ m_channel[i].soundBuffer->Stop();
+ }
+ }
+ }
+ }
+
+ m_lastTime += rTime;
+ if ( m_lastTime >= 0.05f && m_listener != 0 )
+ {
+ m_lastTime = 0.0f;
+ m_listener->CommitDeferredSettings();
+ }
+}
+
+// Specifies the position of the listener.
+// Must be called whenever the camera moves.
+
+void CSound::SetListener(Math::Vector eye, Math::Vector lookat)
+{
+ DS3DLISTENER listenerParams;
+ HRESULT err;
+ float amplitude, pan;
+ int i, iVolume, iPan;
+
+ m_eye = eye;
+ m_lookat = lookat;
+
+ if ( m_listener == 0 )
+ {
+ if ( m_ctrl3D ) return;
+
+ for ( i=0 ; i<m_maxSound ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+
+ ComputeVolumePan2D(i, m_channel[i].pos);
+
+ if ( !m_channel[i].oper[0].bUsed )
+ {
+ amplitude = m_channel[i].startAmplitude;
+ amplitude *= m_channel[i].volume;
+ amplitude *= (float)m_audioVolume/MAXVOLUME;
+ iVolume = (int)((powf(amplitude, 0.2f)-1.0f)*10000.0f);
+ if ( iVolume > 0 ) iVolume = 0;
+ err = m_channel[i].soundBuffer->SetVolume(iVolume);
+ DisplayError("SetVolume", m_channel[i].type, err);
+ }
+
+ pan = m_channel[i].pan;
+ iPan = (int)(pan*10000.0f);
+ err = m_channel[i].soundBuffer->SetPan(iPan);
+ DisplayError("SetPan", m_channel[i].type, err);
+ }
+ return;
+ }
+
+ // Get listener parameters.
+ listenerParams.dwSize = sizeof(DS3DLISTENER);
+ m_listener->GetAllParameters(&listenerParams);
+
+ listenerParams.vPosition = VEC_TO_D3DVEC(eye);
+ listenerParams.vOrientFront = VEC_TO_D3DVEC(lookat-eye);
+ listenerParams.vOrientTop = D3DVECTOR(0.0f, 1.0f, 0.0f);
+ listenerParams.flDistanceFactor = 10.0f;
+ listenerParams.flRolloffFactor = 1.0f;
+
+ m_listener->SetAllParameters(&listenerParams, DS3D_DEFERRED);
+}
+
+
+
+
+// Uses MCI to play a MIDI file. The window procedure
+// is notified when playback is complete.
+
+bool CSound::PlayMusic(int rank, bool bRepeat)
+{
+ MCI_OPEN_PARMS mciOpenParms;
+ MCI_PLAY_PARMS mciPlayParms;
+ DWORD dwReturn;
+ char filename[MAX_PATH];
+
+ m_bRepeatMusic = bRepeat;
+ m_playTime = 0.0f;
+
+ if ( m_midiVolume == 0 ) return true;
+
+ if ( m_bAudioTrack )
+ {
+ return PlayAudioTrack(rank);
+ }
+
+ if ( !m_bEnable ) return true;
+ InitMidiVolume(m_midiVolume);
+ m_lastMidiVolume = m_midiVolume;
+
+ GetCurrentDir(filename, MAX_PATH-30);
+ sprintf(filename+strlen(filename), "sound\\music%.3d.blp", rank-1);
+
+ // Open the device by specifying the device and filename.
+ // MCI will attempt to choose the MIDI mapper as the output port.
+ mciOpenParms.lpstrDeviceType = "sequencer";
+ mciOpenParms.lpstrElementName = filename;
+ dwReturn = mciSendCommand(NULL,
+ MCI_OPEN,
+ MCI_OPEN_TYPE|MCI_OPEN_ELEMENT,
+ (DWORD)(LPVOID)&mciOpenParms);
+ if ( dwReturn != 0 )
+ {
+ mciGetErrorString(dwReturn, filename, 128);
+ // Failed to open device. Don't close it; just return error.
+ return false;
+ }
+
+ // The device opened successfully; get the device ID.
+ m_MidiDeviceID = mciOpenParms.wDeviceID;
+
+ // Begin playback.
+ mciPlayParms.dwCallback = (DWORD)m_hWnd;
+ dwReturn = mciSendCommand(m_MidiDeviceID,
+ MCI_PLAY,
+ MCI_NOTIFY,
+ (DWORD)(LPVOID)&mciPlayParms);
+ if ( dwReturn != 0 )
+ {
+ mciGetErrorString(dwReturn, filename, 128);
+ StopMusic();
+ return false;
+ }
+
+ m_MIDIMusic = rank;
+ return true;
+}
+
+// Uses MCI to play a CD-audio track. The window procedure
+// is notified when playback is complete.
+// The rank parameter is in space [1..n] !
+// For CD mix (data/audio), it will be [2..n] !
+
+bool CSound::PlayAudioTrack(int rank)
+{
+#if _SOUNDTRACKS
+ MCI_OPEN_PARMS mciOpenParms;
+ MCI_PLAY_PARMS mciPlayParms;
+ MCI_SET_PARMS mciSetParms;
+ DWORD dwReturn;
+ char filename[MAX_PATH];
+ char device[10];
+
+ if ( !m_bEnable ) return true;
+//? if ( m_midiVolume == 0 ) return true;
+ InitAudioTrackVolume(m_midiVolume);
+ m_lastMidiVolume = m_midiVolume;
+
+ // Open the device by specifying the device and filename.
+ // MCI will attempt to choose the MIDI mapper as the output port.
+ memset(&mciOpenParms, 0, sizeof(MCI_OPEN_PARMS));
+//? mciOpenParms.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO;
+//? dwReturn = mciSendCommand(NULL,
+//? MCI_OPEN,
+//? MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID,
+//? (DWORD)(LPVOID)&mciOpenParms);
+ mciOpenParms.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO;
+ if ( m_CDpath[0] == 0 )
+ {
+ dwReturn = mciSendCommand(NULL,
+ MCI_OPEN,
+ MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID,
+ (DWORD)(LPVOID)&mciOpenParms);
+ }
+ else
+ {
+ device[0] = m_CDpath[0];
+ device[1] = ':';
+ device[2] = 0;
+ mciOpenParms.lpstrElementName = device;
+ dwReturn = mciSendCommand(NULL,
+ MCI_OPEN,
+ MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_OPEN_ELEMENT,
+ (DWORD)(LPVOID)&mciOpenParms);
+ }
+ if ( dwReturn != 0 )
+ {
+ mciGetErrorString(dwReturn, filename, 128);
+ // Failed to open device. Don't close it; just return error.
+ return false;
+ }
+
+ // The device opened successfully; get the device ID.
+ m_MidiDeviceID = mciOpenParms.wDeviceID;
+
+ // Set the time format to track/minute/second/frame (TMSF).
+ memset(&mciSetParms, 0, sizeof(MCI_SET_PARMS));
+ mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
+ dwReturn = mciSendCommand(m_MidiDeviceID,
+ MCI_SET,
+ MCI_SET_TIME_FORMAT,
+ (DWORD)&mciSetParms);
+ if ( dwReturn != 0 )
+ {
+ mciGetErrorString(dwReturn, filename, 128);
+ StopMusic();
+ return false;
+ }
+
+ // Begin playback.
+ memset(&mciPlayParms, 0, sizeof(MCI_PLAY_PARMS));
+ mciPlayParms.dwCallback = (DWORD)m_hWnd;
+ mciPlayParms.dwFrom = MCI_MAKE_TMSF(rank+0, 0, 0, 0);
+ mciPlayParms.dwTo = MCI_MAKE_TMSF(rank+1, 0, 0, 0);
+ dwReturn = mciSendCommand(m_MidiDeviceID,
+ MCI_PLAY,
+ MCI_NOTIFY|MCI_FROM|MCI_TO,
+ (DWORD)(LPVOID)&mciPlayParms);
+ if ( dwReturn != 0 )
+ {
+ mciGetErrorString(dwReturn, filename, 128);
+ StopMusic();
+ return false;
+ }
+
+ m_MIDIMusic = rank;
+#endif
+ return true;
+}
+
+// Restart the MIDI player.
+
+bool CSound::RestartMusic()
+{
+ if ( !m_bRepeatMusic ) return false;
+
+ OutputDebugString("RestartMusic\n");
+ if ( !m_bEnable ) return true;
+//? if ( m_midiVolume == 0 ) return true;
+ if ( m_MIDIMusic == 0 ) return false;
+ if ( m_playTime < 5.0f ) return false;
+
+ return PlayMusic(m_MIDIMusic, true);
+}
+
+// Shuts down the MIDI player.
+
+void CSound::SuspendMusic()
+{
+ if ( !m_bEnable ) return;
+
+//? if ( m_MidiDeviceID && m_midiVolume != 0 )
+ if ( m_MidiDeviceID )
+ {
+ if ( m_bAudioTrack ) mciSendCommand(m_MidiDeviceID, MCI_STOP, 0, NULL);
+ mciSendCommand(m_MidiDeviceID, MCI_CLOSE, 0, NULL);
+ }
+ m_MidiDeviceID = 0;
+}
+
+// Shuts down the MIDI player.
+
+void CSound::StopMusic()
+{
+ SuspendMusic();
+ m_MIDIMusic = 0;
+}
+
+// Returns true if the music is in progress.
+
+bool CSound::IsPlayingMusic()
+{
+ return (m_MIDIMusic != 0);
+}
+
+// Adjusts the volume of currently music, if necessary.
+
+void CSound::AdaptVolumeMusic()
+{
+ if ( m_midiVolume != m_lastMidiVolume )
+ {
+ if ( m_bAudioTrack )
+ {
+ InitAudioTrackVolume(m_midiVolume);
+ }
+ else
+ {
+ InitMidiVolume(m_midiVolume);
+ }
+ m_lastMidiVolume = m_midiVolume;
+ RestartMusic();
+ }
+}
+
diff --git a/src/old/sound.h b/src/old/sound.h new file mode 100644 index 0000000..2dcdc2c --- /dev/null +++ b/src/old/sound.h @@ -0,0 +1,242 @@ +// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+// sound.h
+
+#pragma once
+
+
+#include <dsound.h>
+
+
+const int MAXFILES = 200;
+const int MAXSOUND = 32;
+const int MAXVOLUME = 20;
+const int MAXOPER = 4;
+
+class CInstanceManager;
+
+
+enum Sound
+{
+ SOUND_CLICK = 0,
+ SOUND_BOUM = 1,
+ SOUND_EXPLO = 2,
+ SOUND_FLYh = 3, // human
+ SOUND_FLY = 4,
+ SOUND_STEPs = 5, // smooth
+ SOUND_MOTORw = 6, // wheel
+ SOUND_MOTORt = 7, // tank
+ SOUND_MOTORr = 8, // roller
+ SOUND_ERROR = 9,
+ SOUND_CONVERT = 10,
+ SOUND_ENERGY = 11,
+ SOUND_PLOUF = 12,
+ SOUND_BLUP = 13,
+ SOUND_WARNING = 14,
+ SOUND_DERRICK = 15,
+ SOUND_LABO = 16,
+ SOUND_STATION = 17,
+ SOUND_REPAIR = 18,
+ SOUND_RESEARCH = 19,
+ SOUND_INSECTs = 20, // spider
+ SOUND_BURN = 21,
+ SOUND_TZOING = 22,
+ SOUND_GGG = 23,
+ SOUND_MANIP = 24,
+ SOUND_FIRE = 25, // shooting with fireball
+ SOUND_HUMAN1 = 26, // breathing
+ SOUND_STEPw = 27, // water
+ SOUND_SWIM = 28,
+ SOUND_RADAR = 29,
+ SOUND_BUILD = 30,
+ SOUND_ALARM = 31, // energy alarm
+ SOUND_SLIDE = 32,
+ SOUND_EXPLOi = 33, // insect
+ SOUND_INSECTa = 34, // ant
+ SOUND_INSECTb = 35, // bee
+ SOUND_INSECTw = 36, // worm
+ SOUND_INSECTm = 37, // mother
+ SOUND_TREMBLE = 38,
+ SOUND_PSHHH = 39,
+ SOUND_NUCLEAR = 40,
+ SOUND_INFO = 41,
+ SOUND_OPEN = 42,
+ SOUND_CLOSE = 43,
+ SOUND_FACTORY = 44,
+ SOUND_EGG = 45,
+ SOUND_MOTORs = 46, // submarine
+ SOUND_MOTORi = 47, // insect (legs)
+ SOUND_SHIELD = 48,
+ SOUND_FIREi = 49, // shooting with orgaball (insect)
+ SOUND_GUNDEL = 50,
+ SOUND_PSHHH2 = 51, // shield
+ SOUND_MESSAGE = 52,
+ SOUND_BOUMm = 53, // metal
+ SOUND_BOUMv = 54, // plant
+ SOUND_BOUMs = 55, // smooth
+ SOUND_EXPLOl = 56, // little
+ SOUND_EXPLOlp = 57, // little power
+ SOUND_EXPLOp = 58, // power
+ SOUND_STEPh = 59, // hard
+ SOUND_STEPm = 60, // metal
+ SOUND_POWERON = 61,
+ SOUND_POWEROFF = 62,
+ SOUND_AIE = 63,
+ SOUND_WAYPOINT = 64,
+ SOUND_RECOVER = 65,
+ SOUND_DEADi = 66,
+ SOUND_JOSTLE = 67,
+ SOUND_GFLAT = 68,
+ SOUND_DEADg = 69, // shooting death
+ SOUND_DEADw = 70, // drowning
+ SOUND_FLYf = 71, // reactor fail
+ SOUND_ALARMt = 72, // temperature alarm
+ SOUND_FINDING = 73, // finds a cache object
+ SOUND_THUMP = 74,
+ SOUND_TOUCH = 75,
+ SOUND_BLITZ = 76,
+ SOUND_MUSHROOM = 77,
+ SOUND_FIREp = 78, // shooting with phazer
+ SOUND_EXPLOg1 = 79, // impact gun 1
+ SOUND_EXPLOg2 = 80, // impact gun 2
+ SOUND_MOTORd = 81, // engine friction
+};
+
+enum SoundNext
+{
+ SOPER_CONTINUE = 1,
+ SOPER_STOP = 2,
+ SOPER_LOOP = 3,
+};
+
+struct SoundOper
+{
+ char bUsed;
+ float finalAmplitude;
+ float finalFrequency;
+ float totalTime;
+ float currentTime;
+ SoundNext nextOper;
+};
+
+struct SoundChannel
+{
+ char bUsed; // buffer used?
+ char bMute; // silence?
+ Sound type; // SOUND_*
+ int priority; // so great -> important
+ Math::Vector pos; // position in space
+ unsigned short uniqueStamp; // unique marker
+ LPDIRECTSOUNDBUFFER soundBuffer;
+ LPDIRECTSOUND3DBUFFER soundBuffer3D;
+ float startAmplitude;
+ float startFrequency;
+ float changeFrequency;
+ int initFrequency;
+ float volume; // 2D: volume 1..0 depending on position
+ float pan; // 2D: pan -1..+1 depending on position
+ SoundOper oper[MAXOPER];
+};
+
+
+
+class CSound
+{
+public:
+ CSound(CInstanceManager* iMan);
+ ~CSound();
+
+ void SetDebugMode(bool bMode);
+ bool Create(HWND hWnd, bool b3D);
+ void CacheAll();
+
+ void SetState(bool bState);
+ bool RetEnable();
+
+ void SetCDpath(char *path);
+ void SetAudioTrack(bool bAudio);
+
+ void SetSound3D(bool bMode);
+ bool RetSound3D();
+ bool RetSound3DCap();
+
+ void SetAudioVolume(int volume);
+ int RetAudioVolume();
+ void SetMidiVolume(int volume);
+ int RetMidiVolume();
+
+ void SetListener(Math::Vector eye, Math::Vector lookat);
+ void FrameMove(float rTime);
+
+ int Play(Sound sound, float amplitude=1.0f, float frequency=1.0f, bool bLoop=false);
+ int Play(Sound sound, Math::Vector pos, float amplitude=1.0f, float frequency=1.0f, bool bLoop=false);
+ bool FlushEnvelope(int channel);
+ bool AddEnvelope(int channel, float amplitude, float frequency, float time, SoundNext oper);
+ bool Position(int channel, Math::Vector pos);
+ bool Frequency(int channel, float frequency);
+ bool Stop(int channel);
+ bool StopAll();
+ bool MuteAll(bool bMute);
+
+ bool PlayMusic(int rank, bool bRepeat);
+ bool RestartMusic();
+ void SuspendMusic();
+ void StopMusic();
+ bool IsPlayingMusic();
+ void AdaptVolumeMusic();
+
+protected:
+ bool CheckChannel(int &channel);
+ bool CreateSoundBuffer(int channel, DWORD size, DWORD freq, DWORD bitsPerSample, DWORD blkAlign, bool bStereo);
+ bool ReadData(LPDIRECTSOUNDBUFFER lpDSB, Sound sound, DWORD size);
+ bool CreateBuffer(int channel, Sound sound);
+ void ComputeVolumePan2D(int channel, const Math::Vector &pos);
+ bool ReadFile(Sound sound, char *metaname, char *filename);
+ int RetPriority(Sound sound);
+ bool SearchFreeBuffer(Sound sound, int &channel, bool &bAlreadyLoaded);
+ void OperNext(int channel);
+ bool PlayAudioTrack(int rank);
+
+protected:
+ CInstanceManager* m_iMan;
+
+ HWND m_hWnd;
+ bool m_bEnable;
+ bool m_bState;
+ bool m_bAudioTrack;
+ bool m_ctrl3D;
+ bool m_bDebugMode;
+ LPDIRECTSOUND m_lpDS;
+ LPDIRECTSOUND3DLISTENER m_listener;
+ SoundChannel m_channel[MAXSOUND];
+ char* m_files[MAXFILES];
+ UINT m_MidiDeviceID;
+ int m_MIDIMusic;
+ bool m_bRepeatMusic;
+ int m_audioVolume;
+ int m_midiVolume;
+ int m_lastMidiVolume;
+ Math::Vector m_eye;
+ Math::Vector m_lookat;
+ float m_lastTime;
+ float m_playTime;
+ int m_uniqueStamp;
+ int m_maxSound;
+ char m_CDpath[100];
+};
+
+
diff --git a/src/old/water.cpp b/src/old/water.cpp index 510d1fe..215bac9 100644 --- a/src/old/water.cpp +++ b/src/old/water.cpp @@ -34,7 +34,7 @@ #include "old/particule.h"
#include "old/terrain.h"
#include "object/object.h"
-#include "sound/sound.h"
+#include "old/sound.h"
#include "old/water.h"
diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index e4420a1..49d7684 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -42,7 +42,7 @@ #include "object/brain.h"
#include "object/motion/motion.h"
#include "object/motion/motionhuman.h"
-#include "sound/sound.h"
+#include "old/sound.h"
#include "object/task/task.h"
#include "script/cmdtoken.h"
#include "physics/physics.h"
diff --git a/src/sound/sound.cpp b/src/sound/sound.cpp index f307838..e69de29 100644 --- a/src/sound/sound.cpp +++ b/src/sound/sound.cpp @@ -1,1659 +0,0 @@ -// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.
-
-// sound.cpp
-
-
-#include <stdlib.h>
-#include <ctype.h>
-#include <d3dtypes.h>
-#include <dsound.h>
-#include <stdio.h>
-
-#include "common/language.h"
-#include "common/struct.h"
-#include "common/iman.h"
-#include "math/geometry.h"
-#include "math/conv.h"
-#include "old/math3d.h"
-#include "sound/sound.h"
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-
-const int LXIMAGE = 640;
-const int LYIMAGE = 480;
-
-
-
-// Header .WAV file.
-
-struct WaveHeader
-{
- BYTE RIFF[4]; // "RIFF"
- DWORD dwSize; // size of data to follow
- BYTE WAVE[4]; // "WAVE"
- BYTE fmt_[4]; // "fmt "
- DWORD dw16; // 16
- WORD wOne_0; // 1
- WORD wChnls; // number of Channels
- DWORD dwSRate; // sample Rate
- DWORD BytesPerSec; // sample Rate
- WORD wBlkAlign; // 1
- WORD BitsPerSample; // sample size
- BYTE DATA[4]; // "DATA"
- DWORD dwDSize; // number of Samples
-};
-
-
-
-
-// Displays an error DirectSound.
-
-void DisplayError(char *name, Sound sound, HRESULT err)
-{
- char s[100];
- unsigned int i = err;
- if ( err == DS_OK ) return;
- sprintf(s, "SoundError in %s, sound=%d err=%d\n", name, sound, i);
- OutputDebugString(s);
-
- if ( err == DSERR_ALLOCATED ) OutputDebugString("DSERR_ALLOCATED\n");
- if ( err == DSERR_CONTROLUNAVAIL ) OutputDebugString("DSERR_CONTROLUNAVAIL\n");
- if ( err == DSERR_INVALIDPARAM ) OutputDebugString("DSERR_INVALIDPARAM\n");
- if ( err == DSERR_INVALIDCALL ) OutputDebugString("DSERR_INVALIDCALL\n");
- if ( err == DSERR_GENERIC ) OutputDebugString("DSERR_GENERIC\n");
- if ( err == DSERR_PRIOLEVELNEEDED ) OutputDebugString("DSERR_PRIOLEVELNEEDED\n");
- if ( err == DSERR_OUTOFMEMORY ) OutputDebugString("DSERR_OUTOFMEMORY\n");
- if ( err == DSERR_BADFORMAT ) OutputDebugString("DSERR_BADFORMAT\n");
- if ( err == DSERR_UNSUPPORTED ) OutputDebugString("DSERR_UNSUPPORTED\n");
- if ( err == DSERR_NODRIVER ) OutputDebugString("DSERR_NODRIVER\n");
- if ( err == DSERR_ALREADYINITIALIZED ) OutputDebugString("DSERR_ALREADYINITIALIZED\n");
- if ( err == DSERR_NOAGGREGATION ) OutputDebugString("DSERR_NOAGGREGATION\n");
- if ( err == DSERR_BUFFERLOST ) OutputDebugString("DSERR_BUFFERLOST\n");
- if ( err == DSERR_OTHERAPPHASPRIO ) OutputDebugString("DSERR_OTHERAPPHASPRIO\n");
- if ( err == DSERR_UNINITIALIZED ) OutputDebugString("DSERR_UNINITIALIZED\n");
- if ( err == DSERR_NOINTERFACE ) OutputDebugString("DSERR_NOINTERFACE\n");
- if ( err == DSERR_ACCESSDENIED ) OutputDebugString("DSERR_ACCESSDENIED\n");
-}
-
-// Returns the name of the current folder.
-
-void GetCurrentDir(char *pName, int lg)
-{
- int i;
-
- strncpy(pName, _pgmptr, lg-1);
- pName[lg-1] = 0;
-
- lg = strlen(pName);
- if ( lg == 0 ) return;
-
- for ( i=0 ; i<lg ; i++ )
- {
- pName[i] = tolower(pName[i]);
- }
-
- while ( lg > 0 )
- {
- lg --;
- if ( pName[lg] == '\\' )
- {
- pName[lg+1] = 0;
- break;
- }
- }
-
- if ( lg > 6 && strcmp(pName+lg-6, "\\debug\\") == 0 )
- {
- pName[lg-5] = 0; // ignores the folder \debug!
- }
-
- if ( lg > 6 && strcmp(pName+lg-6, "\\release\\") == 0 )
- {
- pName[lg-7] = 0; // ignores the folder \release !
- }
-}
-
-
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-
-// Changes the volume of midi.
-// The volume is between 0 and 20!
-
-void InitMidiVolume(int volume)
-{
- int nb, i, n;
- MMRESULT result;
- HMIDIOUT hmo = 0;
-
- static int table[21] =
- {
- 0x00000000,
- 0x11111111,
- 0x22222222,
- 0x33333333,
- 0x44444444,
- 0x55555555,
- 0x66666666,
- 0x77777777,
- 0x88888888,
- 0x99999999,
- 0xAAAAAAAA,
- 0xBBBBBBBB,
- 0xCCCCCCCC,
- 0xDDDDDDDD,
- 0xEEEEEEEE,
- 0xF222F222,
- 0xF555F555,
- 0xF777F777,
- 0xFAAAFAAA,
- 0xFDDDFDDD,
- 0xFFFFFFFF,
- };
-
- if ( volume < 0 ) volume = 0;
- if ( volume > MAXVOLUME ) volume = MAXVOLUME;
-
- nb = midiOutGetNumDevs();
- for ( i=0 ; i<nb ; i++ )
- {
- result = midiOutOpen((LPHMIDIOUT)&hmo, i, 0L, 0L, 0L);
- if ( result != MMSYSERR_NOERROR )
- {
- continue;
- }
-
- result = midiOutSetVolume(hmo, table[volume]);
- if ( result != MMSYSERR_NOERROR )
- {
- n = 1;
- }
- midiOutClose(hmo);
- hmo = 0;
- }
-}
-
-// Changes the volume of audio CD.
-// The volume is between 0 and 20!
-// Crashing in Vista. The current craft (if _SOUNDTRACKS = true) no longer crashes,
-// but this is not the correct volume which is modified!
-
-bool InitAudioTrackVolume(int volume)
-{
-#if _SOUNDTRACKS
- MMRESULT rc; // Return code.
- HMIXER hMixer; // Mixer handle used in mixer API calls.
- MIXERCONTROL mxc; // Holds the mixer control data.
- MIXERLINE mxl; // Holds the mixer line data.
- MIXERLINECONTROLS mxlc; // Obtains the mixer control.
-
- if ( volume < 0 ) volume = 0;
- if ( volume > MAXVOLUME ) volume = MAXVOLUME;
-
- // Open the mixer. This opens the mixer with a deviceID of 0. If you
- // have a single sound card/mixer, then this will open it. If you have
- // multiple sound cards/mixers, the deviceIDs will be 0, 1, 2, and
- // so on.
- rc = mixerOpen(&hMixer, 0,0,0,0);
- if ( rc != MMSYSERR_NOERROR )
- {
- return false; // Couldn't open the mixer.
- }
-
- // Initialize MIXERLINE structure.
- ZeroMemory(&mxl,sizeof(mxl));
- mxl.cbStruct = sizeof(mxl);
-
- // Specify the line you want to get. You are getting the input line
- // here. If you want to get the output line, you need to use
- // MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT.
- mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
-
- rc = mixerGetLineInfo((HMIXEROBJ)hMixer, &mxl,
- MIXER_GETLINEINFOF_COMPONENTTYPE);
- if ( rc != MMSYSERR_NOERROR )
- {
- return false; // Couldn't get the mixer line.
- }
-
- // Get the control.
- ZeroMemory(&mxlc, sizeof(mxlc));
- mxlc.cbStruct = sizeof(mxlc);
- mxlc.dwLineID = mxl.dwLineID;
-//? mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_PEAKMETER;
-//? mxlc.dwControlType = MIXERCONTROL_CONTROLF_UNIFORM;
- mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
- mxlc.cControls = 1;
- mxlc.cbmxctrl = sizeof(mxc);
- mxlc.pamxctrl = &mxc;
- ZeroMemory(&mxc, sizeof(mxc));
- mxc.cbStruct = sizeof(mxc);
- rc = mixerGetLineControls((HMIXEROBJ)hMixer,&mxlc,
- MIXER_GETLINECONTROLSF_ONEBYTYPE);
-//? MIXER_GETLINECONTROLSF_ALL);
- if ( rc != MMSYSERR_NOERROR )
- {
- return false; // Couldn't get the control.
- }
-
- // After successfully getting the peakmeter control, the volume range
- // will be specified by mxc.Bounds.lMinimum to mxc.Bounds.lMaximum.
-
- MIXERCONTROLDETAILS mxcd; // Gets the control values.
- MIXERCONTROLDETAILS_SIGNED volStruct; // Gets the control values.
-
- volStruct.lValue = volume*(mxc.Bounds.lMaximum-mxc.Bounds.lMinimum);
- volStruct.lValue /= MAXVOLUME;
- volStruct.lValue += mxc.Bounds.lMinimum;
-
- // Initialize the MIXERCONTROLDETAILS structure
- ZeroMemory(&mxcd, sizeof(mxcd));
- mxcd.cbStruct = sizeof(mxcd);
- mxcd.cbDetails = sizeof(volStruct);
- mxcd.dwControlID = mxc.dwControlID;
- mxcd.paDetails = &volStruct;
- mxcd.cChannels = 1;
-
- // Get the current value of the peakmeter control. Typically, you
- // would set a timer in your program to query the volume every 10th
- // of a second or so.
- rc = mixerSetControlDetails((HMIXEROBJ)hMixer, &mxcd,
- MIXER_SETCONTROLDETAILSF_VALUE);
- if ( rc != MMSYSERR_NOERROR )
- {
- return false; // Couldn't get the current volume.
- }
-#endif
-
- return true;
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-
-// Constructor.
-
-CSound::CSound(CInstanceManager* iMan)
-{
- int i;
-
- m_iMan = iMan;
- m_iMan->AddInstance(CLASS_SOUND, this);
-
- m_bEnable = false;
- m_bState = false;
- m_bAudioTrack = true;
- m_ctrl3D = true;
- m_bDebugMode = false;
- m_MidiDeviceID = 0;
- m_MIDIMusic = 0;
- m_audioVolume = 20;
- m_midiVolume = 15;
- m_lastMidiVolume = 0;
- m_listener = 0;
- m_lastTime = 0.0f;
- m_playTime = 0.0f;
- m_uniqueStamp = 0;
- m_maxSound = MAXSOUND;
- m_eye = Math::Vector(0.0f, 0.0f, 0.0f);
- m_hWnd = 0;
-
- m_lpDS = NULL;
-
- ZeroMemory(m_channel, sizeof(SoundChannel)*MAXSOUND);
- for ( i=0 ; i<MAXSOUND ; i++ )
- {
- m_channel[i].bUsed = false;
- }
-
- for ( i=0 ; i<MAXFILES ; i++ )
- {
- m_files[i] = 0;
- }
-}
-
-// Destructor.
-
-CSound::~CSound()
-{
- int i;
-
- if ( m_bEnable )
- {
- InitMidiVolume(15); // gives an average volume!
- InitAudioTrackVolume(15); // gives an average volume!
- }
-
- for ( i=0 ; i<MAXSOUND ; i++ )
- {
- if ( m_channel[i].bUsed )
- {
- m_channel[i].soundBuffer->Stop();
- m_channel[i].soundBuffer->Release();
- m_channel[i].soundBuffer = 0;
- m_channel[i].bUsed = false;
- }
- }
-
- if ( m_listener != NULL )
- {
- m_listener->Release();
- m_listener = NULL;
- }
-
- if ( m_lpDS != NULL )
- {
- m_lpDS->Release();
- m_lpDS = NULL;
- }
-}
-
-
-// Specifies whether you are in debug mode.
-
-void CSound::SetDebugMode(bool bMode)
-{
- m_bDebugMode = bMode;
-}
-
-
-// Initializes DirectSound.
-
-bool CSound::Create(HWND hWnd, bool b3D)
-{
- LPDIRECTSOUNDBUFFER primary;
- DSBUFFERDESC dsbdesc;
- DSCAPS dscaps;
- WAVEFORMATEX wfx;
- HRESULT hr;
-
- if ( !DirectSoundCreate(NULL, &m_lpDS, NULL) == DS_OK )
- {
- OutputDebugString("Fatal error: DirectSoundCreate\n");
- m_bEnable = false;
- return false;
- }
-
-//? m_lpDS->SetCooperativeLevel(hWnd, DSSCL_NORMAL);
- m_lpDS->SetCooperativeLevel(hWnd, DSSCL_PRIORITY);
-
- if ( !RetSound3DCap() ) b3D = false;
-
- m_ctrl3D = false;
- if ( b3D )
- {
- // Obtain primary buffer, asking it for 3D control.
- ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
- dsbdesc.dwSize = sizeof(DSBUFFERDESC);
- dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
- hr = m_lpDS->CreateSoundBuffer( &dsbdesc, &primary, NULL );
- if ( hr == S_OK )
- {
- m_ctrl3D = true;
- }
- }
-
- if ( !m_ctrl3D )
- {
- // Obtain primary buffer, without 3D control.
- ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
- dsbdesc.dwSize = sizeof(DSBUFFERDESC);
- dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
- hr = m_lpDS->CreateSoundBuffer( &dsbdesc, &primary, NULL );
- if ( hr != S_OK )
- {
- return false;
- }
- m_ctrl3D = false;
- }
-
- if ( m_ctrl3D )
- {
- hr = primary->QueryInterface( IID_IDirectSound3DListener,
- (VOID**)&m_listener );
- if ( hr != S_OK )
- {
- primary->Release();
- return false;
- }
- }
-
- // Set primary buffer format to 44kHz and 16-bit output.
- ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
- wfx.wFormatTag = WAVE_FORMAT_PCM;
- wfx.nChannels = 2;
- wfx.nSamplesPerSec = 22050;
-//? wfx.nSamplesPerSec = 44100;
- wfx.wBitsPerSample = 16;
- wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
- wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
- hr = primary->SetFormat(&wfx);
- if ( hr != S_OK )
- {
- DisplayError("SetFormat", SOUND_CLICK, hr);
- }
-
- // Release the primary buffer, since it is not need anymore.
- primary->Release();
-
- // Search the maximum possible voices.
- if ( m_ctrl3D )
- {
- ZeroMemory( &dscaps, sizeof(DSCAPS) );
- dscaps.dwSize = sizeof(DSCAPS);
- hr = m_lpDS->GetCaps(&dscaps);
- if ( hr == DS_OK )
- {
- m_maxSound = dscaps.dwMaxHwMixingAllBuffers;
- if ( dscaps.dwMaxHw3DAllBuffers > 0 &&
- m_maxSound > (int)dscaps.dwMaxHw3DAllBuffers )
- {
- m_maxSound = dscaps.dwMaxHw3DAllBuffers;
- }
- if ( m_maxSound > MAXSOUND ) m_maxSound = MAXSOUND;
- }
- }
-
- m_bEnable = true;
- m_hWnd = hWnd;
- return true;
-}
-
-
-// Indicates whether to play sounds in 3D or not.
-
-void CSound::SetSound3D(bool bMode)
-{
- StopAll();
-
- if ( m_listener != NULL )
- {
- m_listener->Release();
- m_listener = NULL;
- }
-
- if ( m_lpDS != NULL )
- {
- m_lpDS->Release();
- m_lpDS = NULL;
- }
-
- Create(m_hWnd, bMode);
-}
-
-bool CSound::RetSound3D()
-{
- return m_ctrl3D;
-}
-
-// Indicates whether it is possible to play sounds in 3D.
-
-bool CSound::RetSound3DCap()
-{
- DSCAPS dscaps;
- HRESULT hr;
-
- ZeroMemory( &dscaps, sizeof(DSCAPS) );
- dscaps.dwSize = sizeof(DSCAPS);
- hr = m_lpDS->GetCaps(&dscaps);
- if ( hr != DS_OK ) return false;
-
- return ( dscaps.dwMaxHw3DAllBuffers > 0 );
-}
-
-
-
-// Returns the state of DirectSound.
-
-bool CSound::RetEnable()
-{
- return m_bEnable;
-}
-
-
-// Switches on or off the sound.
-
-void CSound::SetState(bool bState)
-{
- m_bState = bState;
-}
-
-// Specifies the pathname to the CD.
-
-void CSound::SetCDpath(char *path)
-{
- strcpy(m_CDpath, path);
-}
-
-// Switches on or off the CD-audio music.
-
-void CSound::SetAudioTrack(bool bAudio)
-{
- m_bAudioTrack = bAudio;
-}
-
-
-// Manages volumes of audio (. Wav) and midi (. Mid).
-
-void CSound::SetAudioVolume(int volume)
-{
- m_audioVolume = volume;
-}
-
-int CSound::RetAudioVolume()
-{
- if ( !m_bEnable ) return 0;
- return m_audioVolume;
-}
-
-void CSound::SetMidiVolume(int volume)
-{
- m_midiVolume = volume;
-
- if ( m_bAudioTrack )
- {
- InitAudioTrackVolume(m_midiVolume);
- }
-}
-
-int CSound::RetMidiVolume()
-{
- if ( !m_bEnable ) return 0;
- return m_midiVolume;
-}
-
-
-// Reads a file.
-
-bool CSound::ReadFile(Sound sound, char *metaname, char *filename)
-{
- WaveHeader wavHdr;
- DWORD size;
- int err;
-
- // Open the wave file.
- err = g_metafile.Open(metaname, filename);
- if ( err != 0 ) return false;
-
- // Read in the wave header.
- g_metafile.Read(&wavHdr, sizeof(wavHdr));
-
- // Figure out the size of the data region.
- size = wavHdr.dwDSize;
-
- if ( m_files[sound] != 0 )
- {
- free(m_files[sound]);
- }
- m_files[sound] = (char*)malloc(sizeof(WaveHeader)+size);
-
- memcpy(m_files[sound], &wavHdr, sizeof(WaveHeader));
- g_metafile.Read(m_files[sound]+sizeof(WaveHeader), size);
-
- // Close out the wave file.
- g_metafile.Close();
- return true;
-}
-
-// Hides all sound files (. Wav).
-
-void CSound::CacheAll()
-{
- int i;
- char meta[50];
- char name[50];
-
- if ( !m_bEnable ) return;
-
- if ( m_bDebugMode )
- {
- strcpy(meta, "");
- }
- else
- {
-#if _SCHOOL
- strcpy(meta, "ceebot3.dat");
-#else
- strcpy(meta, "colobot3.dat");
-#endif
- }
-
- for ( i=0 ; i<MAXFILES ; i++ )
- {
- if ( m_bDebugMode )
- {
- sprintf(name, "sound\\sound%.3d.wav", i);
- }
- else
- {
- sprintf(name, "sound%.3d.wav", i);
- }
- if ( !ReadFile((Sound)i, meta, name) ) break;
- }
-}
-
-
-// Return the priority of a sound.
-// The higher the value, the greater the sound is important.
-
-int CSound::RetPriority(Sound sound)
-{
- if ( sound == SOUND_FLYh ||
- sound == SOUND_FLY ||
- sound == SOUND_MOTORw ||
- sound == SOUND_MOTORt ||
- sound == SOUND_MOTORr ||
- sound == SOUND_MOTORs ||
- sound == SOUND_SLIDE ||
- sound == SOUND_ERROR )
- {
- return 30;
- }
-
- if ( sound == SOUND_CONVERT ||
- sound == SOUND_ENERGY ||
- sound == SOUND_DERRICK ||
- sound == SOUND_STATION ||
- sound == SOUND_REPAIR ||
- sound == SOUND_RESEARCH ||
- sound == SOUND_BURN ||
- sound == SOUND_BUILD ||
- sound == SOUND_TREMBLE ||
- sound == SOUND_NUCLEAR ||
- sound == SOUND_EXPLO ||
- sound == SOUND_EXPLOl ||
- sound == SOUND_EXPLOlp ||
- sound == SOUND_EXPLOp ||
- sound == SOUND_EXPLOi )
- {
- return 20;
- }
-
- if ( sound == SOUND_BLUP ||
- sound == SOUND_INSECTs ||
- sound == SOUND_INSECTa ||
- sound == SOUND_INSECTb ||
- sound == SOUND_INSECTw ||
- sound == SOUND_INSECTm ||
- sound == SOUND_PSHHH ||
- sound == SOUND_EGG )
- {
- return 0;
- }
-
- return 10;
-}
-
-// Seeks a free buffer.
-
-bool CSound::SearchFreeBuffer(Sound sound, int &channel, bool &bAlreadyLoaded)
-{
- DWORD status;
- int i, priority;
-
- priority = RetPriority(sound);
-
-#if 1
- // Seeks a channel used which sound is stopped.
- for ( i=0 ; i<m_maxSound ; i++ )
- {
- if ( !m_channel[i].bUsed ) continue;
- if ( m_channel[i].type != sound ) continue;
-
- m_channel[i].soundBuffer->GetStatus(&status);
- if ( (status&DSBSTATUS_PLAYING) == 0 )
- {
- m_channel[i].priority = priority;
- m_channel[i].uniqueStamp = m_uniqueStamp++;
- channel = i;
- bAlreadyLoaded = true;
- return true;
- }
- }
-#endif
-
- // Seeks a channel completely free.
- for ( i=0 ; i<m_maxSound ; i++ )
- {
- if ( !m_channel[i].bUsed )
- {
- m_channel[i].priority = priority;
- m_channel[i].uniqueStamp = m_uniqueStamp++;
- channel = i;
- bAlreadyLoaded = false;
- return true;
- }
- }
-
- // Seeks a channel used which sound is stopped.
- for ( i=0 ; i<m_maxSound ; i++ )
- {
- if ( !m_channel[i].bUsed ) continue;
-
- m_channel[i].soundBuffer->GetStatus(&status);
- if ( (status&DSBSTATUS_PLAYING) == 0 )
- {
- m_channel[i].soundBuffer->Release();
- m_channel[i].soundBuffer = 0;
- m_channel[i].priority = priority;
- m_channel[i].uniqueStamp = m_uniqueStamp++;
-
- channel = i;
- bAlreadyLoaded = false;
- return true;
- }
- }
-
- // Seeks a lower priority channel used.
- for ( i=0 ; i<m_maxSound ; i++ )
- {
- if ( !m_channel[i].bUsed ) continue;
- if ( m_channel[i].priority >= priority ) continue;
-
- m_channel[i].soundBuffer->Stop();
- m_channel[i].soundBuffer->Release();
- m_channel[i].soundBuffer = 0;
- m_channel[i].priority = priority;
- m_channel[i].uniqueStamp = m_uniqueStamp++;
-
- channel = i;
- bAlreadyLoaded = false;
- return true;
- }
-
- // Seeks a channel used the same or lower priority.
- for ( i=0 ; i<m_maxSound ; i++ )
- {
- if ( !m_channel[i].bUsed ) continue;
- if ( m_channel[i].priority > priority ) continue;
-
- m_channel[i].soundBuffer->Stop();
- m_channel[i].soundBuffer->Release();
- m_channel[i].soundBuffer = 0;
- m_channel[i].priority = priority;
- m_channel[i].uniqueStamp = m_uniqueStamp++;
-
- channel = i;
- bAlreadyLoaded = false;
- return true;
- }
-
- char s[100];
- sprintf(s, "Sound %d forget (priority=%d)\n", sound, priority);
- OutputDebugString(s);
-
- return false;
-}
-
-// Reads in data from a wave file.
-
-bool CSound::ReadData(LPDIRECTSOUNDBUFFER lpDSB, Sound sound, DWORD size)
-{
- LPVOID pData1;
- DWORD dwData1Size;
- LPVOID pData2;
- DWORD dwData2Size;
- HRESULT hr;
-
- // Lock data in buffer for writing.
- hr = lpDSB->Lock(0, size, &pData1, &dwData1Size, &pData2, &dwData2Size, DSBLOCK_FROMWRITECURSOR);
- if ( hr != DS_OK )
- {
- return false;
- }
-
- // Read in first chunk of data.
- if ( dwData1Size > 0 )
- {
- memcpy(pData1, m_files[sound]+sizeof(WaveHeader), dwData1Size);
- }
-
- // Read in second chunk if necessary.
- if ( dwData2Size > 0 )
- {
- memcpy(pData2, m_files[sound]+sizeof(WaveHeader)+dwData1Size, dwData2Size);
- }
-
- // Unlock data in buffer.
- hr = lpDSB->Unlock(pData1, dwData1Size, pData2, dwData2Size);
- if ( hr != DS_OK )
- {
- return false;
- }
-
- return true;
-}
-
-// Creates a DirectSound buffer.
-
-bool CSound::CreateSoundBuffer(int channel, DWORD size, DWORD freq,
- DWORD bitsPerSample, DWORD blkAlign,
- bool bStereo)
-{
- PCMWAVEFORMAT pcmwf;
- DSBUFFERDESC dsbdesc;
- DS3DBUFFER bufferParams; // 3D buffer properties
- HRESULT hr;
-
- // Set up wave format structure.
- memset( &pcmwf, 0, sizeof(PCMWAVEFORMAT) );
- pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM;
- pcmwf.wf.nChannels = bStereo ? 2 : 1;
- pcmwf.wf.nSamplesPerSec = freq;
- pcmwf.wf.nBlockAlign = (WORD)blkAlign;
- pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign;
- pcmwf.wBitsPerSample = (WORD)bitsPerSample;
-
- // Set up DSBUFFERDESC structure.
- memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
- dsbdesc.dwSize = sizeof(DSBUFFERDESC);
- if ( m_ctrl3D )
- {
- dsbdesc.dwFlags = DSBCAPS_CTRL3D|DSBCAPS_MUTE3DATMAXDISTANCE|
- DSBCAPS_LOCDEFER|
- DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLFREQUENCY;
- }
- else
- {
- dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN|DSBCAPS_CTRLFREQUENCY;
- }
- dsbdesc.dwBufferBytes = size;
- dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;
-
- hr = m_lpDS->CreateSoundBuffer(&dsbdesc, &m_channel[channel].soundBuffer, NULL);
- if ( hr != DS_OK ) return false;
-
- if ( m_ctrl3D )
- {
- hr = m_channel[channel].soundBuffer->QueryInterface
- (
- IID_IDirectSound3DBuffer,
- (VOID**)&m_channel[channel].soundBuffer3D
- );
- if ( hr != DS_OK ) return false;
- }
-
- m_channel[channel].bUsed = true;
- m_channel[channel].bMute = false;
- return true;
-}
-
-// Creates a DirectSound buffer from a wave file.
-
-bool CSound::CreateBuffer(int channel, Sound sound)
-{
- WaveHeader* wavHdr;
- DWORD size;
- bool bStereo;
-
- if ( m_files[sound] == 0 ) return false;
-
- wavHdr = (WaveHeader*)m_files[sound];
- size = wavHdr->dwDSize;
- bStereo = wavHdr->wChnls > 1 ? true : false;
-
- // Create the sound buffer for the wave file.
- if ( !CreateSoundBuffer(channel, size, wavHdr->dwSRate,
- wavHdr->BitsPerSample, wavHdr->wBlkAlign, bStereo) )
- {
- return false;
- }
-
- // Read the data for the wave file into the sound buffer.
- if ( !ReadData(m_channel[channel].soundBuffer, sound, size) )
- {
- return false;
- }
-
- m_channel[channel].type = sound;
-
- // Close out the wave file.
- return true;
-}
-
-// Calculates the volume and pan of a sound, non-3D mode.
-
-void CSound::ComputeVolumePan2D(int channel, const Math::Vector &pos)
-{
- float dist, a, g;
-
- if ( pos.x == m_eye.x &&
- pos.y == m_eye.y &&
- pos.z == m_eye.z )
- {
- m_channel[channel].volume = 1.0f; // maximum volume
- m_channel[channel].pan = 0.0f; // at the center
- return;
- }
-
-#if _TEEN
- dist = Math::Distance(pos, m_eye);
- if ( dist >= 210.0f ) // very far?
- {
- m_channel[channel].volume = 0.0f; // silence
- m_channel[channel].pan = 0.0f; // at the center
- return;
- }
- if ( dist <= 10.0f ) // very close?
- {
- m_channel[channel].volume = 1.0f; // maximum volume
- m_channel[channel].pan = 0.0f; // at the center
- return;
- }
- m_channel[channel].volume = 1.0f-((dist-10.0f)/200.0f);
-#else
- dist = Math::Distance(pos, m_eye);
- if ( dist >= 110.0f ) // very far?
- {
- m_channel[channel].volume = 0.0f; // silence
- m_channel[channel].pan = 0.0f; // at the center
- return;
- }
- if ( dist <= 10.0f ) // very close?
- {
- m_channel[channel].volume = 1.0f; // maximum volume
- m_channel[channel].pan = 0.0f; // at the center
- return;
- }
- m_channel[channel].volume = 1.0f-((dist-10.0f)/100.0f);
-#endif
-
- a = Math::RotateAngle(m_lookat.x-m_eye.x, m_eye.z-m_lookat.z);
- g = Math::RotateAngle(pos.x-m_eye.x, m_eye.z-pos.z);
- m_channel[channel].pan = sinf(Math::Direction(a, g));
-}
-
-// Sounds in the middle.
-// Returns the associated channel or -1.
-
-int CSound::Play(Sound sound, float amplitude, float frequency, bool bLoop)
-{
- return Play(sound, m_lookat, amplitude, frequency, bLoop);
-}
-
-// Sounds at a given position.
-// Returns the associated channel or -1.
-
-int CSound::Play(Sound sound, Math::Vector pos,
- float amplitude, float frequency, bool bLoop)
-{
- DS3DBUFFER sb;
- int channel, iVolume, iPan, iFreq, uniqueStamp;
- bool bAlreadyLoaded;
- DWORD flag, freq;
- HRESULT err;
-
- if ( !m_bEnable ) return -1;
- if ( !m_bState || m_audioVolume == 0 ) return -1;
-
-//? if ( Math::Distance(pos, m_eye) > 100.0f ) return -1;
-
- if ( !SearchFreeBuffer(sound, channel, bAlreadyLoaded) ) return -1;
-
- if ( !bAlreadyLoaded )
- {
- if ( !CreateBuffer(channel, sound) )
- {
- if ( m_channel[channel].bUsed &&
- m_channel[channel].soundBuffer != 0 )
- {
- m_channel[channel].soundBuffer->Release();
- m_channel[channel].soundBuffer = 0;
- }
- m_channel[channel].bUsed = false;
- return -1;
- }
- }
-
- m_channel[channel].pos = pos;
-
- if ( m_ctrl3D )
- {
- m_channel[channel].volume = 1.0f;
- m_channel[channel].pan = 0.0f;
- }
- else
- {
- ComputeVolumePan2D(channel, pos);
- }
-
-#if 0
- DWORD status;
- m_channel[channel].soundBuffer->GetStatus(&status);
- char s[100];
- sprintf(s, "Play sound=%d status=%d channel=%d flag=%d\n", sound, status, channel, bAlreadyLoaded);
- OutputDebugString(s);
-#endif
-
- m_channel[channel].oper[0].bUsed = false;
- m_channel[channel].startAmplitude = amplitude;
- m_channel[channel].startFrequency = frequency;
- m_channel[channel].changeFrequency = 1.0f;
-
- if ( m_ctrl3D )
- {
- sb.dwSize = sizeof(DS3DBUFFER);
- err = m_channel[channel].soundBuffer3D->GetAllParameters(&sb);
- DisplayError("GetAllParameters", sound, err);
-
- sb.vPosition = VEC_TO_D3DVEC(pos);
-//? sb.dwInsideConeAngle = 90;
-//? sb.dwOutsideConeAngle = 180;
-//? sb.vConeOrientation = Math::Vector(0.0f, 1.0f, 0.0f);
- sb.lConeOutsideVolume = DSBVOLUME_MIN;
-#if _TEEN
- sb.flMinDistance = 50.0f;
-#else
- sb.flMinDistance = 20.0f;
-#endif
- sb.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
-
- err = m_channel[channel].soundBuffer3D->SetAllParameters(&sb, DS3D_IMMEDIATE);
- DisplayError("SetAllParameters", sound, err);
- }
-
- amplitude *= m_channel[channel].volume;
- amplitude *= (float)m_audioVolume/MAXVOLUME;
- iVolume = (int)((powf(amplitude, 0.2f)-1.0f)*10000.0f);
- if ( iVolume > 0 ) iVolume = 0;
- err = m_channel[channel].soundBuffer->SetVolume(iVolume);
- DisplayError("SetVolume", sound, err);
-
- if ( !m_ctrl3D )
- {
- iPan = (int)(m_channel[channel].pan*10000.0f);
- err = m_channel[channel].soundBuffer->SetPan(iPan);
- DisplayError("SetPan", sound, err);
- }
-
- if ( !bAlreadyLoaded )
- {
- err = m_channel[channel].soundBuffer->GetFrequency(&freq);
- DisplayError("GetFrequency", sound, err);
- m_channel[channel].initFrequency = freq;
- }
- iFreq = (int)(frequency*m_channel[channel].initFrequency);
- err = m_channel[channel].soundBuffer->SetFrequency(iFreq);
- DisplayError("SetFrequency", sound, err);
-
- err = m_channel[channel].soundBuffer->SetCurrentPosition(0);
- DisplayError("SetCurrentPosition", sound, err);
-
- flag = bLoop?DSBPLAY_LOOPING:0;
-//? flag |= DSBPLAY_LOCHARDWARE|DSBPLAY_TERMINATEBY_DISTANCE;
-//? flag |= DSBPLAY_TERMINATEBY_DISTANCE;
- err = m_channel[channel].soundBuffer->Play(0, 0, flag);
- DisplayError("Play", sound, err);
- if ( err == DSERR_BADFORMAT )
- {
- iFreq = m_channel[channel].initFrequency;
- err = m_channel[channel].soundBuffer->SetFrequency(iFreq);
- DisplayError("SetFrequency (repeat)", sound, err);
-
- err = m_channel[channel].soundBuffer->Play(0, 0, flag);
- DisplayError("Play (repeat)", sound, err);
- }
-
- uniqueStamp = m_channel[channel].uniqueStamp;
- return channel | ((uniqueStamp&0xffff)<<16);
-}
-
-// Check a channel number.
-// Adapts the channel, so it can be used as an offset in m_channel.
-
-bool CSound::CheckChannel(int &channel)
-{
- int uniqueStamp;
-
- uniqueStamp = (channel>>16)&0xffff;
- channel &= 0xffff;
-
- if ( !m_bEnable ) return false;
- if ( !m_bState || m_audioVolume == 0 ) return false;
-
- if ( channel < 0 || channel >= m_maxSound ) return false;
- if ( !m_channel[channel].bUsed ) return false;
-
- if ( m_channel[channel].uniqueStamp != uniqueStamp ) return false;
-
- return true;
-}
-
-// Removes all envelopes.
-
-bool CSound::FlushEnvelope(int channel)
-{
- if ( !CheckChannel(channel) ) return false;
-
- m_channel[channel].oper[0].bUsed = false;
- return true;
-}
-
-// Adds an operation envelope.
-
-bool CSound::AddEnvelope(int channel, float amplitude, float frequency,
- float time, SoundNext oper)
-{
- int i;
-
- if ( !CheckChannel(channel) ) return false;
-
- for ( i=0 ; i<MAXOPER ; i++ )
- {
- if ( m_channel[channel].oper[i].bUsed ) continue;
-
- m_channel[channel].oper[i].bUsed = true;
- m_channel[channel].oper[i].finalAmplitude = amplitude;
- m_channel[channel].oper[i].finalFrequency = frequency;
- m_channel[channel].oper[i].totalTime = time;
- m_channel[channel].oper[i].currentTime = 0;
- m_channel[channel].oper[i].nextOper = oper;
-
- if ( i < MAXOPER-1 )
- {
- m_channel[channel].oper[i+1].bUsed = false;
- }
- return true;
- }
- return false;
-}
-
-// Changes the position of a sound.
-
-bool CSound::Position(int channel, Math::Vector pos)
-{
- float amplitude, pan;
- int iVolume, iPan;
- HRESULT err;
-
- if ( !CheckChannel(channel) ) return false;
-
- m_channel[channel].pos = pos;
-
- if ( m_ctrl3D )
- {
- m_channel[channel].soundBuffer3D->SetPosition(pos.x, pos.y, pos.z, DS3D_DEFERRED);
- }
- else
- {
- ComputeVolumePan2D(channel, pos);
-
- if ( !m_channel[channel].oper[0].bUsed )
- {
- amplitude = m_channel[channel].startAmplitude;
- amplitude *= m_channel[channel].volume;
- amplitude *= (float)m_audioVolume/MAXVOLUME;
- iVolume = (int)((powf(amplitude, 0.2f)-1.0f)*10000.0f);
- if ( iVolume > 0 ) iVolume = 0;
- err = m_channel[channel].soundBuffer->SetVolume(iVolume);
- DisplayError("SetVolume", m_channel[channel].type, err);
- }
-
- pan = m_channel[channel].pan;
- iPan = (int)(pan*10000.0f);
- err = m_channel[channel].soundBuffer->SetPan(iPan);
- DisplayError("SetPan", m_channel[channel].type, err);
- }
- return true;
-}
-
-// Changes the frequency of a sound.
-// 0.5 down of an octave and 2.0 up of an octave.
-
-bool CSound::Frequency(int channel, float frequency)
-{
- HRESULT err;
- int iFreq;
-
- if ( !CheckChannel(channel) ) return false;
-
- m_channel[channel].changeFrequency = frequency;
-
- if ( !m_channel[channel].oper[0].bUsed )
- {
- iFreq = (int)(frequency*m_channel[channel].initFrequency);
- err = m_channel[channel].soundBuffer->SetFrequency(iFreq);
- DisplayError("Frequency", m_channel[channel].type, err);
- }
-
- return true;
-}
-
-// Stops sound.
-
-bool CSound::Stop(int channel)
-{
- if ( !CheckChannel(channel) ) return false;
-
- m_channel[channel].soundBuffer->Stop();
- return true;
-}
-
-// Stops all sounds.
-
-bool CSound::StopAll()
-{
- DWORD status;
- int i;
-
- for ( i=0 ; i<MAXSOUND ; i++ )
- {
- if ( !m_channel[i].bUsed ) continue;
-
- m_channel[i].soundBuffer->GetStatus(&status);
- if ( (status&DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING )
- {
- m_channel[i].soundBuffer->Stop();
- }
- m_channel[i].soundBuffer->Stop();
- m_channel[i].soundBuffer->Release();
- m_channel[i].soundBuffer = 0;
-
- m_channel[i].bUsed = false;
- }
- return true;
-}
-
-// Silent all sounds.
-
-bool CSound::MuteAll(bool bMute)
-{
- int i;
-
- for ( i=0 ; i<MAXSOUND ; i++ )
- {
- if ( !m_channel[i].bUsed ) continue;
-
- m_channel[i].bMute = bMute;
- }
- return true;
-}
-
-
-// Passes the following operation for a channel.
-
-void CSound::OperNext(int channel)
-{
- int i;
-
- m_channel[channel].startAmplitude = m_channel[channel].oper[0].finalAmplitude;
- m_channel[channel].startFrequency = m_channel[channel].oper[0].finalFrequency;
-
- for ( i=0 ; i<MAXOPER-1 ; i++ )
- {
- if ( !m_channel[channel].oper[i+1].bUsed ) break;
-
- m_channel[channel].oper[i] = m_channel[channel].oper[i+1];
- }
-
- m_channel[channel].oper[i].bUsed = false;
-}
-
-// Updates the sound buffers.
-
-void CSound::FrameMove(float rTime)
-{
- HRESULT err;
- SoundNext next;
- float progress, volume, freq;
- int i, iVolume, iFreq;
-
- m_playTime += rTime;
-
- for ( i=0 ; i<m_maxSound ; i++ )
- {
- if ( !m_channel[i].bUsed ) continue;
- if ( !m_channel[i].oper[0].bUsed ) continue;
-
- if ( m_channel[i].bMute )
- {
- m_channel[i].soundBuffer->SetVolume(-10000); // silence
- continue;
- }
-
- m_channel[i].oper[0].currentTime += rTime;
-
- progress = m_channel[i].oper[0].currentTime / m_channel[i].oper[0].totalTime;
- if ( progress > 1.0f ) progress = 1.0f;
-
- volume = progress;
- volume *= m_channel[i].oper[0].finalAmplitude-m_channel[i].startAmplitude;
- volume += m_channel[i].startAmplitude;
- volume *= m_channel[i].volume;
- volume *= (float)m_audioVolume/MAXVOLUME;
- iVolume = (int)((powf(volume, 0.2f)-1.0f)*10000.0f);
- if ( iVolume > 0 ) iVolume = 0;
- m_channel[i].soundBuffer->SetVolume(iVolume);
-
- freq = progress;
- freq *= m_channel[i].oper[0].finalFrequency-m_channel[i].startFrequency;
- freq += m_channel[i].startFrequency;
- freq *= m_channel[i].changeFrequency;
- iFreq = (int)(freq*m_channel[i].initFrequency);
- err = m_channel[i].soundBuffer->SetFrequency(iFreq);
- DisplayError("FrameMove::Frequency", m_channel[i].type, err);
-
- if ( m_channel[i].oper[0].currentTime >=
- m_channel[i].oper[0].totalTime )
- {
- next = m_channel[i].oper[0].nextOper;
-
- if ( next == SOPER_LOOP )
- {
- m_channel[i].oper[0].currentTime = 0.0f;
- }
- else
- {
- OperNext(i);
-
- if ( next == SOPER_STOP )
- {
- m_channel[i].soundBuffer->Stop();
- }
- }
- }
- }
-
- m_lastTime += rTime;
- if ( m_lastTime >= 0.05f && m_listener != 0 )
- {
- m_lastTime = 0.0f;
- m_listener->CommitDeferredSettings();
- }
-}
-
-// Specifies the position of the listener.
-// Must be called whenever the camera moves.
-
-void CSound::SetListener(Math::Vector eye, Math::Vector lookat)
-{
- DS3DLISTENER listenerParams;
- HRESULT err;
- float amplitude, pan;
- int i, iVolume, iPan;
-
- m_eye = eye;
- m_lookat = lookat;
-
- if ( m_listener == 0 )
- {
- if ( m_ctrl3D ) return;
-
- for ( i=0 ; i<m_maxSound ; i++ )
- {
- if ( !m_channel[i].bUsed ) continue;
-
- ComputeVolumePan2D(i, m_channel[i].pos);
-
- if ( !m_channel[i].oper[0].bUsed )
- {
- amplitude = m_channel[i].startAmplitude;
- amplitude *= m_channel[i].volume;
- amplitude *= (float)m_audioVolume/MAXVOLUME;
- iVolume = (int)((powf(amplitude, 0.2f)-1.0f)*10000.0f);
- if ( iVolume > 0 ) iVolume = 0;
- err = m_channel[i].soundBuffer->SetVolume(iVolume);
- DisplayError("SetVolume", m_channel[i].type, err);
- }
-
- pan = m_channel[i].pan;
- iPan = (int)(pan*10000.0f);
- err = m_channel[i].soundBuffer->SetPan(iPan);
- DisplayError("SetPan", m_channel[i].type, err);
- }
- return;
- }
-
- // Get listener parameters.
- listenerParams.dwSize = sizeof(DS3DLISTENER);
- m_listener->GetAllParameters(&listenerParams);
-
- listenerParams.vPosition = VEC_TO_D3DVEC(eye);
- listenerParams.vOrientFront = VEC_TO_D3DVEC(lookat-eye);
- listenerParams.vOrientTop = D3DVECTOR(0.0f, 1.0f, 0.0f);
- listenerParams.flDistanceFactor = 10.0f;
- listenerParams.flRolloffFactor = 1.0f;
-
- m_listener->SetAllParameters(&listenerParams, DS3D_DEFERRED);
-}
-
-
-
-
-// Uses MCI to play a MIDI file. The window procedure
-// is notified when playback is complete.
-
-bool CSound::PlayMusic(int rank, bool bRepeat)
-{
- MCI_OPEN_PARMS mciOpenParms;
- MCI_PLAY_PARMS mciPlayParms;
- DWORD dwReturn;
- char filename[MAX_PATH];
-
- m_bRepeatMusic = bRepeat;
- m_playTime = 0.0f;
-
- if ( m_midiVolume == 0 ) return true;
-
- if ( m_bAudioTrack )
- {
- return PlayAudioTrack(rank);
- }
-
- if ( !m_bEnable ) return true;
- InitMidiVolume(m_midiVolume);
- m_lastMidiVolume = m_midiVolume;
-
- GetCurrentDir(filename, MAX_PATH-30);
- sprintf(filename+strlen(filename), "sound\\music%.3d.blp", rank-1);
-
- // Open the device by specifying the device and filename.
- // MCI will attempt to choose the MIDI mapper as the output port.
- mciOpenParms.lpstrDeviceType = "sequencer";
- mciOpenParms.lpstrElementName = filename;
- dwReturn = mciSendCommand(NULL,
- MCI_OPEN,
- MCI_OPEN_TYPE|MCI_OPEN_ELEMENT,
- (DWORD)(LPVOID)&mciOpenParms);
- if ( dwReturn != 0 )
- {
- mciGetErrorString(dwReturn, filename, 128);
- // Failed to open device. Don't close it; just return error.
- return false;
- }
-
- // The device opened successfully; get the device ID.
- m_MidiDeviceID = mciOpenParms.wDeviceID;
-
- // Begin playback.
- mciPlayParms.dwCallback = (DWORD)m_hWnd;
- dwReturn = mciSendCommand(m_MidiDeviceID,
- MCI_PLAY,
- MCI_NOTIFY,
- (DWORD)(LPVOID)&mciPlayParms);
- if ( dwReturn != 0 )
- {
- mciGetErrorString(dwReturn, filename, 128);
- StopMusic();
- return false;
- }
-
- m_MIDIMusic = rank;
- return true;
-}
-
-// Uses MCI to play a CD-audio track. The window procedure
-// is notified when playback is complete.
-// The rank parameter is in space [1..n] !
-// For CD mix (data/audio), it will be [2..n] !
-
-bool CSound::PlayAudioTrack(int rank)
-{
-#if _SOUNDTRACKS
- MCI_OPEN_PARMS mciOpenParms;
- MCI_PLAY_PARMS mciPlayParms;
- MCI_SET_PARMS mciSetParms;
- DWORD dwReturn;
- char filename[MAX_PATH];
- char device[10];
-
- if ( !m_bEnable ) return true;
-//? if ( m_midiVolume == 0 ) return true;
- InitAudioTrackVolume(m_midiVolume);
- m_lastMidiVolume = m_midiVolume;
-
- // Open the device by specifying the device and filename.
- // MCI will attempt to choose the MIDI mapper as the output port.
- memset(&mciOpenParms, 0, sizeof(MCI_OPEN_PARMS));
-//? mciOpenParms.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO;
-//? dwReturn = mciSendCommand(NULL,
-//? MCI_OPEN,
-//? MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID,
-//? (DWORD)(LPVOID)&mciOpenParms);
- mciOpenParms.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO;
- if ( m_CDpath[0] == 0 )
- {
- dwReturn = mciSendCommand(NULL,
- MCI_OPEN,
- MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID,
- (DWORD)(LPVOID)&mciOpenParms);
- }
- else
- {
- device[0] = m_CDpath[0];
- device[1] = ':';
- device[2] = 0;
- mciOpenParms.lpstrElementName = device;
- dwReturn = mciSendCommand(NULL,
- MCI_OPEN,
- MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_OPEN_ELEMENT,
- (DWORD)(LPVOID)&mciOpenParms);
- }
- if ( dwReturn != 0 )
- {
- mciGetErrorString(dwReturn, filename, 128);
- // Failed to open device. Don't close it; just return error.
- return false;
- }
-
- // The device opened successfully; get the device ID.
- m_MidiDeviceID = mciOpenParms.wDeviceID;
-
- // Set the time format to track/minute/second/frame (TMSF).
- memset(&mciSetParms, 0, sizeof(MCI_SET_PARMS));
- mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
- dwReturn = mciSendCommand(m_MidiDeviceID,
- MCI_SET,
- MCI_SET_TIME_FORMAT,
- (DWORD)&mciSetParms);
- if ( dwReturn != 0 )
- {
- mciGetErrorString(dwReturn, filename, 128);
- StopMusic();
- return false;
- }
-
- // Begin playback.
- memset(&mciPlayParms, 0, sizeof(MCI_PLAY_PARMS));
- mciPlayParms.dwCallback = (DWORD)m_hWnd;
- mciPlayParms.dwFrom = MCI_MAKE_TMSF(rank+0, 0, 0, 0);
- mciPlayParms.dwTo = MCI_MAKE_TMSF(rank+1, 0, 0, 0);
- dwReturn = mciSendCommand(m_MidiDeviceID,
- MCI_PLAY,
- MCI_NOTIFY|MCI_FROM|MCI_TO,
- (DWORD)(LPVOID)&mciPlayParms);
- if ( dwReturn != 0 )
- {
- mciGetErrorString(dwReturn, filename, 128);
- StopMusic();
- return false;
- }
-
- m_MIDIMusic = rank;
-#endif
- return true;
-}
-
-// Restart the MIDI player.
-
-bool CSound::RestartMusic()
-{
- if ( !m_bRepeatMusic ) return false;
-
- OutputDebugString("RestartMusic\n");
- if ( !m_bEnable ) return true;
-//? if ( m_midiVolume == 0 ) return true;
- if ( m_MIDIMusic == 0 ) return false;
- if ( m_playTime < 5.0f ) return false;
-
- return PlayMusic(m_MIDIMusic, true);
-}
-
-// Shuts down the MIDI player.
-
-void CSound::SuspendMusic()
-{
- if ( !m_bEnable ) return;
-
-//? if ( m_MidiDeviceID && m_midiVolume != 0 )
- if ( m_MidiDeviceID )
- {
- if ( m_bAudioTrack ) mciSendCommand(m_MidiDeviceID, MCI_STOP, 0, NULL);
- mciSendCommand(m_MidiDeviceID, MCI_CLOSE, 0, NULL);
- }
- m_MidiDeviceID = 0;
-}
-
-// Shuts down the MIDI player.
-
-void CSound::StopMusic()
-{
- SuspendMusic();
- m_MIDIMusic = 0;
-}
-
-// Returns true if the music is in progress.
-
-bool CSound::IsPlayingMusic()
-{
- return (m_MIDIMusic != 0);
-}
-
-// Adjusts the volume of currently music, if necessary.
-
-void CSound::AdaptVolumeMusic()
-{
- if ( m_midiVolume != m_lastMidiVolume )
- {
- if ( m_bAudioTrack )
- {
- InitAudioTrackVolume(m_midiVolume);
- }
- else
- {
- InitMidiVolume(m_midiVolume);
- }
- m_lastMidiVolume = m_midiVolume;
- RestartMusic();
- }
-}
-
diff --git a/src/sound/sound.h b/src/sound/sound.h index 2dcdc2c..be63558 100644 --- a/src/sound/sound.h +++ b/src/sound/sound.h @@ -1,242 +1,165 @@ -// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.
-
-// sound.h
-
-#pragma once
-
-
-#include <dsound.h>
-
-
-const int MAXFILES = 200;
-const int MAXSOUND = 32;
-const int MAXVOLUME = 20;
-const int MAXOPER = 4;
-
-class CInstanceManager;
-
-
-enum Sound
-{
- SOUND_CLICK = 0,
- SOUND_BOUM = 1,
- SOUND_EXPLO = 2,
- SOUND_FLYh = 3, // human
- SOUND_FLY = 4,
- SOUND_STEPs = 5, // smooth
- SOUND_MOTORw = 6, // wheel
- SOUND_MOTORt = 7, // tank
- SOUND_MOTORr = 8, // roller
- SOUND_ERROR = 9,
- SOUND_CONVERT = 10,
- SOUND_ENERGY = 11,
- SOUND_PLOUF = 12,
- SOUND_BLUP = 13,
- SOUND_WARNING = 14,
- SOUND_DERRICK = 15,
- SOUND_LABO = 16,
- SOUND_STATION = 17,
- SOUND_REPAIR = 18,
- SOUND_RESEARCH = 19,
- SOUND_INSECTs = 20, // spider
- SOUND_BURN = 21,
- SOUND_TZOING = 22,
- SOUND_GGG = 23,
- SOUND_MANIP = 24,
- SOUND_FIRE = 25, // shooting with fireball
- SOUND_HUMAN1 = 26, // breathing
- SOUND_STEPw = 27, // water
- SOUND_SWIM = 28,
- SOUND_RADAR = 29,
- SOUND_BUILD = 30,
- SOUND_ALARM = 31, // energy alarm
- SOUND_SLIDE = 32,
- SOUND_EXPLOi = 33, // insect
- SOUND_INSECTa = 34, // ant
- SOUND_INSECTb = 35, // bee
- SOUND_INSECTw = 36, // worm
- SOUND_INSECTm = 37, // mother
- SOUND_TREMBLE = 38,
- SOUND_PSHHH = 39,
- SOUND_NUCLEAR = 40,
- SOUND_INFO = 41,
- SOUND_OPEN = 42,
- SOUND_CLOSE = 43,
- SOUND_FACTORY = 44,
- SOUND_EGG = 45,
- SOUND_MOTORs = 46, // submarine
- SOUND_MOTORi = 47, // insect (legs)
- SOUND_SHIELD = 48,
- SOUND_FIREi = 49, // shooting with orgaball (insect)
- SOUND_GUNDEL = 50,
- SOUND_PSHHH2 = 51, // shield
- SOUND_MESSAGE = 52,
- SOUND_BOUMm = 53, // metal
- SOUND_BOUMv = 54, // plant
- SOUND_BOUMs = 55, // smooth
- SOUND_EXPLOl = 56, // little
- SOUND_EXPLOlp = 57, // little power
- SOUND_EXPLOp = 58, // power
- SOUND_STEPh = 59, // hard
- SOUND_STEPm = 60, // metal
- SOUND_POWERON = 61,
- SOUND_POWEROFF = 62,
- SOUND_AIE = 63,
- SOUND_WAYPOINT = 64,
- SOUND_RECOVER = 65,
- SOUND_DEADi = 66,
- SOUND_JOSTLE = 67,
- SOUND_GFLAT = 68,
- SOUND_DEADg = 69, // shooting death
- SOUND_DEADw = 70, // drowning
- SOUND_FLYf = 71, // reactor fail
- SOUND_ALARMt = 72, // temperature alarm
- SOUND_FINDING = 73, // finds a cache object
- SOUND_THUMP = 74,
- SOUND_TOUCH = 75,
- SOUND_BLITZ = 76,
- SOUND_MUSHROOM = 77,
- SOUND_FIREp = 78, // shooting with phazer
- SOUND_EXPLOg1 = 79, // impact gun 1
- SOUND_EXPLOg2 = 80, // impact gun 2
- SOUND_MOTORd = 81, // engine friction
-};
-
-enum SoundNext
-{
- SOPER_CONTINUE = 1,
- SOPER_STOP = 2,
- SOPER_LOOP = 3,
-};
-
-struct SoundOper
-{
- char bUsed;
- float finalAmplitude;
- float finalFrequency;
- float totalTime;
- float currentTime;
- SoundNext nextOper;
-};
-
-struct SoundChannel
-{
- char bUsed; // buffer used?
- char bMute; // silence?
- Sound type; // SOUND_*
- int priority; // so great -> important
- Math::Vector pos; // position in space
- unsigned short uniqueStamp; // unique marker
- LPDIRECTSOUNDBUFFER soundBuffer;
- LPDIRECTSOUND3DBUFFER soundBuffer3D;
- float startAmplitude;
- float startFrequency;
- float changeFrequency;
- int initFrequency;
- float volume; // 2D: volume 1..0 depending on position
- float pan; // 2D: pan -1..+1 depending on position
- SoundOper oper[MAXOPER];
-};
-
-
-
-class CSound
-{
-public:
- CSound(CInstanceManager* iMan);
- ~CSound();
-
- void SetDebugMode(bool bMode);
- bool Create(HWND hWnd, bool b3D);
- void CacheAll();
-
- void SetState(bool bState);
- bool RetEnable();
-
- void SetCDpath(char *path);
- void SetAudioTrack(bool bAudio);
-
- void SetSound3D(bool bMode);
- bool RetSound3D();
- bool RetSound3DCap();
-
- void SetAudioVolume(int volume);
- int RetAudioVolume();
- void SetMidiVolume(int volume);
- int RetMidiVolume();
-
- void SetListener(Math::Vector eye, Math::Vector lookat);
- void FrameMove(float rTime);
-
- int Play(Sound sound, float amplitude=1.0f, float frequency=1.0f, bool bLoop=false);
- int Play(Sound sound, Math::Vector pos, float amplitude=1.0f, float frequency=1.0f, bool bLoop=false);
- bool FlushEnvelope(int channel);
- bool AddEnvelope(int channel, float amplitude, float frequency, float time, SoundNext oper);
- bool Position(int channel, Math::Vector pos);
- bool Frequency(int channel, float frequency);
- bool Stop(int channel);
- bool StopAll();
- bool MuteAll(bool bMute);
-
- bool PlayMusic(int rank, bool bRepeat);
- bool RestartMusic();
- void SuspendMusic();
- void StopMusic();
- bool IsPlayingMusic();
- void AdaptVolumeMusic();
-
-protected:
- bool CheckChannel(int &channel);
- bool CreateSoundBuffer(int channel, DWORD size, DWORD freq, DWORD bitsPerSample, DWORD blkAlign, bool bStereo);
- bool ReadData(LPDIRECTSOUNDBUFFER lpDSB, Sound sound, DWORD size);
- bool CreateBuffer(int channel, Sound sound);
- void ComputeVolumePan2D(int channel, const Math::Vector &pos);
- bool ReadFile(Sound sound, char *metaname, char *filename);
- int RetPriority(Sound sound);
- bool SearchFreeBuffer(Sound sound, int &channel, bool &bAlreadyLoaded);
- void OperNext(int channel);
- bool PlayAudioTrack(int rank);
-
-protected:
- CInstanceManager* m_iMan;
-
- HWND m_hWnd;
- bool m_bEnable;
- bool m_bState;
- bool m_bAudioTrack;
- bool m_ctrl3D;
- bool m_bDebugMode;
- LPDIRECTSOUND m_lpDS;
- LPDIRECTSOUND3DLISTENER m_listener;
- SoundChannel m_channel[MAXSOUND];
- char* m_files[MAXFILES];
- UINT m_MidiDeviceID;
- int m_MIDIMusic;
- bool m_bRepeatMusic;
- int m_audioVolume;
- int m_midiVolume;
- int m_lastMidiVolume;
- Math::Vector m_eye;
- Math::Vector m_lookat;
- float m_lastTime;
- float m_playTime;
- int m_uniqueStamp;
- int m_maxSound;
- char m_CDpath[100];
-};
-
-
+// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +// sound.h + +#pragma once + + +#include "math/vector.h" + + +class CInstanceManager; + +namespace Snd { + +const int MAXFILES = 200; +const int MAXSOUND = 32; +const int MAXVOLUME = 20; +const int MAXOPER = 4; + + +enum Sound +{ + SOUND_CLICK = 0, + SOUND_BOUM = 1, + SOUND_EXPLO = 2, + SOUND_FLYh = 3, // human + SOUND_FLY = 4, + SOUND_STEPs = 5, // smooth + SOUND_MOTORw = 6, // wheel + SOUND_MOTORt = 7, // tank + SOUND_MOTORr = 8, // roller + SOUND_ERROR = 9, + SOUND_CONVERT = 10, + SOUND_ENERGY = 11, + SOUND_PLOUF = 12, + SOUND_BLUP = 13, + SOUND_WARNING = 14, + SOUND_DERRICK = 15, + SOUND_LABO = 16, + SOUND_STATION = 17, + SOUND_REPAIR = 18, + SOUND_RESEARCH = 19, + SOUND_INSECTs = 20, // spider + SOUND_BURN = 21, + SOUND_TZOING = 22, + SOUND_GGG = 23, + SOUND_MANIP = 24, + SOUND_FIRE = 25, // shooting with fireball + SOUND_HUMAN1 = 26, // breathing + SOUND_STEPw = 27, // water + SOUND_SWIM = 28, + SOUND_RADAR = 29, + SOUND_BUILD = 30, + SOUND_ALARM = 31, // energy alarm + SOUND_SLIDE = 32, + SOUND_EXPLOi = 33, // insect + SOUND_INSECTa = 34, // ant + SOUND_INSECTb = 35, // bee + SOUND_INSECTw = 36, // worm + SOUND_INSECTm = 37, // mother + SOUND_TREMBLE = 38, + SOUND_PSHHH = 39, + SOUND_NUCLEAR = 40, + SOUND_INFO = 41, + SOUND_OPEN = 42, + SOUND_CLOSE = 43, + SOUND_FACTORY = 44, + SOUND_EGG = 45, + SOUND_MOTORs = 46, // submarine + SOUND_MOTORi = 47, // insect (legs) + SOUND_SHIELD = 48, + SOUND_FIREi = 49, // shooting with orgaball (insect) + SOUND_GUNDEL = 50, + SOUND_PSHHH2 = 51, // shield + SOUND_MESSAGE = 52, + SOUND_BOUMm = 53, // metal + SOUND_BOUMv = 54, // plant + SOUND_BOUMs = 55, // smooth + SOUND_EXPLOl = 56, // little + SOUND_EXPLOlp = 57, // little power + SOUND_EXPLOp = 58, // power + SOUND_STEPh = 59, // hard + SOUND_STEPm = 60, // metal + SOUND_POWERON = 61, + SOUND_POWEROFF = 62, + SOUND_AIE = 63, + SOUND_WAYPOINT = 64, + SOUND_RECOVER = 65, + SOUND_DEADi = 66, + SOUND_JOSTLE = 67, + SOUND_GFLAT = 68, + SOUND_DEADg = 69, // shooting death + SOUND_DEADw = 70, // drowning + SOUND_FLYf = 71, // reactor fail + SOUND_ALARMt = 72, // temperature alarm + SOUND_FINDING = 73, // finds a cache object + SOUND_THUMP = 74, + SOUND_TOUCH = 75, + SOUND_BLITZ = 76, + SOUND_MUSHROOM = 77, + SOUND_FIREp = 78, // shooting with phazer + SOUND_EXPLOg1 = 79, // impact gun 1 + SOUND_EXPLOg2 = 80, // impact gun 2 + SOUND_MOTORd = 81, // engine friction +}; + +enum SoundNext +{ + SOPER_CONTINUE = 1, + SOPER_STOP = 2, + SOPER_LOOP = 3, +}; + +struct SoundOper +{ + char bUsed; + float finalAmplitude; + float finalFrequency; + float totalTime; + float currentTime; + Snd::SoundNext nextOper; +}; + +struct SoundChannel +{ + char bUsed; // buffer used? + char bMute; // silence? + Snd::Sound type; // SOUND_* + int priority; // so great -> important + Math::Vector pos; // position in space + unsigned short uniqueStamp; // unique marker +// LPDIRECTSOUNDBUFFER soundBuffer; +// LPDIRECTSOUND3DBUFFER soundBuffer3D; + float startAmplitude; + float startFrequency; + float changeFrequency; + int initFrequency; + float volume; // 2D: volume 1..0 depending on position + float pan; // 2D: pan -1..+1 depending on position + Snd::SoundOper oper[MAXOPER]; +}; + + + +class CSound +{ + // TODO +}; + +}; // namespace Sound diff --git a/src/ui/control.cpp b/src/ui/control.cpp index 330eacc..525cab2 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -31,7 +31,7 @@ #include "common/misc.h"
#include "common/iman.h"
#include "old/text.h"
-#include "sound/sound.h"
+#include "old/sound.h"
#include "ui/control.h"
diff --git a/src/ui/displaytext.cpp b/src/ui/displaytext.cpp index df08c24..b21d96e 100644 --- a/src/ui/displaytext.cpp +++ b/src/ui/displaytext.cpp @@ -36,7 +36,7 @@ #include "ui/window.h"
#include "ui/group.h"
#include "old/text.h"
-#include "sound/sound.h"
+#include "old/sound.h"
#include "ui/displaytext.h"
diff --git a/src/ui/key.cpp b/src/ui/key.cpp index a581674..941dd8a 100644 --- a/src/ui/key.cpp +++ b/src/ui/key.cpp @@ -28,7 +28,7 @@ #include "common/misc.h"
#include "common/iman.h"
#include "common/restext.h"
-#include "sound/sound.h"
+#include "old/sound.h"
#include "old/text.h"
#include "ui/key.h"
diff --git a/src/ui/maindialog.cpp b/src/ui/maindialog.cpp index bc9f5b4..267c4b1 100644 --- a/src/ui/maindialog.cpp +++ b/src/ui/maindialog.cpp @@ -52,7 +52,7 @@ #include "ui/editvalue.h"
#include "old/text.h"
#include "old/camera.h"
-#include "sound/sound.h"
+#include "old/sound.h"
#include "script/cmdtoken.h"
#include "object/robotmain.h"
#include "ui/maindialog.h"
diff --git a/src/ui/studio.cpp b/src/ui/studio.cpp index b9f8d95..d37c6fd 100644 --- a/src/ui/studio.cpp +++ b/src/ui/studio.cpp @@ -38,7 +38,7 @@ #include "object/robotmain.h"
#include "object/object.h"
#include "old/camera.h"
-#include "sound/sound.h"
+#include "old/sound.h"
#include "script/script.h"
#include "ui/interface.h"
#include "ui/button.h"
|