From b08a63790c0fbeacb3f96a74e3eb15abe8c70dab Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski <piotrdz@gmail.com> Date: Mon, 25 Jun 2012 19:59:17 +0200 Subject: [PATCH] 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 --- CMakeLists.txt | 11 +- src/CMakeLists.txt | 192 +++- src/app/app.cpp | 504 +++++++++- src/app/app.h | 111 +-- src/app/main.cpp | 41 + src/app/system.cpp | 253 +++++ src/app/system.h | 57 ++ src/common/config.h.cmake | 8 + src/common/event.cpp | 19 +- src/common/event.h | 4 +- src/common/iman.cpp | 1 - src/common/restext.h | 6 +- src/common/struct.h | 2 - src/graphics/common/camera.h | 1 - src/graphics/common/cloud.h | 2 +- src/graphics/common/device.cpp | 14 + src/graphics/common/device.h | 22 + src/graphics/common/engine.cpp | 50 + src/graphics/common/lightning.h | 4 +- src/graphics/common/model.h | 1 - src/graphics/common/particle.h | 2 +- src/graphics/common/planet.h | 1 - src/graphics/common/pyro.h | 8 +- src/object/brain.cpp | 2 +- src/object/object.cpp | 2 +- src/object/object.h | 2 +- src/object/robotmain.cpp | 2 +- src/old/blitz.cpp | 2 +- src/old/d3dapp.cpp | 2 +- src/old/d3dengine.cpp | 2 +- src/old/particule.cpp | 2 +- src/old/particule.h | 2 +- src/old/pyro.cpp | 2 +- src/old/sound.cpp | 1659 +++++++++++++++++++++++++++++++ src/old/sound.h | 242 +++++ src/old/water.cpp | 2 +- src/physics/physics.cpp | 2 +- src/sound/sound.cpp | 1659 ------------------------------- src/sound/sound.h | 407 +++----- src/ui/control.cpp | 2 +- src/ui/displaytext.cpp | 2 +- src/ui/key.cpp | 2 +- src/ui/maindialog.cpp | 2 +- src/ui/studio.cpp | 2 +- 44 files changed, 3284 insertions(+), 2031 deletions(-) create mode 100644 src/app/main.cpp create mode 100644 src/app/system.cpp create mode 100644 src/app/system.h create mode 100644 src/common/config.h.cmake create mode 100644 src/graphics/common/device.cpp create mode 100644 src/old/sound.cpp create mode 100644 src/old/sound.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 02016af6..ae0231d1 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 024489d6..3f5e2387 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) -# To build with libwine: -# include_directories(/usr/include/wine/windows /usr/include/wine/msvcrt) -# set(LIBS -lwine) +add_executable(colobot_old ${OLD_SOURCES}) -add_executable(colobot ${SOURCES}) +target_link_libraries(colobot_old CBot ${OLD_LIBS}) -target_link_libraries(colobot CBot ${LIBS}) +# New target +set(NEW_LIBS ${SDL_LIBRARY} ${SDLIMAGE_LIBRARY} ${OPENGL_LIBRARY}) + +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 0938f2aa..726d32dc 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 ee4965d8..ee6184f5 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; + //! Code to return at exit + int m_exitCode; - //HANDLE m_thread; - //DWORD m_threadId; - - 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 00000000..28d21eee --- /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 00000000..4f7cd264 --- /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 00000000..fd1c0516 --- /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 00000000..b0663872 --- /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 b323e430..0a56fb94 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -16,16 +16,23 @@ // 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 0dc6cedc..95e303cd 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(); }; @@ -619,8 +621,6 @@ public: bool AddEvent(const Event &event); bool GetEvent(Event &event); -protected: - protected: CInstanceManager* m_iMan; diff --git a/src/common/iman.cpp b/src/common/iman.cpp index 139f56a5..53735a48 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 019f67a8..241951a6 100644 --- a/src/common/restext.h +++ b/src/common/restext.h @@ -19,12 +19,12 @@ #pragma once - - -#include "old/d3dengine.h" #include "common/event.h" +class CD3DEngine; + + // Possible types of the text resources. diff --git a/src/common/struct.h b/src/common/struct.h index eb0078b7..b143334d 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 59e76097..28397b93 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 579eb9a5..9ca8c113 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 00000000..2e3db61b --- /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 a8bf32cd..cd52fa5a 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 acd09953..29857ce3 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 2077954c..8edf9e52 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 d67c71a1..349c15cd 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 9e9fd365..4047cb5e 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 2bf4d990..4ffccfc4 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 704febff..e6b58443 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 1ffe1b51..afc99033 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 10cc190a..6931bd2b 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 9d77ae16..735da8a5 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 a897349a..902c1cba 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 b73bd3ef..15488d22 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 0614fc35..7f042798 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 305adc2f..e28483de 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 3fb77919..8c8a1620 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 004decee..23d0899e 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 72f370e3..fc61e62b 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 00000000..8b4089a6 --- /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 00000000..2dcdc2cf --- /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 510d1fef..215bac94 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 e4420a10..49d7684e 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 f3078389..e69de29b 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 2dcdc2cf..be635585 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 330eaccc..525cab26 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 df08c247..b21d96e3 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 a581674f..941dd8a4 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 bc9f5b4c..267c4b1d 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 b9f8d957..d37c6fdf 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"