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