summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPiotr Dziwiński <piotrdz@gmail.com>2012-08-12 10:15:19 -0700
committerPiotr Dziwiński <piotrdz@gmail.com>2012-08-12 10:15:19 -0700
commit50deedb6cbc927f6c7d6c3c5e9134d11c20782ae (patch)
tree8eb3fbd914cfea11660534b296bfddcffcc5f7b4 /src
parentbc24b9f9e516e657fcc0034808e010287fc2e393 (diff)
parent62b545128f37746c343760e464872655b5523c6f (diff)
downloadcolobot-50deedb6cbc927f6c7d6c3c5e9134d11c20782ae.tar.gz
colobot-50deedb6cbc927f6c7d6c3c5e9134d11c20782ae.tar.bz2
colobot-50deedb6cbc927f6c7d6c3c5e9134d11c20782ae.zip
Merge pull request #36 from Erihel/dev
Merge of new features: plugins and INI profile, changes from dev-graphics
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/app/README.txt7
-rw-r--r--src/app/app.cpp98
-rw-r--r--src/app/app.h18
-rw-r--r--src/app/main.cpp5
-rw-r--r--src/app/system.h9
-rw-r--r--src/app/system_linux.h9
-rw-r--r--src/app/system_other.h9
-rw-r--r--src/app/system_windows.h9
-rw-r--r--src/common/README.txt7
-rw-r--r--src/common/event.h63
-rw-r--r--src/common/iman.cpp15
-rw-r--r--src/common/iman.h8
-rw-r--r--src/common/logger.cpp16
-rw-r--r--src/common/logger.h16
-rw-r--r--src/common/profile.cpp111
-rw-r--r--src/common/profile.h98
-rw-r--r--src/common/stringutils.cpp10
-rw-r--r--src/common/test/CMakeLists.txt8
-rw-r--r--src/common/test/colobot.ini15
-rw-r--r--src/common/test/profile_test.cpp43
-rw-r--r--src/graphics/README.txt13
-rw-r--r--src/graphics/core/README.txt13
-rw-r--r--src/graphics/core/color.h11
-rw-r--r--src/graphics/core/device.h27
-rw-r--r--src/graphics/core/light.h5
-rw-r--r--src/graphics/core/material.h5
-rw-r--r--src/graphics/core/texture.h9
-rw-r--r--src/graphics/core/vertex.h5
-rw-r--r--src/graphics/d3d/README.txt7
-rw-r--r--src/graphics/engine/README.txt17
-rw-r--r--src/graphics/engine/camera.cpp81
-rw-r--r--src/graphics/engine/camera.h9
-rw-r--r--src/graphics/engine/cloud.cpp262
-rw-r--r--src/graphics/engine/cloud.h83
-rw-r--r--src/graphics/engine/engine.cpp2718
-rw-r--r--src/graphics/engine/engine.h613
-rw-r--r--src/graphics/engine/lightman.h5
-rw-r--r--src/graphics/engine/lightning.cpp68
-rw-r--r--src/graphics/engine/lightning.h7
-rw-r--r--src/graphics/engine/modelfile.h5
-rw-r--r--src/graphics/engine/particle.cpp281
-rw-r--r--src/graphics/engine/particle.h98
-rw-r--r--src/graphics/engine/planet.cpp164
-rw-r--r--src/graphics/engine/planet.h77
-rw-r--r--src/graphics/engine/pyro.cpp158
-rw-r--r--src/graphics/engine/pyro.h56
-rw-r--r--src/graphics/engine/terrain.cpp1802
-rw-r--r--src/graphics/engine/terrain.h263
-rw-r--r--src/graphics/engine/text.cpp781
-rw-r--r--src/graphics/engine/text.h284
-rw-r--r--src/graphics/engine/water.cpp635
-rw-r--r--src/graphics/engine/water.h152
-rw-r--r--src/graphics/opengl/README.txt13
-rw-r--r--src/graphics/opengl/gldevice.cpp58
-rw-r--r--src/graphics/opengl/gldevice.h12
-rw-r--r--src/math/README.txt13
-rw-r--r--src/math/all.h9
-rw-r--r--src/math/const.h18
-rw-r--r--src/math/func.h29
-rw-r--r--src/math/geometry.h15
-rw-r--r--src/math/intpoint.h18
-rw-r--r--src/math/intsize.h61
-rw-r--r--src/math/matrix.h24
-rw-r--r--src/math/point.h9
-rw-r--r--src/math/size.h66
-rw-r--r--src/math/vector.h9
-rw-r--r--src/object/README.txt10
-rw-r--r--src/object/object.h229
-rw-r--r--src/object/robotmain.cpp2
-rw-r--r--src/physics/README.txt7
-rw-r--r--src/physics/physics.h82
-rw-r--r--src/plugins/plugininterface.h65
-rw-r--r--src/plugins/pluginloader.cpp126
-rw-r--r--src/plugins/pluginloader.h88
-rw-r--r--src/plugins/pluginmanager.cpp132
-rw-r--r--src/plugins/pluginmanager.h88
-rw-r--r--src/plugins/test/CMakeLists.txt12
-rw-r--r--src/plugins/test/colobot.ini3
-rw-r--r--src/plugins/test/manager_test.cpp31
-rw-r--r--src/sound/README.txt7
-rw-r--r--src/sound/plugins/oalsound/CMakeLists.txt24
-rw-r--r--src/sound/plugins/oalsound/alsound.cpp553
-rw-r--r--src/sound/plugins/oalsound/alsound.h95
-rw-r--r--src/sound/plugins/oalsound/buffer.cpp80
-rw-r--r--src/sound/plugins/oalsound/buffer.h48
-rw-r--r--src/sound/plugins/oalsound/channel.cpp304
-rw-r--r--src/sound/plugins/oalsound/channel.h99
-rw-r--r--src/sound/plugins/oalsound/check.h (renamed from src/plugins/plugin.h)26
-rw-r--r--src/sound/plugins/oalsound/test/CMakeLists.txt11
-rw-r--r--src/sound/plugins/oalsound/test/plugin_test.cpp40
-rw-r--r--src/sound/sound.h13
-rw-r--r--src/ui/README.txt7
93 files changed, 10319 insertions, 1508 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9bcd288..b998d19 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -67,7 +67,7 @@ common/iman.cpp
# common/restext.cpp
common/stringutils.cpp
graphics/core/color.cpp
-# graphics/engine/camera.cpp # new code but depends on other modules
+graphics/engine/camera.cpp
graphics/engine/cloud.cpp
graphics/engine/engine.cpp
graphics/engine/lightman.cpp
@@ -176,6 +176,7 @@ graphics/opengl/gldevice.cpp
set(LIBS
${SDL_LIBRARY}
${SDLIMAGE_LIBRARY}
+${SDLTTF_LIBRARY}
${OPENGL_LIBRARY}
${PNG_LIBRARIES}
${OPTIONAL_LIBS}
diff --git a/src/app/README.txt b/src/app/README.txt
index 1df1fcc..e4f69ec 100644
--- a/src/app/README.txt
+++ b/src/app/README.txt
@@ -1,3 +1,4 @@
-src/app
-
-Contains the main class of the application.
+/**
+ * \dir app
+ * Main class of the application and system functions
+ */
diff --git a/src/app/app.cpp b/src/app/app.cpp
index d20232d..a0518db 100644
--- a/src/app/app.cpp
+++ b/src/app/app.cpp
@@ -122,6 +122,7 @@ bool CApplication::ParseArguments(int argc, char *argv[])
{
waitDataDir = false;
m_dataPath = arg;
+ continue;
}
if (arg == "-debug")
@@ -153,10 +154,6 @@ bool CApplication::Create()
// Temporarily -- only in windowed mode
m_deviceConfig.fullScreen = false;
- // Create the 3D engine
- m_engine = new Gfx::CEngine(m_iMan, this);
-
-
/* // Create the sound instance.
m_sound = new CSound(m_iMan);
@@ -218,27 +215,20 @@ bool CApplication::Create()
if (! m_device->Create() )
{
SystemDialog( SDT_ERROR, "COLOBT - Fatal Error",
- std::string("Error in CDevice::Create() :\n") +
- std::string(m_device->GetError()) );
+ std::string("Error in CDevice::Create()") );
m_exitCode = 1;
return false;
}
+ // Create the 3D engine
+ m_engine = new Gfx::CEngine(m_iMan, this);
+
m_engine->SetDevice(m_device);
- if (! m_engine->Create() )
- {
- SystemDialog( SDT_ERROR, "COLOBT - Fatal Error",
- std::string("Error in CEngine::Create() :\n") +
- std::string(m_engine->GetError()) );
- m_exitCode = 1;
- return false;
- }
- if (! m_engine->AfterDeviceSetInit() )
+ if (! m_engine->Create() )
{
SystemDialog( SDT_ERROR, "COLOBT - Fatal Error",
- std::string("Error in CEngine::AfterDeviceSetInit() :\n") +
- std::string(m_engine->GetError()) );
+ std::string("Error in CEngine::Init()") );
m_exitCode = 1;
return false;
}
@@ -293,7 +283,7 @@ bool CApplication::CreateVideoSurface()
if (m_deviceConfig.hardwareAccel)
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
- m_private->surface = SDL_SetVideoMode(m_deviceConfig.size.w, m_deviceConfig.size.h,
+ m_private->surface = SDL_SetVideoMode(m_deviceConfig.size.x, m_deviceConfig.size.y,
m_deviceConfig.bpp, videoFlags);
return true;
@@ -315,8 +305,7 @@ void CApplication::Destroy()
if (m_engine != NULL)
{
- if (m_engine->GetWasInit())
- m_engine->Destroy();
+ m_engine->Destroy();
delete m_engine;
m_engine = NULL;
@@ -324,8 +313,7 @@ void CApplication::Destroy()
if (m_device != NULL)
{
- if (m_device->GetWasInit())
- m_device->Destroy();
+ m_device->Destroy();
delete m_device;
m_device = NULL;
@@ -508,6 +496,14 @@ void CApplication::UpdateJoystick()
}
}
+void CApplication::UpdateMouse()
+{
+ Math::IntPoint pos;
+ SDL_GetMouseState(&pos.x, &pos.y);
+ m_systemMousePos = m_engine->WindowToInterfaceCoords(pos);
+ m_engine->SetMousePos(m_systemMousePos);
+}
+
int CApplication::Run()
{
m_active = true;
@@ -582,17 +578,12 @@ int CApplication::Run()
m_robotMain->ProcessEvent(event); */
}
- // Update game and render a frame during idle time (no messages are waiting)
- bool ok = Render();
+ /* Update mouse position explicitly right before rendering
+ * because mouse events are usually way behind */
+ UpdateMouse();
- // If an error occurs, push quit event to the queue
- if (! ok)
- {
- SDL_Event quitEvent;
- memset(&quitEvent, 0, sizeof(SDL_Event));
- quitEvent.type = SDL_QUIT;
- SDL_PushEvent(&quitEvent);
- }
+ // Update game and render a frame during idle time (no messages are waiting)
+ Render();
}
}
@@ -616,21 +607,6 @@ PressState TranslatePressState(unsigned char state)
return STATE_RELEASED;
}
-/** Conversion of the position of the mouse from window coords to interface coords:
- - x: 0=left, 1=right
- - y: 0=down, 1=up */
-Math::Point CApplication::WindowToInterfaceCoords(Math::IntPoint pos)
-{
- return Math::Point( static_cast<float>(pos.x) / static_cast<float>(m_deviceConfig.size.w),
- 1.0f - static_cast<float>(pos.y) / static_cast<float>(m_deviceConfig.size.h) );
-}
-
-Math::IntPoint CApplication::InterfaceToWindowCoords(Math::Point pos)
-{
- return Math::IntPoint(static_cast<int>(pos.x * m_deviceConfig.size.w),
- static_cast<int>((1.0f - pos.y) * m_deviceConfig.size.h));
-}
-
/** The SDL event parsed is stored internally.
If event is not available or is not understood, returned event is of type EVENT_NULL. */
Event CApplication::ParseEvent()
@@ -666,14 +642,16 @@ Event CApplication::ParseEvent()
event.mouseButton.button = m_private->currentEvent.button.button;
event.mouseButton.state = TranslatePressState(m_private->currentEvent.button.state);
- event.mouseButton.pos = WindowToInterfaceCoords(Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
+ event.mouseButton.pos = m_engine->WindowToInterfaceCoords(
+ Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
}
else if (m_private->currentEvent.type == SDL_MOUSEMOTION)
{
event.type = EVENT_MOUSE_MOVE;
event.mouseMove.state = TranslatePressState(m_private->currentEvent.button.state);
- event.mouseMove.pos = WindowToInterfaceCoords(Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
+ event.mouseMove.pos = m_engine->WindowToInterfaceCoords(
+ Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
}
else if (m_private->currentEvent.type == SDL_JOYAXISMOTION)
{
@@ -774,17 +752,13 @@ bool CApplication::ProcessEvent(const Event &event)
return true;
}
-/** Renders the frame and swaps buffers as necessary. Returns \c false on error. */
-bool CApplication::Render()
+/** Renders the frame and swaps buffers as necessary */
+void CApplication::Render()
{
- bool result = m_engine->Render();
- if (! result)
- return false;
+ m_engine->Render();
if (m_deviceConfig.doubleBuf)
SDL_GL_SwapBuffers();
-
- return true;
}
void CApplication::StepSimulation(float rTime)
@@ -792,7 +766,12 @@ void CApplication::StepSimulation(float rTime)
// TODO
}
-VideoQueryResult CApplication::GetVideoResolutionList(std::vector<Math::IntSize> &resolutions,
+Gfx::GLDeviceConfig CApplication::GetVideoConfig()
+{
+ return m_deviceConfig;
+}
+
+VideoQueryResult CApplication::GetVideoResolutionList(std::vector<Math::IntPoint> &resolutions,
bool fullScreen, bool resizeable)
{
resolutions.clear();
@@ -830,7 +809,7 @@ VideoQueryResult CApplication::GetVideoResolutionList(std::vector<Math::IntSize>
for (int i = 0; modes[i] != NULL; ++i)
- resolutions.push_back(Math::IntSize(modes[i]->w, modes[i]->h));
+ resolutions.push_back(Math::IntPoint(modes[i]->w, modes[i]->h));
return VIDEO_QUERY_OK;
}
@@ -888,10 +867,9 @@ bool CApplication::GetSystemMouseVisibile()
return result == SDL_ENABLE;
}
-
void CApplication::SetSystemMousePos(Math::Point pos)
{
- Math::IntPoint windowPos = InterfaceToWindowCoords(pos);
+ Math::IntPoint windowPos = m_engine->InterfaceToWindowCoords(pos);
SDL_WarpMouse(windowPos.x, windowPos.y);
m_systemMousePos = pos;
}
diff --git a/src/app/app.h b/src/app/app.h
index 483aa55..0cfaad2 100644
--- a/src/app/app.h
+++ b/src/app/app.h
@@ -15,7 +15,10 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// app.h
+/**
+ * \file app/app.h
+ * \brief CApplication class
+ */
#pragma once
@@ -25,7 +28,6 @@
#include "graphics/core/device.h"
#include "graphics/engine/engine.h"
#include "graphics/opengl/gldevice.h"
-#include "math/intsize.h"
#include <string>
#include <vector>
@@ -133,7 +135,7 @@ public:
void Destroy();
//! Returns a list of possible video modes
- VideoQueryResult GetVideoResolutionList(std::vector<Math::IntSize> &resolutions,
+ VideoQueryResult GetVideoResolutionList(std::vector<Math::IntPoint> &resolutions,
bool fullScreen, bool resizeable);
//! Returns the current video mode
@@ -162,6 +164,9 @@ public:
//! Polls the state of joystick axes and buttons
void UpdateJoystick();
+ //! Updates the mouse position explicitly
+ void UpdateMouse();
+
void FlushPressKey();
void ResetKey();
void SetKey(int keyRank, int option, int key);
@@ -199,18 +204,13 @@ protected:
//! Handles some incoming events
bool ProcessEvent(const Event &event);
//! Renders the image in window
- bool Render();
+ void Render();
//! Opens the joystick device
bool OpenJoystick();
//! Closes the joystick device
void CloseJoystick();
- //! Converts window coords to interface coords
- Math::Point WindowToInterfaceCoords(Math::IntPoint pos);
- //! Converts the interface coords to window coords
- Math::IntPoint InterfaceToWindowCoords(Math::Point pos);
-
protected:
//! Instance manager
CInstanceManager* m_iMan;
diff --git a/src/app/main.cpp b/src/app/main.cpp
index dce13da..619043e 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -15,7 +15,10 @@
// * 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
+/**
+ * \file app/main.cpp
+ * \brief Entry point of application - main() function
+ */
#include "app/app.h"
#include "app/system.h"
diff --git a/src/app/system.h b/src/app/system.h
index 3c04760..e216842 100644
--- a/src/app/system.h
+++ b/src/app/system.h
@@ -15,7 +15,10 @@
// * 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
+/**
+ * \file app/system.h
+ * \brief System functions: time stamps, info dialogs, etc.
+ */
#pragma once
@@ -26,7 +29,7 @@
/* Dialog utils */
/**
- * \enum SysDialogType
+ * \enum SystemDialogType
* \brief Type of system dialog
*/
enum SystemDialogType
@@ -44,7 +47,7 @@ enum SystemDialogType
};
/**
- * \enum SysDialogResult
+ * \enum SystemDialogResult
* \brief Result of system dialog
*
* Means which button was pressed.
diff --git a/src/app/system_linux.h b/src/app/system_linux.h
index f58c9a1..69893de 100644
--- a/src/app/system_linux.h
+++ b/src/app/system_linux.h
@@ -15,10 +15,13 @@
// * 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_linux.h
+/**
+ * \file app/system_linux.h
+ * \brief Linux-specific implementation of system functions
+ */
-/* This header contains Linux-specific code for system utils
- from system.h. There is no separate .cpp module for simplicity.*/
+/* NOTE: code is contained in this header;
+ * there is no separate .cpp module for simplicity */
#include <sys/time.h>
#include <time.h>
diff --git a/src/app/system_other.h b/src/app/system_other.h
index 9f13ffa..eff0c8a 100644
--- a/src/app/system_other.h
+++ b/src/app/system_other.h
@@ -15,10 +15,13 @@
// * 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_other.h
+/**
+ * \file app/system_other.h
+ * \brief Fallback code for other systems
+ */
-/* This header contains fallback code for other platforms for system utils
- from system.h. There is no separate .cpp module for simplicity.*/
+/* NOTE: code is contained in this header;
+ * there is no separate .cpp module for simplicity */
#include <SDL/SDL.h>
diff --git a/src/app/system_windows.h b/src/app/system_windows.h
index eb6beec..72d9f88 100644
--- a/src/app/system_windows.h
+++ b/src/app/system_windows.h
@@ -15,10 +15,13 @@
// * 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_windows.h
+/**
+ * \file app/system_windows.h
+ * \brief Windows-specific implementation of system functions
+ */
-/* This header contains Windows-specific code for system utils
- from system.h. There is no separate .cpp module for simplicity.*/
+/* NOTE: code is contained in this header;
+ * there is no separate .cpp module for simplicity */
#include <windows.h>
diff --git a/src/common/README.txt b/src/common/README.txt
index 36653cc..73d65b7 100644
--- a/src/common/README.txt
+++ b/src/common/README.txt
@@ -1,3 +1,4 @@
-src/common
-
-Contains headers and modules with common structs and enums.
+/**
+ * \dir common
+ * \brief Structs and utils shared throughout the application
+ */
diff --git a/src/common/event.h b/src/common/event.h
index 0d9aa7c..1cfab35 100644
--- a/src/common/event.h
+++ b/src/common/event.h
@@ -19,8 +19,8 @@
#pragma once
-#include "common/key.h"
-#include "math/point.h"
+#include <common/key.h>
+#include <math/point.h>
#include <string.h>
@@ -40,9 +40,10 @@ enum EventType
EVENT_NULL = 0,
//! Event sent on user or system quit request
- EVENT_QUIT = 1,
+ EVENT_QUIT = 1,
- //? EVENT_FRAME = 2,
+ //! Frame update event
+ EVENT_FRAME = 2,
//! Event sent after pressing a mouse button
EVENT_MOUSE_BUTTON_DOWN = 3,
@@ -669,29 +670,41 @@ struct Event
//! If true, the event was produced by system (SDL); else, it has come from user interface
bool systemEvent;
- //! Additional data for EVENT_KEY_DOWN and EVENT_KEY_UP
- KeyEventData key;
- //! Additional data for EVENT_MOUSE_BUTTON_DOWN and EVENT_MOUSE_BUTTON_UP
- MouseButtonEventData mouseButton;
- //! Additional data for EVENT_MOUSE_MOVE
- MouseMoveEventData mouseMove;
- //! Additional data for EVENT_JOY
- JoyAxisEventData joyAxis;
- //! Additional data for EVENT_JOY_AXIS
- JoyButtonEventData joyButton;
- //! Additional data for EVENT_ACTIVE
- ActiveEventData active;
-
- //? long param; // parameter
- //? Math::Point pos; // mouse position (0 .. 1)
- //? float axeX; // control the X axis (-1 .. 1)
- //? float axeY; // control of the Y axis (-1 .. 1)
- //? float axeZ; // control the Z axis (-1 .. 1)
- //? short keyState; // state of the keyboard (KS_ *)
- //? float rTime; // relative time
+ union
+ {
+ //! Additional data for EVENT_KEY_DOWN and EVENT_KEY_UP
+ KeyEventData key;
+ //! Additional data for EVENT_MOUSE_BUTTON_DOWN and EVENT_MOUSE_BUTTON_UP
+ MouseButtonEventData mouseButton;
+ //! Additional data for EVENT_MOUSE_MOVE
+ MouseMoveEventData mouseMove;
+ //! Additional data for EVENT_JOY
+ JoyAxisEventData joyAxis;
+ //! Additional data for EVENT_JOY_AXIS
+ JoyButtonEventData joyButton;
+ //! Additional data for EVENT_ACTIVE
+ ActiveEventData active;
+ };
+
+ // TODO: refactor/rewrite
+ long param; // parameter
+ Math::Point pos; // mouse position (0 .. 1)
+ float axeX; // control the X axis (-1 .. 1)
+ float axeY; // control of the Y axis (-1 .. 1)
+ float axeZ; // control the Z axis (-1 .. 1)
+ short keyState; // state of the keyboard (KS_ *)
+ float rTime; // relative time
Event(EventType aType = EVENT_NULL)
- : type(aType), systemEvent(false) {}
+ {
+ type = aType;
+ systemEvent = false;
+
+ param = 0;
+ axeX = axeY = axeZ = 0.0f;
+ keyState = 0;
+ rTime = 0.0f;
+ }
};
diff --git a/src/common/iman.cpp b/src/common/iman.cpp
index 90b0c1e..4b89ecf 100644
--- a/src/common/iman.cpp
+++ b/src/common/iman.cpp
@@ -23,6 +23,21 @@
#include "common/iman.h"
+template<> CInstanceManager* CSingleton<CInstanceManager>::mInstance = nullptr;
+
+
+CInstanceManager& CInstanceManager::GetInstance()
+{
+ assert(mInstance);
+ return *mInstance;
+}
+
+
+CInstanceManager* CInstanceManager::GetInstancePointer()
+{
+ assert(mInstance);
+ return mInstance;
+}
// Object's constructor.
diff --git a/src/common/iman.h b/src/common/iman.h
index 7a7b499..89b5206 100644
--- a/src/common/iman.h
+++ b/src/common/iman.h
@@ -18,8 +18,8 @@
#pragma once
-
-#include "common/misc.h"
+#include <common/singleton.h>
+#include <common/misc.h>
@@ -32,7 +32,7 @@ struct BaseClass
-class CInstanceManager
+class CInstanceManager : public CSingleton<CInstanceManager>
{
public:
CInstanceManager();
@@ -44,6 +44,8 @@ public:
bool DeleteInstance(ClassType classType, void* pointer);
void* SearchInstance(ClassType classType, int rank=0);
+ static CInstanceManager& GetInstance();
+ static CInstanceManager* GetInstancePointer();
protected:
void Compress(ClassType classType);
diff --git a/src/common/logger.cpp b/src/common/logger.cpp
index f24726e..be73ec7 100644
--- a/src/common/logger.cpp
+++ b/src/common/logger.cpp
@@ -21,21 +21,7 @@
#include <stdio.h>
-template<> CLogger* CSingleton<CLogger>::mInstance = 0;
-
-
-CLogger& CLogger::GetInstance()
-{
- assert(mInstance);
- return *mInstance;
-}
-
-
-CLogger* CLogger::GetInstancePointer()
-{
- assert(mInstance);
- return mInstance;
-}
+template<> CLogger* CSingleton<CLogger>::mInstance = nullptr;
CLogger::CLogger()
diff --git a/src/common/logger.h b/src/common/logger.h
index a67aefe..f126e52 100644
--- a/src/common/logger.h
+++ b/src/common/logger.h
@@ -21,6 +21,7 @@
#include <string>
#include <cstdarg>
+#include <cstdio>
#include <common/singleton.h>
@@ -57,42 +58,39 @@ class CLogger : public CSingleton<CLogger>
~CLogger();
/** Write message to console or file
- * @param const char str - message to write
+ * @param str - message to write
* @param ... - additional arguments
*/
void Message(const char *str, ...);
/** Write message to console or file with LOG_INFO level
- * @param const char str - message to write
+ * @param str - message to write
* @param ... - additional arguments
*/
void Info(const char *str, ...);
/** Write message to console or file with LOG_WARN level
- * @param const char str - message to write
+ * @param str - message to write
* @param ... - additional arguments
*/
void Warn(const char *str, ...);
/** Write message to console or file with LOG_ERROR level
- * @param const char str - message to write
+ * @param str - message to write
* @param ... - additional arguments
*/
void Error(const char *str, ...);
/** Set output file to write logs to
- * @param std::string filename - output file to write to
+ * @param filename - output file to write to
*/
void SetOutputFile(std::string filename);
/** Set log level. Logs with level below will not be shown
- * @param LogType level - minimum log level to write
+ * @param level - minimum log level to write
*/
void SetLogLevel(LogType level);
- static CLogger& GetInstance();
- static CLogger* GetInstancePointer();
-
private:
std::string mFilename;
FILE *mFile;
diff --git a/src/common/profile.cpp b/src/common/profile.cpp
index d921d34..29a68e1 100644
--- a/src/common/profile.cpp
+++ b/src/common/profile.cpp
@@ -17,98 +17,89 @@
// profile.cpp
-#include <stdio.h>
-#include <d3d.h>
-#include <stdlib.h>
+#include <common/profile.h>
-#include "common/language.h"
-#include "common/struct.h"
-#include "common/profile.h"
+template<> CProfile* CSingleton<CProfile>::mInstance = nullptr;
-static char g_filename[100];
-
+CProfile::CProfile()
+{
+ m_ini = new CSimpleIniA();
+ m_ini->SetUnicode();
+ m_ini->SetMultiKey();
+}
-bool InitCurrentDirectory()
+CProfile::~CProfile()
{
-#if _SCHOOL
- _fullpath(g_filename, "ceebot.ini", 100);
-#else
- _fullpath(g_filename, "colobot.ini", 100);
-#endif
- return true;
+ m_ini->Reset();
+ delete m_ini;
}
-bool SetLocalProfileString(char* section, char* key, char* string)
+bool CProfile::InitCurrentDirectory()
{
- WritePrivateProfileString(section, key, string, g_filename);
- return true;
+ bool result = m_ini->LoadFile("colobot.ini") == SI_OK;
+ return result;
}
-bool GetLocalProfileString(char* section, char* key, char* buffer, int max)
+
+bool CProfile::SetLocalProfileString(std::string section, std::string key, std::string value)
{
- int nb;
+ return (m_ini->SetValue(section.c_str(), key.c_str(), value.c_str()) == SI_OK);
+}
- nb = GetPrivateProfileString(section, key, "", buffer, max, g_filename);
- if ( nb == 0 )
- {
- buffer[0] = 0;
- return false;
+
+bool CProfile::GetLocalProfileString(std::string section, std::string key, std::string &buffer)
+{
+ const char* value = m_ini->GetValue(section.c_str(), key.c_str(), nullptr);
+ if (strlen(value) > 0) {
+ buffer = std::string(value);
+ return true;
}
- return true;
+
+ return false;
}
-bool SetLocalProfileInt(char* section, char* key, int value)
+bool CProfile::SetLocalProfileInt(std::string section, std::string key, int value)
{
- char s[20];
-
- sprintf(s, "%d", value);
- WritePrivateProfileString(section, key, s, g_filename);
- return true;
+ return (m_ini->SetLongValue(section.c_str(), key.c_str(), value) == SI_OK);
}
-bool GetLocalProfileInt(char* section, char* key, int &value)
+
+bool CProfile::GetLocalProfileInt(std::string section, std::string key, int &value)
{
- char s[20];
- int nb;
-
- nb = GetPrivateProfileString(section, key, "", s, 20, g_filename);
- if ( nb == 0 )
- {
- value = 0;
- return false;
- }
- sscanf(s, "%d", &value);
+ value = m_ini->GetLongValue(section.c_str(), key.c_str(), 0L);
return true;
}
-bool SetLocalProfileFloat(char* section, char* key, float value)
+bool CProfile::SetLocalProfileFloat(std::string section, std::string key, float value)
{
- char s[20];
-
- sprintf(s, "%.2f", value);
- WritePrivateProfileString(section, key, s, g_filename);
- return true;
+ return (m_ini->SetDoubleValue(section.c_str(), key.c_str(), value) == SI_OK);
}
-bool GetLocalProfileFloat(char* section, char* key, float &value)
+
+bool CProfile::GetLocalProfileFloat(std::string section, std::string key, float &value)
{
- char s[20];
- int nb;
-
- nb = GetPrivateProfileString(section, key, "", s, 20, g_filename);
- if ( nb == 0 )
- {
- value = 0.0f;
- return false;
- }
- sscanf(s, "%f", &value);
+ value = m_ini->GetDoubleValue(section.c_str(), key.c_str(), 0.0d);
return true;
}
+std::vector< std::string > CProfile::GetLocalProfileSection(std::string section, std::string key)
+{
+ std::vector< std::string > ret_list;
+
+ CSimpleIniA::TNamesDepend values;
+ m_ini->GetAllValues(section.c_str(), key.c_str(), values);
+ values.sort(CSimpleIniA::Entry::LoadOrder());
+
+ for (auto item : values) {
+ ret_list.push_back(item.pItem);
+ }
+
+ return ret_list;
+}
diff --git a/src/common/profile.h b/src/common/profile.h
index 2c76a0b..0886522 100644
--- a/src/common/profile.h
+++ b/src/common/profile.h
@@ -18,13 +18,97 @@
#pragma once
+#include <cstdlib>
+#include <vector>
+#include <utility>
-extern bool InitCurrentDirectory();
-extern bool SetLocalProfileString(char* section, char* key, char* string);
-extern bool GetLocalProfileString(char* section, char* key, char* buffer, int max);
-extern bool SetLocalProfileInt(char* section, char* key, int value);
-extern bool GetLocalProfileInt(char* section, char* key, int &value);
-extern bool SetLocalProfileFloat(char* section, char* key, float value);
-extern bool GetLocalProfileFloat(char* section, char* key, float &value);
+#include <lib/simpleini/SimpleIni.h>
+#include <common/singleton.h>
+/**
+ * @file common/profile.h
+ * @brief Class for loading profile (currently for loading ini config file)
+ */
+
+
+/**
+* @class CProfile
+*
+* @brief Class for loading profile (currently for loading ini config file)
+*
+*/
+class CProfile : public CSingleton<CProfile>
+{
+ public:
+ CProfile();
+ ~CProfile();
+
+ /** Loads colobot.ini from current directory
+ * @return return true on success
+ */
+ bool InitCurrentDirectory();
+
+ /** Sets string value in section under specified key
+ * @param std::string section
+ * @param std::string key
+ * @param std::string value
+ * @return return true on success
+ */
+ bool SetLocalProfileString(std::string section, std::string key, std::string value);
+
+ /** Gets string value in section under specified key
+ * @param std::string section
+ * @param std::string key
+ * @param std::string& buffer
+ * @return return true on success
+ */
+ bool GetLocalProfileString(std::string section, std::string key, std::string& buffer);
+
+ /** Sets int value in section under specified key
+ * @param std::string section
+ * @param std::string key
+ * @param int value
+ * @return return true on success
+ */
+ bool SetLocalProfileInt(std::string section, std::string key, int value);
+
+ /** Gets int value in section under specified key
+ * @param std::string section
+ * @param std::string key
+ * @param int& value
+ * @return return true on success
+ */
+ bool GetLocalProfileInt(std::string section, std::string key, int &value);
+
+ /** Sets float value in section under specified key
+ * @param std::string section
+ * @param std::string key
+ * @param float value
+ * @return return true on success
+ */
+ bool SetLocalProfileFloat(std::string section, std::string key, float value);
+
+ /** Gets float value in section under specified key
+ * @param std::string section
+ * @param std::string key
+ * @param float& value
+ * @return return true on success
+ */
+ bool GetLocalProfileFloat(std::string section, std::string key, float &value);
+
+ /** Gets all values in section under specified key
+ * @param std::string section
+ * @param std::string key
+ * @return vector of values
+ */
+ std::vector< std::string > GetLocalProfileSection(std::string section, std::string key);
+
+ private:
+ CSimpleIniA *m_ini;
+};
+
+//! Global function to get profile instance
+inline CProfile* GetProfile() {
+ return CProfile::GetInstancePointer();
+}
diff --git a/src/common/stringutils.cpp b/src/common/stringutils.cpp
index 585bb46..12a3179 100644
--- a/src/common/stringutils.cpp
+++ b/src/common/stringutils.cpp
@@ -135,15 +135,11 @@ int StrUtils::Utf8CharSizeAt(const std::string &str, unsigned int pos)
size_t StrUtils::Utf8StringLength(const std::string &str)
{
size_t result = 0;
- for (unsigned int i = 0; i < str.size(); ++i)
+ unsigned int i = 0;
+ while (i < str.size())
{
- char ch = str[i];
- if ((ch & 0x80) == 0)
+ i += Utf8CharSizeAt(str, i);
++result;
- else if ((ch & 0xC0) == 0xC0)
- result += 2;
- else
- result += 3;
}
return result;
}
diff --git a/src/common/test/CMakeLists.txt b/src/common/test/CMakeLists.txt
index 680116c..d81acab 100644
--- a/src/common/test/CMakeLists.txt
+++ b/src/common/test/CMakeLists.txt
@@ -1,6 +1,12 @@
cmake_minimum_required(VERSION 2.8)
set(CMAKE_BUILD_TYPE debug)
-set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0")
+set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0 -std=c++11")
+
+include_directories("../../")
+include_directories("../../../")
add_executable(image_test ../image.cpp image_test.cpp)
+add_executable(profile_test ../profile.cpp profile_test.cpp)
+
+add_test(profile_test ./profile_test)
diff --git a/src/common/test/colobot.ini b/src/common/test/colobot.ini
new file mode 100644
index 0000000..f6a5f96
--- /dev/null
+++ b/src/common/test/colobot.ini
@@ -0,0 +1,15 @@
+[test_float]
+float_value=1.5
+
+[test_string]
+string_value=Hello world
+
+[test_int]
+int_value=42
+
+[test_multi]
+entry=1
+entry=2
+entry=3
+entry=4
+entry=5
diff --git a/src/common/test/profile_test.cpp b/src/common/test/profile_test.cpp
new file mode 100644
index 0000000..65e20c5
--- /dev/null
+++ b/src/common/test/profile_test.cpp
@@ -0,0 +1,43 @@
+#include "../profile.h"
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+using namespace std;
+
+int main()
+{
+ CProfile profile;
+ profile.InitCurrentDirectory(); // load colobot.ini file
+
+ string result;
+ profile.GetLocalProfileString("test_string", "string_value", result);
+ if (result != "Hello world") {
+ cout << "GetLocalProfileString failed!" << endl;
+ return 1;
+ }
+
+ int int_value;
+ profile.GetLocalProfileInt("test_int", "int_value", int_value);
+ if (int_value != 42) {
+ cout << "GetLocalProfileInt failed!" << endl;
+ return 1;
+ }
+
+ float float_value;
+ profile.GetLocalProfileFloat("test_float", "float_value", float_value);
+ if (float_value != 1.5) {
+ cout << "GetLocalProfileFloat failed!" << endl;
+ return 1;
+ }
+
+ vector<string> list;
+ list = profile.GetLocalProfileSection("test_multi", "entry");
+ if (list.size() != 5) {
+ cout << "GetLocalProfileSection failed!" << endl;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/src/graphics/README.txt b/src/graphics/README.txt
index 3ec3871..479747b 100644
--- a/src/graphics/README.txt
+++ b/src/graphics/README.txt
@@ -1,3 +1,12 @@
-src/graphics
+/**
+ * \dir graphics
+ * \brief Graphics engine
+ */
-Graphics engine
+/**
+ * \namespace Gfx
+ * \brief Namespace for (new) graphics code
+ *
+ * This namespace was created to avoid clashing with old code, but now it still serves,
+ * defining a border between pure graphics engine and other parts of application.
+ */ \ No newline at end of file
diff --git a/src/graphics/core/README.txt b/src/graphics/core/README.txt
index 12beef9..ca3768c 100644
--- a/src/graphics/core/README.txt
+++ b/src/graphics/core/README.txt
@@ -1,6 +1,7 @@
-src/graphics/core
-
-Abstract core of graphics engine
-
-Core types, enums, structs and CDevice abstract class that define
-the abstract graphics device used in graphics engine
+/**
+ * \dir graphics/core
+ * \brief Abstract core of graphics engine
+ *
+ * Core types, enums, structs and CDevice abstract class that define
+ * the abstract graphics device used in graphics engine
+ */ \ No newline at end of file
diff --git a/src/graphics/core/color.h b/src/graphics/core/color.h
index 6973644..ff8a2eb 100644
--- a/src/graphics/core/color.h
+++ b/src/graphics/core/color.h
@@ -14,11 +14,13 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// color.h
+/**
+ * \file graphics/core/color.h
+ * \brief Color structs and related functions
+ */
#pragma once
-
#include <sstream>
@@ -66,6 +68,11 @@ struct Color
{
return r == other.r && g == other.g && b == other.b && a == other.a;
}
+
+ inline bool operator!=(const Gfx::Color &other) const
+ {
+ return ! this->operator==(other);
+ }
};
/**
diff --git a/src/graphics/core/device.h b/src/graphics/core/device.h
index c10b853..a3d0208 100644
--- a/src/graphics/core/device.h
+++ b/src/graphics/core/device.h
@@ -15,7 +15,10 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// device.h
+/**
+ * \file graphics/core/device.h
+ * \brief Abstract graphics device - Gfx::CDevice class and related structs/enums
+ */
#pragma once
@@ -25,13 +28,14 @@
#include "graphics/core/material.h"
#include "graphics/core/texture.h"
#include "graphics/core/vertex.h"
-#include "math/intsize.h"
+#include "math/intpoint.h"
#include "math/matrix.h"
#include <string>
class CImage;
+struct ImageData;
namespace Gfx {
@@ -45,7 +49,7 @@ namespace Gfx {
struct DeviceConfig
{
//! Screen size
- Math::IntSize size;
+ Math::IntPoint size;
//! Bits per pixel
int bpp;
//! Full screen
@@ -63,7 +67,7 @@ struct DeviceConfig
//! Loads the default values
inline void LoadDefault()
{
- size = Math::IntSize(800, 600);
+ size = Math::IntPoint(800, 600);
bpp = 32;
fullScreen = false;
resizeable = false;
@@ -149,9 +153,9 @@ enum FogMode
\brief Culling mode for polygons */
enum CullMode
{
- //! Cull clockwise side
+ //! Cull clockwise faces
CULL_CW,
- //! Cull counter-clockwise side
+ //! Cull counter-clockwise faces
CULL_CCW
};
@@ -274,13 +278,14 @@ class CDevice
public:
virtual ~CDevice() {}
+ //! Provides a hook to debug graphics code (implementation-specific)
+ virtual void DebugHook() = 0;
+
//! Initializes the device, setting the initial state
virtual bool Create() = 0;
//! Destroys the device, releasing every acquired resource
virtual void Destroy() = 0;
- //! Returns whether the device has been initialized
- virtual bool GetWasInit() = 0;
//! Returns the last encountered error
virtual std::string GetError() = 0;
@@ -317,6 +322,8 @@ public:
//! Creates a texture from image; the image can be safely removed after that
virtual Gfx::Texture CreateTexture(CImage *image, const Gfx::TextureCreateParams &params) = 0;
+ //! Creates a texture from raw image data; image data can be freed after that
+ virtual Gfx::Texture CreateTexture(ImageData *data, const Gfx::TextureCreateParams &params) = 0;
//! Deletes a given texture, freeing it from video memory
virtual void DestroyTexture(const Gfx::Texture &texture) = 0;
//! Deletes all textures created so far
@@ -324,8 +331,10 @@ public:
//! Returns the maximum number of multitexture stages
virtual int GetMaxTextureCount() = 0;
- //! Sets the (multi)texture at given index
+ //! Sets the texture at given texture stage
virtual void SetTexture(int index, const Gfx::Texture &texture) = 0;
+ //! Sets the texture image by ID at given texture stage
+ virtual void SetTexture(int index, unsigned int textureId) = 0;
//! Returns the (multi)texture at given index
virtual Gfx::Texture GetTexture(int index) = 0;
//! Enables/disables the given texture stage
diff --git a/src/graphics/core/light.h b/src/graphics/core/light.h
index b787cb2..a39d1f5 100644
--- a/src/graphics/core/light.h
+++ b/src/graphics/core/light.h
@@ -15,7 +15,10 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// light.h
+/**
+ * \file graphics/core/light.h
+ * \brief Light struct and related enums
+ */
#pragma once
diff --git a/src/graphics/core/material.h b/src/graphics/core/material.h
index 31b42f3..eb73c50 100644
--- a/src/graphics/core/material.h
+++ b/src/graphics/core/material.h
@@ -14,7 +14,10 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// material.h
+/**
+ * \file graphics/core/material.h
+ * \brief Material struct
+ */
#pragma once
diff --git a/src/graphics/core/texture.h b/src/graphics/core/texture.h
index 8d6b082..c36b6c6 100644
--- a/src/graphics/core/texture.h
+++ b/src/graphics/core/texture.h
@@ -14,11 +14,14 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// texture.h
+/**
+ * \file graphics/core/texture.h
+ * \brief Texture struct and related enums
+ */
#pragma once
-#include "math/intsize.h"
+#include "math/intpoint.h"
namespace Gfx {
@@ -194,7 +197,7 @@ struct Texture
//! ID of the texture in graphics engine
unsigned int id;
//! Size of texture
- Math::IntSize size;
+ Math::IntPoint size;
//! Whether the texture has alpha channel
bool alpha;
diff --git a/src/graphics/core/vertex.h b/src/graphics/core/vertex.h
index b7fab1c..53dd642 100644
--- a/src/graphics/core/vertex.h
+++ b/src/graphics/core/vertex.h
@@ -14,7 +14,10 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// vertex.h
+/**
+ * \file graphics/core/vertex.h
+ * \brief Vertex structs
+ */
#pragma once
diff --git a/src/graphics/d3d/README.txt b/src/graphics/d3d/README.txt
index 8388120..524ae7b 100644
--- a/src/graphics/d3d/README.txt
+++ b/src/graphics/d3d/README.txt
@@ -1,3 +1,4 @@
-src/graphics/d3d
-
-Possible future DirectX implementation of graphics engine
+/**
+ * \dir graphics/d3d
+ * \brief Possible future DirectX implementation of graphics engine
+ */ \ No newline at end of file
diff --git a/src/graphics/engine/README.txt b/src/graphics/engine/README.txt
index 308b601..f64d3dd 100644
--- a/src/graphics/engine/README.txt
+++ b/src/graphics/engine/README.txt
@@ -1,8 +1,9 @@
-src/graphics/engine
-
-Graphics engine
-
-CEngine class and various other classes implementing the main features
-of graphics engine from model loading to decorative particles
-
-Graphics operations are done on abstract interface from src/graphics/core
+/**
+ * \dir graphics/engine
+ * \brief Graphics engine
+ *
+ * CEngine class and various other classes implementing the main features
+ * of graphics engine from model loading to decorative particles
+ *
+ * Graphics operations are done on abstract interface from src/graphics/core
+ */ \ No newline at end of file
diff --git a/src/graphics/engine/camera.cpp b/src/graphics/engine/camera.cpp
index c7ca503..2db6398 100644
--- a/src/graphics/engine/camera.cpp
+++ b/src/graphics/engine/camera.cpp
@@ -29,6 +29,66 @@
#include "physics/physics.h"
+// TODO temporary stubs for CObject and CPhysics
+
+void CObject::SetTransparency(float)
+{
+}
+
+CObject* CObject::GetFret()
+{
+ return nullptr;
+}
+
+CObject* CObject::GetPower()
+{
+ return nullptr;
+}
+
+CObject* CObject::GetTruck()
+{
+ return nullptr;
+}
+
+ObjectType CObject::GetType()
+{
+ return OBJECT_NULL;
+}
+
+void CObject::SetGunGoalH(float)
+{
+}
+
+void CObject::GetGlobalSphere(Math::Vector &pos, float &radius)
+{
+}
+
+float CObject::GetAngleY(int)
+{
+ return 0.0f;
+}
+
+Math::Vector CObject::GetPosition(int)
+{
+ return Math::Vector();
+}
+
+void CObject::SetViewFromHere(Math::Vector &eye, float &dirH, float &dirV,
+ Math::Vector &lookat, Math::Vector &upVec,
+ Gfx::CameraType type)
+{
+}
+
+CPhysics* CObject::GetPhysics()
+{
+ return nullptr;
+}
+
+bool CPhysics::GetLand()
+{
+ return false;
+}
+
//! Changes the level of transparency of an object and objects transported (battery & cargo)
void SetTransparency(CObject* obj, float value)
{
@@ -332,7 +392,7 @@ void Gfx::CCamera::SetType(CameraType type)
SetSmooth(Gfx::CAM_SMOOTH_NORM);
}
-CameraType Gfx::CCamera::GetType()
+Gfx::CameraType Gfx::CCamera::GetType()
{
return m_type;
}
@@ -342,7 +402,7 @@ void Gfx::CCamera::SetSmooth(CameraSmooth type)
m_smooth = type;
}
-CameraSmooth Gfx::CCamera::GetSmoth()
+Gfx::CameraSmooth Gfx::CCamera::GetSmoth()
{
return m_smooth;
}
@@ -692,7 +752,7 @@ void Gfx::CCamera::OverFrame(const Event &event)
}
else
{
- color = Gfx::Color(0.0f. 0.0f, 0.0f);
+ color = Gfx::Color(0.0f, 0.0f, 0.0f);
}
color.a = 0.0f;
m_engine->SetOverColor(color, m_overMode);
@@ -873,7 +933,7 @@ bool Gfx::CCamera::IsCollisionBack(Math::Vector &eye, Math::Vector lookat)
for (int i = 0 ;i < 1000000; i++)
{
- CObject *obj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ CObject *obj = static_cast<CObject*>( m_iMan->SearchInstance(CLASS_OBJECT, i) );
if (obj == NULL) break;
if (obj->GetTruck()) continue; // battery or cargo?
@@ -899,7 +959,7 @@ bool Gfx::CCamera::IsCollisionBack(Math::Vector &eye, Math::Vector lookat)
iType == OBJECT_SAFE ||
iType == OBJECT_HUSTON ) continue;
- ObjType oType = obj->GetType();
+ ObjectType oType = obj->GetType();
if ( oType == OBJECT_HUMAN ||
oType == OBJECT_TECH ||
oType == OBJECT_TOTO ||
@@ -995,7 +1055,6 @@ bool Gfx::CCamera::EventProcess(const Event &event)
{
switch (event.type)
{
- // TODO: frame update event
case EVENT_FRAME:
EventFrame(event);
break;
@@ -1004,11 +1063,11 @@ bool Gfx::CCamera::EventProcess(const Event &event)
EventMouseMove(event);
break;
- case EVENT_KEY_DOWN:
- // TODO: mouse wheel event
+ // TODO: mouse wheel event
+ /*case EVENT_KEY_DOWN:
if ( event.param == VK_WHEELUP ) EventMouseWheel(+1);
if ( event.param == VK_WHEELDOWN ) EventMouseWheel(-1);
- break;
+ break;*/
default:
break;
@@ -1489,8 +1548,6 @@ bool Gfx::CCamera::EventFrameFix(const Event &event)
bool Gfx::CCamera::EventFrameExplo(const Event &event)
{
- float factor = m_heightEye * 0.5f + 30.0f;
-
if (m_mouseDirH != 0.0f)
m_directionH -= m_mouseDirH * event.rTime * 0.7f * m_speed;
@@ -1526,7 +1583,7 @@ bool Gfx::CCamera::EventFrameOnBoard(const Event &event)
{
Math::Vector lookatPt, upVec;
m_cameraObj->SetViewFromHere(m_eyePt, m_directionH, m_directionV,
- lookatPt, vUpVec, m_type);
+ lookatPt, upVec, m_type);
Math::Vector eye = m_effectOffset * 0.3f + m_eyePt;
Math::Vector lookat = m_effectOffset * 0.3f + lookatPt;
diff --git a/src/graphics/engine/camera.h b/src/graphics/engine/camera.h
index 935f8b0..1a82f9f 100644
--- a/src/graphics/engine/camera.h
+++ b/src/graphics/engine/camera.h
@@ -15,7 +15,10 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// camera.h
+/**
+ * \file graphics/engine/camera.h
+ * \brief Camera handling - Gfx::CCamera class
+ */
#pragma once
@@ -353,13 +356,13 @@ protected:
float m_centeringTime;
float m_centeringProgress;
- CameraEffect m_effectType;
+ Gfx::CameraEffect m_effectType;
Math::Vector m_effectPos;
float m_effectForce;
float m_effectProgress;
Math::Vector m_effectOffset;
- OverEffect m_overType;
+ Gfx::CameraOverEffect m_overType;
float m_overForce;
float m_overTime;
Gfx::Color m_overColorBase;
diff --git a/src/graphics/engine/cloud.cpp b/src/graphics/engine/cloud.cpp
index d0e5ed8..f3c0002 100644
--- a/src/graphics/engine/cloud.cpp
+++ b/src/graphics/engine/cloud.cpp
@@ -19,5 +19,265 @@
#include "graphics/engine/cloud.h"
+#include "common/iman.h"
+#include "graphics/engine/engine.h"
+#include "graphics/engine/terrain.h"
+#include "math/geometry.h"
-// TODO implementation
+
+const int CLOUD_LINE_PREALLOCATE_COUNT = 100;
+
+const int DIMEXPAND = 4; // extension of the dimensions
+
+
+Gfx::CCloud::CCloud(CInstanceManager* iMan, Gfx::CEngine* engine)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_CLOUD, this);
+
+ m_engine = engine;
+ m_terrain = nullptr;
+
+ m_level = 0.0f;
+ m_wind = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_subdiv = 8;
+ m_enable = true;
+
+ m_line.reserve(CLOUD_LINE_PREALLOCATE_COUNT);
+}
+
+Gfx::CCloud::~CCloud()
+{
+ m_iMan = nullptr;
+ m_engine = nullptr;
+ m_terrain = nullptr;
+}
+
+bool Gfx::CCloud::EventProcess(const Event &event)
+{
+ if ( event.type == EVENT_FRAME )
+ return EventFrame(event);
+
+ return true;
+}
+
+bool Gfx::CCloud::EventFrame(const Event &event)
+{
+ if (m_engine->GetPause()) return true;
+
+ m_time += event.rTime;
+
+ if (m_level == 0.0f) return true;
+
+ if (m_time - m_lastTest < 0.2f) return true;
+
+ m_lastTest = m_time;
+
+ return true;
+}
+
+void Gfx::CCloud::AdjustLevel(Math::Vector &pos, Math::Vector &eye, float deep,
+ Math::Point &uv1, Math::Point &uv2)
+{
+ uv1.x = (pos.x+20000.0f)/1280.0f;
+ uv1.y = (pos.z+20000.0f)/1280.0f;
+ uv1.x -= m_time*(m_wind.x/100.0f);
+ uv1.y -= m_time*(m_wind.z/100.0f);
+
+ uv2.x = 0.0f;
+ uv2.y = 0.0f;
+
+ float dist = Math::DistanceProjected(pos, eye);
+ float factor = powf(dist/deep, 2.0f);
+ pos.y -= m_level*factor*10.0f;
+}
+
+void Gfx::CCloud::Draw()
+{
+ /* TODO!
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2* vertex;
+ Math::Matrix* matView;
+ D3DMATERIAL7 material;
+ Math::Matrix matrix;
+ Math::Vector n, pos, p, eye;
+ Math::Point uv1, uv2;
+ float iDeep, deep, size, fogStart, fogEnd;
+ int i, j, u;
+
+ if ( !m_enable ) return;
+ if ( m_level == 0.0f ) return;
+ if ( m_lineUsed == 0 ) return;
+
+ vertex = (D3DVERTEX2*)malloc(sizeof(D3DVERTEX2)*(m_brick+2)*2);
+
+ iDeep = m_engine->GetDeepView();
+ deep = (m_brick*m_size)/2.0f;
+ m_engine->SetDeepView(deep);
+ m_engine->SetFocus(m_engine->GetFocus());
+ m_engine->UpdateMatProj(); // increases the depth of view
+
+ fogStart = deep*0.15f;
+ fogEnd = deep*0.24f;
+
+ device = m_engine->GetD3DDevice();
+ device->SetRenderState(D3DRENDERSTATE_AMBIENT, 0x00000000);
+ device->SetRenderState(D3DRENDERSTATE_LIGHTING, false);
+ device->SetRenderState(D3DRENDERSTATE_ZENABLE, false);
+ device->SetRenderState(D3DRENDERSTATE_FOGENABLE, true);
+ device->SetRenderState(D3DRENDERSTATE_FOGSTART, F2DW(fogStart));
+ device->SetRenderState(D3DRENDERSTATE_FOGEND, F2DW(fogEnd));
+
+ matView = m_engine->GetMatView();
+ {
+ D3DMATRIX mat = MAT_TO_D3DMAT(*matView);
+ device->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat);
+ }
+
+ ZeroMemory( &material, sizeof(D3DMATERIAL7) );
+ material.diffuse = m_diffuse;
+ material.ambient = m_ambient;
+ m_engine->SetMaterial(material);
+
+ m_engine->SetTexture(m_filename, 0);
+ m_engine->SetTexture(m_filename, 1);
+
+ m_engine->SetState(D3DSTATETTb|D3DSTATEFOG|D3DSTATEWRAP);
+
+ matrix.LoadIdentity();
+ {
+ D3DMATRIX mat = MAT_TO_D3DMAT(matrix);
+ device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
+ }
+
+ size = m_size/2.0f;
+ eye = m_engine->GetEyePt();
+ n = Math::Vector(0.0f, -1.0f, 0.0f);
+
+ // Draws all the lines.
+ for ( i=0 ; i<m_lineUsed ; i++ )
+ {
+ pos.y = m_level;
+ pos.z = m_line[i].pz;
+ pos.x = m_line[i].px1;
+
+ u = 0;
+ p.x = pos.x-size;
+ p.z = pos.z+size;
+ p.y = pos.y;
+ AdjustLevel(p, eye, deep, uv1, uv2);
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ p.x = pos.x-size;
+ p.z = pos.z-size;
+ p.y = pos.y;
+ AdjustLevel(p, eye, deep, uv1, uv2);
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ for ( j=0 ; j<m_line[i].len ; j++ )
+ {
+ p.x = pos.x+size;
+ p.z = pos.z+size;
+ p.y = pos.y;
+ AdjustLevel(p, eye, deep, uv1, uv2);
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ p.x = pos.x+size;
+ p.z = pos.z-size;
+ p.y = pos.y;
+ AdjustLevel(p, eye, deep, uv1, uv2);
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ pos.x += size*2.0f;
+ }
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, u, NULL);
+ m_engine->AddStatisticTriangle(u-2);
+ }
+
+ m_engine->SetDeepView(iDeep);
+ m_engine->SetFocus(m_engine->GetFocus());
+ m_engine->UpdateMatProj(); // gives depth to initial
+
+ free(vertex); */
+}
+
+void Gfx::CCloud::CreateLine(int x, int y, int len)
+{
+ Gfx::CloudLine line;
+
+ line.x = x;
+ line.y = y;
+ line.len = len;
+
+ float offset = m_brick*m_size/2.0f - m_size/2.0f;
+
+ line.px1 = m_size* line.x - offset;
+ line.px2 = m_size*(line.x+line.len) - offset;
+ line.pz = m_size* line.y - offset;
+
+ m_line.push_back(line);
+}
+
+void Gfx::CCloud::Create(const std::string& fileName,
+ Gfx::Color diffuse, Gfx::Color ambient,
+ float level)
+{
+ m_diffuse = diffuse;
+ m_ambient = ambient;
+ m_level = level;
+ m_time = 0.0f;
+ m_lastTest = 0.0f;
+ m_fileName = fileName;
+
+ if (! m_fileName.empty())
+ m_engine->LoadTexture(m_fileName);
+
+ if (m_terrain == nullptr)
+ m_terrain = static_cast<CTerrain*>(m_iMan->SearchInstance(CLASS_TERRAIN));
+
+ m_wind = m_terrain->GetWind();
+
+ m_brick = m_terrain->GetBrick()*m_terrain->GetMosaic()*DIMEXPAND;
+ m_size = m_terrain->GetSize();
+
+ m_brick /= m_subdiv*DIMEXPAND;
+ m_size *= m_subdiv*DIMEXPAND;
+
+ if (m_level == 0.0f)
+ return;
+
+ m_line.clear();
+ for (int y = 0; y < m_brick; y++)
+ CreateLine(0, y, m_brick);
+
+ return;
+}
+
+void Gfx::CCloud::Flush()
+{
+ m_level = 0.0f;
+}
+
+
+void Gfx::CCloud::SetLevel(float level)
+{
+ m_level = level;
+
+ Create(m_fileName, m_diffuse, m_ambient, m_level);
+}
+
+float Gfx::CCloud::GetLevel()
+{
+ return m_level;
+}
+
+void Gfx::CCloud::SetEnable(bool enable)
+{
+ m_enable = enable;
+}
+
+bool Gfx::CCloud::GetEnable()
+{
+ return m_enable;
+}
diff --git a/src/graphics/engine/cloud.h b/src/graphics/engine/cloud.h
index d2d29d7..881a598 100644
--- a/src/graphics/engine/cloud.h
+++ b/src/graphics/engine/cloud.h
@@ -15,7 +15,10 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// cloud.h
+/**
+ * \file graphics/engine/cloud.h
+ * \brief Cloud rendering - Gfx::CCloud class
+ */
#pragma once
@@ -24,6 +27,9 @@
#include "math/point.h"
#include "math/vector.h"
+#include <vector>
+#include <string>
+
class CInstanceManager;
@@ -34,13 +40,20 @@ namespace Gfx {
class CEngine;
class CTerrain;
-const short MAXCLOUDLINE = 100;
-
struct CloudLine
{
- short x, y; // beginning
- short len; // in length x
+ //! Beginning
+ short x, y;
+ //! In length x
+ short len;
float px1, px2, pz;
+
+ CloudLine()
+ {
+ x = y = 0;
+ len = 0;
+ px1 = px2 = pz = 0;
+ }
};
@@ -51,43 +64,59 @@ public:
~CCloud();
bool EventProcess(const Event &event);
+ //! Removes all the clouds
void Flush();
- bool Create(const char *filename, Gfx::Color diffuse, Gfx::Color ambient, float level);
+ //! Creates all areas of cloud
+ void Create(const std::string& fileName, Gfx::Color diffuse, Gfx::Color ambient, float level);
+ //! Draw the clouds
void Draw();
- bool SetLevel(float level);
- float RetLevel();
+ //! Modifies the cloud level
+ void SetLevel(float level);
+ //! Returns the current level of clouds
+ float GetLevel();
- void SetEnable(bool bEnable);
- bool RetEnable();
+ //! Activate management of clouds
+ void SetEnable(bool enable);
+ bool GetEnable();
protected:
+ //! Makes the clouds evolve
bool EventFrame(const Event &event);
- void AdjustLevel(Math::Vector &pos, Math::Vector &eye, float deep, Math::Point &uv1, Math::Point &uv2);
- bool CreateLine(int x, int y, int len);
+ //! Adjusts the position to normal, to imitate the clouds at movement
+ void AdjustLevel(Math::Vector &pos, Math::Vector &eye, float deep,
+ Math::Point &uv1, Math::Point &uv2);
+ //! Updates the positions, relative to the ground
+ void CreateLine(int x, int y, int len);
protected:
- CInstanceManager* m_iMan;
- CEngine* m_engine;
- CTerrain* m_terrain;
-
- char m_filename[100];
- float m_level; // overall level
- Math::Point m_speed; // feedrate (wind)
- Gfx::Color m_diffuse; // diffuse color
- Gfx::Color m_ambient; // ambient color
+ CInstanceManager* m_iMan;
+ Gfx::CEngine* m_engine;
+ Gfx::CTerrain* m_terrain;
+
+ std::string m_fileName;
+ //! Overall level
+ float m_level;
+ //! Feedrate (wind)
+ Math::Point m_speed;
+ //! Diffuse color
+ Gfx::Color m_diffuse;
+ //! Ambient color
+ Gfx::Color m_ambient;
float m_time;
float m_lastTest;
int m_subdiv;
- Math::Vector m_wind; // wind speed
- int m_brick; // brick mosaic
- float m_size; // size of a brick element
+ //! Wind speed
+ Math::Vector m_wind;
+ //! Brick mosaic
+ int m_brick;
+ //! Size of a brick element
+ float m_size;
- int m_lineUsed;
- CloudLine m_line[MAXCLOUDLINE];
+ std::vector<Gfx::CloudLine> m_line;
- bool m_bEnable;
+ bool m_enable;
};
diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp
index e544ee3..644ecaf 100644
--- a/src/graphics/engine/engine.cpp
+++ b/src/graphics/engine/engine.cpp
@@ -25,7 +25,19 @@
#include "common/key.h"
#include "common/logger.h"
#include "graphics/core/device.h"
+#include "graphics/engine/camera.h"
+#include "graphics/engine/cloud.h"
+#include "graphics/engine/lightman.h"
+#include "graphics/engine/lightning.h"
+#include "graphics/engine/particle.h"
+#include "graphics/engine/planet.h"
+#include "graphics/engine/pyro.h"
+#include "graphics/engine/terrain.h"
+#include "graphics/engine/text.h"
+#include "graphics/engine/water.h"
#include "math/geometry.h"
+#include "sound/sound.h"
+
// Initial size of various vectors
const int OBJECT_PREALLOCATE_COUNT = 1200;
@@ -40,32 +52,35 @@ const int LEVEL5_PREALLOCATE_COUNT = 100;
const int LEVEL5_VERTEX_PREALLOCATE_COUNT = 200;
+// TODO: temporary stub for CInterface
+class CInterface
+{
+public:
+ void Draw() {}
+};
+
Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
{
m_iMan = iMan;
m_app = app;
- m_device = NULL;
-
- m_wasInit = false;
+ m_device = nullptr;
m_iMan = iMan;
m_iMan->AddInstance(CLASS_ENGINE, this);
m_app = app;
- m_lightMan = NULL;
- m_text = NULL;
- m_particle = NULL;
- m_water = NULL;
- m_cloud = NULL;
- m_lightning = NULL;
- m_planet = NULL;
- m_sound = NULL;
- m_terrain = NULL;
+ m_lightMan = nullptr;
+ m_text = nullptr;
+ m_particle = nullptr;
+ m_water = nullptr;
+ m_cloud = nullptr;
+ m_lightning = nullptr;
+ m_planet = nullptr;
+ m_sound = nullptr;
+ m_terrain = nullptr;
m_focus = 0.75f;
- m_baseTime = 0;
- m_lastTime = 0;
- m_absTime = 0.0f;
+
m_rankView = 0;
m_ambientColor[0] = Gfx::Color(0.5f, 0.5f, 0.5f, 0.5f);
@@ -99,15 +114,15 @@ Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
m_overFront = true;
m_overColor = 0;
m_overMode = ENG_RSTATE_TCOLOR_BLACK;
- m_frontsizeName = ""; // no front image
- m_hiliteRank[0] = -1; // empty list
+ m_highlightRank[0] = -1; // empty list
+ m_highlightTime = 0.0f;
m_eyePt = Math::Vector(0.0f, 0.0f, 0.0f);
m_lookatPt = Math::Vector(0.0f, 0.0f, 1.0f);
m_drawWorld = true;
m_drawFront = false;
m_limitLOD[0] = 100.0f;
m_limitLOD[1] = 200.0f;
- m_particuleDensity = 1.0f;
+ m_particleDensity = 1.0f;
m_clippingDistance = 1.0f;
m_lastClippingDistance = m_clippingDistance;
m_objectDetail = 1.0f;
@@ -119,7 +134,7 @@ Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
m_lensMode = true;
m_waterMode = true;
m_skyMode = true;
- m_backForce = true;
+ m_backForce = false; // TODO: change to true?
m_planetMode = true;
m_lightMode = true;
m_editIndentMode = true;
@@ -131,33 +146,24 @@ Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
m_forceStateColor = true;
m_stateColor = false;
- m_blackSrcBlend[0] = 0;
- m_blackDestBlend[0] = 0;
- m_whiteSrcBlend[0] = 0;
- m_whiteDestBlend[0] = 0;
- m_diffuseSrcBlend[0] = 0;
- m_diffuseDestBlend[0] = 0;
- m_alphaSrcBlend[0] = 0;
- m_alphaDestBlend[0] = 0;
-
m_updateGeometry = false;
- m_mice[Gfx::ENG_MOUSE_NORM] = Gfx::EngineMouse( 0, 1, 32, Gfx::ENG_RSTATE_TCOLOR_WHITE, Gfx::ENG_RSTATE_TCOLOR_BLACK, Math::Point( 1.0f, 1.0f));
- m_mice[Gfx::ENG_MOUSE_WAIT] = Gfx::EngineMouse( 2, 3, 33, Gfx::ENG_RSTATE_TCOLOR_WHITE, Gfx::ENG_RSTATE_TCOLOR_BLACK, Math::Point( 8.0f, 12.0f));
- m_mice[Gfx::ENG_MOUSE_HAND] = Gfx::EngineMouse( 4, 5, 34, Gfx::ENG_RSTATE_TCOLOR_WHITE, Gfx::ENG_RSTATE_TCOLOR_BLACK, Math::Point( 7.0f, 2.0f));
- m_mice[Gfx::ENG_MOUSE_NO] = Gfx::EngineMouse( 6, 7, 35, Gfx::ENG_RSTATE_TCOLOR_WHITE, Gfx::ENG_RSTATE_TCOLOR_BLACK, Math::Point(10.0f, 10.0f));
- m_mice[Gfx::ENG_MOUSE_EDIT] = Gfx::EngineMouse( 8, 9, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 6.0f, 10.0f));
- m_mice[Gfx::ENG_MOUSE_CROSS] = Gfx::EngineMouse(10, 11, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(10.0f, 10.0f));
- m_mice[Gfx::ENG_MOUSE_MOVEV] = Gfx::EngineMouse(12, 13, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 5.0f, 11.0f));
- m_mice[Gfx::ENG_MOUSE_MOVEH] = Gfx::EngineMouse(14, 15, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(11.0f, 5.0f));
- m_mice[Gfx::ENG_MOUSE_MOVED] = Gfx::EngineMouse(16, 17, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 9.0f, 9.0f));
- m_mice[Gfx::ENG_MOUSE_MOVEI] = Gfx::EngineMouse(18, 19, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 9.0f, 9.0f));
- m_mice[Gfx::ENG_MOUSE_MOVE] = Gfx::EngineMouse(20, 21, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(11.0f, 11.0f));
- m_mice[Gfx::ENG_MOUSE_TARGET] = Gfx::EngineMouse(22, 23, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(15.0f, 15.0f));
- m_mice[Gfx::ENG_MOUSE_SCROLLL] = Gfx::EngineMouse(24, 25, 43, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 2.0f, 9.0f));
- m_mice[Gfx::ENG_MOUSE_SCROLLR] = Gfx::EngineMouse(26, 27, 44, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(17.0f, 9.0f));
- m_mice[Gfx::ENG_MOUSE_SCROLLU] = Gfx::EngineMouse(28, 29, 45, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 9.0f, 2.0f));
- m_mice[Gfx::ENG_MOUSE_SCROLLD] = Gfx::EngineMouse(30, 31, 46, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 9.0f, 17.0f));
+ m_mice[Gfx::ENG_MOUSE_NORM] = Gfx::EngineMouse( 0, 1, 32, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Math::Point( 1.0f, 1.0f));
+ m_mice[Gfx::ENG_MOUSE_WAIT] = Gfx::EngineMouse( 2, 3, 33, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Math::Point( 8.0f, 12.0f));
+ m_mice[Gfx::ENG_MOUSE_HAND] = Gfx::EngineMouse( 4, 5, 34, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Math::Point( 7.0f, 2.0f));
+ m_mice[Gfx::ENG_MOUSE_NO] = Gfx::EngineMouse( 6, 7, 35, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Math::Point(10.0f, 10.0f));
+ m_mice[Gfx::ENG_MOUSE_EDIT] = Gfx::EngineMouse( 8, 9, -1, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Math::Point( 6.0f, 10.0f));
+ m_mice[Gfx::ENG_MOUSE_CROSS] = Gfx::EngineMouse(10, 11, -1, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Math::Point(10.0f, 10.0f));
+ m_mice[Gfx::ENG_MOUSE_MOVEV] = Gfx::EngineMouse(12, 13, -1, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Math::Point( 5.0f, 11.0f));
+ m_mice[Gfx::ENG_MOUSE_MOVEH] = Gfx::EngineMouse(14, 15, -1, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Math::Point(11.0f, 5.0f));
+ m_mice[Gfx::ENG_MOUSE_MOVED] = Gfx::EngineMouse(16, 17, -1, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Math::Point( 9.0f, 9.0f));
+ m_mice[Gfx::ENG_MOUSE_MOVEI] = Gfx::EngineMouse(18, 19, -1, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Math::Point( 9.0f, 9.0f));
+ m_mice[Gfx::ENG_MOUSE_MOVE] = Gfx::EngineMouse(20, 21, -1, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Math::Point(11.0f, 11.0f));
+ m_mice[Gfx::ENG_MOUSE_TARGET] = Gfx::EngineMouse(22, 23, -1, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Math::Point(15.0f, 15.0f));
+ m_mice[Gfx::ENG_MOUSE_SCROLLL] = Gfx::EngineMouse(24, 25, 43, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Math::Point( 2.0f, 9.0f));
+ m_mice[Gfx::ENG_MOUSE_SCROLLR] = Gfx::EngineMouse(26, 27, 44, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Math::Point(17.0f, 9.0f));
+ m_mice[Gfx::ENG_MOUSE_SCROLLU] = Gfx::EngineMouse(28, 29, 45, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Math::Point( 9.0f, 2.0f));
+ m_mice[Gfx::ENG_MOUSE_SCROLLD] = Gfx::EngineMouse(30, 31, 46, Gfx::ENG_RSTATE_TTEXTURE_BLACK, Gfx::ENG_RSTATE_TTEXTURE_WHITE, Math::Point( 9.0f, 17.0f));
m_mouseSize = Math::Point(0.04f, 0.04f * (800.0f / 600.0f));
m_mousePos = Math::Point(0.5f, 0.5f);
@@ -165,185 +171,721 @@ Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
m_mouseVisible = false;
m_texPath = "textures/";
- m_defaultTexParams.format = Gfx::TEX_IMG_RGBA;
+ m_defaultTexParams.format = Gfx::TEX_IMG_RGB;
m_defaultTexParams.mipmap = true;
m_defaultTexParams.minFilter = Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR;
m_defaultTexParams.magFilter = Gfx::TEX_MAG_FILTER_LINEAR;
m_objectTree.reserve(LEVEL1_PREALLOCATE_COUNT);
m_objects.reserve(OBJECT_PREALLOCATE_COUNT);
- m_shadow.reserve(SHADOW_PREALLOCATE_COUNT);
- m_groundSpot.reserve(GROUNDSPOT_PREALLOCATE_COUNT);
+ m_shadows.reserve(SHADOW_PREALLOCATE_COUNT);
+ m_groundSpots.reserve(GROUNDSPOT_PREALLOCATE_COUNT);
}
Gfx::CEngine::~CEngine()
{
- m_iMan = NULL;
- m_app = NULL;
- m_device = NULL;
+ m_iMan = nullptr;
+ m_app = nullptr;
+ m_device = nullptr;
+ m_sound = nullptr;
+ m_terrain = nullptr;
+}
- m_sound = NULL;
- m_terrain = NULL;
+void Gfx::CEngine::SetDevice(Gfx::CDevice *device)
+{
+ m_device = device;
}
-bool Gfx::CEngine::GetWasInit()
+Gfx::CDevice* Gfx::CEngine::GetDevice()
+{
+ return m_device;
+}
+
+void Gfx::CEngine::SetTerrain(Gfx::CTerrain* terrain)
{
- return m_wasInit;
+ m_terrain = terrain;
}
-std::string Gfx::CEngine::GetError()
+Gfx::CText* Gfx::CEngine::GetText()
{
- return m_error;
+ return m_text;
}
bool Gfx::CEngine::Create()
{
- m_wasInit = true;
+ m_size = m_lastSize = m_app->GetVideoConfig().size;
- /*m_lightMan = new Gfx::CLight(m_iMan, this);
+ m_lightMan = new Gfx::CLightManager(m_iMan, this);
m_text = new Gfx::CText(m_iMan, this);
m_particle = new Gfx::CParticle(m_iMan, this);
m_water = new Gfx::CWater(m_iMan, this);
m_cloud = new Gfx::CCloud(m_iMan, this);
m_lightning = new Gfx::CLightning(m_iMan, this);
- m_planet = new Gfx::CPlanet(m_iMan, this);*/
+ m_planet = new Gfx::CPlanet(m_iMan, this);
+
+ m_text->SetDevice(m_device);
+ if (! m_text->Create())
+ {
+ std::string error = m_text->GetError();
+ GetLogger()->Error("Error creating CText: %s\n", error.c_str());
+ return false;
+ }
+
+ m_device->SetClearColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f));
+ m_device->SetShadeModel(Gfx::SHADE_SMOOTH);
+ m_device->SetFillMode(Gfx::FILL_FILL);
+
+ SetFocus(m_focus);
m_matWorldInterface.LoadIdentity();
m_matViewInterface.LoadIdentity();
+
Math::LoadOrthoProjectionMatrix(m_matProjInterface, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
+ Gfx::TextureCreateParams params;
+ params.format = Gfx::TEX_IMG_RGB;
+ params.minFilter = Gfx::TEX_MIN_FILTER_NEAREST;
+ params.magFilter = Gfx::TEX_MAG_FILTER_NEAREST;
+ params.mipmap = false;
+ m_miceTexture = CreateTexture("mouse.png", params);
+
return true;
}
void Gfx::CEngine::Destroy()
{
- // TODO
+ m_text->Destroy();
- /*delete m_lightMan;
- m_lightMan = NULL;
+ delete m_lightMan;
+ m_lightMan = nullptr;
delete m_text;
- m_text = NULL;
+ m_text = nullptr;
delete m_particle;
- m_particle = NULL;
+ m_particle = nullptr;
delete m_water;
- m_water = NULL;
+ m_water = nullptr;
delete m_cloud;
- m_cloud = NULL;
+ m_cloud = nullptr;
delete m_lightning;
- m_lightning = NULL;
+ m_lightning = nullptr;
delete m_planet;
- m_planet = NULL;*/
+ m_planet = nullptr;
+}
- m_wasInit = false;
+void Gfx::CEngine::ResetAfterDeviceChanged()
+{
+ // TODO reload textures, reset device state, etc.
}
-void Gfx::CEngine::SetDevice(Gfx::CDevice *device)
+bool Gfx::CEngine::ProcessEvent(const Event &event)
{
- m_device = device;
+ if (event.type == EVENT_KEY_DOWN)
+ {
+ // !! Debug, to be removed later !!
+
+ if (event.key.key == KEY(F1))
+ {
+ m_mouseVisible = !m_mouseVisible;
+ m_app->SetSystemMouseVisible(! m_app->GetSystemMouseVisibile());
+ }
+ else if (event.key.key == KEY(F2))
+ {
+ int index = static_cast<int>(m_mouseType);
+ m_mouseType = static_cast<Gfx::EngineMouseType>( (index + 1) % Gfx::ENG_MOUSE_COUNT );
+ }
+ else if (event.key.key == KEY(F3))
+ {
+ m_backgroundQuarter = !m_backgroundQuarter;
+ if (m_backgroundQuarter)
+ {
+ m_backgroundFull = true;
+ m_backgroundName = "geneda.png";
+ }
+ else
+ {
+ m_backgroundFull = false;
+ m_backgroundName = "";
+ }
+ }
+ else if (event.key.key == KEY(F4))
+ {
+ m_backForce = !m_backForce;
+ if (m_backForce)
+ {
+ m_backgroundColorDown = Gfx::Color(0.2f, 0.2f, 0.2f);
+ m_backgroundColorUp = Gfx::Color(0.8f, 0.8f, 0.8f);
+ }
+ else
+ {
+ m_backgroundColorDown = m_backgroundColorUp = Gfx::Color(0.0f, 0.0f, 0.0f);
+ }
+ }
+ }
+ else if (event.type == EVENT_FRAME)
+ {
+ m_highlightTime += event.rTime;
+ }
+
+ // By default, pass on all events
+ return true;
}
-Gfx::CDevice* Gfx::CEngine::GetDevice()
+void Gfx::CEngine::FrameMove(float rTime)
{
- return m_device;
+ m_lightMan->UpdateProgression(rTime);
+ m_particle->FrameParticle(rTime);
+ ComputeDistance();
+ UpdateGeometry();
+
+ if (m_groundMark.draw)
+ {
+ if (m_groundMark.phase == Gfx::ENG_GR_MARK_PHASE_INC) // growing?
+ {
+ m_groundMark.intensity += rTime*(1.0f/m_groundMark.delay[0]);
+ if (m_groundMark.intensity >= 1.0f)
+ {
+ m_groundMark.intensity = 1.0f;
+ m_groundMark.fix = 0.0f;
+ m_groundMark.phase = Gfx::ENG_GR_MARK_PHASE_FIX;
+ }
+ }
+ else if (m_groundMark.phase == Gfx::ENG_GR_MARK_PHASE_FIX) // fixed?
+ {
+ m_groundMark.fix += rTime*(1.0f/m_groundMark.delay[1]);
+ if (m_groundMark.fix >= 1.0f)
+ m_groundMark.phase = Gfx::ENG_GR_MARK_PHASE_DEC;
+ }
+ else if (m_groundMark.phase == Gfx::ENG_GR_MARK_PHASE_DEC) // decay?
+ {
+ m_groundMark.intensity -= rTime*(1.0f/m_groundMark.delay[2]);
+ if (m_groundMark.intensity < 0.0f)
+ {
+ m_groundMark.intensity = 0.0f;
+ m_groundMark.phase = Gfx::ENG_GR_MARK_PHASE_NULL;
+ m_groundMark.draw = false;
+ }
+ }
+ }
+
+ if (m_sound == nullptr)
+ m_sound = static_cast<CSoundInterface*>( m_iMan->SearchInstance(CLASS_SOUND) );
+
+ m_sound->FrameMove(rTime);
}
-bool Gfx::CEngine::AfterDeviceSetInit()
+void Gfx::CEngine::StepSimulation(float rTime)
{
- m_device->SetClearColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f));
+ m_app->StepSimulation(rTime);
+}
- m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, false);
+bool Gfx::CEngine::WriteScreenShot(const std::string& fileName, int width, int height)
+{
+ // TODO!
+ return true;
+}
- Gfx::TextureCreateParams params;
- params.format = Gfx::TEX_IMG_RGB;
- params.minFilter = Gfx::TEX_MIN_FILTER_NEAREST;
- params.magFilter = Gfx::TEX_MAG_FILTER_NEAREST;
- params.mipmap = false;
- m_miceTexture = CreateTexture("mouse.png", params);
+bool Gfx::CEngine::ReadSettings()
+{
+ // TODO!
+ return true;
+}
+bool Gfx::CEngine::WriteSettings()
+{
+ // TODO!
return true;
}
-void Gfx::CEngine::ResetAfterDeviceChanged()
+void Gfx::CEngine::SetPause(bool pause)
{
- // TODO
+ m_pause = pause;
}
+bool Gfx::CEngine::GetPause()
+{
+ return m_pause;
+}
-Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName, const Gfx::TextureCreateParams &params)
+void Gfx::CEngine::SetMovieLock(bool lock)
{
- CImage img;
- if (! img.Load(m_app->GetDataFilePath(m_texPath, texName)))
+ m_movieLock = lock;
+}
+
+bool Gfx::CEngine::GetMovieLock()
+{
+ return m_movieLock;
+}
+
+void Gfx::CEngine::SetShowStats(bool show)
+{
+ m_showStats = show;
+}
+
+bool Gfx::CEngine::GetShowStats()
+{
+ return m_showStats;
+}
+
+void Gfx::CEngine::SetRenderEnable(bool enable)
+{
+ m_render = enable;
+}
+
+Math::IntPoint Gfx::CEngine::GetWindowSize()
+{
+ return m_size;
+}
+
+Math::IntPoint Gfx::CEngine::GetLastWindowSize()
+{
+ return m_lastSize;
+}
+
+Math::Point Gfx::CEngine::WindowToInterfaceCoords(Math::IntPoint pos)
+{
+ return Math::Point( static_cast<float>(pos.x) / static_cast<float>(m_size.x),
+ 1.0f - static_cast<float>(pos.y) / static_cast<float>(m_size.y) );
+}
+
+Math::IntPoint Gfx::CEngine::InterfaceToWindowCoords(Math::Point pos)
+{
+ return Math::IntPoint(static_cast<int>(pos.x * m_size.x),
+ static_cast<int>((1.0f - pos.y) * m_size.y));
+}
+
+Math::Point Gfx::CEngine::WindowToInterfaceSize(Math::IntPoint size)
+{
+ return Math::Point(static_cast<float>(size.x) / static_cast<float>(m_size.x),
+ static_cast<float>(size.y) / static_cast<float>(m_size.y));
+}
+
+Math::IntPoint Gfx::CEngine::InterfaceToWindowSize(Math::Point size)
+{
+ return Math::IntPoint(static_cast<int>(size.x * m_size.x),
+ static_cast<int>(size.y * m_size.y));
+}
+
+std::string Gfx::CEngine::GetTextureDir()
+{
+ return m_texPath;
+}
+
+void Gfx::CEngine::AddStatisticTriangle(int count)
+{
+ m_statisticTriangle += count;
+}
+
+int Gfx::CEngine::GetStatisticTriangle()
+{
+ return m_statisticTriangle;
+}
+
+
+
+/*******************************************************
+ Object management
+ *******************************************************/
+
+
+
+int Gfx::CEngine::CreateObject()
+{
+ // TODO!
+ return 0;
+}
+
+void Gfx::CEngine::FlushObject()
+{
+ // TODO!
+}
+
+bool Gfx::CEngine::DeleteObject(int objRank)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::SetDrawWorld(int objRank, bool draw)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::SetDrawFront(int objRank, bool draw)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::AddTriangle(int objRank, Gfx::VertexTex2* vertex, int nb,
+ const Gfx::Material& mat, int state,
+ std::string texName1, std::string texName2,
+ float min, float max, bool globalUpdate)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::AddSurface(int objRank, Gfx::VertexTex2* vertex, int nb,
+ const Gfx::Material& mat, int state,
+ std::string texName1, std::string texName2,
+ float min, float max, bool globalUpdate)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::AddQuick(int objRank, const Gfx::EngineObjLevel5& buffer,
+ std::string texName1, std::string texName2,
+ float min, float max, bool globalUpdate)
+{
+ // TODO!
+ return true;
+}
+
+Gfx::EngineObjLevel5* Gfx::CEngine::SearchTriangle(int objRank, const Gfx::Material& mat,
+ int state, std::string texName1,
+ std::string texName2, float min, float max)
+{
+ // TODO!
+ return nullptr;
+}
+
+void Gfx::CEngine::ChangeLOD()
+{
+ // TODO!
+}
+
+bool Gfx::CEngine::ChangeSecondTexture(int objRank, const std::string& texName2)
+{
+ // TODO!
+ return true;
+}
+
+int Gfx::CEngine::GetTotalTriangles(int objRank)
+{
+ // TODO!
+ return 0;
+}
+
+int Gfx::CEngine::GetTriangles(int objRank, float min, float max, Gfx::EngineTriangle* buffer, int size, float percent)
+{
+ // TODO!
+ return 0;
+}
+
+bool Gfx::CEngine::GetBBox(int objRank, Math::Vector& min, Math::Vector& max)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::ChangeTextureMapping(int objRank, const Gfx::Material& mat, int state,
+ const std::string& texName1, const std::string& texName2,
+ float min, float max, Gfx::EngineTextureMapping mode,
+ float au, float bu, float av, float bv)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::TrackTextureMapping(int objRank, const Gfx::Material& mat, int state,
+ const std::string& texName1, const std::string& texName2,
+ float min, float max, Gfx::EngineTextureMapping mode,
+ float pos, float factor, float tl, float ts, float tt)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectTransform(int objRank, const Math::Matrix& transform)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::GetObjectTransform(int objRank, Math::Matrix& transform)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectType(int objRank, Gfx::EngineObjectType type)
+{
+ // TODO!
+ return true;
+}
+
+Gfx::EngineObjectType Gfx::CEngine::GetObjectType(int objRank)
+{
+ // TODO!
+ return Gfx::ENG_OBJTYPE_FIX;
+}
+
+bool Gfx::CEngine::SetObjectTransparency(int objRank, float value)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::ShadowCreate(int objRank)
+{
+ // TODO!
+ return true;
+}
+
+void Gfx::CEngine::ShadowDelete(int objRank)
+{
+ // TODO!
+}
+
+bool Gfx::CEngine::SetObjectShadowHide(int objRank, bool hide)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectShadowType(int objRank, Gfx::EngineShadowType type)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectShadowPos(int objRank, const Math::Vector& pos)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectShadowNormal(int objRank, const Math::Vector& n)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectShadowAngle(int objRank, float angle)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectShadowRadius(int objRank, float radius)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectShadowIntensity(int objRank, float intensity)
+{
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectShadowHeight(int objRank, float h)
+{
+ // TODO!
+ return true;
+}
+
+float Gfx::CEngine::GetObjectShadowRadius(int objRank)
+{
+ // TODO!
+ return 0.0f;
+}
+
+bool Gfx::CEngine::GetHighlight(Math::Point &p1, Math::Point &p2)
+{
+ p1 = m_highlightP1;
+ p2 = m_highlightP2;
+ return m_highlight;
+}
+
+void Gfx::CEngine::SetHighlightRank(int *rankList)
+{
+ int i = 0;
+ while ( *rankList != -1 )
{
- std::stringstream str;
- str << "Couldn't load texture '" << texName << "': " << img.GetError();
- m_error = str.str();
- return Gfx::Texture(); // invalid texture
+ m_highlightRank[i++] = *rankList++;
}
+ m_highlightRank[i] = -1; // terminator
+}
- Gfx::Texture result = m_device->CreateTexture(&img, params);
+bool Gfx::CEngine::GetBBox2D(int objRank, Math::Point &min, Math::Point &max)
+{
+ min.x = 1000000.0f;
+ min.y = 1000000.0f;
+ max.x = -1000000.0f;
+ max.y = -1000000.0f;
- if (! result.valid)
+ for (int i = 0; i < 8; i++)
{
- std::stringstream str;
- str << "Couldn't load texture '" << texName << "': " << m_device->GetError();
- m_error = str.str();
- return result;
+ Math::Vector p;
+
+ if ( i & (1<<0) ) p.x = m_objects[objRank].bboxMin.x;
+ else p.x = m_objects[objRank].bboxMax.x;
+ if ( i & (1<<1) ) p.y = m_objects[objRank].bboxMin.y;
+ else p.y = m_objects[objRank].bboxMax.y;
+ if ( i & (1<<2) ) p.z = m_objects[objRank].bboxMin.z;
+ else p.z = m_objects[objRank].bboxMax.z;
+
+ Math::Vector pp;
+ if (TransformPoint(pp, objRank, p))
+ {
+ if (pp.x < min.x) min.x = pp.x;
+ if (pp.x > max.x) max.x = pp.x;
+ if (pp.y < min.y) min.y = pp.y;
+ if (pp.y > max.y) max.y = pp.y;
+ }
}
- m_texNameMap[texName] = result;
- m_revTexNameMap[result] = texName;
+ if ( min.x == 1000000.0f ||
+ min.y == 1000000.0f ||
+ max.x == -1000000.0f ||
+ max.y == -1000000.0f ) return false;
- return result;
+ return true;
}
-Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName)
+void Gfx::CEngine::GroundSpotFlush()
{
- return CreateTexture(texName, m_defaultTexParams);
+ // TODO
}
-void Gfx::CEngine::DestroyTexture(const std::string &texName)
+int Gfx::CEngine::GroundSpotCreate()
{
- std::map<std::string, Gfx::Texture>::iterator it = m_texNameMap.find(texName);
- if (it == m_texNameMap.end())
- return;
+ // TODO!
+ return 0;
+}
- std::map<Gfx::Texture, std::string>::iterator revIt = m_revTexNameMap.find((*it).second);
+void Gfx::CEngine::GroundSpotDelete(int rank)
+{
+ // TODO!
+}
- m_device->DestroyTexture((*it).second);
+bool Gfx::CEngine::SetObjectGroundSpotPos(int rank, const Math::Vector& pos)
+{
+ // TODO!
+ return true;
+}
- m_revTexNameMap.erase(revIt);
- m_texNameMap.erase(it);
+bool Gfx::CEngine::SetObjectGroundSpotRadius(int rank, float radius)
+{
+ // TODO!
+ return true;
}
-void Gfx::CEngine::SetTexture(const std::string &name, int stage)
+bool Gfx::CEngine::SetObjectGroundSpotColor(int rank, const Gfx::Color& color)
{
- std::map<std::string, Gfx::Texture>::iterator it = m_texNameMap.find(name);
- if (it != m_texNameMap.end())
- m_device->SetTexture(stage, (*it).second);
+ // TODO!
+ return true;
+}
- // TODO if not present...
+bool Gfx::CEngine::SetObjectGroundSpotMinMax(int rank, float min, float max)
+{
+ // TODO!
+ return true;
}
-void Gfx::CEngine::SetMaterial(const Gfx::Material &mat)
+bool Gfx::CEngine::SetObjectGroundSpotSmooth(int rank, float smooth)
{
- m_device->SetMaterial(mat);
+ // TODO!
+ return true;
+}
+
+int Gfx::CEngine::GroundMarkCreate(Math::Vector pos, float radius,
+ float delay1, float delay2, float delay3,
+ int dx, int dy, char* table)
+{
+ // TODO!
+ return 0;
+}
+
+bool Gfx::CEngine::GroundMarkDelete(int rank)
+{
+ // TODO!
+ return true;
+}
+
+void Gfx::CEngine::ComputeDistance()
+{
+ // TODO!
+}
+
+void Gfx::CEngine::UpdateGeometry()
+{
+ // TODO!
+}
+
+void Gfx::CEngine::Update()
+{
+ ComputeDistance();
+ UpdateGeometry();
+}
+
+bool Gfx::CEngine::DetectBBox(int objRank, Math::Point mouse)
+{
+ // TODO!
+ return true;
+}
+
+int Gfx::CEngine::DetectObject(Math::Point mouse)
+{
+ // TODO!
+ return 0;
+}
+
+bool Gfx::CEngine::DetectTriangle(Math::Point mouse, Gfx::VertexTex2* triangle, int objRank, float& dist)
+{
+ // TODO!
+ return true;
}
-void Gfx::CEngine::SetState(int state, Gfx::Color color)
+bool Gfx::CEngine::IsVisible(int objRank)
{
- if ( state == m_lastState && color == m_lastColor )
+ // TODO!
+ return true;
+}
+
+bool Gfx::CEngine::TransformPoint(Math::Vector& p2D, int objRank, Math::Vector p3D)
+{
+ p3D = Math::Transform(m_objects[objRank].transform, p3D);
+ p3D = Math::Transform(m_matView, p3D);
+
+ if (p3D.z < 2.0f) return false; // behind?
+
+ p2D.x = (p3D.x/p3D.z)*m_matProj.Get(1,1);
+ p2D.y = (p3D.y/p3D.z)*m_matProj.Get(2,2);
+ p2D.z = p3D.z;
+
+ p2D.x = (p2D.x+1.0f)/2.0f; // [-1..1] -> [0..1]
+ p2D.y = (p2D.y+1.0f)/2.0f;
+
+ return true;
+}
+
+
+
+/*******************************************************
+ Mode setting
+ *******************************************************/
+
+
+
+void Gfx::CEngine::SetState(int state, const Gfx::Color& color)
+{
+ if (state == m_lastState && color == m_lastColor)
return;
m_lastState = state;
m_lastColor = color;
- if ( m_alphaMode != 1 && (state & Gfx::ENG_RSTATE_ALPHA) )
+ if (m_alphaMode != 1 && (state & Gfx::ENG_RSTATE_ALPHA))
{
state &= ~Gfx::ENG_RSTATE_ALPHA;
@@ -351,120 +893,168 @@ void Gfx::CEngine::SetState(int state, Gfx::Color color)
state |= Gfx::ENG_RSTATE_TTEXTURE_BLACK;
}
- // TODO other modes & thorough testing
- if (state & Gfx::ENG_RSTATE_TTEXTURE_BLACK) // The transparent black texture?
+ if (state & Gfx::ENG_RSTATE_TTEXTURE_BLACK) // transparent black texture?
{
m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
- m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
- m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
m_device->SetBlendFunc(Gfx::BLEND_ONE, Gfx::BLEND_INV_SRC_COLOR);
- m_device->SetTextureEnabled(0, true);
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+
m_device->SetTextureFactor(color);
Gfx::TextureStageParams params;
params.colorOperation = Gfx::TEX_MIX_OPER_MODULATE;
params.colorArg1 = Gfx::TEX_MIX_ARG_TEXTURE;
params.colorArg2 = Gfx::TEX_MIX_ARG_FACTOR;
- params.alphaOperation = Gfx::TEX_MIX_OPER_MODULATE;
+ params.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT; // TODO: replace with src color ?
+
+ m_device->SetTextureEnabled(0, true);
m_device->SetTextureStageParams(0, params);
}
- else if (state & Gfx::ENG_RSTATE_TTEXTURE_WHITE) // The transparent white texture?
+ else if (state & Gfx::ENG_RSTATE_TTEXTURE_WHITE) // transparent white texture?
{
m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
- m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
- m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
m_device->SetBlendFunc(Gfx::BLEND_DST_COLOR, Gfx::BLEND_ZERO);
- m_device->SetTextureEnabled(0, true);
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+
m_device->SetTextureFactor(color.Inverse());
Gfx::TextureStageParams params;
params.colorOperation = Gfx::TEX_MIX_OPER_ADD;
params.colorArg1 = Gfx::TEX_MIX_ARG_TEXTURE;
params.colorArg2 = Gfx::TEX_MIX_ARG_FACTOR;
- params.alphaOperation = Gfx::TEX_MIX_OPER_MODULATE;
+ params.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT; // TODO: replace with src color ?
+
+ m_device->SetTextureEnabled(0, true);
m_device->SetTextureStageParams(0, params);
}
- else if (state & Gfx::ENG_RSTATE_TCOLOR_BLACK) // The transparent black color?
+ else if (state & Gfx::ENG_RSTATE_TCOLOR_BLACK) // transparent black color?
{
- m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
- m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
- m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
- m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
m_device->SetBlendFunc(Gfx::BLEND_ONE, Gfx::BLEND_INV_SRC_COLOR);
-
- m_device->SetTextureFactor(color);
- m_device->SetTextureEnabled(0, true);
- m_device->SetTextureStageParams(0, Gfx::TextureStageParams());
}
- else if (state & Gfx::ENG_RSTATE_TCOLOR_WHITE) // The transparent white color?
+ else if (state & Gfx::ENG_RSTATE_TCOLOR_WHITE) // transparent white color?
{
- m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
- m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
- m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
- m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
m_device->SetBlendFunc(Gfx::BLEND_DST_COLOR, Gfx::BLEND_ZERO);
+ }
+ else if (state & Gfx::ENG_RSTATE_TDIFFUSE) // diffuse color as transparent?
+ {
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
+ m_device->SetBlendFunc(Gfx::BLEND_SRC_ALPHA, Gfx::BLEND_DST_ALPHA);
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+
+ Gfx::TextureStageParams params;
+ params.colorOperation = Gfx::TEX_MIX_OPER_REPLACE;
+ params.colorArg1 = Gfx::TEX_MIX_ARG_TEXTURE;
+ params.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT; // TODO: replace with src color ?
- m_device->SetTextureFactor(color.Inverse());
m_device->SetTextureEnabled(0, true);
- m_device->SetTextureStageParams(0, Gfx::TextureStageParams());
+ m_device->SetTextureStageParams(0, params);
}
- else if (state & Gfx::ENG_RSTATE_TDIFFUSE) // diffuse color as transparent?
+ else if (state & Gfx::ENG_RSTATE_OPAQUE_TEXTURE) // opaque texture ?
{
- /*m_device->SetRenderState(D3DRENDERSTATE_FOGENABLE, false);
- m_device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false);
- m_device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, true);
- m_device->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, false);
- m_device->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_diffuseSrcBlend[1]);
- m_device->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_diffuseDestBlend[1]);
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, false);
- m_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
- m_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
- m_device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);*/
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+ m_device->SetTextureEnabled(0, true);
+ m_device->SetTextureStageParams(0, Gfx::TextureStageParams()); // default operation
}
- else if (state & Gfx::ENG_RSTATE_ALPHA) // image with alpha channel?
+ else if (state & Gfx::ENG_RSTATE_OPAQUE_COLOR) // opaque color ?
{
- /*m_device->SetRenderState(D3DRENDERSTATE_FOGENABLE, true);
- m_device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, true);
- m_device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, false);
- m_device->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, true);
- m_device->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATER);
- m_device->SetRenderState(D3DRENDERSTATE_ALPHAREF, (DWORD)(128));
- m_device->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_alphaSrcBlend[1]);
- m_device->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_alphaSrcBlend[1]);
-
- m_device->SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR, color);
- m_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
- m_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
- m_device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
- m_device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
- m_device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);*/
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, false);
}
- else // normal ?
+ else if (state & Gfx::ENG_RSTATE_TEXT) // font rendering?
+ {
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
+ m_device->SetBlendFunc(Gfx::BLEND_SRC_ALPHA, Gfx::BLEND_INV_SRC_ALPHA);
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+
+ Gfx::TextureStageParams params;
+ params.colorOperation = Gfx::TEX_MIX_OPER_DEFAULT; // default modulate operation
+ params.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT; // default modulate operation
+
+ m_device->SetTextureEnabled(0, true);
+ m_device->SetTextureStageParams(0, params);
+ }
+ else if (state & Gfx::ENG_RSTATE_ALPHA) // image with alpha channel?
{
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, false);
+
m_device->SetRenderState(Gfx::RENDER_STATE_FOG, true);
m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, true);
- m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, false);
- m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, true);
+
+ m_device->SetAlphaTestFunc(Gfx::COMP_FUNC_GREATER, 0.5f);
+
m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+ m_device->SetTextureFactor(color);
+
+ Gfx::TextureStageParams params;
+ params.colorOperation = Gfx::TEX_MIX_OPER_MODULATE;
+ params.colorArg1 = Gfx::TEX_MIX_ARG_TEXTURE;
+ params.colorArg2 = Gfx::TEX_MIX_ARG_SRC_COLOR;
+ params.alphaOperation = Gfx::TEX_MIX_OPER_REPLACE;
+ params.alphaArg1 = Gfx::TEX_MIX_ARG_TEXTURE;
+
m_device->SetTextureEnabled(0, true);
- m_device->SetTextureStageParams(0, Gfx::TextureStageParams());
+ m_device->SetTextureStageParams(0, params);
+ }
+ else // normal ?
+ {
+ m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, false);
- /*m_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
- m_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
- m_device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
- m_device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);*/
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, true);
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+
+ Gfx::TextureStageParams params;
+ params.colorOperation = Gfx::TEX_MIX_OPER_DEFAULT; // default modulate
+ params.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT; // TODO: replace with src color ?
+
+ m_device->SetTextureEnabled(0, true);
+ m_device->SetTextureStageParams(0, params);
}
if (state & Gfx::ENG_RSTATE_FOG)
@@ -476,21 +1066,25 @@ void Gfx::CEngine::SetState(int state, Gfx::Color color)
if ( !m_groundSpotVisible && (state & Gfx::ENG_RSTATE_SECOND) != 0 ) second = false;
if ( !m_dirty && (state & Gfx::ENG_RSTATE_SECOND) == 0 ) second = false;
- if ( (state & ENG_RSTATE_DUAL_BLACK) && second )
+ if ((state & ENG_RSTATE_DUAL_BLACK) && second)
{
- /*m_device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
- m_device->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
- m_device->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
- m_device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
- m_device->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);*/
+ Gfx::TextureStageParams params;
+ params.colorOperation = Gfx::TEX_MIX_OPER_MODULATE;
+ params.colorArg1 = Gfx::TEX_MIX_ARG_TEXTURE;
+ params.colorArg2 = Gfx::TEX_MIX_ARG_COMPUTED_COLOR;
+ params.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT; // TODO: ???
+ m_device->SetTextureEnabled(0, true);
+ m_device->SetTextureStageParams(1, params);
}
- else if ( (state & ENG_RSTATE_DUAL_WHITE) && second )
+ else if ((state & ENG_RSTATE_DUAL_WHITE) && second)
{
- /*m_device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_ADD);
- m_device->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
- m_device->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
- m_device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
- m_device->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);*/
+ Gfx::TextureStageParams params;
+ params.colorOperation = Gfx::TEX_MIX_OPER_ADD;
+ params.colorArg1 = Gfx::TEX_MIX_ARG_TEXTURE;
+ params.colorArg2 = Gfx::TEX_MIX_ARG_COMPUTED_COLOR;
+ params.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT; // TODO: ???
+ m_device->SetTextureEnabled(0, true);
+ m_device->SetTextureStageParams(1, params);
}
else
{
@@ -499,18 +1093,25 @@ void Gfx::CEngine::SetState(int state, Gfx::Color color)
if (state & Gfx::ENG_RSTATE_WRAP)
{
- /*m_device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP);
- m_device->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_WRAP);*/
- }
- else if (state & Gfx::ENG_RSTATE_CLAMP)
- {
- /*m_device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
- m_device->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);*/
+ // TODO: separate function for setting wrap mode?
+
+ Gfx::TextureStageParams p1 = m_device->GetTextureStageParams(0);
+ p1.wrapS = p1.wrapT = Gfx::TEX_WRAP_REPEAT;
+ m_device->SetTextureStageParams(0, p1);
+
+ Gfx::TextureStageParams p2 = m_device->GetTextureStageParams(1);
+ p2.wrapS = p2.wrapT = Gfx::TEX_WRAP_REPEAT;
+ m_device->SetTextureStageParams(1, p2);
}
- else
+ else // if (state & Gfx::ENG_RSTATE_CLAMP) or otherwise
{
- /*m_device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
- m_device->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);*/
+ Gfx::TextureStageParams p1 = m_device->GetTextureStageParams(0);
+ p1.wrapS = p1.wrapT = Gfx::TEX_WRAP_CLAMP;
+ m_device->SetTextureStageParams(0, p1);
+
+ Gfx::TextureStageParams p2 = m_device->GetTextureStageParams(1);
+ p2.wrapS = p2.wrapT = Gfx::TEX_WRAP_CLAMP;
+ m_device->SetTextureStageParams(1, p2);
}
if (state & Gfx::ENG_RSTATE_2FACE)
@@ -529,90 +1130,1657 @@ void Gfx::CEngine::SetState(int state, Gfx::Color color)
m_device->SetGlobalAmbient(m_ambientColor[m_rankView]);
}
-bool Gfx::CEngine::ProcessEvent(const Event &event)
+void Gfx::CEngine::SetMaterial(const Gfx::Material &mat)
{
- if (event.type == EVENT_MOUSE_MOVE)
+ m_lastMaterial = mat;
+ m_device->SetMaterial(mat);
+}
+
+void Gfx::CEngine::SetViewParams(const Math::Vector& eyePt, const Math::Vector& lookatPt,
+ const Math::Vector& upVec, float eyeDistance)
+{
+ m_eyePt = eyePt;
+ m_lookatPt = lookatPt;
+ m_eyeDirH = Math::RotateAngle(eyePt.x - lookatPt.x, eyePt.z - lookatPt.z);
+ m_eyeDirV = Math::RotateAngle(Math::DistanceProjected(eyePt, lookatPt), eyePt.y - lookatPt.y);
+
+ Math::LoadViewMatrix(m_matView, eyePt, lookatPt, upVec);
+
+ if (m_sound == nullptr)
+ m_sound = static_cast<CSoundInterface*>( m_iMan->SearchInstance(CLASS_SOUND) );
+
+ m_sound->SetListener(eyePt, lookatPt);
+}
+
+Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName, const Gfx::TextureCreateParams &params)
+{
+ if (m_texBlacklist.find(texName) != m_texBlacklist.end())
+ return Gfx::Texture(); // invalid texture
+
+ // TODO: detect alpha channel?
+
+ CImage img;
+ if (! img.Load(m_app->GetDataFilePath(m_texPath, texName)))
{
- m_mousePos = event.mouseMove.pos;
+ std::string error = img.GetError();
+ GetLogger()->Error("Couldn't load texture '%s': %s\n", texName.c_str(), error.c_str());
+ GetLogger()->Error("Blacklisting texture '%s'\n", texName.c_str());
+ m_texBlacklist.insert(texName);
+ return Gfx::Texture(); // invalid texture
}
- else if (event.type == EVENT_KEY_DOWN)
+
+ Gfx::Texture result = m_device->CreateTexture(&img, params);
+
+ if (! result.valid)
{
- // !! Debug, to be removed later !!
+ std::string error = m_device->GetError();
+ GetLogger()->Error("Couldn't load texture '%s': %s\n", texName.c_str(), error.c_str());
+ GetLogger()->Error("Blacklisting texture '%s'\n", texName.c_str());
+ m_texBlacklist.insert(texName);
+ return result;
+ }
- if (event.key.key == KEY(F1))
+ m_texNameMap[texName] = result;
+ m_revTexNameMap[result] = texName;
+
+ return result;
+}
+
+Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName)
+{
+ return CreateTexture(texName, m_defaultTexParams);
+}
+
+void Gfx::CEngine::DestroyTexture(const std::string &texName)
+{
+ std::map<std::string, Gfx::Texture>::iterator it = m_texNameMap.find(texName);
+ if (it == m_texNameMap.end())
+ return;
+
+ std::map<Gfx::Texture, std::string>::iterator revIt = m_revTexNameMap.find((*it).second);
+
+ m_device->DestroyTexture((*it).second);
+
+ m_revTexNameMap.erase(revIt);
+ m_texNameMap.erase(it);
+}
+
+bool Gfx::CEngine::LoadTexture(const std::string& name)
+{
+ if (m_texBlacklist.find(name) != m_texBlacklist.end())
+ return false;
+
+ std::map<std::string, Gfx::Texture>::iterator it = m_texNameMap.find(name);
+ if (it != m_texNameMap.end())
+ return true;
+
+ Gfx::Texture tex = CreateTexture(name);
+ return tex.valid;
+}
+
+// TODO: create separate variables for 4 quarter names
+void QuarterName(std::string& buffer, const std::string& name, int quarter)
+{
+ size_t pos = name.find('.');
+ if (pos == std::string::npos)
+ {
+ buffer = name;
+ return;
+ }
+
+ buffer = name.substr(0, pos) + std::string(1, static_cast<char>('a' + quarter)) + name.substr(pos);
+}
+
+bool Gfx::CEngine::LoadAllTextures()
+{
+ LoadTexture("text.png");
+ LoadTexture("mouse.png");
+ LoadTexture("button1.png");
+ LoadTexture("button2.png");
+ LoadTexture("button3.png");
+ LoadTexture("effect00.png");
+ LoadTexture("effect01.png");
+ LoadTexture("effect02.png");
+ LoadTexture("map.png");
+
+ if (! m_backgroundName.empty())
+ {
+ if (m_backgroundQuarter) // image into 4 pieces?
{
- m_mouseVisible = !m_mouseVisible;
- m_app->SetSystemMouseVisible(! m_app->GetSystemMouseVisibile());
+ for (int i = 0; i < 4; i++)
+ {
+ std::string name;
+ QuarterName(name, m_backgroundName, i);
+ LoadTexture(name);
+ }
}
- else if (event.key.key == KEY(F2))
+ else
{
- int index = static_cast<int>(m_mouseType);
- m_mouseType = static_cast<Gfx::EngineMouseType>( (index + 1) % Gfx::ENG_MOUSE_COUNT );
+ LoadTexture(m_backgroundName);
}
}
- // By default, pass on all events
- return true;
+ if (! m_foregroundName.empty())
+ LoadTexture(m_foregroundName);
+
+ m_planet->LoadTexture();
+
+ bool ok = true;
+
+ /* TODO
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ int l1;
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+
+ if ( p2 == 0 || p2->texName1[0] != 0 )
+ {
+ if ( !LoadTexture(p2->texName1) ) ok = false;
+ }
+
+ if ( p2 == 0 || p2->texName2[0] != 0 )
+ {
+ if ( !LoadTexture(p2->texName2) ) ok = false;
+ }
+ }*/
+
+ return ok;
}
-bool Gfx::CEngine::Render()
+bool Gfx::CEngine::SetTexture(const std::string& name, int stage)
{
- m_statisticTriangle = 0;
+ auto it = m_texNameMap.find(name);
+ if (it != m_texNameMap.end())
+ {
+ m_device->SetTexture(stage, (*it).second);
+ return true;
+ }
+
+ if (! LoadTexture(name))
+ {
+ m_device->SetTexture(stage, 0); // invalid texture
+ return false;
+ }
+
+ it = m_texNameMap.find(name);
+ if (it != m_texNameMap.end())
+ {
+ m_device->SetTexture(stage, (*it).second);
+ return true;
+ }
+
+ m_device->SetTexture(stage, 0); // invalid texture
+ return false; // should not happen normally
+}
+
+void Gfx::CEngine::SetLimitLOD(int rank, float limit)
+{
+ m_limitLOD[rank] = limit;
+}
+float Gfx::CEngine::GetLimitLOD(int rank, bool last)
+{
+ float limit = 0.0f;
+
+ if (last)
+ {
+ limit = m_limitLOD[rank];
+ limit *= m_lastSize.x/640.0f; // limit further if large window!
+ limit += m_limitLOD[0]*(m_lastObjectDetail*2.0f);
+ }
+ else
+ {
+ limit = m_limitLOD[rank];
+ limit *= m_size.x/640.0f; // limit further if large window!
+ limit += m_limitLOD[0]*(m_objectDetail*2.0f);
+ }
+
+ if (limit < 0.0f) limit = 0.0f;
+
+ return limit;
+}
+
+void Gfx::CEngine::SetTerrainVision(float vision)
+{
+ m_terrainVision = vision;
+}
+
+void Gfx::CEngine::SetFocus(float focus)
+{
+ m_focus = focus;
+ m_size = m_app->GetVideoConfig().size;
+
+ float aspect = (static_cast<float>(m_size.y)) / m_size.x;
+ Math::LoadProjectionMatrix(m_matProj, m_focus, aspect, 0.5f, m_deepView[0]);
+}
+
+float Gfx::CEngine::GetFocus()
+{
+ return m_focus;
+}
+
+void Gfx::CEngine::SetGroundSpot(bool mode)
+{
+ m_groundSpotVisible = mode;
+}
+
+bool Gfx::CEngine::GetGroundSpot()
+{
+ return m_groundSpotVisible;
+}
+
+void Gfx::CEngine::SetShadow(bool mode)
+{
+ m_shadowVisible = mode;
+}
+
+bool Gfx::CEngine::GetShadow()
+{
+ return m_shadowVisible;
+}
+
+void Gfx::CEngine::SetDirty(bool mode)
+{
+ m_dirty = mode;
+}
+
+bool Gfx::CEngine::GetDirty()
+{
+ return m_dirty;
+}
+
+void Gfx::CEngine::SetFog(bool mode)
+{
+ m_fog = mode;
+}
+
+bool Gfx::CEngine::GetFog()
+{
+ return m_fog;
+}
+
+bool Gfx::CEngine::GetStateColor()
+{
+ return m_stateColor;
+}
+
+void Gfx::CEngine::SetSecondTexture(int texNum)
+{
+ m_secondTexNum = texNum;
+}
+
+int Gfx::CEngine::GetSecondTexture()
+{
+ return m_secondTexNum;
+}
+
+void Gfx::CEngine::SetRankView(int rank)
+{
+ if (rank < 0) rank = 0;
+ if (rank > 1) rank = 1;
+
+ if (m_rankView == 0 && rank == 1) // enters the water?
+ m_lightMan->AdaptLightColor(m_waterAddColor, +1.0f);
+
+ if (m_rankView == 1 && rank == 0) // out of the water?
+ m_lightMan->AdaptLightColor(m_waterAddColor, -1.0f);
+
+ m_rankView = rank;
+}
+
+int Gfx::CEngine::GetRankView()
+{
+ return m_rankView;
+}
+
+void Gfx::CEngine::SetDrawWorld(bool draw)
+{
+ m_drawWorld = draw;
+}
+
+void Gfx::CEngine::SetDrawFront(bool draw)
+{
+ m_drawFront = draw;
+}
+
+void Gfx::CEngine::SetAmbientColor(const Gfx::Color& color, int rank)
+{
+ m_ambientColor[rank] = color;
+}
+
+Gfx::Color Gfx::CEngine::GetAmbientColor(int rank)
+{
+ return m_ambientColor[rank];
+}
+
+void Gfx::CEngine::SetWaterAddColor(const Gfx::Color& color)
+{
+ m_waterAddColor = color;
+}
+
+Gfx::Color Gfx::CEngine::GetWaterAddColor()
+{
+ return m_waterAddColor;
+}
+
+void Gfx::CEngine::SetFogColor(const Gfx::Color& color, int rank)
+{
+ m_fogColor[rank] = color;
+}
+
+Gfx::Color Gfx::CEngine::GetFogColor(int rank)
+{
+ return m_fogColor[rank];
+}
+
+void Gfx::CEngine::SetDeepView(float length, int rank, bool ref)
+{
+ if (ref)
+ length *= m_clippingDistance;
+
+ m_deepView[rank] = length;
+}
+
+float Gfx::CEngine::GetDeepView(int rank)
+{
+ return m_deepView[rank];
+}
+
+void Gfx::CEngine::SetFogStart(float start, int rank)
+{
+ m_fogStart[rank] = start;
+}
+
+float Gfx::CEngine::GetFogStart(int rank)
+{
+ return m_fogStart[rank];
+}
+
+void Gfx::CEngine::SetBackground(const std::string& name, Gfx::Color up, Gfx::Color down,
+ Gfx::Color cloudUp, Gfx::Color cloudDown,
+ bool full, bool quarter)
+{
+ m_backgroundName = name;
+ m_backgroundColorUp = up;
+ m_backgroundColorDown = down;
+ m_backgroundCloudUp = cloudUp;
+ m_backgroundCloudDown = cloudDown;
+ m_backgroundFull = full;
+ m_backgroundQuarter = quarter;
+}
+
+void Gfx::CEngine::GetBackground(std::string& name, Gfx::Color& up, Gfx::Color& down,
+ Gfx::Color& cloudUp, Gfx::Color& cloudDown,
+ bool &full, bool &quarter)
+{
+ name = m_backgroundName;
+ up = m_backgroundColorUp;
+ down = m_backgroundColorDown;
+ cloudUp = m_backgroundCloudUp;
+ cloudDown = m_backgroundCloudDown;
+ full = m_backgroundFull;
+ quarter = m_backgroundQuarter;
+}
+
+void Gfx::CEngine::SetForegroundName(const std::string& name)
+{
+ if (! m_foregroundName.empty())
+ DestroyTexture(m_foregroundName);
+
+ m_foregroundName = name;
+}
+
+void Gfx::CEngine::SetOverFront(bool front)
+{
+ m_overFront = front;
+}
+
+void Gfx::CEngine::SetOverColor(const Gfx::Color& color, int mode)
+{
+ m_overColor = color;
+ m_overMode = mode;
+}
+
+void Gfx::CEngine::SetParticleDensity(float value)
+{
+ if (value < 0.0f) value = 0.0f;
+ if (value > 2.0f) value = 2.0f;
+ m_particleDensity = value;
+}
+
+float Gfx::CEngine::GetParticleDensity()
+{
+ return m_particleDensity;
+}
+
+float Gfx::CEngine::ParticleAdapt(float factor)
+{
+ if (m_particleDensity == 0.0f)
+ return 1000000.0f;
+
+ return factor / m_particleDensity;
+}
+
+void Gfx::CEngine::SetClippingDistance(float value)
+{
+ if (value < 0.5f) value = 0.5f;
+ if (value > 2.0f) value = 2.0f;
+ m_clippingDistance = value;
+}
+
+float Gfx::CEngine::GetClippingDistance()
+{
+ return m_clippingDistance;
+}
+
+void Gfx::CEngine::SetObjectDetail(float value)
+{
+ if ( value < 0.0f ) value = 0.0f;
+ if ( value > 2.0f ) value = 2.0f;
+ m_objectDetail = value;
+}
+
+float Gfx::CEngine::GetObjectDetail()
+{
+ return m_objectDetail;
+}
+
+void Gfx::CEngine::SetGadgetQuantity(float value)
+{
+ if (value < 0.0f) value = 0.0f;
+ if (value > 1.0f) value = 1.0f;
+
+ m_gadgetQuantity = value;
+}
+
+float Gfx::CEngine::GetGadgetQuantity()
+{
+ return m_gadgetQuantity;
+}
+
+void Gfx::CEngine::SetTextureQuality(int value)
+{
+ if (value < 0) value = 0;
+ if (value > 2) value = 2;
+
+ if (value != m_textureQuality)
+ {
+ m_textureQuality = value;
+ LoadAllTextures();
+ }
+}
+
+int Gfx::CEngine::GetTextureQuality()
+{
+ return m_textureQuality;
+}
+
+void Gfx::CEngine::SetTotoMode(bool present)
+{
+ m_totoMode = present;
+}
+
+bool Gfx::CEngine::GetTotoMode()
+{
+ return m_totoMode;
+}
+
+void Gfx::CEngine::SetLensMode(bool present)
+{
+ m_lensMode = present;
+}
+
+bool Gfx::CEngine::GetLensMode()
+{
+ return m_lensMode;
+}
+
+void Gfx::CEngine::SetWaterMode(bool present)
+{
+ m_waterMode = present;
+}
+
+bool Gfx::CEngine::GetWaterMode()
+{
+ return m_waterMode;
+}
+
+void Gfx::CEngine::SetLightingMode(bool present)
+{
+ m_lightMode = present;
+}
+
+bool Gfx::CEngine::GetLightingMode()
+{
+ return m_lightMode;
+}
+
+void Gfx::CEngine::SetSkyMode(bool present)
+{
+ m_skyMode = present;
+}
+
+bool Gfx::CEngine::GetSkyMode()
+{
+ return m_skyMode;
+}
+
+void Gfx::CEngine::SetBackForce(bool present)
+{
+ m_backForce = present;
+}
+
+bool Gfx::CEngine::GetBackForce()
+{
+ return m_backForce;
+}
+
+void Gfx::CEngine::SetPlanetMode(bool present)
+{
+ m_planetMode = present;
+}
+
+bool Gfx::CEngine::GetPlanetMode()
+{
+ return m_planetMode;
+}
+
+void Gfx::CEngine::SetLightMode(bool present)
+{
+ m_lightMode = present;
+}
+
+bool Gfx::CEngine::GetLightMode()
+{
+ return m_lightMode;
+}
+
+void Gfx::CEngine::SetEditIndentMode(bool autoIndent)
+{
+ m_editIndentMode = autoIndent;
+}
+
+bool Gfx::CEngine::GetEditIndentMode()
+{
+ return m_editIndentMode;
+}
+
+void Gfx::CEngine::SetEditIndentValue(int value)
+{
+ m_editIndentValue = value;
+}
+
+int Gfx::CEngine::GetEditIndentValue()
+{
+ return m_editIndentValue;
+}
+
+void Gfx::CEngine::SetSpeed(float speed)
+{
+ m_speed = speed;
+}
+
+float Gfx::CEngine::GetSpeed()
+{
+ return m_speed;
+}
+
+void Gfx::CEngine::SetTracePrecision(float factor)
+{
+ m_tracePrecision = factor;
+}
+
+float Gfx::CEngine::GetTracePrecision()
+{
+ return m_tracePrecision;
+}
+
+void Gfx::CEngine::SetMouseVisible(bool visible)
+{
+ m_mouseVisible = visible;
+}
+
+bool Gfx::CEngine::GetMouseVisible()
+{
+ return m_mouseVisible;
+}
+
+void Gfx::CEngine::SetMousePos(Math::Point pos)
+{
+ m_mousePos = pos;
+}
+
+Math::Point Gfx::CEngine::GetMousePos()
+{
+ return m_mousePos;
+}
+
+void Gfx::CEngine::SetMouseType(Gfx::EngineMouseType type)
+{
+ m_mouseType = type;
+}
+
+Gfx::EngineMouseType Gfx::CEngine::GetMouseType()
+{
+ return m_mouseType;
+}
+
+const Math::Matrix& Gfx::CEngine::GetMatView()
+{
+ return m_matView;
+}
+
+Math::Vector Gfx::CEngine::GetEyePt()
+{
+ return m_eyePt;
+}
+
+Math::Vector Gfx::CEngine::GetLookatPt()
+{
+ return m_lookatPt;
+}
+
+float Gfx::CEngine::GetEyeDirH()
+{
+ return m_eyeDirH;
+}
+
+float Gfx::CEngine::GetEyeDirV()
+{
+ return m_eyeDirV;
+}
+
+bool Gfx::CEngine::IsVisiblePoint(const Math::Vector &pos)
+{
+ return Math::Distance(m_eyePt, pos) <= m_deepView[0];
+}
+
+void Gfx::CEngine::UpdateMatProj()
+{
+ m_device->SetTransform(Gfx::TRANSFORM_PROJECTION, m_matProj);
+}
+
+void Gfx::CEngine::ApplyChange()
+{
+ m_deepView[0] /= m_lastClippingDistance;
+ m_deepView[1] /= m_lastClippingDistance;
+
+ SetFocus(m_focus);
+ ChangeLOD();
+
+ m_deepView[0] *= m_clippingDistance;
+ m_deepView[1] *= m_clippingDistance;
+}
+
+
+
+/*******************************************************
+ Rendering
+ *******************************************************/
+
+
+
+/**
+ This function sets up render states, clears the
+ viewport, and renders the scene. */
+void Gfx::CEngine::Render()
+{
+ if (! m_render) return;
+
+ m_statisticTriangle = 0;
m_lastState = -1;
- SetState(Gfx::ENG_RSTATE_NORMAL);
+ m_lastColor = 999;
+ m_lastMaterial = Gfx::Material();
- m_device->BeginScene();
+ m_lightMan->UpdateLights();
- SetUp3DView();
+ Gfx::Color color;
+ if (m_skyMode && m_cloud->GetLevel() != 0.0f) // clouds?
+ color = m_backgroundCloudDown;
+ else
+ color = m_backgroundColorDown;
- if (! Draw3DScene() )
- return false;
+ m_device->SetClearColor(color);
+
+ // Begin the scene
+ m_device->BeginScene();
- SetUpInterfaceView();
+ if (m_drawWorld)
+ Draw3DScene();
- if (! DrawInterface() )
- return false;
+ DrawInterface();
+ // End the scene
m_device->EndScene();
+}
- return true;
+void Gfx::CEngine::Draw3DScene()
+{
+ /* TODO!
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DVERTEX2* pv;
+ int l1, l2, l3, l4, l5, objRank;*/
+
+ if (m_groundSpotVisible)
+ UpdateGroundSpotTextures();
+
+ DrawBackground(); // draws the background
+ if (m_planetMode) DrawPlanet(); // draws the planets
+ if (m_skyMode) m_cloud->Draw(); // draws the clouds
+
+
+ // Display the objects
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, true);
+
+ float fogStart = m_deepView[m_rankView]*m_fogStart[m_rankView];
+ float fogEnd = m_deepView[m_rankView];
+ m_device->SetFogParams(Gfx::FOG_LINEAR, m_fogColor[m_rankView], fogStart, fogEnd, 1.0f);
+
+ m_device->SetTransform(Gfx::TRANSFORM_PROJECTION, m_matProj);
+ m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matView);
+
+ if (m_waterMode) m_water->DrawBack(); // draws water background
+
+ if (m_shadowVisible)
+ {
+ // Draw the field
+ // TODO!
+ /*
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ SetTexture(p2->texName1, 0);
+ SetTexture(p2->texName2, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( m_objectParam[objRank].type != TYPETERRAIN ) continue;
+ if ( !m_objectParam[objRank].bDrawWorld ) continue;
+
+ {
+ D3DMATRIX mat = MAT_TO_D3DMAT(m_objectParam[objRank].transform);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
+ }
+
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objectParam[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objectParam[objRank].distance < p4->min ||
+ m_objectParam[objRank].distance >= p4->max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ SetMaterial(p6->material);
+ SetState(p6->state);
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed/3;
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed-2;
+ }
+ }
+ }
+ }
+ }
+ }*/
+
+ // Draws the shadows
+ DrawShadow();
+ }
+
+ // Draw objects
+ bool transparent = false;
+ /* TODO!
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ SetTexture(p2->texName1, 0);
+ SetTexture(p2->texName2, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( m_bShadow && m_objectParam[objRank].type == TYPETERRAIN ) continue;
+ if ( !m_objectParam[objRank].bDrawWorld ) continue;
+
+ {
+ D3DMATRIX mat = MAT_TO_D3DMAT(m_objectParam[objRank].transform);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
+ }
+
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objectParam[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objectParam[objRank].distance < p4->min ||
+ m_objectParam[objRank].distance >= p4->max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ SetMaterial(p6->material);
+ if ( m_objectParam[objRank].transparency != 0.0f ) // transparent ?
+ {
+ transparent = true;
+ continue;
+ }
+ SetState(p6->state);
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed/3;
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed-2;
+ }
+ }
+ }
+ }
+ }
+ }*/
+
+ if (transparent)
+ {
+ int tState = 0;
+ Gfx::Color tColor;
+ if (m_stateColor)
+ {
+ tState = Gfx::ENG_RSTATE_TTEXTURE_BLACK | Gfx::ENG_RSTATE_2FACE;
+ tColor = Gfx::Color(68.0f / 255.0f, 68.0f / 255.0f, 68.0f / 255.0f, 68.0f / 255.0f);
+ }
+ else
+ {
+ tState = Gfx::ENG_RSTATE_TCOLOR_BLACK;
+ tColor = Gfx::Color(136.0f / 255.0f, 136.0f / 255.0f, 136.0f / 255.0f, 136.0f / 255.0f);
+ }
+
+ // Draw transparent objects.
+ /* TODO!
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ SetTexture(p2->texName1, 0);
+ SetTexture(p2->texName2, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( m_bShadow && m_objectParam[objRank].type == TYPETERRAIN ) continue;
+ if ( !m_objectParam[objRank].bDrawWorld ) continue;
+
+ {
+ D3DMATRIX mat = MAT_TO_D3DMAT(m_objectParam[objRank].transform);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
+ }
+
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objectParam[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objectParam[objRank].distance < p4->min ||
+ m_objectParam[objRank].distance >= p4->max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ SetMaterial(p6->material);
+ if ( m_objectParam[objRank].transparency == 0.0f ) continue;
+ SetState(tState, tColor);
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed/3;
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed-2;
+ }
+ }
+ }
+ }
+ }
+ } */
+ }
+
+ m_lightMan->UpdateLightsEnableState(Gfx::ENG_OBJTYPE_TERRAIN);
+
+ if (m_waterMode) m_water->DrawSurf(); // draws water surface
+
+ m_particle->DrawParticle(Gfx::SH_WORLD); // draws the particles of the 3D world
+ m_lightning->Draw(); // draws lightning
+ if (m_lensMode) DrawForegroundImage(); // draws the foreground
+ if (! m_overFront) DrawOverColor(); // draws the foreground color
}
-void Gfx::CEngine::SetUp3DView()
+void Gfx::CEngine::DrawInterface()
{
- // TODO
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
+
+ m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matViewInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_PROJECTION, m_matProjInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_matWorldInterface);
+
+ // Draw the entire interface
+ CInterface* interface = static_cast<CInterface*>( m_iMan->SearchInstance(CLASS_INTERFACE) );
+ if (interface != nullptr)
+ interface->Draw();
+
+ m_particle->DrawParticle(Gfx::SH_INTERFACE); // draws the particles of the interface
+
+ // 3D objects drawn in front of interface
+ if (m_drawFront)
+ {
+ // Display the objects
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, true);
+
+ m_device->SetTransform(Gfx::TRANSFORM_PROJECTION, m_matProj);
+
+ m_device->SetGlobalAmbient(m_ambientColor[m_rankView]);
+ m_device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, true);
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, true);
+
+ float fogStart = m_deepView[m_rankView]*m_fogStart[m_rankView];
+ float fogEnd = m_deepView[m_rankView];
+ m_device->SetFogParams(Gfx::FOG_LINEAR, m_fogColor[m_rankView], fogStart, fogEnd, 1.0f);
+
+ m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matView);
+
+ // TODO!
+ /*
+ for (int l1 = 0; l1 < m_objectTree.size(); l1++)
+ {
+ Gfx::EngineObjLevel1* p1 = &m_objectTree[l1];
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ SetTexture(p2->texName1, 0);
+ SetTexture(p2->texName2, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( !m_objectParam[objRank].bDrawFront ) continue;
+
+ {
+ D3DMATRIX mat = MAT_TO_D3DMAT(m_objectParam[objRank].transform);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
+ }
+
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objectParam[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objectParam[objRank].distance < p4->min ||
+ m_objectParam[objRank].distance >= p4->max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ SetMaterial(p6->material);
+ SetState(p6->state);
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed/3;
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed-2;
+ }
+ }
+ }
+ }
+ }
+ }*/
+
+ m_particle->DrawParticle(Gfx::SH_FRONT); // draws the particles of the 3D world
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
+
+ m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matViewInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_PROJECTION, m_matProjInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_matWorldInterface);
+ }
+
+ // Draw foreground color
+ if (m_overFront)
+ DrawOverColor();
+
+ // Mouse & highlight at the end
+ DrawMouse();
+ DrawHighlight();
}
-bool Gfx::CEngine::Draw3DScene()
+void Gfx::CEngine::UpdateGroundSpotTextures()
{
- // TODO
- return true;
+ // TODO the original code modifying the textures is very complex, so stub for now
+ GetLogger()->Info("CEngine::UpdateGroundSpotTextures(): stub!\n");
}
-void Gfx::CEngine::SetUpInterfaceView()
+void Gfx::CEngine::DrawShadow()
{
- m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_matWorldInterface);
- m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matViewInterface);
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, false);
+
+ Math::Matrix matrix;
+ matrix.LoadIdentity();
+ m_device->SetTransform(Gfx::TRANSFORM_WORLD, matrix);
+
+
+ Gfx::Material material;
+ material.diffuse = Gfx::Color(1.0f, 1.0f, 1.0f);
+ material.ambient = Gfx::Color(0.5f, 0.5f, 0.5f);
+ SetMaterial(material);
+
+ // TODO: create a separate texture
+ SetTexture("text.png");
+
+ Math::Point ts, ti;
+
+ float dp = 0.5f/256.0f;
+ ts.y = 192.0f/256.0f;
+ ti.y = 224.0f/256.0f;
+ ts.y += dp;
+ ti.y -= dp;
+
+ Math::Vector n(0.0f, 1.0f, 0.0f);
+
+ float startDeepView = m_deepView[m_rankView]*m_fogStart[m_rankView];
+ float endDeepView = m_deepView[m_rankView];
+
+ float lastIntensity = -1.0f;
+ for (int i = 0; i < static_cast<int>( m_shadows.size() ); i++)
+ {
+ if (m_shadows[i].hide) continue;
+
+ Math::Vector pos = m_shadows[i].pos; // pos = center of the shadow on the ground
+
+ if (m_eyePt.y == pos.y) continue; // camera at the same level?
+
+ float d = 0.0f;
+ float D = 0.0f;
+
+ // h is the height above the ground to which the shadow
+ // will be drawn.
+ if (m_eyePt.y > pos.y) // camera on?
+ {
+ float height = m_eyePt.y-pos.y;
+ float h = m_shadows[i].radius;
+ float max = height*0.5f;
+ if ( h > max ) h = max;
+ if ( h > 4.0f ) h = 4.0f;
+
+ D = Math::Distance(m_eyePt, pos);
+ if ( D >= endDeepView ) continue;
+ d = D*h/height;
+
+ pos.x += (m_eyePt.x-pos.x)*d/D;
+ pos.z += (m_eyePt.z-pos.z)*d/D;
+ pos.y += h;
+ }
+ else // camera underneath?
+ {
+ float height = pos.y-m_eyePt.y;
+ float h = m_shadows[i].radius;
+ float max = height*0.1f;
+ if ( h > max ) h = max;
+ if ( h > 4.0f ) h = 4.0f;
+
+ D = Math::Distance(m_eyePt, pos);
+ if ( D >= endDeepView ) continue;
+ d = D*h/height;
+
+ pos.x += (m_eyePt.x-pos.x)*d/D;
+ pos.z += (m_eyePt.z-pos.z)*d/D;
+ pos.y -= h;
+ }
+
+ // The hFactor decreases the intensity and size increases more
+ // the object is high relative to the ground.
+ float hFactor = m_shadows[i].height/20.0f;
+ if ( hFactor < 0.0f ) hFactor = 0.0f;
+ if ( hFactor > 1.0f ) hFactor = 1.0f;
+ hFactor = powf(1.0f-hFactor, 2.0f);
+ if ( hFactor < 0.2f ) hFactor = 0.2f;
+
+ float radius = m_shadows[i].radius*1.5f;
+ radius *= 2.0f-hFactor; // greater if high
+ radius *= 1.0f-d/D; // smaller if close
+
+
+ Math::Vector corner[4];
+
+ if (m_shadows[i].type == Gfx::ENG_SHADOW_NORM)
+ {
+ corner[0].x = +radius;
+ corner[0].z = +radius;
+ corner[0].y = 0.0f;
+
+ corner[1].x = -radius;
+ corner[1].z = +radius;
+ corner[1].y = 0.0f;
+
+ corner[2].x = +radius;
+ corner[2].z = -radius;
+ corner[2].y = 0.0f;
+
+ corner[3].x = -radius;
+ corner[3].z = -radius;
+ corner[3].y = 0.0f;
+
+ ts.x = 64.0f/256.0f;
+ ti.x = 96.0f/256.0f;
+ }
+ else
+ {
+ Math::Point rot;
+
+ rot = Math::RotatePoint(-m_shadows[i].angle, Math::Point(radius, radius));
+ corner[0].x = rot.x;
+ corner[0].z = rot.y;
+ corner[0].y = 0.0f;
+
+ rot = Math::RotatePoint(-m_shadows[i].angle, Math::Point(-radius, radius));
+ corner[1].x = rot.x;
+ corner[1].z = rot.y;
+ corner[1].y = 0.0f;
+
+ rot = Math::RotatePoint(-m_shadows[i].angle, Math::Point(radius, -radius));
+ corner[2].x = rot.x;
+ corner[2].z = rot.y;
+ corner[2].y = 0.0f;
+
+ rot = Math::RotatePoint(-m_shadows[i].angle, Math::Point(-radius, -radius));
+ corner[3].x = rot.x;
+ corner[3].z = rot.y;
+ corner[3].y = 0.0f;
+
+ if (m_shadows[i].type == Gfx::ENG_SHADOW_WORM)
+ {
+ ts.x = 96.0f/256.0f;
+ ti.x = 128.0f/256.0f;
+ }
+ else
+ {
+ ts.x = 64.0f/256.0f;
+ ti.x = 96.0f/256.0f;
+ }
+ }
+
+ corner[0] = Math::CrossProduct(corner[0], m_shadows[i].normal);
+ corner[1] = Math::CrossProduct(corner[1], m_shadows[i].normal);
+ corner[2] = Math::CrossProduct(corner[2], m_shadows[i].normal);
+ corner[3] = Math::CrossProduct(corner[3], m_shadows[i].normal);
+
+ corner[0] += pos;
+ corner[1] += pos;
+ corner[2] += pos;
+ corner[3] += pos;
+
+ ts.x += dp;
+ ti.x -= dp;
+
+ Gfx::Vertex vertex[4] =
+ {
+ Gfx::Vertex(corner[1], n, Math::Point(ts.x, ts.y)),
+ Gfx::Vertex(corner[0], n, Math::Point(ti.x, ts.y)),
+ Gfx::Vertex(corner[3], n, Math::Point(ts.x, ti.y)),
+ Gfx::Vertex(corner[2], n, Math::Point(ti.x, ti.y))
+ };
+
+ float intensity = (0.5f+m_shadows[i].intensity*0.5f)*hFactor;
+
+ // Decreases the intensity of the shade if you're in the area
+ // between the beginning and the end of the fog.
+ if ( D > startDeepView )
+ intensity *= 1.0f-(D-startDeepView)/(endDeepView-startDeepView);
+
+ if (intensity == 0.0f) continue;
+
+ if (lastIntensity != intensity) // intensity changed?
+ {
+ lastIntensity = intensity;
+ SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE, Gfx::Color(intensity, intensity, intensity, intensity));
+ }
+
+ m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertex, 4);
+ AddStatisticTriangle(2);
+ }
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, true);
+}
+
+// STATUS: TESTED, VERIFIED
+void Gfx::CEngine::DrawBackground()
+{
+ if (m_skyMode && m_cloud->GetLevel() != 0.0f) // clouds ?
+ {
+ if (m_backgroundCloudUp != m_backgroundCloudDown) // degraded?
+ DrawBackgroundGradient(m_backgroundCloudUp, m_backgroundCloudDown);
+ }
+ else
+ {
+ if (m_backgroundColorUp != m_backgroundColorDown) // degraded?
+ DrawBackgroundGradient(m_backgroundColorUp, m_backgroundColorDown);
+ }
+
+ if (m_backForce || (m_skyMode && !m_backgroundName.empty()) )
+ {
+ DrawBackgroundImage(); // image
+ }
+}
+
+// STATUS: TESTED
+void Gfx::CEngine::DrawBackgroundGradient(const Gfx::Color& up, const Gfx::Color& down)
+{
+ Math::Point p1(0.0f, 0.5f);
+ Math::Point p2(1.0f, 1.0f);
+
+ Gfx::Color color[3] =
+ {
+ up,
+ down,
+ Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)
+ };
+
+ SetState(Gfx::ENG_RSTATE_OPAQUE_COLOR);
+
+ m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matViewInterface);
m_device->SetTransform(Gfx::TRANSFORM_PROJECTION, m_matProjInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_matWorldInterface);
+
+ Gfx::VertexCol vertex[4] =
+ {
+ Gfx::VertexCol(Math::Vector(p1.x, p1.y, 0.0f), color[1], color[2]),
+ Gfx::VertexCol(Math::Vector(p1.x, p2.y, 0.0f), color[0], color[2]),
+ Gfx::VertexCol(Math::Vector(p2.x, p1.y, 0.0f), color[1], color[2]),
+ Gfx::VertexCol(Math::Vector(p2.x, p2.y, 0.0f), color[0], color[2])
+ };
+
+ m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertex, 4);
+ AddStatisticTriangle(2);
}
-bool Gfx::CEngine::DrawInterface()
+// Status: PART_TESTED
+void Gfx::CEngine::DrawBackgroundImageQuarter(Math::Point p1, Math::Point p2, const std::string& name)
{
- Gfx::VertexCol vertices[3] =
+ Math::Vector n = Math::Vector(0.0f, 0.0f, -1.0f); // normal
+
+ float u1, u2, v1, v2;
+ if (m_backgroundFull)
+ {
+ u1 = 0.0f;
+ v1 = 0.0f;
+ u2 = 1.0f;
+ v2 = 1.0f;
+
+ if (m_backgroundQuarter)
+ {
+ u1 += 0.5f/512.0f;
+ v1 += 0.5f/384.0f;
+ u2 -= 0.5f/512.0f;
+ v2 -= 0.5f/384.0f;
+ }
+ }
+ else
{
- Gfx::VertexCol(Math::Vector( 0.25f, 0.25f, 0.0f), Gfx::Color(1.0f, 0.0f, 0.0f)),
- Gfx::VertexCol(Math::Vector( 0.75f, 0.25f, 0.0f), Gfx::Color(0.0f, 1.0f, 0.0f)),
- Gfx::VertexCol(Math::Vector( 0.5f, 0.75f, 0.0f), Gfx::Color(0.0f, 0.0f, 1.0f))
+ float h = 0.5f; // visible area vertically (1=all)
+ float a = m_eyeDirV-Math::PI*0.15f;
+ if (a > Math::PI ) a -= Math::PI*2.0f; // a = -Math::PI..Math::PI
+ if (a > Math::PI/4.0f) a = Math::PI/4.0f;
+ if (a < -Math::PI/4.0f) a = -Math::PI/4.0f;
+
+ u1 = -m_eyeDirH/Math::PI;
+ u2 = u1+1.0f/Math::PI;
+
+ v1 = (1.0f-h)*(0.5f+a/(2.0f*Math::PI/4.0f))+0.1f;
+ v2 = v1+h;
+ }
+
+ SetTexture(name);
+ SetState(Gfx::ENG_RSTATE_OPAQUE_TEXTURE | Gfx::ENG_RSTATE_WRAP);
+
+ m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matViewInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_PROJECTION, m_matProjInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_matWorldInterface);
+
+ Gfx::Vertex vertex[4] =
+ {
+ Gfx::Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(u1, v2)),
+ Gfx::Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(u1, v1)),
+ Gfx::Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(u2, v2)),
+ Gfx::Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(u2, v1))
};
- m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, vertices, 3);
+ m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertex, 4);
+ AddStatisticTriangle(2);
+}
- DrawMouse();
+// Status: TESTED, VERIFIED
+void Gfx::CEngine::DrawBackgroundImage()
+{
+ Math::Point p1, p2;
+ std::string name;
- return true;
+ if (m_backgroundQuarter)
+ {
+ p1.x = 0.0f;
+ p1.y = 0.5f;
+ p2.x = 0.5f;
+ p2.y = 1.0f;
+ QuarterName(name, m_backgroundName, 0);
+ DrawBackgroundImageQuarter(p1, p2, name);
+
+ p1.x = 0.5f;
+ p1.y = 0.5f;
+ p2.x = 1.0f;
+ p2.y = 1.0f;
+ QuarterName(name, m_backgroundName, 1);
+ DrawBackgroundImageQuarter(p1, p2, name);
+
+ p1.x = 0.0f;
+ p1.y = 0.0f;
+ p2.x = 0.5f;
+ p2.y = 0.5f;
+ QuarterName(name, m_backgroundName, 2);
+ DrawBackgroundImageQuarter(p1, p2, name);
+
+ p1.x = 0.5f;
+ p1.y = 0.0f;
+ p2.x = 1.0f;
+ p2.y = 0.5f;
+ QuarterName(name, m_backgroundName, 3);
+ DrawBackgroundImageQuarter(p1, p2, name);
+ }
+ else
+ {
+ p1.x = 0.0f;
+ p1.y = 0.0f;
+ p2.x = 1.0f;
+ p2.y = 1.0f;
+ DrawBackgroundImageQuarter(p1, p2, m_backgroundName);
+ }
+}
+
+void Gfx::CEngine::DrawPlanet()
+{
+ if (! m_planet->PlanetExist()) return;
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
+
+ m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matViewInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_PROJECTION, m_matProjInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_matWorldInterface);
+
+ m_planet->Draw(); // draws the planets
+}
+
+// Status: PART_TESTED
+void Gfx::CEngine::DrawForegroundImage()
+{
+ if (m_foregroundName.empty()) return;
+
+ Math::Vector n = Math::Vector(0.0f, 0.0f, -1.0f); // normal
+
+ Math::Point p1(0.0f, 0.0f);
+ Math::Point p2(1.0f, 1.0f);
+
+ float u1 = -m_eyeDirH/(Math::PI*0.6f)+Math::PI*0.5f;
+ float u2 = u1+0.50f;
+
+ float v1 = 0.2f;
+ float v2 = 1.0f;
+
+
+ Gfx::Vertex vertex[4] =
+ {
+ Gfx::Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(u1, v2)),
+ Gfx::Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(u1, v1)),
+ Gfx::Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(u2, v2)),
+ Gfx::Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(u2, v1))
+ };
+
+ SetTexture(m_foregroundName);
+ SetState(Gfx::ENG_RSTATE_CLAMP | Gfx::ENG_RSTATE_TTEXTURE_BLACK);
+
+ m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matViewInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_PROJECTION, m_matProjInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_matWorldInterface);
+
+ m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertex, 4);
+ AddStatisticTriangle(2);
+}
+
+// Status: PART_TESTED
+void Gfx::CEngine::DrawOverColor()
+{
+ if (! m_stateColor) return;
+
+ // TODO: fuzzy compare?
+ if ( (m_overColor == Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f) && m_overMode == Gfx::ENG_RSTATE_TCOLOR_BLACK) ||
+ (m_overColor == Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f) && m_overMode == Gfx::ENG_RSTATE_TCOLOR_WHITE) ) return;
+
+ Math::Point p1(0.0f, 0.0f);
+ Math::Point p2(1.0f, 1.0f);
+
+ Gfx::Color color[3] =
+ {
+ m_overColor,
+ m_overColor,
+ Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)
+ };
+
+ SetState(m_overMode);
+
+ // TODO: set also with m_overMode ?
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, false);
+
+ m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matViewInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_PROJECTION, m_matProjInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_matWorldInterface);
+
+ Gfx::VertexCol vertex[4] =
+ {
+ Gfx::VertexCol(Math::Vector(p1.x, p1.y, 0.0f), color[1], color[2]),
+ Gfx::VertexCol(Math::Vector(p1.x, p2.y, 0.0f), color[0], color[2]),
+ Gfx::VertexCol(Math::Vector(p2.x, p1.y, 0.0f), color[1], color[2]),
+ Gfx::VertexCol(Math::Vector(p2.x, p2.y, 0.0f), color[0], color[2])
+ };
+
+ m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertex, 4);
+ AddStatisticTriangle(2);
+}
+
+// Status: TESTED, VERIFIED
+void Gfx::CEngine::DrawHighlight()
+{
+ Math::Point min, max;
+ min.x = 1000000.0f;
+ min.y = 1000000.0f;
+ max.x = -1000000.0f;
+ max.y = -1000000.0f;
+
+ int i = 0;
+ while (m_highlightRank[i] != -1)
+ {
+ Math::Point omin, omax;
+ if (GetBBox2D(m_highlightRank[i++], omin, omax))
+ {
+ min.x = Math::Min(min.x, omin.x);
+ min.y = Math::Min(min.y, omin.y);
+ max.x = Math::Max(max.x, omax.x);
+ max.y = Math::Max(max.y, omax.y);
+ }
+ }
+
+ if ( min.x == 1000000.0f ||
+ min.y == 1000000.0f ||
+ max.x == -1000000.0f ||
+ max.y == -1000000.0f )
+ {
+ m_highlight = false; // not highlighted
+ }
+ else
+ {
+ m_highlightP1 = min;
+ m_highlightP2 = max;
+ m_highlight = true;
+ }
+
+ if (! m_highlight)
+ return;
+
+ Math::Point p1 = m_highlightP1;
+ Math::Point p2 = m_highlightP2;
+
+ int nbOut = 0;
+ if (p1.x < 0.0f || p1.x > 1.0f) nbOut++;
+ if (p1.y < 0.0f || p1.y > 1.0f) nbOut++;
+ if (p2.x < 0.0f || p2.x > 1.0f) nbOut++;
+ if (p2.y < 0.0f || p2.y > 1.0f) nbOut++;
+ if (nbOut > 2)
+ return;
+
+ SetState(Gfx::ENG_RSTATE_OPAQUE_COLOR);
+
+ float d = 0.5f+sinf(m_highlightTime*6.0f)*0.5f;
+ d *= (p2.x-p1.x)*0.1f;
+ p1.x += d;
+ p1.y += d;
+ p2.x -= d;
+ p2.y -= d;
+
+ Gfx::Color color(1.0f, 1.0f, 0.0f); // yellow
+
+ Gfx::VertexCol line[3] =
+ {
+ Gfx::VertexCol(Math::Vector(), color),
+ Gfx::VertexCol(Math::Vector(), color),
+ Gfx::VertexCol(Math::Vector(), color)
+ };
+
+ float dx = (p2.x - p1.x) / 5.0f;
+ float dy = (p2.y - p1.y) / 5.0f;
+
+ line[0].coord = Math::Vector(p1.x, p1.y + dy, 0.0f);
+ line[1].coord = Math::Vector(p1.x, p1.y, 0.0f);
+ line[2].coord = Math::Vector(p1.x + dx, p1.y, 0.0f);
+ m_device->DrawPrimitive(Gfx::PRIMITIVE_LINE_STRIP, line, 3);
+
+ line[0].coord = Math::Vector(p2.x - dx, p1.y, 0.0f);
+ line[1].coord = Math::Vector(p2.x, p1.y, 0.0f);
+ line[2].coord = Math::Vector(p2.x, p1.y + dy, 0.0f);
+ m_device->DrawPrimitive(Gfx::PRIMITIVE_LINE_STRIP, line, 3);
+
+ line[0].coord = Math::Vector(p2.x, p2.y - dy, 0.0f);
+ line[1].coord = Math::Vector(p2.x, p2.y, 0.0f);
+ line[2].coord = Math::Vector(p2.x - dx, p2.y, 0.0f);
+ m_device->DrawPrimitive(Gfx::PRIMITIVE_LINE_STRIP, line, 3);
+
+ line[0].coord = Math::Vector(p1.x + dx, p2.y, 0.0f);
+ line[1].coord = Math::Vector(p1.x, p2.y, 0.0f);
+ line[2].coord = Math::Vector(p1.x, p2.y - dy, 0.0f);
+ m_device->DrawPrimitive(Gfx::PRIMITIVE_LINE_STRIP, line, 3);
}
+// Status: TESTED, VERIFIED
void Gfx::CEngine::DrawMouse()
{
if (! m_mouseVisible)
@@ -648,6 +2816,7 @@ void Gfx::CEngine::DrawMouse()
DrawMouseSprite(pos, m_mouseSize, m_mice[index].icon2);
}
+// Status: TESTED, VERIFIED
void Gfx::CEngine::DrawMouseSprite(Math::Point pos, Math::Point size, int icon)
{
if (icon == -1)
@@ -672,72 +2841,11 @@ void Gfx::CEngine::DrawMouseSprite(Math::Point pos, Math::Point size, int icon)
Gfx::Vertex vertex[4] =
{
Gfx::Vertex(Math::Vector(p1.x, p1.y, 0.0f), normal, Math::Point(u1, v2)),
- Gfx::Vertex(Math::Vector(p2.x, p1.y, 0.0f), normal, Math::Point(u2, v2)),
Gfx::Vertex(Math::Vector(p1.x, p2.y, 0.0f), normal, Math::Point(u1, v1)),
+ Gfx::Vertex(Math::Vector(p2.x, p1.y, 0.0f), normal, Math::Point(u2, v2)),
Gfx::Vertex(Math::Vector(p2.x, p2.y, 0.0f), normal, Math::Point(u2, v1))
};
m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertex, 4);
AddStatisticTriangle(2);
}
-
-bool Gfx::CEngine::GetPause()
-{
- return m_pause;
-}
-
-Math::Vector Gfx::CEngine::GetLookatPt()
-{
- return m_lookatPt;
-}
-
-Math::Vector Gfx::CEngine::GetEyePt()
-{
- return m_eyePt;
-}
-
-void Gfx::CEngine::SetMouseVisible(bool visible)
-{
- m_mouseVisible = visible;
-}
-
-bool Gfx::CEngine::GetMouseVisible()
-{
- return m_mouseVisible;
-}
-
-void Gfx::CEngine::SetMousePos(Math::Point pos)
-{
- m_mousePos = pos;
-}
-
-Math::Point Gfx::CEngine::GetMousePos()
-{
- return m_mousePos;
-}
-
-void Gfx::CEngine::SetMouseType(Gfx::EngineMouseType type)
-{
- m_mouseType = type;
-}
-
-Gfx::EngineMouseType Gfx::CEngine::GetMouseType()
-{
- return m_mouseType;
-}
-
-void Gfx::CEngine::AddStatisticTriangle(int count)
-{
- m_statisticTriangle += count;
-}
-
-void Gfx::CEngine::SetShowStat(bool show)
-{
- m_showStats = show;
-}
-
-bool Gfx::CEngine::GetShowStat()
-{
- return m_showStats;
-}
-
diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h
index 25c5e5d..5a64e4e 100644
--- a/src/graphics/engine/engine.h
+++ b/src/graphics/engine/engine.h
@@ -1,5 +1,5 @@
// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * 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
@@ -15,18 +15,20 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// engine.h
+/**
+ * \file graphics/engine/engine.h
+ * \brief Main graphics engine - Gfx::CEngine class
+ */
#pragma once
-
+#include "app/system.h"
#include "common/event.h"
#include "graphics/core/color.h"
#include "graphics/core/material.h"
#include "graphics/core/texture.h"
#include "graphics/core/vertex.h"
#include "math/intpoint.h"
-#include "math/intsize.h"
#include "math/matrix.h"
#include "math/point.h"
#include "math/vector.h"
@@ -35,12 +37,13 @@
#include <string>
#include <vector>
#include <map>
+#include <set>
class CApplication;
class CInstanceManager;
class CObject;
-class CSound;
+class CSoundInterface;
namespace Gfx {
@@ -76,7 +79,7 @@ struct EngineTriangle
Gfx::VertexTex2 triangle[3];
//! Material
Gfx::Material material;
- //! Render state (TODO: ?)
+ //! Render state
int state;
//! 1st texture
Gfx::Texture tex1;
@@ -169,7 +172,10 @@ struct EngineObjLevel5
Gfx::EngineTriangleType type;
std::vector<Gfx::VertexTex2> vertices;
- EngineObjLevel5();
+ EngineObjLevel5()
+ {
+ state = 0;
+ }
};
/**
@@ -181,7 +187,10 @@ struct EngineObjLevel4
std::vector<Gfx::EngineObjLevel5> up;
Gfx::EngineObjLevel3* down;
- EngineObjLevel4();
+ EngineObjLevel4()
+ {
+ reserved = 0;
+ }
};
/**
@@ -194,7 +203,10 @@ struct EngineObjLevel3
std::vector<Gfx::EngineObjLevel4> up;
Gfx::EngineObjLevel2* down;
- EngineObjLevel3();
+ EngineObjLevel3()
+ {
+ min = max = 0.0f;
+ }
};
/**
@@ -206,7 +218,10 @@ struct EngineObjLevel2
std::vector<Gfx::EngineObjLevel3> up;
Gfx::EngineObjLevel1* down;
- EngineObjLevel2();
+ EngineObjLevel2()
+ {
+ objRank = 0;
+ }
};
/**
@@ -218,7 +233,7 @@ struct EngineObjLevel1
Gfx::Texture tex2;
std::vector<Gfx::EngineObjLevel2> up;
- EngineObjLevel1();
+ EngineObjLevel1() {}
};
/**
@@ -297,12 +312,14 @@ struct EngineGroundSpot
\brief Phase of life of an EngineGroundMark */
enum EngineGroundMarkPhase
{
+ //! Null phase
+ ENG_GR_MARK_PHASE_NULL = 0,
//! Increase
ENG_GR_MARK_PHASE_INC = 1,
//! Fixed
ENG_GR_MARK_PHASE_FIX = 2,
//! Decrease
- ENG_GR_MARK_PHASE_DEC = 2
+ ENG_GR_MARK_PHASE_DEC = 3
};
/**
@@ -407,7 +424,13 @@ enum EngineRenderState
//! The transparent color (black = no)
ENG_RSTATE_TCOLOR_BLACK = (1<<16),
//! The transparent color (white = no)
- ENG_RSTATE_TCOLOR_WHITE = (1<<17)
+ ENG_RSTATE_TCOLOR_WHITE = (1<<17),
+ //! Mode for rendering text
+ ENG_RSTATE_TEXT = (1<<18),
+ //! Only opaque texture, no blending, etc.
+ ENG_RSTATE_OPAQUE_TEXTURE = (1<<19),
+ //! Only opaque color, no texture, blending, etc.
+ ENG_RSTATE_OPAQUE_COLOR = (1<<20)
};
@@ -511,114 +534,138 @@ struct EngineMouse
class CEngine
{
public:
- CEngine(CInstanceManager *iMan, CApplication *app);
+ CEngine(CInstanceManager* iMan, CApplication* app);
~CEngine();
- //! Returns whether the device was initialized
- bool GetWasInit();
- //! Returns the last error encountered
- std::string GetError();
-
- //! Performs the first initialization, before a device was set
- bool Create();
- //! Frees all resources before exit
- void Destroy();
-
//! Sets the device to be used
- void SetDevice(Gfx::CDevice *device);
+ void SetDevice(Gfx::CDevice* device);
//! Returns the current device
Gfx::CDevice* GetDevice();
- //! Performs initialization after a device was created and set
- bool AfterDeviceSetInit();
+ //! Sets the terrain object
+ void SetTerrain(Gfx::CTerrain* terrain);
+
+ //! Returns the text rendering engine
+ CText* GetText();
+
+
+ //! Performs the initialization; must be called after device was set
+ bool Create();
+ //! Frees all resources before exit
+ void Destroy();
//! Resets some states and flushes textures after device was changed (e.g. resoulution changed)
void ResetAfterDeviceChanged();
- void SetTerrain(Gfx::CTerrain* terrain);
+
+ //! Called once per frame, the call is the entry point for rendering
+ void Render();
+
//! Processes incoming event
- bool ProcessEvent(const Event &event);
+ bool ProcessEvent(const Event& event);
- //! Renders a single frame
- bool Render();
+ //! Called once per frame, the call is the entry point for animating the scene
+ void FrameMove(float rTime);
+ //! Evolved throughout the game
+ void StepSimulation(float rTime);
- bool WriteProfile();
+ //! Writes a screenshot containing the current frame
+ bool WriteScreenShot(const std::string& fileName, int width, int height);
+
+ //! Reads settings from INI
+ bool ReadSettings();
+ //! Writes settings to INI
+ bool WriteSettings();
+
+ //@{
+ //! Management of game pause mode
void SetPause(bool pause);
bool GetPause();
+ //@}
+ //@{
+ //! Management of lock for the duration of movie sequence
void SetMovieLock(bool lock);
bool GetMovieLock();
+ //@}
- void SetShowStat(bool show);
- bool GetShowStat();
+ //@{
+ //! Management of displaying statistic information
+ void SetShowStats(bool show);
+ bool GetShowStats();
+ //@}
+ //! Enables/disables rendering
void SetRenderEnable(bool enable);
- int OneTimeSceneInit();
- int InitDeviceObjects();
- int DeleteDeviceObjects();
- int RestoreSurfaces();
- int FrameMove(float rTime);
- void StepSimulation(float rTime);
- int FinalCleanup();
+ //! Returns current size of viewport window
+ Math::IntPoint GetWindowSize();
+ //! Returns the last size of viewport window
+ Math::IntPoint GetLastWindowSize();
+
+ //@{
+ //! Conversion functions between window and interface coordinates
+ /** Window coordinates are from top-left (0,0) to bottom-right (w,h) - size of window
+ Interface cords are from bottom-left (0,0) to top-right (1,1) - and do not depend on window size */
+ Math::Point WindowToInterfaceCoords(Math::IntPoint pos);
+ Math::IntPoint InterfaceToWindowCoords(Math::Point pos);
+ //@}
+
+ //@{
+ //! Conversion functions between window and interface sizes
+ /** Unlike coordinate conversions, this is only scale conversion, not translation and scale. */
+ Math::Point WindowToInterfaceSize(Math::IntPoint size);
+ Math::IntPoint InterfaceToWindowSize(Math::Point size);
+ //@}
+
+ //! Returns the name of directory with textures
+ std::string GetTextureDir();
+
+ //! Increments the triangle counter for the current frame
void AddStatisticTriangle(int nb);
+ //! Returns the number of triangles in current frame
int GetStatisticTriangle();
- void SetHiliteRank(int *rankList);
- bool GetHilite(Math::Point &p1, Math::Point &p2);
- bool GetSpriteCoord(int &x, int &y);
- void SetInfoText(int line, char* text);
- char* GetInfoText(int line);
- void FirstExecuteAdapt(bool first);
- bool GetFullScreen();
- Math::Matrix* GetMatView();
- Math::Matrix* GetMatLeftView();
- Math::Matrix* GetMatRightView();
+ /* *************** Object management *************** */
- void TimeInit();
- void TimeEnterGel();
- void TimeExitGel();
- float TimeGet();
-
- int GetRestCreate();
int CreateObject();
void FlushObject();
bool DeleteObject(int objRank);
bool SetDrawWorld(int objRank, bool draw);
bool SetDrawFront(int objRank, bool draw);
- bool AddTriangle(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material &mat,
+ bool AddTriangle(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material& mat,
int state, std::string texName1, std::string texName2,
float min, float max, bool globalUpdate);
- bool AddSurface(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material &mat,
+ bool AddSurface(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material& mat,
int state, std::string texName1, std::string texName2,
float min, float max, bool globalUpdate);
- bool AddQuick(int objRank, Gfx::EngineObjLevel5* buffer,
+ bool AddQuick(int objRank, const Gfx::EngineObjLevel5& buffer,
std::string texName1, std::string texName2,
float min, float max, bool globalUpdate);
- Gfx::EngineObjLevel5* SearchTriangle(int objRank, const Gfx::Material &mat,
+ Gfx::EngineObjLevel5* SearchTriangle(int objRank, const Gfx::Material& mat,
int state, std::string texName1, std::string texName2,
float min, float max);
void ChangeLOD();
- bool ChangeSecondTexture(int objRank, char* texName2);
+ bool ChangeSecondTexture(int objRank, const std::string& texName2);
int GetTotalTriangles(int objRank);
int GetTriangles(int objRank, float min, float max, Gfx::EngineTriangle* buffer, int size, float percent);
- bool GetBBox(int objRank, Math::Vector &min, Math::Vector &max);
- bool ChangeTextureMapping(int objRank, const Gfx::Material &mat, int state,
- const std::string &texName1, const std::string &texName2,
+ bool GetBBox(int objRank, Math::Vector& min, Math::Vector& max);
+ bool ChangeTextureMapping(int objRank, const Gfx::Material& mat, int state,
+ const std::string& texName1, const std::string& texName2,
float min, float max, Gfx::EngineTextureMapping mode,
float au, float bu, float av, float bv);
- bool TrackTextureMapping(int objRank, const Gfx::Material &mat, int state,
- const std::string &texName1, const std::string &texName2,
+ bool TrackTextureMapping(int objRank, const Gfx::Material& mat, int state,
+ const std::string& texName1, const std::string& texName2,
float min, float max, Gfx::EngineTextureMapping mode,
float pos, float factor, float tl, float ts, float tt);
- bool SetObjectTransform(int objRank, const Math::Matrix &transform);
- bool GetObjectTransform(int objRank, Math::Matrix &transform);
+ bool SetObjectTransform(int objRank, const Math::Matrix& transform);
+ bool GetObjectTransform(int objRank, Math::Matrix& transform);
bool SetObjectType(int objRank, Gfx::EngineObjectType type);
Gfx::EngineObjectType GetObjectType(int objRank);
bool SetObjectTransparency(int objRank, float value);
@@ -627,20 +674,25 @@ public:
void ShadowDelete(int objRank);
bool SetObjectShadowHide(int objRank, bool hide);
bool SetObjectShadowType(int objRank, Gfx::EngineShadowType type);
- bool SetObjectShadowPos(int objRank, const Math::Vector &pos);
- bool SetObjectShadowNormal(int objRank, const Math::Vector &n);
+ bool SetObjectShadowPos(int objRank, const Math::Vector& pos);
+ bool SetObjectShadowNormal(int objRank, const Math::Vector& n);
bool SetObjectShadowAngle(int objRank, float angle);
bool SetObjectShadowRadius(int objRank, float radius);
bool SetObjectShadowIntensity(int objRank, float intensity);
bool SetObjectShadowHeight(int objRank, float h);
float GetObjectShadowRadius(int objRank);
+ //! Lists the ranks of objects and subobjects selected
+ void SetHighlightRank(int* rankList);
+ //! Returns the highlighted rectangle
+ bool GetHighlight(Math::Point& p1, Math::Point& p2);
+
void GroundSpotFlush();
int GroundSpotCreate();
void GroundSpotDelete(int rank);
- bool SetObjectGroundSpotPos(int rank, const Math::Vector &pos);
+ bool SetObjectGroundSpotPos(int rank, const Math::Vector& pos);
bool SetObjectGroundSpotRadius(int rank, float radius);
- bool SetObjectGroundSpotColor(int rank, const Gfx::Color &color);
+ bool SetObjectGroundSpotColor(int rank, const Gfx::Color& color);
bool SetObjectGroundSpotMinMax(int rank, float min, float max);
bool SetObjectGroundSpotSmooth(int rank, float smooth);
@@ -649,216 +701,356 @@ public:
int dx, int dy, char* table);
bool GroundMarkDelete(int rank);
+ //! Updates the state after creating objects
void Update();
- void SetViewParams(const Math::Vector &eyePt, const Math::Vector &lookatPt,
- const Math::Vector &upVec, float eyeDistance);
- Gfx::Texture CreateTexture(const std::string &texName,
- const Gfx::TextureCreateParams &params);
- Gfx::Texture CreateTexture(const std::string &texName);
- void DestroyTexture(const std::string &texName);
+ /* *************** Mode setting *************** */
+
+ //! Sets the current rendering state
+ void SetState(int state, const Gfx::Color& color = Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f));
+
+ //! Sets the current material
+ void SetMaterial(const Gfx::Material& mat);
+
+ //! Specifies the location and direction of view
+ void SetViewParams(const Math::Vector& eyePt, const Math::Vector& lookatPt,
+ const Math::Vector& upVec, float eyeDistance);
+
+ //! Creates texture with the specified params
+ Gfx::Texture CreateTexture(const std::string& texName,
+ const Gfx::TextureCreateParams& params);
+ //! Creates texture
+ Gfx::Texture CreateTexture(const std::string& texName);
- bool LoadTexture(const std::string &name, int stage = 0);
+ //! Destroys texture, unloading it and removing from cache
+ void DestroyTexture(const std::string& texName);
+
+ //! Loads texture, creating it if not already present
+ bool LoadTexture(const std::string& name);
+ //! Loads all necessary textures
bool LoadAllTextures();
+ //! Sets texture for given stage; if not present in cache, the texture is loaded
+ bool SetTexture(const std::string& name, int stage = 0);
+
+ //@{
+ //! Border management (distance limits) depends of the resolution (LOD = level-of-detail)
void SetLimitLOD(int rank, float limit);
float GetLimitLOD(int rank, bool last=false);
+ //@}
+ //! Defines of the distance field of vision
void SetTerrainVision(float vision);
+ //@{
+ //! Management of camera angle
+ /**
+ 0.75 = normal
+ 1.50 = wide-angle */
+ void SetFocus(float focus);
+ float GetFocus();
+ //@}
+
+ //@{
+ //! Management of the global mode of marking
void SetGroundSpot(bool mode);
bool GetGroundSpot();
+ //@}
+
+ //@{
+ //! Management of the global mode of shading
void SetShadow(bool mode);
bool GetShadow();
+ //@}
+
+ //@{
+ //! Management of the global mode of contamination
void SetDirty(bool mode);
bool GetDirty();
+ //@}
+
+ //@{
+ //! Management of the global mode of horizontal fog patches
void SetFog(bool mode);
bool GetFog();
+ //@}
+
+ //! Indicates whether it is possible to give a color SetState
bool GetStateColor();
+ //@{
+ //! Management of the global mode of secondary texturing
void SetSecondTexture(int texNum);
int GetSecondTexture();
+ //@}
+ //@{
+ //! Management of view mode
void SetRankView(int rank);
int GetRankView();
+ //@}
+ //! Whether to draw the world
void SetDrawWorld(bool draw);
+
+ //! Whether to draw the world on the interface
void SetDrawFront(bool draw);
- void SetAmbientColor(const Gfx::Color &color, int rank = 0);
+ //@{
+ //! Ambient color management
+ void SetAmbientColor(const Gfx::Color& color, int rank = 0);
Gfx::Color GetAmbientColor(int rank = 0);
+ //@}
- void SetWaterAddColor(const Gfx::Color &color);
+ //@{
+ //! Color management under water
+ void SetWaterAddColor(const Gfx::Color& color);
Gfx::Color GetWaterAddColor();
+ //@}
- void SetFogColor(const Gfx::Color &color, int rank = 0);
+ //@{
+ //! Management of the fog color
+ void SetFogColor(const Gfx::Color& color, int rank = 0);
Gfx::Color GetFogColor(int rank = 0);
+ //@}
+ //@{
+ //! Management of the depth of field.
+ /** Beyond this distance, nothing is visible.
+ Shortly (according SetFogStart), one enters the fog. */
void SetDeepView(float length, int rank = 0, bool ref=false);
float GetDeepView(int rank = 0);
+ //@}
+
+ //@{
+ //! Management the start of fog.
+ /** With 0.0, the fog from the point of view (fog max).
+ With 1.0, the fog from the depth of field (no fog). */
void SetFogStart(float start, int rank = 0);
float GetFogStart(int rank = 0);
+ //@}
- void SetBackground(const std::string &name, Gfx::Color up = Gfx::Color(), Gfx::Color down = Gfx::Color(),
+ //@{
+ //! Management of the background image to use
+ void SetBackground(const std::string& name, Gfx::Color up = Gfx::Color(), Gfx::Color down = Gfx::Color(),
Gfx::Color cloudUp = Gfx::Color(), Gfx::Color cloudDown = Gfx::Color(),
bool full = false, bool quarter = false);
- void GetBackground(const std::string &name, Gfx::Color &up, Gfx::Color &down,
- Gfx::Color &cloudUp, Gfx::Color &cloudDown,
- bool &full, bool &quarter);
- void SetFrontsizeName(char *name);
+ void GetBackground(std::string& name, Gfx::Color& up, Gfx::Color& down,
+ Gfx::Color& cloudUp, Gfx::Color& cloudDown,
+ bool& full, bool& quarter);
+ //@}
+
+ //! Specifies the name of foreground texture
+ void SetForegroundName(const std::string& name);
+ //! Specifies whether to draw the foreground
void SetOverFront(bool front);
- void SetOverColor(const Gfx::Color &color = Gfx::Color(), int mode = ENG_RSTATE_TCOLOR_BLACK);
+ //! Sets the foreground overlay color
+ void SetOverColor(const Gfx::Color& color = Gfx::Color(), int mode = ENG_RSTATE_TCOLOR_BLACK);
+ //@{
+ //! Management of the particle density
void SetParticleDensity(float value);
float GetParticleDensity();
+ //@}
+
+ //! Adapts particle factor according to particle density
float ParticleAdapt(float factor);
+ //@{
+ //! Management of the distance of clipping.
void SetClippingDistance(float value);
float GetClippingDistance();
+ //@}
+ //@{
+ //! Management of objects detals.
void SetObjectDetail(float value);
float GetObjectDetail();
+ //@}
+ //@{
+ //! The amount of management objects gadgets
void SetGadgetQuantity(float value);
float GetGadgetQuantity();
+ //@}
+ //@{
+ //! Management the quality of textures
void SetTextureQuality(int value);
int GetTextureQuality();
+ //@}
+ //@{
+ //! Management mode of toto
void SetTotoMode(bool present);
bool GetTotoMode();
+ //@}
+ //@{
+ //! Management the mode of foreground
void SetLensMode(bool present);
bool GetLensMode();
+ //@}
+ //@{
+ //! Management the mode of water
void SetWaterMode(bool present);
bool GetWaterMode();
+ //@}
void SetLightingMode(bool present);
bool GetLightingMode();
+ //@{
+ //! Management the mode of sky
void SetSkyMode(bool present);
bool GetSkyMode();
+ //@}
+ //@{
+ //! Management the mode of background
void SetBackForce(bool present);
bool GetBackForce();
+ //@}
+ //@{
+ //! Management the mode of planets
void SetPlanetMode(bool present);
bool GetPlanetMode();
+ //@}
+ //@{
+ //! Managing the mode of dynamic lights.
void SetLightMode(bool present);
bool GetLightMode();
+ //@}
+ //@{
+ // TODO: move to more appropriate class ?
+ //! Management of the indentation mode while editing (CEdit)
void SetEditIndentMode(bool autoIndent);
bool GetEditIndentMode();
+ //@}
+ //@{
+ // TODO: move to more appropriate class ?
+ //! Management of tab indent when editing (CEdit)
void SetEditIndentValue(int value);
int GetEditIndentValue();
+ //@}
+ //@{
+ //! Management of game speed
void SetSpeed(float speed);
float GetSpeed();
+ //@{
+ //! Management of precision of robot tracks
void SetTracePrecision(float factor);
float GetTracePrecision();
+ //@}
- void SetFocus(float focus);
- float GetFocus();
- Math::Vector GetEyePt();
- Math::Vector GetLookatPt();
- float GetEyeDirH();
- float GetEyeDirV();
- Math::Point GetDim();
- void UpdateMatProj();
-
- void ApplyChange();
-
- void FlushPressKey();
- void ResetKey();
- void SetKey(int keyRank, int option, int key);
- int GetKey(int keyRank, int option);
-
- void SetJoystick(bool enable);
- bool GetJoystick();
-
- void SetDebugMode(bool mode);
- bool GetDebugMode();
- bool GetSetupMode();
-
- bool IsVisiblePoint(const Math::Vector &pos);
-
- int DetectObject(Math::Point mouse);
- void SetState(int state, Gfx::Color color = Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f));
- void SetTexture(const std::string &name, int stage = 0);
- void SetMaterial(const Gfx::Material &mat);
-
+ //@{
+ //! Management of mouse cursor visibility
void SetMouseVisible(bool show);
bool GetMouseVisible();
+ //@}
+
+ //@{
+ //! Management of mouse cursor position
void SetMousePos(Math::Point pos);
Math::Point GetMousePos();
+ //@}
+
+ //@{
+ //! Management of mouse cursor type
void SetMouseType(Gfx::EngineMouseType type);
Gfx::EngineMouseType GetMouseType();
+ //@}
- CText* GetText();
+ //! Returns the view matrix
+ const Math::Matrix& GetMatView();
+ //! Returns the camera center point
+ Math::Vector GetEyePt();
+ //! Returns the camera target point
+ Math::Vector GetLookatPt();
+ //! Returns the horizontal direction angle of view
+ float GetEyeDirH();
+ //! Returns the vertical direction angle of view
+ float GetEyeDirV();
+ //! Indicates whether a point is visible
+ bool IsVisiblePoint(const Math::Vector& pos);
+
+ //! Resets the projection matrix after changes
+ void UpdateMatProj();
- bool ChangeColor(char *name, Gfx::Color colorRef1, Gfx::Color colorNew1,
- Gfx::Color colorRef2, Gfx::Color colorNew2,
- float tolerance1, float tolerance2,
- Math::Point ts, Math::Point ti,
- Math::Point *pExclu=0, float shift=0.0f, bool hSV=false);
- bool OpenImage(char *name);
- bool CopyImage();
- bool LoadImage();
- bool ScrollImage(int dx, int dy);
- bool SetDot(int x, int y, Gfx::Color color);
- bool CloseImage();
- 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);
+ //! Updates the scene after a change of parameters
+ void ApplyChange();
protected:
+ //! Prepares the interface for 3D scene
+ void Draw3DScene();
+ //! Draws the user interface over the scene
+ void DrawInterface();
- void SetUp3DView();
- bool Draw3DScene();
-
- void SetUpInterfaceView();
- bool DrawInterface();
+ //! Updates the textures used for drawing ground spot
+ void UpdateGroundSpotTextures();
- void DrawGroundSpot();
+ //! Draws shadows
void DrawShadow();
+ //! Draws the gradient background
void DrawBackground();
- void DrawBackgroundGradient(Gfx::Color up, Gfx::Color down);
- void DrawBackgroundImageQuarter(Math::Point p1, Math::Point p2, char *name);
+ //! Draws the gradient background
+ void DrawBackgroundGradient(const Gfx::Color& up, const Gfx::Color& down);
+ //! Draws a portion of the image background
+ void DrawBackgroundImageQuarter(Math::Point p1, Math::Point p2, const std::string& name);
+ //! Draws the image background
void DrawBackgroundImage();
+ //! Draws all the planets
void DrawPlanet();
- void DrawFrontsize();
+ //! Draws the image foreground
+ void DrawForegroundImage();
+ //! Draws the foreground color
void DrawOverColor();
- void DrawHilite();
+ //! Draws the rectangle of the object highlighted
+ void DrawHighlight();
+ //! Draws the mouse cursor
void DrawMouse();
+ //! Draw part of mouse cursor sprite
void DrawMouseSprite(Math::Point pos, Math::Point dim, int icon);
- /*
- Gfx::ObjLevel2* AddLevel1(Gfx::ObjLevel1 *&p1, char* texName1, char* texName2);
- Gfx::ObjLevel3* AddLevel2(Gfx::ObjLevel2 *&p2, int objRank);
- Gfx::ObjLevel4* AddLevel3(Gfx::ObjLevel3 *&p3, float min, float max);
- Gfx::ObjLevel5* AddLevel4(Gfx::ObjLevel4 *&p4, int reserve);
- Gfx::ObjLevel6* AddLevel5(Gfx::ObjLevel5 *&p5, Gfx::TriangleType type, const Gfx::Material &mat, int state, int nb);*/
-
+ //! Tests whether the given object is visible
bool IsVisible(int objRank);
+
+ //! Detects whether an object is affected by the mouse
bool DetectBBox(int objRank, Math::Point mouse);
- bool GetBBox2D(int objRank, Math::Point &min, Math::Point &max);
- bool DetectTriangle(Math::Point mouse, Gfx::VertexTex2 *triangle, int objRank, float &dist);
- bool TransformPoint(Math::Vector &p2D, int objRank, Math::Vector p3D);
+
+ //! Compute and return the 2D box on screen of any object
+ bool GetBBox2D(int objRank, Math::Point& min, Math::Point& max);
+
+ //! Detects the target object that is selected with the mouse
+ /** Returns the rank of the object or -1. */
+ int DetectObject(Math::Point mouse);
+
+ //! Detects whether the mouse is in a triangle.
+ bool DetectTriangle(Math::Point mouse, Gfx::VertexTex2* triangle, int objRank, float& dist);
+
+ //! Transforms a 3D point (x, y, z) in 2D space (x, y, -) of the window
+ /** The coordinated p2D.z gives the distance. */
+ bool TransformPoint(Math::Vector& p2D, int objRank, Math::Vector p3D);
+
+ //! Calculates the distances between the viewpoint and the origin of different objects
void ComputeDistance();
+
+ //! Updates all the geometric parameters of objects
void UpdateGeometry();
protected:
CInstanceManager* m_iMan;
CApplication* m_app;
- CSound* m_sound;
+ CSoundInterface* m_sound;
Gfx::CDevice* m_device;
Gfx::CText* m_text;
Gfx::CLightManager* m_lightMan;
@@ -869,51 +1061,54 @@ protected:
Gfx::CPlanet* m_planet;
Gfx::CTerrain* m_terrain;
- bool m_wasInit;
+ //! Last encountered error
std::string m_error;
//! Whether to show stats (FPS, etc)
bool m_showStats;
- int m_blackSrcBlend[2];
- int m_blackDestBlend[2];
- int m_whiteSrcBlend[2];
- int m_whiteDestBlend[2];
- int m_diffuseSrcBlend[2];
- int m_diffuseDestBlend[2];
- int m_alphaSrcBlend[2];
- int m_alphaDestBlend[2];
+ //! Speed of animation
+ float m_speed;
+ //! Pause mode
+ bool m_pause;
+ //! Rendering enabled?
+ bool m_render;
+ //! Lock for duration of movie?
+ bool m_movieLock;
+ //! Projection matrix for 3D scene
Math::Matrix m_matProj;
- Math::Matrix m_matLeftView;
- Math::Matrix m_matRightView;
+ //! View matrix for 3D scene
Math::Matrix m_matView;
+ //! Camera angle for 3D scene
float m_focus;
+ //! World matrix for 2D interface
Math::Matrix m_matWorldInterface;
+ //! Projection matrix for 2D interface
Math::Matrix m_matProjInterface;
+ //! View matrix for 2D interface
Math::Matrix m_matViewInterface;
- long m_baseTime;
- long m_stopTime;
- float m_absTime;
- float m_lastTime;
- float m_speed;
- bool m_pause;
- bool m_render;
- bool m_movieLock;
-
- //! Current size of window
- Math::IntSize m_size;
- Math::IntSize m_lastSize;
+ //! Current size of viewport window
+ Math::IntPoint m_size;
+ //! Previous size of viewport window
+ Math::IntPoint m_lastSize;
+ //! Root of tree object structure (level 1 list)
std::vector<Gfx::EngineObjLevel1> m_objectTree;
+ //! Object parameters
std::vector<Gfx::EngineObject> m_objects;
- std::vector<Gfx::EngineShadow> m_shadow;
- std::vector<Gfx::EngineGroundSpot> m_groundSpot;
+ //! Shadow list
+ std::vector<Gfx::EngineShadow> m_shadows;
+ //! Ground spot list
+ std::vector<Gfx::EngineGroundSpot> m_groundSpots;
+ //! Ground mark
Gfx::EngineGroundMark m_groundMark;
+ //! Location of camera
Math::Vector m_eyePt;
+ //! Camera target
Math::Vector m_lookatPt;
float m_eyeDirH;
float m_eyeDirV;
@@ -926,7 +1121,6 @@ protected:
Gfx::Color m_waterAddColor;
int m_statisticTriangle;
bool m_updateGeometry;
- //char m_infoText[10][200];
int m_alphaMode;
bool m_stateColor;
bool m_forceStateColor;
@@ -946,11 +1140,11 @@ protected:
bool m_overFront;
Gfx::Color m_overColor;
int m_overMode;
- std::string m_frontsizeName;
+ std::string m_foregroundName;
bool m_drawWorld;
bool m_drawFront;
float m_limitLOD[2];
- float m_particuleDensity;
+ float m_particleDensity;
float m_clippingDistance;
float m_lastClippingDistance;
float m_objectDetail;
@@ -969,34 +1163,53 @@ protected:
int m_editIndentValue;
float m_tracePrecision;
- int m_hiliteRank[100];
- bool m_hilite;
- Math::Point m_hiliteP1;
- Math::Point m_hiliteP2;
-
- int m_lastState;
- Gfx::Color m_lastColor;
- char m_lastTexture[2][50];
- Gfx::Material m_lastMaterial;
-
+ //! Ranks of highlighted objects
+ int m_highlightRank[100];
+ //! Highlight visible?
+ bool m_highlight;
+ //! Time counter for highlight animation
+ float m_highlightTime;
+ //@{
+ //! Highlight rectangle points
+ Math::Point m_highlightP1;
+ Math::Point m_highlightP2;
+ //@}
+
+ //! Texture directory name
std::string m_texPath;
+ //! Default texture create params
Gfx::TextureCreateParams m_defaultTexParams;
+ //! Map of loaded textures (by name)
std::map<std::string, Gfx::Texture> m_texNameMap;
+ //! Reverse map of loaded textures (by texture)
std::map<Gfx::Texture, std::string> m_revTexNameMap;
+ //! Blacklist map of textures
+ /** Textures on this list were not successful in first loading,
+ * so are disabled for subsequent load calls. */
+ std::set<std::string> m_texBlacklist;
+ //! Mouse cursor definitions
Gfx::EngineMouse m_mice[Gfx::ENG_MOUSE_COUNT];
+ //! Texture with mouse cursors
Gfx::Texture m_miceTexture;
+ //! Size of mouse cursor
Math::Point m_mouseSize;
+ //! Type of mouse cursor
Gfx::EngineMouseType m_mouseType;
+ //! Position of mouse in interface coords
Math::Point m_mousePos;
+ //! Is mouse visible?
bool m_mouseVisible;
- //LPDIRECTDRAWSURFACE7 m_imageSurface;
- //DDSURFACEDESC2 m_imageDDSD;
- //WORD* m_imageCopy;
- //int m_imageDX;
- //int m_imageDY;
+ //! Last engine render state (-1 at the beginning of frame)
+ int m_lastState;
+ //! Last color set with render state
+ Gfx::Color m_lastColor;
+ //! Last texture names for 2 used texture stages
+ std::string m_lastTexture[2];
+ //! Last material
+ Gfx::Material m_lastMaterial;
};
}; // namespace Gfx
diff --git a/src/graphics/engine/lightman.h b/src/graphics/engine/lightman.h
index 8272125..52058c8 100644
--- a/src/graphics/engine/lightman.h
+++ b/src/graphics/engine/lightman.h
@@ -15,7 +15,10 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// lightman.h
+/**
+ * \file graphics/engine/lightman.h
+ * \brief Dynamic light manager - Gfx::CLightManager class
+ */
#pragma once
diff --git a/src/graphics/engine/lightning.cpp b/src/graphics/engine/lightning.cpp
index 4db5511..4ecdb3c 100644
--- a/src/graphics/engine/lightning.cpp
+++ b/src/graphics/engine/lightning.cpp
@@ -19,5 +19,71 @@
#include "graphics/engine/lightning.h"
+#include "common/logger.h"
-// TODO implementation
+
+Gfx::CLightning::CLightning(CInstanceManager* iMan, Gfx::CEngine* engine)
+{
+ GetLogger()->Info("CLightning::CLightning() stub!\n");
+ // TODO!
+}
+
+Gfx::CLightning::~CLightning()
+{
+ GetLogger()->Info("CLightning::~CLightning() stub!\n");
+ // TODO!
+}
+
+void Gfx::CLightning::Flush()
+{
+ GetLogger()->Info("CLightning::Flush() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CLightning::EventProcess(const Event &event)
+{
+ GetLogger()->Info("CLightning::EventProcess() stub!\n");
+ // TODO!
+ return true;
+}
+
+bool Gfx::CLightning::Create(float sleep, float delay, float magnetic)
+{
+ GetLogger()->Info("CLightning::Create() stub!\n");
+ // TODO!
+ return true;
+}
+
+bool Gfx::CLightning::GetStatus(float &sleep, float &delay, float &magnetic, float &progress)
+{
+ GetLogger()->Info("CLightning::GetStatus() stub!\n");
+ // TODO!
+ return true;
+}
+
+bool Gfx::CLightning::SetStatus(float sleep, float delay, float magnetic, float progress)
+{
+ GetLogger()->Info("CLightning::SetStatus() stub!\n");
+ // TODO!
+ return true;
+}
+
+void Gfx::CLightning::Draw()
+{
+ GetLogger()->Info("CLightning::Draw() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CLightning::EventFrame(const Event &event)
+{
+ GetLogger()->Info("CLightning::EventFrame() stub!\n");
+ // TODO!
+ return true;
+}
+
+CObject* Gfx::CLightning::SearchObject(Math::Vector pos)
+{
+ GetLogger()->Info("CLightning::SearchObject() stub!\n");
+ // TODO!
+ return nullptr;
+}
diff --git a/src/graphics/engine/lightning.h b/src/graphics/engine/lightning.h
index 957344c..3b4e2cf 100644
--- a/src/graphics/engine/lightning.h
+++ b/src/graphics/engine/lightning.h
@@ -15,7 +15,10 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// lightning.h (aka blitz.h)
+/**
+ * \file graphics/engine/lightning.h
+ * \brief Lightning rendering - Gfx::CLightning class (aka blitz)
+ */
#pragma once
@@ -73,7 +76,7 @@ protected:
float m_sleep;
float m_delay;
float m_magnetic;
- BlitzPhase m_phase;
+ Gfx::BlitzPhase m_phase;
float m_time;
float m_speed;
float m_progress;
diff --git a/src/graphics/engine/modelfile.h b/src/graphics/engine/modelfile.h
index 6a30487..fab190f 100644
--- a/src/graphics/engine/modelfile.h
+++ b/src/graphics/engine/modelfile.h
@@ -15,7 +15,10 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// modelfile.h (aka modfile.h)
+/**
+ * \file graphics/engine/modelfile.h
+ * \brief Model loading - Gfx::CModelFile class (aka modfile)
+ */
#include "graphics/engine/engine.h"
#include "graphics/core/vertex.h"
diff --git a/src/graphics/engine/particle.cpp b/src/graphics/engine/particle.cpp
index 84e2f9d..9a21fe0 100644
--- a/src/graphics/engine/particle.cpp
+++ b/src/graphics/engine/particle.cpp
@@ -19,5 +19,284 @@
#include "graphics/engine/particle.h"
+#include "common/logger.h"
-// TODO implementation
+
+Gfx::CParticle::CParticle(CInstanceManager* iMan, Gfx::CEngine* engine)
+{
+ GetLogger()->Info("CParticle::CParticle() stub!\n");
+ // TODO!
+}
+
+Gfx::CParticle::~CParticle()
+{
+ GetLogger()->Info("CParticle::~CParticle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetDevice(Gfx::CDevice* device)
+{
+ GetLogger()->Info("CParticle::SetDevice() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::FlushParticle()
+{
+ GetLogger()->Info("CParticle::FlushParticle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::FlushParticle(int sheet)
+{
+ GetLogger()->Info("CParticle::FlushParticle() stub!\n");
+ // TODO!
+}
+
+int Gfx::CParticle::CreateParticle(Math::Vector pos, Math::Vector speed, Math::Point dim,
+ Gfx::ParticleType type, float duration, float mass,
+ float windSensitivity, int sheet)
+{
+ GetLogger()->Info("CParticle::CreateParticle() stub!\n");
+ // TODO!
+ return 0;
+}
+
+int Gfx::CParticle::CreateFrag(Math::Vector pos, Math::Vector speed, Gfx::EngineTriangle *triangle,
+ Gfx::ParticleType type, float duration, float mass,
+ float windSensitivity, int sheet)
+{
+ GetLogger()->Info("CParticle::CreateFrag() stub!\n");
+ // TODO!
+ return 0;
+}
+
+int Gfx::CParticle::CreatePart(Math::Vector pos, Math::Vector speed, Gfx::ParticleType type,
+ float duration, float mass, float weight,
+ float windSensitivity, int sheet)
+{
+ GetLogger()->Info("CParticle::CreatePart() stub!\n");
+ // TODO!
+ return 0;
+}
+
+int Gfx::CParticle::CreateRay(Math::Vector pos, Math::Vector goal, Gfx::ParticleType type, Math::Point dim,
+ float duration, int sheet)
+{
+ GetLogger()->Info("CParticle::CreateRay() stub!\n");
+ // TODO!
+ return 0;
+}
+
+int Gfx::CParticle::CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, Gfx::ParticleType type,
+ float duration, float mass, float length, float width)
+{
+ GetLogger()->Info("CParticle::CreateTrack() stub!\n");
+ // TODO!
+ return 0;
+}
+
+void Gfx::CParticle::CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3,
+ const Math::Vector &p4, Gfx::ParticleType type)
+{
+ GetLogger()->Info("CParticle::CreateWheelTrace() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DeleteParticle(Gfx::ParticleType type)
+{
+ GetLogger()->Info("CParticle::DeleteParticle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DeleteParticle(int channel)
+{
+ GetLogger()->Info("CParticle::DeleteParticle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetObjectLink(int channel, CObject *object)
+{
+ GetLogger()->Info("CParticle::SetObjectLink() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetObjectFather(int channel, CObject *object)
+{
+ GetLogger()->Info("CParticle::SetObjectFather() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetPosition(int channel, Math::Vector pos)
+{
+ GetLogger()->Info("CParticle::SetPosition() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetDimension(int channel, Math::Point dim)
+{
+ GetLogger()->Info("CParticle::SetDimension() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetZoom(int channel, float zoom)
+{
+ GetLogger()->Info("CParticle::SetZoom() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetAngle(int channel, float angle)
+{
+ GetLogger()->Info("CParticle::SetAngle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetIntensity(int channel, float intensity)
+{
+ GetLogger()->Info("CParticle::SetIntensity() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, float angle, float intensity)
+{
+ GetLogger()->Info("CParticle::SetParam() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetPhase(int channel, Gfx::ParticlePhase phase, float duration)
+{
+ GetLogger()->Info("CParticle::SetPhase() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CParticle::GetPosition(int channel, Math::Vector &pos)
+{
+ GetLogger()->Info("CParticle::GetPosition() stub!\n");
+ // TODO!
+ return true;
+}
+
+Gfx::Color Gfx::CParticle::GetFogColor(Math::Vector pos)
+{
+ GetLogger()->Info("CParticle::GetFogColor() stub!\n");
+ // TODO!
+ return Gfx::Color();
+}
+
+void Gfx::CParticle::SetFrameUpdate(int sheet, bool update)
+{
+ GetLogger()->Info("CParticle::SetFrameUpdate() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::FrameParticle(float rTime)
+{
+ GetLogger()->Info("CParticle::FrameParticle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticle(int sheet)
+{
+ GetLogger()->Info("CParticle::DrawParticle() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CParticle::WriteWheelTrace(char *filename, int width, int height, Math::Vector dl, Math::Vector ur)
+{
+ GetLogger()->Info("CParticle::WriteWheelTrace() stub!\n");
+ // TODO!
+ return true;
+}
+
+void Gfx::CParticle::DeleteRank(int rank)
+{
+ GetLogger()->Info("CParticle::DeleteRank() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CParticle::CheckChannel(int &channel)
+{
+ GetLogger()->Info("CParticle::CheckChannel() stub!\n");
+ // TODO!
+ return true;
+}
+
+void Gfx::CParticle::DrawParticleTriangle(int i)
+{
+ GetLogger()->Info("CParticle::DrawParticleTriangle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticleNorm(int i)
+{
+ GetLogger()->Info("CParticle::DrawParticleNorm() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticleFlat(int i)
+{
+ GetLogger()->Info("CParticle::DrawParticleFlat() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticleFog(int i)
+{
+ GetLogger()->Info("CParticle::DrawParticleFog() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticleRay(int i)
+{
+ GetLogger()->Info("CParticle::DrawParticleRay() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticleSphere(int i)
+{
+ GetLogger()->Info("CParticle::DrawParticleSphere() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticleCylinder(int i)
+{
+ GetLogger()->Info("CParticle::DrawParticleCylinder() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticleWheel(int i)
+{
+ GetLogger()->Info("CParticle::DrawParticleWheel() stub!\n");
+ // TODO!
+}
+
+CObject* Gfx::CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos, Gfx::ParticleType type, CObject *father)
+{
+ GetLogger()->Info("CParticle::SearchObjectGun() stub!\n");
+ // TODO!
+ return nullptr;
+}
+
+CObject* Gfx::CParticle::SearchObjectRay(Math::Vector pos, Math::Vector goal, Gfx::ParticleType type, CObject *father)
+{
+ GetLogger()->Info("CParticle::SearchObjectRay() stub!\n");
+ // TODO!
+ return nullptr;
+}
+
+void Gfx::CParticle::Play(Sound sound, Math::Vector pos, float amplitude)
+{
+ GetLogger()->Info("CParticle::Play() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CParticle::TrackMove(int i, Math::Vector pos, float progress)
+{
+ GetLogger()->Info("CParticle::TrackMove() stub!\n");
+ // TODO!
+ return true;
+}
+
+void Gfx::CParticle::TrackDraw(int i, Gfx::ParticleType type)
+{
+ GetLogger()->Info("CParticle::TrackDraw() stub!\n");
+ // TODO!
+}
diff --git a/src/graphics/engine/particle.h b/src/graphics/engine/particle.h
index bd9741f..45396d2 100644
--- a/src/graphics/engine/particle.h
+++ b/src/graphics/engine/particle.h
@@ -15,7 +15,10 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// particle.h (aka particule.h)
+/**
+ * \file graphics/engine/particle.h
+ * \brief Particle rendering - Gfx::CParticle class (aka particule)
+ */
#pragma once
@@ -202,26 +205,26 @@ enum ParticlePhase
struct Particle
{
- char bUsed; // TRUE -> particle used
- char bRay; // TRUE -> ray with goal
- unsigned short uniqueStamp; // unique mark
+ char used; // TRUE -> particle used
+ char ray; // TRUE -> ray with goal
+ unsigned short uniqueStamp; // unique mark
short sheet; // sheet (0..n)
- ParticleType type; // type PARTI*
- ParticlePhase phase; // phase PARPH*
+ ParticleType type; // type PARTI*
+ ParticlePhase phase; // phase PARPH*
float mass; // mass of the particle (in rebounding)
float weight; // weight of the particle (for noise)
float duration; // length of life
- Math::Vector pos; // absolute position (relative if object links)
- Math::Vector goal; // goal position (if bRay)
- Math::Vector speed; // speed of displacement
+ Math::Vector pos; // absolute position (relative if object links)
+ Math::Vector goal; // goal position (if ray)
+ Math::Vector speed; // speed of displacement
float windSensitivity;
short bounce; // number of rebounds
- Math::Point dim; // dimensions of the rectangle
+ Math::Point dim; // dimensions of the rectangle
float zoom; // zoom (0..1)
float angle; // angle of rotation
float intensity; // intensity
- Math::Point texSup; // coordinated upper texture
- Math::Point texInf; // coordinated lower texture
+ Math::Point texSup; // coordinated upper texture
+ Math::Point texInf; // coordinated lower texture
float time; // age of the particle (0..n)
float phaseTime; // age at the beginning of phase
float testTime; // time since last test
@@ -233,22 +236,22 @@ struct Particle
struct Track
{
- char bUsed; // TRUE -> drag used
- char bDrawParticle;
+ char used; // TRUE -> drag used
+ char drawParticle;
float step; // duration of not
float last; // increase last not memorized
float intensity; // intensity at starting (0..1)
float width; // tail width
- int used; // number of positions in "pos"
- int head; // head to write index
- Math::Vector pos[MAXTRACKLEN];
+ int posUsed; // number of positions in "pos"
+ int head; // head to write index
+ Math::Vector pos[MAXTRACKLEN];
float len[MAXTRACKLEN];
};
struct WheelTrace
{
- ParticleType type; // type PARTI*
- Math::Vector pos[4]; // rectangle positions
+ ParticleType type; // type PARTI*
+ Math::Vector pos[4]; // rectangle positions
float startTime; // beginning of life
};
@@ -257,20 +260,29 @@ struct WheelTrace
class CParticle
{
public:
- CParticle(CInstanceManager* iMan, CEngine* engine);
+ CParticle(CInstanceManager* iMan, Gfx::CEngine* engine);
~CParticle();
- void SetGLDevice(CDevice device);
+ void SetDevice(Gfx::CDevice* device);
void FlushParticle();
void FlushParticle(int sheet);
- int CreateParticle(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0);
- int CreateFrag(Math::Vector pos, Math::Vector speed, Gfx::EngineTriangle *triangle, ParticleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0);
- int CreatePart(Math::Vector pos, Math::Vector speed, ParticleType type, float duration=1.0f, float mass=0.0f, float weight=0.0f, float windSensitivity=1.0f, int sheet=0);
- int CreateRay(Math::Vector pos, Math::Vector goal, ParticleType type, Math::Point dim, float duration=1.0f, int sheet=0);
- int CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticleType type, float duration=1.0f, float mass=0.0f, float length=10.0f, float width=1.0f);
- void CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3, const Math::Vector &p4, ParticleType type);
- void DeleteParticle(ParticleType type);
+ int CreateParticle(Math::Vector pos, Math::Vector speed, Math::Point dim,
+ Gfx::ParticleType type, float duration=1.0f, float mass=0.0f,
+ float windSensitivity=1.0f, int sheet=0);
+ int CreateFrag(Math::Vector pos, Math::Vector speed, Gfx::EngineTriangle *triangle,
+ Gfx::ParticleType type, float duration=1.0f, float mass=0.0f,
+ float windSensitivity=1.0f, int sheet=0);
+ int CreatePart(Math::Vector pos, Math::Vector speed, Gfx::ParticleType type,
+ float duration=1.0f, float mass=0.0f, float weight=0.0f,
+ float windSensitivity=1.0f, int sheet=0);
+ int CreateRay(Math::Vector pos, Math::Vector goal, Gfx::ParticleType type, Math::Point dim,
+ float duration=1.0f, int sheet=0);
+ int CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, Gfx::ParticleType type,
+ float duration=1.0f, float mass=0.0f, float length=10.0f, float width=1.0f);
+ void CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3,
+ const Math::Vector &p4, Gfx::ParticleType type);
+ void DeleteParticle(Gfx::ParticleType type);
void DeleteParticle(int channel);
void SetObjectLink(int channel, CObject *object);
void SetObjectFather(int channel, CObject *object);
@@ -280,12 +292,12 @@ public:
void SetAngle(int channel, float angle);
void SetIntensity(int channel, float intensity);
void SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, float angle, float intensity);
- void SetPhase(int channel, ParticlePhase phase, float duration);
+ void SetPhase(int channel, Gfx::ParticlePhase phase, float duration);
bool GetPosition(int channel, Math::Vector &pos);
- Gfx::Color RetFogColor(Math::Vector pos);
+ Gfx::Color GetFogColor(Math::Vector pos);
- void SetFrameUpdate(int sheet, bool bUpdate);
+ void SetFrameUpdate(int sheet, bool update);
void FrameParticle(float rTime);
void DrawParticle(int sheet);
@@ -302,29 +314,29 @@ protected:
void DrawParticleSphere(int i);
void DrawParticleCylinder(int i);
void DrawParticleWheel(int i);
- CObject* SearchObjectGun(Math::Vector old, Math::Vector pos, ParticleType type, CObject *father);
- CObject* SearchObjectRay(Math::Vector pos, Math::Vector goal, ParticleType type, CObject *father);
+ CObject* SearchObjectGun(Math::Vector old, Math::Vector pos, Gfx::ParticleType type, CObject *father);
+ CObject* SearchObjectRay(Math::Vector pos, Math::Vector goal, Gfx::ParticleType type, CObject *father);
void Play(Sound sound, Math::Vector pos, float amplitude);
bool TrackMove(int i, Math::Vector pos, float progress);
- void TrackDraw(int i, ParticleType type);
+ void TrackDraw(int i, Gfx::ParticleType type);
protected:
CInstanceManager* m_iMan;
- CEngine* m_engine;
- CDevice* m_pDevice;
- CRobotMain* m_main;
- CTerrain* m_terrain;
- CWater* m_water;
- CSound* m_sound;
+ Gfx::CEngine* m_engine;
+ Gfx::CDevice* m_device;
+ Gfx::CTerrain* m_terrain;
+ Gfx::CWater* m_water;
+ CRobotMain* m_main;
+ CSound* m_sound;
Gfx::Particle m_particule[MAXPARTICULE*MAXPARTITYPE];
Gfx::EngineTriangle m_triangle[MAXPARTICULE]; // triangle if PartiType == 0
- Track m_track[MAXTRACK];
+ Gfx::Track m_track[MAXTRACK];
int m_wheelTraceTotal;
int m_wheelTraceIndex;
- WheelTrace m_wheelTrace[MAXWHEELTRACE];
+ Gfx::WheelTrace m_wheelTrace[MAXWHEELTRACE];
int m_totalInterface[MAXPARTITYPE][SH_MAX];
- bool m_bFrameUpdate[SH_MAX];
+ bool m_frameUpdate[SH_MAX];
int m_fogTotal;
int m_fog[MAXPARTIFOG];
int m_uniqueStamp;
diff --git a/src/graphics/engine/planet.cpp b/src/graphics/engine/planet.cpp
index 4f1f614..022de66 100644
--- a/src/graphics/engine/planet.cpp
+++ b/src/graphics/engine/planet.cpp
@@ -19,5 +19,167 @@
#include "graphics/engine/planet.h"
+#include "common/iman.h"
+#include "graphics/core/device.h"
+#include "graphics/engine/engine.h"
-// TODO implementation
+
+const int PLANET_PREALLOCATE_COUNT = 10;
+
+
+Gfx::CPlanet::CPlanet(CInstanceManager* iMan, Gfx::CEngine* engine)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_PLANET, this);
+
+ m_planet[0].reserve(PLANET_PREALLOCATE_COUNT);
+ m_planet[1].reserve(PLANET_PREALLOCATE_COUNT);
+
+ m_engine = engine;
+ Flush();
+
+}
+
+Gfx::CPlanet::~CPlanet()
+{
+ m_iMan = nullptr;
+}
+
+void Gfx::CPlanet::Flush()
+{
+ for (int j = 0; j < 2; j++)
+ m_planet[j].clear();
+
+ m_planetExist = false;
+ m_mode = 0;
+ m_time = 0.0f;
+}
+
+bool Gfx::CPlanet::EventProcess(const Event &event)
+{
+ if (event.type == EVENT_FRAME)
+ return EventFrame(event);
+
+ return true;
+}
+
+bool Gfx::CPlanet::EventFrame(const Event &event)
+{
+ if (m_engine->GetPause()) return true;
+
+ m_time += event.rTime;
+
+ for (int i = 0; i < static_cast<int>( m_planet[m_mode].size() ); i++)
+ {
+ float a = m_time*m_planet[m_mode][i].speed;
+ if (a < 0.0f)
+ a += Math::PI*1000.0f;
+
+ m_planet[m_mode][i].angle.x = a+m_planet[m_mode][i].start.x;
+ m_planet[m_mode][i].angle.y = sinf(a)*sinf(m_planet[m_mode][i].dir)+m_planet[m_mode][i].start.y;
+ }
+
+ return true;
+}
+
+void Gfx::CPlanet::LoadTexture()
+{
+ for (int j = 0; j < 2; j++)
+ {
+ for (int i = 0; i < static_cast<int>( m_planet[j].size() ); i++)
+ {
+ m_engine->LoadTexture(m_planet[j][i].name);
+ }
+ }
+}
+
+void Gfx::CPlanet::Draw()
+{
+ Gfx::CDevice* device = m_engine->GetDevice();
+ float eyeDirH = m_engine->GetEyeDirH();
+ float eyeDirV = m_engine->GetEyeDirV();
+
+ Math::Vector n = Math::Vector(0.0f, 0.0f, -1.0f); // normal
+ float dp = 0.5f/256.0f;
+
+ for (int i = 0; i < static_cast<int>( m_planet[m_mode].size() ); i++)
+ {
+ m_engine->SetTexture(m_planet[m_mode][i].name);
+
+ if (m_planet[m_mode][i].transparent)
+ m_engine->SetState(Gfx::ENG_RSTATE_WRAP | Gfx::ENG_RSTATE_ALPHA);
+ else
+ m_engine->SetState(Gfx::ENG_RSTATE_WRAP | Gfx::ENG_RSTATE_TTEXTURE_BLACK);
+
+ Math::Point p1, p2;
+
+ float a = eyeDirH + m_planet[m_mode][i].angle.x;
+ p1.x = Math::Mod(a, Math::PI*2.0f)-0.5f;
+
+ a = eyeDirV + m_planet[m_mode][i].angle.y;
+ p1.y = 0.4f+(Math::Mod(a+Math::PI, Math::PI*2.0f)-Math::PI)*(2.0f/Math::PI);
+
+ p1.x -= m_planet[m_mode][i].dim/2.0f*0.75f;
+ p1.y -= m_planet[m_mode][i].dim/2.0f;
+ p2.x = p1.x+m_planet[m_mode][i].dim*0.75f;
+ p2.y = p1.y+m_planet[m_mode][i].dim;
+
+ float u1 = m_planet[m_mode][i].uv1.x + dp;
+ float v1 = m_planet[m_mode][i].uv1.y + dp;
+ float u2 = m_planet[m_mode][i].uv2.x - dp;
+ float v2 = m_planet[m_mode][i].uv2.y - dp;
+
+ Gfx::Vertex quad[4] =
+ {
+ Gfx::Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(u1, v2)),
+ Gfx::Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(u1, v1)),
+ Gfx::Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(u2, v2)),
+ Gfx::Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(u2, v1))
+ };
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4);
+ m_engine->AddStatisticTriangle(2);
+ }
+}
+
+void Gfx::CPlanet::Create(int mode, Math::Point start, float dim, float speed,
+ float dir, const std::string& name, Math::Point uv1, Math::Point uv2)
+{
+ if (mode < 0) mode = 0;
+ if (mode > 1) mode = 1;
+
+ Gfx::Planet planet;
+
+ planet.start = start;
+ planet.angle = start;
+ planet.dim = dim;
+ planet.speed = speed;
+ planet.dir = dir;
+
+ planet.name = name;
+ planet.uv1 = uv1;
+ planet.uv2 = uv2;
+
+ planet.transparent = planet.name.find("planet") != std::string::npos;
+
+ m_planet[mode].push_back(planet);
+
+ m_planetExist = true;
+}
+
+bool Gfx::CPlanet::PlanetExist()
+{
+ return m_planetExist;
+}
+
+void Gfx::CPlanet::SetMode(int mode)
+{
+ if (mode < 0) mode = 0;
+ if (mode > 1) mode = 1;
+ m_mode = mode;
+}
+
+int Gfx::CPlanet::GetMode()
+{
+ return m_mode;
+}
diff --git a/src/graphics/engine/planet.h b/src/graphics/engine/planet.h
index 264d05c..54d8b55 100644
--- a/src/graphics/engine/planet.h
+++ b/src/graphics/engine/planet.h
@@ -15,13 +15,18 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// planet.h
+/**
+ * \file graphics/engine/planet.h
+ * \brief Planet rendering - Gfx::CPlanet class
+ */
#pragma once
#include "common/event.h"
#include "math/point.h"
+#include <vector>
+
class CInstanceManager;
@@ -30,51 +35,69 @@ namespace Gfx {
class CEngine;
-
-const short MAXPLANET = 10;
-
struct Planet
{
- char bUsed; // TRUE -> planet exists
- Math::Point start; // initial position in degrees
- Math::Point angle; // current position in degrees
- float dim; // dimensions (0..1)
- float speed; // speed
- float dir; // direction in the sky
- char name[20]; // name of the texture
- Math::Point uv1, uv2; // texture mapping
- char bTGA; // texture .TGA
+ //! Initial position in degrees
+ Math::Point start;
+ //! Current position in degrees
+ Math::Point angle;
+ //! Dimensions (0..1)
+ float dim;
+ //! Speed
+ float speed;
+ //! Direction in the sky
+ float dir;
+ //! Name of the texture
+ std::string name;
+ //! Texture mapping
+ Math::Point uv1, uv2;
+ //! Transparent texture
+ bool transparent;
+
+ Planet()
+ {
+ dim = speed = dir = 0.0f;
+ transparent = false;
+ }
};
-
-
-
-class CPlanet {
+class CPlanet
+{
public:
- CPlanet(CInstanceManager* iMan, CEngine* engine);
+ CPlanet(CInstanceManager* iMan, Gfx::CEngine* engine);
~CPlanet();
+ //! Removes all the planets
void Flush();
+ //! Management of an event
bool EventProcess(const Event &event);
- bool Create(int mode, Math::Point start, float dim, float speed, float dir, char *name, Math::Point uv1, Math::Point uv2);
+ //! Creates a new planet
+ void Create(int mode, Math::Point start, float dim, float speed, float dir,
+ const std::string& name, Math::Point uv1, Math::Point uv2);
+ //! Indicates if there is at least one planet
bool PlanetExist();
+ //! Load all the textures for the planets
void LoadTexture();
+ //! Draws all the planets
void Draw();
+ //@{
+ //! Choice of mode
void SetMode(int mode);
- int RetMode();
+ int GetMode();
+ //@}
protected:
+ //! Makes the planets evolve
bool EventFrame(const Event &event);
protected:
- CInstanceManager* m_iMan;
- CEngine* m_engine;
+ CInstanceManager* m_iMan;
+ Gfx::CEngine* m_engine;
- float m_time;
- int m_mode;
- Planet m_planet[2][MAXPLANET];
- bool m_bPlanetExist;
+ float m_time;
+ int m_mode;
+ std::vector<Gfx::Planet> m_planet[2];
+ bool m_planetExist;
};
-
}; // namespace Gfx
diff --git a/src/graphics/engine/pyro.cpp b/src/graphics/engine/pyro.cpp
index e699db2..327befa 100644
--- a/src/graphics/engine/pyro.cpp
+++ b/src/graphics/engine/pyro.cpp
@@ -19,5 +19,161 @@
#include "graphics/engine/pyro.h"
+#include "common/logger.h"
-// TODO implementation
+
+Gfx::CPyro::CPyro(CInstanceManager* iMan)
+{
+ GetLogger()->Info("CParticle::CPyro() stub!\n");
+ // TODO!
+}
+
+Gfx::CPyro::~CPyro()
+{
+ GetLogger()->Info("CPyro::~CPyro() stub!");
+ // TODO!
+}
+
+void Gfx::CPyro::DeleteObject(bool all)
+{
+ GetLogger()->Info("CPyro::DeleteObject() stub!");
+ // TODO!
+}
+
+bool Gfx::CPyro::Create(Gfx::PyroType type, CObject* pObj, float force)
+{
+ GetLogger()->Info("CPyro::Create() stub!");
+ // TODO!
+ return true;
+}
+
+bool Gfx::CPyro::EventProcess(const Event &event)
+{
+ GetLogger()->Info("CPyro::EventProcess() stub!\n");
+ // TODO!
+ return true;
+}
+
+Error Gfx::CPyro::IsEnded()
+{
+ GetLogger()->Info("CPyro::IsEnded() stub!\n");
+ // TODO!
+ return ERR_OK;
+}
+
+void Gfx::CPyro::CutObjectLink(CObject* pObj)
+{
+ GetLogger()->Info("CPyro::CutObjectLink() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::DisplayError(PyroType type, CObject* pObj)
+{
+ GetLogger()->Info("CPyro::DisplayError() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CPyro::CreateLight(Math::Vector pos, float height)
+{
+ GetLogger()->Info("CPyro::CreateLight() stub!\n");
+ // TODO!
+ return true;
+}
+
+void Gfx::CPyro::DeleteObject(bool primary, bool secondary)
+{
+ GetLogger()->Info("CPyro::DeleteObject() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::CreateTriangle(CObject* pObj, ObjectType oType, int part)
+{
+ GetLogger()->Info("CPyro::CreateTriangle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::ExploStart()
+{
+ GetLogger()->Info("CPyro::ExploStart() stub!\n");
+ // TODO!
+}
+void Gfx::CPyro::ExploTerminate()
+{
+ GetLogger()->Info("CPyro::ExploTerminate() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::BurnStart()
+{
+ GetLogger()->Info("CPyro::BurnStart() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::BurnAddPart(int part, Math::Vector pos, Math::Vector angle)
+{
+ GetLogger()->Info("CPyro::BurnAddPart() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::BurnProgress()
+{
+ GetLogger()->Info("CPyro::BurnProgress() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CPyro::BurnIsKeepPart(int part)
+{
+ GetLogger()->Info("CPyro::BurnIsKeepPart() stub!\n");
+ // TODO!
+ return true;
+}
+
+void Gfx::CPyro::BurnTerminate()
+{
+ GetLogger()->Info("CPyro::BurnTerminate() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::FallStart()
+{
+ GetLogger()->Info("CPyro::FallStart() stub!\n");
+ // TODO!
+}
+
+CObject* Gfx::CPyro::FallSearchBeeExplo()
+{
+ GetLogger()->Info("CPyro::FallSearchBeeExplo() stub!\n");
+ // TODO!
+ return nullptr;
+}
+
+void Gfx::CPyro::FallProgress(float rTime)
+{
+ GetLogger()->Info("CPyro::FallProgress() stub!\n");
+ // TODO!
+}
+
+Error Gfx::CPyro::FallIsEnded()
+{
+ GetLogger()->Info("CPyro::FallIsEnded() stub!\n");
+ // TODO!
+ return ERR_OK;
+}
+
+void Gfx::CPyro::LightOperFlush()
+{
+ GetLogger()->Info("CPyro::LightOperFlush() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::LightOperAdd(float progress, float intensity, float r, float g, float b)
+{
+ GetLogger()->Info("CPyro::LightOperAdd() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::LightOperFrame(float rTime)
+{
+ GetLogger()->Info("CPyro::LightOperFrame() stub!\n");
+ // TODO!
+}
diff --git a/src/graphics/engine/pyro.h b/src/graphics/engine/pyro.h
index d663ca5..768abf8 100644
--- a/src/graphics/engine/pyro.h
+++ b/src/graphics/engine/pyro.h
@@ -15,15 +15,16 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// pyro.h
+/**
+ * \file graphics/engine/pyro.h
+ * \brief Fire effect rendering - Gfx::CPyro class
+ */
#pragma once
#include "common/misc.h"
#include "graphics/engine/engine.h"
-//#include "object/object.h"
-// TEMPORARILY!
-enum ObjectType {};
+#include "object/object.h"
class CInstanceManager;
@@ -90,13 +91,14 @@ struct PyroLightOper
-class CPyro {
+class CPyro
+{
public:
CPyro(CInstanceManager* iMan);
~CPyro();
- void DeleteObject(bool bAll=false);
- bool Create(PyroType type, CObject* pObj, float force=1.0f);
+ void DeleteObject(bool all=false);
+ bool Create(Gfx::PyroType type, CObject* pObj, float force=1.0f);
bool EventProcess(const Event &event);
Error IsEnded();
void CutObjectLink(CObject* pObj);
@@ -104,7 +106,7 @@ public:
protected:
void DisplayError(PyroType type, CObject* pObj);
bool CreateLight(Math::Vector pos, float height);
- void DeleteObject(bool bPrimary, bool bSecondary);
+ void DeleteObject(bool primary, bool secondary);
void CreateTriangle(CObject* pObj, ObjectType oType, int part);
@@ -127,21 +129,21 @@ protected:
void LightOperFrame(float rTime);
protected:
- CInstanceManager* m_iMan;
- CEngine* m_engine;
- CTerrain* m_terrain;
- CCamera* m_camera;
- CParticle* m_particule;
- CLight* m_light;
- CObject* m_object;
- CDisplayText* m_displayText;
- CRobotMain* m_main;
- CSound* m_sound;
-
- Math::Vector m_pos; // center of the effect
- Math::Vector m_posPower; // center of the battery
- bool m_bPower; // battery exists?
- PyroType m_type;
+ CInstanceManager* m_iMan;
+ Gfx::CEngine* m_engine;
+ Gfx::CTerrain* m_terrain;
+ Gfx::CCamera* m_camera;
+ Gfx::CParticle* m_particule;
+ Gfx::CLightManager* m_lightMan;
+ CObject* m_object;
+ CDisplayText* m_displayText;
+ CRobotMain* m_main;
+ CSound* m_sound;
+
+ Math::Vector m_pos; // center of the effect
+ Math::Vector m_posPower; // center of the battery
+ bool m_power; // battery exists?
+ Gfx::PyroType m_type;
float m_force;
float m_size;
float m_progress;
@@ -153,22 +155,22 @@ protected:
int m_lightRank;
int m_lightOperTotal;
- PyroLightOper m_lightOper[10];
+ Gfx::PyroLightOper m_lightOper[10];
float m_lightHeight;
ObjectType m_burnType;
int m_burnPartTotal;
- PyroBurnPart m_burnPart[10];
+ Gfx::PyroBurnPart m_burnPart[10];
int m_burnKeepPart[10];
float m_burnFall;
float m_fallFloor;
float m_fallSpeed;
float m_fallBulletTime;
- bool m_bFallEnding;
+ bool m_fallEnding;
int m_crashSphereUsed; // number of spheres used
- Math::Vector m_crashSpherePos[50];
+ Math::Vector m_crashSpherePos[50];
float m_crashSphereRadius[50];
};
diff --git a/src/graphics/engine/terrain.cpp b/src/graphics/engine/terrain.cpp
index c489321..6d4fcd3 100644
--- a/src/graphics/engine/terrain.cpp
+++ b/src/graphics/engine/terrain.cpp
@@ -19,5 +19,1805 @@
#include "graphics/engine/terrain.h"
+#include "app/app.h"
+#include "common/iman.h"
+#include "common/image.h"
+#include "common/logger.h"
+#include "graphics/engine/engine.h"
+#include "graphics/engine/water.h"
+#include "math/geometry.h"
-// TODO implementation
+#include <sstream>
+
+#include <SDL/SDL.h>
+
+const int LEVEL_MAT_PREALLOCATE_COUNT = 101;
+const int FLYING_LIMIT_PREALLOCATE_COUNT = 10;
+const int BUILDING_LEVEL_PREALLOCATE_COUNT = 101;
+
+
+Gfx::CTerrain::CTerrain(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_TERRAIN, this);
+
+ m_engine = static_cast<Gfx::CEngine*>( m_iMan->SearchInstance(CLASS_ENGINE) );
+ m_water = static_cast<Gfx::CWater*>( m_iMan->SearchInstance(CLASS_WATER) );
+
+ m_mosaic = 20;
+ m_brick = 1 << 4;
+ m_size = 10.0f;
+ m_vision = 200.0f;
+ m_scaleMapping = 0.01f;
+ m_scaleRelief = 1.0f;
+ m_subdivMapping = 1;
+ m_depth = 2;
+ m_levelMatMax = 0;
+ m_multiText = true;
+ m_levelText = false;
+ m_wind = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_defHardness = 0.5f;
+
+ m_levelMat.reserve(LEVEL_MAT_PREALLOCATE_COUNT);
+ m_flyingLimits.reserve(FLYING_LIMIT_PREALLOCATE_COUNT);
+ m_buildingLevels.reserve(BUILDING_LEVEL_PREALLOCATE_COUNT);
+}
+
+Gfx::CTerrain::~CTerrain()
+{
+}
+
+/**
+ The terrain is composed of mosaics, themselves composed of bricks.
+ Each brick is composed of two triangles.
+ mosaic: number of mosaics along the axes X and Z
+ brick: number of bricks (power of 2)
+ size: size of a brick along the axes X and Z
+ vision: vision before a change of resolution
+ scaleMapping: scale textures for mapping
+
+\verbatim
+ ^ z
+ | <---> brick*size
+ +---+---+---+---+
+ | | | |_|_| mosaic = 4
+ | | | | | | brick = 2 (brickP2=1)
+ +---+---+---+---+
+ |\ \| | | |
+ |\ \| | | |
+ +---+---o---+---+---> x
+ | | | | |
+ | | | | |
+ +---+---+---+---+
+ | | | | | The land is viewed from above here.
+ | | | | |
+ +---+---+---+---+
+ <---------------> mosaic*brick*size
+\endverbatim */
+bool Gfx::CTerrain::Generate(int mosaic, int brickPow2, float size, float vision,
+ int depth, float hardness)
+{
+ m_mosaic = mosaic;
+ m_brick = 1 << brickPow2;
+ m_size = size;
+ m_vision = vision;
+ m_depth = depth;
+ m_defHardness = hardness;
+
+ m_engine->SetTerrainVision(vision);
+
+ m_multiText = true;
+ m_levelText = false;
+ m_scaleMapping = 1.0f / (m_brick*m_size);
+ m_subdivMapping = 1;
+
+ int dim = 0;
+
+ dim = (m_mosaic*m_brick+1)*(m_mosaic*m_brick+1);
+ std::vector<float>(dim).swap(m_relief);
+
+ dim = m_mosaic*m_subdivMapping*m_mosaic*m_subdivMapping;
+ std::vector<int>(dim).swap(m_texture);
+
+ dim = m_mosaic*m_mosaic;
+ std::vector<int>(dim).swap(m_objRank);
+
+ return true;
+}
+
+
+int Gfx::CTerrain::GetMosaic()
+{
+ return m_mosaic;
+}
+
+int Gfx::CTerrain::GetBrick()
+{
+ return m_brick;
+}
+
+float Gfx::CTerrain::GetSize()
+{
+ return m_size;
+}
+
+float Gfx::CTerrain::GetScaleRelief()
+{
+ return m_scaleRelief;
+}
+
+bool Gfx::CTerrain::InitTextures(const std::string& baseName, int* table, int dx, int dy)
+{
+ m_levelText = false;
+ m_texBaseName = baseName;
+ size_t pos = baseName.find('.');
+ if (pos == baseName.npos)
+ {
+ m_texBaseExt = ".png";
+ }
+ else
+ {
+ m_texBaseName = m_texBaseName.substr(0, pos);
+ m_texBaseExt = m_texBaseName.substr(pos);
+ }
+
+ for (int y = 0; y < m_mosaic*m_subdivMapping; y++)
+ {
+ for (int x = 0; x < m_mosaic*m_subdivMapping; x++)
+ {
+ m_texture[x+y*m_mosaic] = table[(x%dx)+(y%dy)*dx];
+ }
+ }
+ return true;
+}
+
+
+void Gfx::CTerrain::LevelFlush()
+{
+ m_levelMat.clear();
+ m_levelMatMax = 0;
+ m_levelID = 1000;
+ LevelCloseTable();
+}
+
+void Gfx::CTerrain::LevelMaterial(int id, std::string& baseName, float u, float v,
+ int up, int right, int down, int left,
+ float hardness)
+{
+ LevelOpenTable();
+
+ if (id == 0)
+ id = m_levelID++; // puts an ID internal standard
+
+ Gfx::TerrainMaterial tm;
+ tm.texName = baseName;
+ tm.id = id;
+ tm.u = u;
+ tm.v = v;
+ tm.mat[0] = up;
+ tm.mat[1] = right;
+ tm.mat[2] = down;
+ tm.mat[3] = left;
+ tm.hardness = hardness;
+
+ m_levelMat.push_back(tm);
+
+ if (m_levelMatMax < up+1 ) m_levelMatMax = up+1;
+ if (m_levelMatMax < right+1) m_levelMatMax = right+1;
+ if (m_levelMatMax < down+1 ) m_levelMatMax = down+1;
+ if (m_levelMatMax < left+1 ) m_levelMatMax = left+1;
+
+ m_levelText = true;
+ m_subdivMapping = 4;
+}
+
+
+/**
+ The size of the image must be dimension dx and dy with dx=dy=(mosaic*brick)+1.
+ The image must be 24 bits/pixel
+
+ Converts coordinated image (x;y) -> world (x;-;z) :
+ Wx = 5*Ix-400
+ Wz = -(5*Iy-400)
+
+ Converts coordinated world (x;-;z) -> image (x;y) :
+ Ix = (400+Wx)/5
+ Iy = (400-Wz)/5 */
+bool Gfx::CTerrain::ResFromPNG(const std::string& fileName)
+{
+ CImage img;
+ if (! img.Load(CApplication::GetInstance().GetDataFilePath(m_engine->GetTextureDir(), fileName)))
+ return false;
+
+ ImageData *data = img.GetData();
+
+ int size = (m_mosaic*m_brick)+1;
+
+ m_resources.clear();
+
+ std::vector<unsigned char>(3*size*size).swap(m_resources);
+
+ if ( (data->surface->w != size) || (data->surface->h != size) ||
+ (data->surface->format->BytesPerPixel != 3) )
+ return false;
+
+ // Assuming the data format is compatible
+ memcpy(&m_resources[0], data->surface->pixels, 3*size*size);
+
+ return true;
+}
+
+Gfx::TerrainRes Gfx::CTerrain::GetResource(const Math::Vector &p)
+{
+ if (m_resources.empty())
+ return Gfx::TR_NULL;
+
+ int x = static_cast<int>((p.x + (m_mosaic*m_brick*m_size)/2.0f)/m_size);
+ int y = static_cast<int>((p.z + (m_mosaic*m_brick*m_size)/2.0f)/m_size);
+
+ if ( x < 0 || x > m_mosaic*m_brick ||
+ y < 0 || y > m_mosaic*m_brick )
+ return Gfx::TR_NULL;
+
+ int size = (m_mosaic*m_brick)+1;
+
+ int resR = m_resources[3*x+3*size*(size-y-1)];
+ int resG = m_resources[3*x+3*size*(size-y-1)+1];
+ int resB = m_resources[3*x+3*size*(size-y-1)+2];
+
+ if (resR == 255 && resG == 0 && resB == 0) return Gfx::TR_STONE;
+ if (resR == 255 && resG == 255 && resB == 0) return Gfx::TR_URANIUM;
+ if (resR == 0 && resG == 255 && resB == 0) return Gfx::TR_POWER;
+
+ // TODO key res values
+ //if (ress == 24) return Gfx::TR_KEY_A; // ~green?
+ //if (ress == 25) return Gfx::TR_KEY_B; // ~green?
+ //if (ress == 26) return Gfx::TR_KEY_C; // ~green?
+ //if (ress == 27) return Gfx::TR_KEY_D; // ~green?
+
+ return TR_NULL;
+}
+
+void Gfx::CTerrain::FlushRelief()
+{
+ m_relief.clear();
+}
+
+/**
+ The size of the image must be dimension dx and dy with dx=dy=(mosaic*brick)+1.
+ The image must be 24 bits/pixel, but gray scale:
+ white = ground (y=0)
+ black = mountain (y=255*scaleRelief)
+
+ Converts coordinated image(x;y) -> world (x;-;z) :
+ Wx = 5*Ix-400
+ Wz = -(5*Iy-400)
+
+ Converts coordinated world (x;-;z) -> image (x;y) :
+ Ix = (400+Wx)/5
+ Iy = (400-Wz)/5 */
+bool Gfx::CTerrain::ReliefFromPNG(const std::string &fileName, float scaleRelief,
+ bool adjustBorder)
+{
+ m_scaleRelief = scaleRelief;
+
+ CImage img;
+ if (! img.Load(CApplication::GetInstance().GetDataFilePath(m_engine->GetTextureDir(), fileName)))
+ return false;
+
+ ImageData *data = img.GetData();
+
+ int size = (m_mosaic*m_brick)+1;
+
+ if ( (data->surface->w != size) || (data->surface->h != size) ||
+ (data->surface->format->BytesPerPixel != 3) )
+ return false;
+
+ unsigned char* pixels = static_cast<unsigned char*>(data->surface->pixels);
+
+ float limit = 0.9f;
+ for (int y = 0; y < size; y++)
+ {
+ for (int x = 0; x < size; x++)
+ {
+ float level = (255 - pixels[3*x+3*size*(size-y-1)]) * scaleRelief;
+
+ float dist = Math::Max(fabs(static_cast<float>(x-size/2)),
+ fabs(static_cast<float>(y-size/2)));
+ dist = dist/ static_cast<float>(size / 2);
+ if (dist > limit && adjustBorder)
+ {
+ dist = (dist-limit)/(1.0f-limit); // 0..1
+ if (dist > 1.0f) dist = 1.0f;
+ float border = 300.0f+Math::Rand()*20.0f;
+ level = level+dist*(border-level);
+ }
+
+ m_relief[x+y*size] = level;
+ }
+ }
+
+ return true;
+}
+
+bool Gfx::CTerrain::ReliefAddDot(Math::Vector pos, float scaleRelief)
+{
+ float dim = (m_mosaic*m_brick*m_size)/2.0f;
+ int size = (m_mosaic*m_brick)+1;
+
+ pos.x = (pos.x+dim)/m_size;
+ pos.z = (pos.z+dim)/m_size;
+
+ int x = static_cast<int>(pos.x);
+ int y = static_cast<int>(pos.z);
+
+ if ( x < 0 || x >= size ||
+ y < 0 || y >= size ) return false;
+
+ if (m_relief[x+y*size] < pos.y*scaleRelief)
+ m_relief[x+y*size] = pos.y*scaleRelief;
+
+ return true;
+}
+
+void Gfx::CTerrain::LimitPos(Math::Vector &pos)
+{
+// TODO: #if _TEEN
+// dim = (m_mosaic*m_brick*m_size)/2.0f*0.98f;
+
+ float dim = (m_mosaic*m_brick*m_size)/2.0f*0.92f;
+
+ if (pos.x < -dim) pos.x = -dim;
+ if (pos.x > dim) pos.x = dim;
+ if (pos.z < -dim) pos.z = -dim;
+ if (pos.z > dim) pos.z = dim;
+}
+
+void Gfx::CTerrain::AdjustRelief()
+{
+ if (m_depth == 1) return;
+
+ int ii = m_mosaic*m_brick+1;
+ int b = 1 << (m_depth-1);
+
+ for (int y = 0; y < m_mosaic*m_brick; y += b)
+ {
+ for (int x = 0; x < m_mosaic*m_brick; x += b)
+ {
+ int xx = 0;
+ int yy = 0;
+ if ((y+yy)%m_brick == 0)
+ {
+ float level1 = m_relief[(x+0)+(y+yy)*ii];
+ float level2 = m_relief[(x+b)+(y+yy)*ii];
+ for (xx = 1; xx < b; xx++)
+ {
+ m_relief[(x+xx)+(y+yy)*ii] = ((level2-level1)/b)*xx+level1;
+ }
+ }
+
+ yy = b;
+ if ((y+yy)%m_brick == 0)
+ {
+ float level1 = m_relief[(x+0)+(y+yy)*ii];
+ float level2 = m_relief[(x+b)+(y+yy)*ii];
+ for (xx = 1; xx < b; xx++)
+ {
+ m_relief[(x+xx)+(y+yy)*ii] = ((level2-level1)/b)*xx+level1;
+ }
+ }
+
+ xx = 0;
+ if ((x+xx)%m_brick == 0)
+ {
+ float level1 = m_relief[(x+xx)+(y+0)*ii];
+ float level2 = m_relief[(x+xx)+(y+b)*ii];
+ for (yy = 1; yy < b; yy++)
+ {
+ m_relief[(x+xx)+(y+yy)*ii] = ((level2-level1)/b)*yy+level1;
+ }
+ }
+
+ xx = b;
+ if ((x+xx)%m_brick == 0)
+ {
+ float level1 = m_relief[(x+xx)+(y+0)*ii];
+ float level2 = m_relief[(x+xx)+(y+b)*ii];
+ for (yy = 1; yy < b; yy++)
+ {
+ m_relief[(x+xx)+(y+yy)*ii] = ((level2-level1)/b)*yy+level1;
+ }
+ }
+ }
+ }
+}
+
+Math::Vector Gfx::CTerrain::GetVector(int x, int y)
+{
+ Math::Vector p;
+ p.x = x*m_size - (m_mosaic*m_brick*m_size)/2;
+ p.z = y*m_size - (m_mosaic*m_brick*m_size)/2;
+
+ if ( !m_relief.empty() &&
+ x >= 0 && x <= m_mosaic*m_brick &&
+ y >= 0 && y <= m_mosaic*m_brick )
+ {
+ p.y = m_relief[x+y*(m_mosaic*m_brick+1)];
+ }
+ else
+ {
+ p.y = 0.0f;
+ }
+
+ return p;
+}
+
+/** Calculates a normal soft, taking into account the six adjacent triangles:
+
+\verbatim
+ ^ y
+ |
+ b---c---+
+ |\ |\ |
+ | \| \|
+ a---o---d
+ |\ |\ |
+ | \| \|
+ +---f---e--> x
+\endverbatim */
+Gfx::VertexTex2 Gfx::CTerrain::GetVertex(int x, int y, int step)
+{
+ Gfx::VertexTex2 v;
+
+ Math::Vector o = GetVector(x, y);
+ v.coord = o;
+
+ Math::Vector a = GetVector(x-step, y );
+ Math::Vector b = GetVector(x-step, y+step);
+ Math::Vector c = GetVector(x, y+step);
+ Math::Vector d = GetVector(x+step, y );
+ Math::Vector e = GetVector(x+step, y-step);
+ Math::Vector f = GetVector(x, y-step);
+
+ Math::Vector s(0.0f, 0.0f, 0.0f);
+
+ if (x-step >= 0 && y+step <= m_mosaic*m_brick+1)
+ {
+ s += Math::NormalToPlane(b,a,o);
+ s += Math::NormalToPlane(c,b,o);
+ }
+
+ if (x+step <= m_mosaic*m_brick+1 && y+step <= m_mosaic*m_brick+1)
+ s += Math::NormalToPlane(d,c,o);
+
+ if (x+step <= m_mosaic*m_brick+1 && y-step >= 0)
+ {
+ s += Math::NormalToPlane(e,d,o);
+ s += Math::NormalToPlane(f,e,o);
+ }
+
+ if (x-step >= 0 && y-step >= 0)
+ s += Math::NormalToPlane(a,f,o);
+
+ s = Normalize(s);
+ v.normal = s;
+
+ if (m_multiText)
+ {
+ int brick = m_brick/m_subdivMapping;
+ Math::Vector oo = GetVector((x/brick)*brick, (y/brick)*brick);
+ o = GetVector(x, y);
+ v.texCoord.x = (o.x-oo.x)*m_scaleMapping*m_subdivMapping;
+ v.texCoord.y = 1.0f - (o.z-oo.z)*m_scaleMapping*m_subdivMapping;
+ }
+ else
+ {
+ v.texCoord.x = o.x*m_scaleMapping;
+ v.texCoord.y = o.z*m_scaleMapping;
+ }
+
+ return v;
+}
+
+/** The origin of mosaic is its center.
+\verbatim
+ ^ z
+ |
+ | 2---4---6--
+ | |\ |\ |\
+ | | \| \|
+ | 1---3---5--- ...
+ |
+ +-------------------> x
+\endverbatim */
+bool Gfx::CTerrain::CreateMosaic(int ox, int oy, int step, int objRank,
+ const Gfx::Material &mat,
+ float min, float max)
+{
+ std::string texName1;
+ std::string texName2;
+
+ if ( step == 1 && m_engine->GetGroundSpot() )
+ {
+ int i = (ox/5) + (oy/5)*(m_mosaic/5);
+ std::stringstream s;
+ s << "shadow";
+ s.width(2);
+ s.fill('0');
+ s << i;
+ s << ".png";
+ texName2 = s.str();
+ }
+
+ int brick = m_brick/m_subdivMapping;
+
+ Gfx::VertexTex2 o = GetVertex(ox*m_brick+m_brick/2, oy*m_brick+m_brick/2, step);
+ int total = ((brick/step)+1)*2;
+
+ float pixel = 1.0f/256.0f; // 1 pixel cover (*)
+ float dp = 1.0f/512.0f;
+
+ Math::Point uv;
+
+ for (int my = 0; my < m_subdivMapping; my++)
+ {
+ for (int mx = 0; mx < m_subdivMapping; mx++)
+ {
+ if (m_levelText)
+ {
+ int xx = ox*m_brick + mx*(m_brick/m_subdivMapping);
+ int yy = oy*m_brick + my*(m_brick/m_subdivMapping);
+ LevelTextureName(xx, yy, texName1, uv);
+ }
+ else
+ {
+ int i = (ox*m_subdivMapping+mx)+(oy*m_subdivMapping+my)*m_mosaic;
+ std::stringstream s;
+ s << m_texBaseName;
+ s.width(3);
+ s.fill('0');
+ s << m_texture[i];
+ s << m_texBaseExt;
+ texName1 = s.str();
+ }
+
+ for (int y = 0; y < brick; y += step)
+ {
+ Gfx::EngineObjLevel5 buffer;
+ buffer.vertices.reserve(total);
+
+ buffer.type = Gfx::ENG_TRIANGLE_TYPE_6S;
+ buffer.material = mat;
+
+ buffer.state = Gfx::ENG_RSTATE_WRAP;
+
+ buffer.state |= Gfx::ENG_RSTATE_SECOND;
+ if (step == 1)
+ buffer.state |= Gfx::ENG_RSTATE_DUAL_BLACK;
+
+ for (int x = 0; x <= brick; x += step)
+ {
+ Gfx::VertexTex2 p1 = GetVertex(ox*m_brick+mx*brick+x, oy*m_brick+my*brick+y+0 , step);
+ Gfx::VertexTex2 p2 = GetVertex(ox*m_brick+mx*brick+x, oy*m_brick+my*brick+y+step, step);
+ p1.coord.x -= o.coord.x; p1.coord.z -= o.coord.z;
+ p2.coord.x -= o.coord.x; p2.coord.z -= o.coord.z;
+
+ if (m_multiText)
+ {
+ if (x == 0)
+ {
+ p1.texCoord.x = 0.0f+(0.5f/256.0f);
+ p2.texCoord.x = 0.0f+(0.5f/256.0f);
+ }
+ if (x == brick)
+ {
+ p1.texCoord.x = 1.0f-(0.5f/256.0f);
+ p2.texCoord.x = 1.0f-(0.5f/256.0f);
+ }
+ if (y == 0)
+ p1.texCoord.y = 1.0f-(0.5f/256.0f);
+
+ if (y == brick - step)
+ p2.texCoord.y = 0.0f+(0.5f/256.0f);
+ }
+
+ if (m_levelText)
+ {
+ p1.texCoord.x /= m_subdivMapping; // 0..1 -> 0..0.25
+ p1.texCoord.y /= m_subdivMapping;
+ p2.texCoord.x /= m_subdivMapping;
+ p2.texCoord.y /= m_subdivMapping;
+
+ if (x == 0)
+ {
+ p1.texCoord.x = 0.0f+dp;
+ p2.texCoord.x = 0.0f+dp;
+ }
+ if (x == brick)
+ {
+ p1.texCoord.x = (1.0f/m_subdivMapping)-dp;
+ p2.texCoord.x = (1.0f/m_subdivMapping)-dp;
+ }
+ if (y == 0)
+ p1.texCoord.y = (1.0f/m_subdivMapping)-dp;
+
+ if (y == brick - step)
+ p2.texCoord.y = 0.0f+dp;
+
+ p1.texCoord.x += uv.x;
+ p1.texCoord.y += uv.y;
+ p2.texCoord.x += uv.x;
+ p2.texCoord.y += uv.y;
+ }
+
+ int xx = mx*(m_brick/m_subdivMapping) + x;
+ int yy = my*(m_brick/m_subdivMapping) + y;
+ p1.texCoord2.x = (static_cast<float>(ox%5)*m_brick+xx+0.0f)/(m_brick*5);
+ p1.texCoord2.y = (static_cast<float>(oy%5)*m_brick+yy+0.0f)/(m_brick*5);
+ p2.texCoord2.x = (static_cast<float>(ox%5)*m_brick+xx+0.0f)/(m_brick*5);
+ p2.texCoord2.y = (static_cast<float>(oy%5)*m_brick+yy+1.0f)/(m_brick*5);
+
+// Correction for 1 pixel cover
+// There is 1 pixel cover around each of the 16 surfaces:
+//
+// |<--------------256-------------->|
+// | |<----------254---------->| |
+// |---|---|---|-- ... --|---|---|---|
+// | 0.0 1.0 |
+// | | | |
+// 0.0 min max 1.0
+//
+// The uv coordinates used for texturing are between min and max (instead of 0 and 1)
+// This allows to exclude the pixels situated in a margin of a pixel around the surface
+
+ p1.texCoord2.x = (p1.texCoord2.x+pixel)*(1.0f-pixel)/(1.0f+pixel);
+ p1.texCoord2.y = (p1.texCoord2.y+pixel)*(1.0f-pixel)/(1.0f+pixel);
+ p2.texCoord2.x = (p2.texCoord2.x+pixel)*(1.0f-pixel)/(1.0f+pixel);
+ p2.texCoord2.y = (p2.texCoord2.y+pixel)*(1.0f-pixel)/(1.0f+pixel);
+
+
+ buffer.vertices.push_back(p1);
+ buffer.vertices.push_back(p2);
+ }
+ m_engine->AddQuick(objRank, buffer, texName1, texName2, min, max, true);
+ }
+ }
+ }
+
+ Math::Matrix transform;
+ transform.LoadIdentity();
+ transform.Set(1, 4, o.coord.x);
+ transform.Set(3, 4, o.coord.z);
+ m_engine->SetObjectTransform(objRank, transform);
+
+ return true;
+}
+
+Gfx::TerrainMaterial* Gfx::CTerrain::LevelSearchMat(int id)
+{
+ for (int i = 0; i < static_cast<int>( m_levelMat.size() ); i++)
+ {
+ if (id == m_levelMat[i].id)
+ return &m_levelMat[i];
+ }
+
+ return nullptr;
+}
+
+void Gfx::CTerrain::LevelTextureName(int x, int y, std::string& name, Math::Point &uv)
+{
+ x /= m_brick/m_subdivMapping;
+ y /= m_brick/m_subdivMapping;
+
+ TerrainMaterial* tm = LevelSearchMat(m_levelDot[x+y*m_levelDotSize].id);
+ if (tm == nullptr)
+ {
+ name = "xxx.png";
+ uv.x = 0.0f;
+ uv.y = 0.0f;
+ }
+ else
+ {
+ name = tm->texName;
+ uv.x = tm->u;
+ uv.y = tm->v;
+ }
+}
+
+float Gfx::CTerrain::LevelGetHeight(int x, int y)
+{
+ int size = (m_mosaic*m_brick+1);
+
+ if (x < 0 ) x = 0;
+ if (x >= size) x = size-1;
+ if (y < 0 ) y = 0;
+ if (y >= size) y = size-1;
+
+ return m_relief[x+y*size];
+}
+
+bool Gfx::CTerrain::LevelGetDot(int x, int y, float min, float max, float slope)
+{
+ float hc = LevelGetHeight(x, y);
+ float h[4] =
+ {
+ LevelGetHeight(x+0, y+1),
+ LevelGetHeight(x+1, y+0),
+ LevelGetHeight(x+0, y-1),
+ LevelGetHeight(x-1, y+0)
+ };
+
+ if (hc < min || hc > max)
+ return false;
+
+ if (slope == 0.0f)
+ return true;
+
+ if (slope > 0.0f)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ if (fabs(hc - h[i]) >= slope)
+ return false;
+ }
+ return true;
+ }
+
+ if (slope < 0.0f)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ if (fabs(hc - h[i]) < -slope)
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+
+/** Returns the index within m_levelMat or -1 if there is not.
+ m_levelMat[i].id gives the identifier. */
+int Gfx::CTerrain::LevelTestMat(char *mat)
+{
+ for (int i = 0; i < static_cast<int>( m_levelMat.size() ); i++)
+ {
+ if ( m_levelMat[i].mat[0] == mat[0] &&
+ m_levelMat[i].mat[1] == mat[1] &&
+ m_levelMat[i].mat[2] == mat[2] &&
+ m_levelMat[i].mat[3] == mat[3] ) return i;
+ }
+
+ return -1;
+}
+
+void Gfx::CTerrain::LevelSetDot(int x, int y, int id, char *mat)
+{
+ TerrainMaterial* tm = LevelSearchMat(id);
+ if (tm == nullptr) return;
+
+ if ( tm->mat[0] != mat[0] ||
+ tm->mat[1] != mat[1] ||
+ tm->mat[2] != mat[2] ||
+ tm->mat[3] != mat[3] ) // id incompatible with mat?
+ {
+ int ii = LevelTestMat(mat);
+ if (ii == -1) return;
+ id = m_levelMat[ii].id; // looking for a id compatible with mat
+ }
+
+ // Changes the point
+ m_levelDot[x+y*m_levelDotSize].id = id;
+ m_levelDot[x+y*m_levelDotSize].mat[0] = mat[0];
+ m_levelDot[x+y*m_levelDotSize].mat[1] = mat[1];
+ m_levelDot[x+y*m_levelDotSize].mat[2] = mat[2];
+ m_levelDot[x+y*m_levelDotSize].mat[3] = mat[3];
+
+ // Changes the lower neighbor
+ if ( (x+0) >= 0 && (x+0) < m_levelDotSize &&
+ (y-1) >= 0 && (y-1) < m_levelDotSize )
+ {
+ int i = (x+0)+(y-1)*m_levelDotSize;
+ if (m_levelDot[i].mat[0] != mat[2])
+ {
+ m_levelDot[i].mat[0] = mat[2];
+ int ii = LevelTestMat(m_levelDot[i].mat);
+ if (ii != -1)
+ m_levelDot[i].id = m_levelMat[ii].id;
+ }
+ }
+
+ // Modifies the left neighbor
+ if ( (x-1) >= 0 && (x-1) < m_levelDotSize &&
+ (y+0) >= 0 && (y+0) < m_levelDotSize )
+ {
+ int i = (x-1)+(y+0)*m_levelDotSize;
+ if (m_levelDot[i].mat[1] != mat[3])
+ {
+ m_levelDot[i].mat[1] = mat[3];
+ int ii = LevelTestMat(m_levelDot[i].mat);
+ if (ii != -1)
+ m_levelDot[i].id = m_levelMat[ii].id;
+ }
+ }
+
+ // Changes the upper neighbor
+ if ( (x+0) >= 0 && (x+0) < m_levelDotSize &&
+ (y+1) >= 0 && (y+1) < m_levelDotSize )
+ {
+ int i = (x+0)+(y+1)*m_levelDotSize;
+ if (m_levelDot[i].mat[2] != mat[0])
+ {
+ m_levelDot[i].mat[2] = mat[0];
+ int ii = LevelTestMat(m_levelDot[i].mat);
+ if (ii != -1)
+ m_levelDot[i].id = m_levelMat[ii].id;
+ }
+ }
+
+ // Changes the right neighbor
+ if ( (x+1) >= 0 && (x+1) < m_levelDotSize &&
+ (y+0) >= 0 && (y+0) < m_levelDotSize )
+ {
+ int i = (x+1)+(y+0)*m_levelDotSize;
+ if ( m_levelDot[i].mat[3] != mat[1] )
+ {
+ m_levelDot[i].mat[3] = mat[1];
+ int ii = LevelTestMat(m_levelDot[i].mat);
+ if (ii != -1)
+ m_levelDot[i].id = m_levelMat[ii].id;
+ }
+ }
+}
+
+bool Gfx::CTerrain::LevelIfDot(int x, int y, int id, char *mat)
+{
+ char test[4];
+
+ // Compatible with lower neighbor?
+ if ( x+0 >= 0 && x+0 < m_levelDotSize &&
+ y-1 >= 0 && y-1 < m_levelDotSize )
+ {
+ test[0] = mat[2];
+ test[1] = m_levelDot[(x+0)+(y-1)*m_levelDotSize].mat[1];
+ test[2] = m_levelDot[(x+0)+(y-1)*m_levelDotSize].mat[2];
+ test[3] = m_levelDot[(x+0)+(y-1)*m_levelDotSize].mat[3];
+
+ if ( LevelTestMat(test) == -1 ) return false;
+ }
+
+ // Compatible with left neighbor?
+ if ( x-1 >= 0 && x-1 < m_levelDotSize &&
+ y+0 >= 0 && y+0 < m_levelDotSize )
+ {
+ test[0] = m_levelDot[(x-1)+(y+0)*m_levelDotSize].mat[0];
+ test[1] = mat[3];
+ test[2] = m_levelDot[(x-1)+(y+0)*m_levelDotSize].mat[2];
+ test[3] = m_levelDot[(x-1)+(y+0)*m_levelDotSize].mat[3];
+
+ if ( LevelTestMat(test) == -1 ) return false;
+ }
+
+ // Compatible with upper neighbor?
+ if ( x+0 >= 0 && x+0 < m_levelDotSize &&
+ y+1 >= 0 && y+1 < m_levelDotSize )
+ {
+ test[0] = m_levelDot[(x+0)+(y+1)*m_levelDotSize].mat[0];
+ test[1] = m_levelDot[(x+0)+(y+1)*m_levelDotSize].mat[1];
+ test[2] = mat[0];
+ test[3] = m_levelDot[(x+0)+(y+1)*m_levelDotSize].mat[3];
+
+ if ( LevelTestMat(test) == -1 ) return false;
+ }
+
+ // Compatible with right neighbor?
+ if ( x+1 >= 0 && x+1 < m_levelDotSize &&
+ y+0 >= 0 && y+0 < m_levelDotSize )
+ {
+ test[0] = m_levelDot[(x+1)+(y+0)*m_levelDotSize].mat[0];
+ test[1] = m_levelDot[(x+1)+(y+0)*m_levelDotSize].mat[1];
+ test[2] = m_levelDot[(x+1)+(y+0)*m_levelDotSize].mat[2];
+ test[3] = mat[1];
+
+ if ( LevelTestMat(test) == -1 ) return false;
+ }
+
+ LevelSetDot(x, y, id, mat); // puts the point
+ return true;
+}
+
+bool Gfx::CTerrain::LevelPutDot(int x, int y, int id)
+{
+ char mat[4];
+
+ x /= m_brick/m_subdivMapping;
+ y /= m_brick/m_subdivMapping;
+
+ if ( x < 0 || x >= m_levelDotSize ||
+ y < 0 || y >= m_levelDotSize ) return false;
+
+ TerrainMaterial* tm = LevelSearchMat(id);
+ if (tm == nullptr) return false;
+
+ // Tries without changing neighbors.
+ if ( LevelIfDot(x, y, id, tm->mat) ) return true;
+
+ // Tries changing a single neighbor (4x).
+ for (int up = 0; up < m_levelMatMax; up++)
+ {
+ mat[0] = up;
+ mat[1] = tm->mat[1];
+ mat[2] = tm->mat[2];
+ mat[3] = tm->mat[3];
+
+ if (LevelIfDot(x, y, id, mat)) return true;
+ }
+
+ for (int right = 0; right < m_levelMatMax; right++)
+ {
+ mat[0] = tm->mat[0];
+ mat[1] = right;
+ mat[2] = tm->mat[2];
+ mat[3] = tm->mat[3];
+
+ if (LevelIfDot(x, y, id, mat)) return true;
+ }
+
+ for (int down = 0; down < m_levelMatMax; down++)
+ {
+ mat[0] = tm->mat[0];
+ mat[1] = tm->mat[1];
+ mat[2] = down;
+ mat[3] = tm->mat[3];
+
+ if (LevelIfDot(x, y, id, mat)) return true;
+ }
+
+ for (int left = 0; left < m_levelMatMax; left++)
+ {
+ mat[0] = tm->mat[0];
+ mat[1] = tm->mat[1];
+ mat[2] = tm->mat[2];
+ mat[3] = left;
+
+ if (LevelIfDot(x, y, id, mat)) return true;
+ }
+
+ // Tries changing two neighbors (6x).
+ for (int up = 0; up < m_levelMatMax; up++)
+ {
+ for (int down = 0; down < m_levelMatMax; down++)
+ {
+ mat[0] = up;
+ mat[1] = tm->mat[1];
+ mat[2] = down;
+ mat[3] = tm->mat[3];
+
+ if (LevelIfDot(x, y, id, mat)) return true;
+ }
+ }
+
+ for (int right = 0; right < m_levelMatMax; right++)
+ {
+ for (int left = 0; left < m_levelMatMax; left++)
+ {
+ mat[0] = tm->mat[0];
+ mat[1] = right;
+ mat[2] = tm->mat[2];
+ mat[3] = left;
+
+ if (LevelIfDot(x, y, id, mat)) return true;
+ }
+ }
+
+ for (int up = 0; up < m_levelMatMax; up++)
+ {
+ for (int right = 0; right < m_levelMatMax; right++)
+ {
+ mat[0] = up;
+ mat[1] = right;
+ mat[2] = tm->mat[2];
+ mat[3] = tm->mat[3];
+
+ if (LevelIfDot(x, y, id, mat)) return true;
+ }
+ }
+
+ for (int right = 0; right < m_levelMatMax; right++)
+ {
+ for (int down = 0; down < m_levelMatMax; down++)
+ {
+ mat[0] = tm->mat[0];
+ mat[1] = right;
+ mat[2] = down;
+ mat[3] = tm->mat[3];
+
+ if (LevelIfDot(x, y, id, mat)) return true;
+ }
+ }
+
+ for (int down = 0; down < m_levelMatMax; down++)
+ {
+ for (int left = 0; left < m_levelMatMax; left++)
+ {
+ mat[0] = tm->mat[0];
+ mat[1] = tm->mat[1];
+ mat[2] = down;
+ mat[3] = left;
+
+ if (LevelIfDot(x, y, id, mat)) return true;
+ }
+ }
+
+ for (int up = 0; up < m_levelMatMax; up++)
+ {
+ for (int left = 0; left < m_levelMatMax; left++)
+ {
+ mat[0] = up;
+ mat[1] = tm->mat[1];
+ mat[2] = tm->mat[2];
+ mat[3] = left;
+
+ if (LevelIfDot(x, y, id, mat)) return true;
+ }
+ }
+
+ // Tries changing all the neighbors.
+ for (int up = 0; up < m_levelMatMax; up++)
+ {
+ for (int right = 0; right < m_levelMatMax; right++)
+ {
+ for (int down = 0; down < m_levelMatMax; down++)
+ {
+ for (int left = 0; left < m_levelMatMax; left++)
+ {
+ mat[0] = up;
+ mat[1] = right;
+ mat[2] = down;
+ mat[3] = left;
+
+ if (LevelIfDot(x, y, id, mat)) return true;
+ }
+ }
+ }
+ }
+
+ GetLogger()->Error("LevelPutDot error\n");
+ return false;
+}
+
+bool Gfx::CTerrain::LevelInit(int id)
+{
+ TerrainMaterial* tm = LevelSearchMat(id);
+ if (tm == nullptr) return false;
+
+ for (int i = 0; i < m_levelDotSize*m_levelDotSize; i++)
+ {
+ m_levelDot[i].id = id;
+
+ for (int j = 0; j < 4; j++)
+ m_levelDot[i].mat[j] = tm->mat[j];
+ }
+
+ return true;
+}
+
+bool Gfx::CTerrain::LevelGenerate(int *id, float min, float max,
+ float slope, float freq,
+ Math::Vector center, float radius)
+{
+ static char random[100] =
+ {
+ 84,25,12, 6,34,52,85,38,97,16,
+ 21,31,65,19,62,40,72,22,48,61,
+ 56,47, 8,53,73,77, 4,91,26,88,
+ 76, 1,44,93,39,11,71,17,98,95,
+ 88,83,18,30, 3,57,28,49,74, 9,
+ 32,13,96,66,15,70,36,10,59,94,
+ 45,86, 2,29,63,42,51, 0,79,27,
+ 54, 7,20,69,89,23,64,43,81,92,
+ 90,33,46,14,67,35,50, 5,87,60,
+ 68,55,24,78,41,75,58,80,37,82,
+ };
+
+ TerrainMaterial* tm = nullptr;
+
+ int i = 0;
+ while ( id[i] != 0 )
+ {
+ tm = LevelSearchMat(id[i++]);
+ if (tm == nullptr) return false;
+ }
+ int numID = i;
+
+ int group = m_brick / m_subdivMapping;
+
+ if (radius > 0.0f && radius < 5.0f) // just a square?
+ {
+ float dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ int xx = static_cast<int>((center.x+dim)/m_size);
+ int yy = static_cast<int>((center.z+dim)/m_size);
+
+ int x = xx/group;
+ int y = yy/group;
+
+ tm = LevelSearchMat(id[0]);
+ if (tm != nullptr)
+ LevelSetDot(x, y, id[0], tm->mat); // puts the point
+ }
+ else
+ {
+ for (int y = 0; y < m_levelDotSize; y++)
+ {
+ for (int x = 0; x < m_levelDotSize; x++)
+ {
+ if (radius != 0.0f)
+ {
+ Math::Vector pos;
+ pos.x = (static_cast<float>(x)-m_levelDotSize/2.0f)*group*m_size;
+ pos.z = (static_cast<float>(y)-m_levelDotSize/2.0f)*group*m_size;
+ if (Math::DistanceProjected(pos, center) > radius) continue;
+ }
+
+ if (freq < 100.0f)
+ {
+ int rnd = random[(x%10)+(y%10)*10];
+ if ( static_cast<float>(rnd) > freq ) continue;
+ }
+
+ int xx = x*group + group/2;
+ int yy = y*group + group/2;
+
+ if (LevelGetDot(xx, yy, min, max, slope))
+ {
+ int rnd = random[(x%10)+(y%10)*10];
+ int ii = rnd % numID;
+ LevelPutDot(xx, yy, id[ii]);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+void Gfx::CTerrain::LevelOpenTable()
+{
+ if (! m_levelText) return;
+ if (! m_levelDot.empty()) return; // already allocated
+
+ m_levelDotSize = (m_mosaic*m_brick)/(m_brick/m_subdivMapping)+1;
+ std::vector<Gfx::DotLevel>(m_levelDotSize*m_levelDotSize).swap(m_levelDot);
+
+ for (int i = 0; i < m_levelDotSize * m_levelDotSize; i++)
+ {
+ for (int j = 0; j < 4; j++)
+ m_levelDot[i].mat[j] = 0;
+ }
+}
+
+void Gfx::CTerrain::LevelCloseTable()
+{
+ m_levelDot.clear();
+}
+
+bool Gfx::CTerrain::CreateSquare(bool multiRes, int x, int y)
+{
+ Gfx::Material mat;
+ mat.diffuse = Gfx::Color(1.0f, 1.0f, 1.0f);
+ mat.ambient = Gfx::Color(0.0f, 0.0f, 0.0f);
+
+ int objRank = m_engine->CreateObject();
+ m_engine->SetObjectType(objRank, Gfx::ENG_OBJTYPE_TERRAIN); // it is a terrain
+
+ m_objRank[x+y*m_mosaic] = objRank;
+
+ if (multiRes)
+ {
+ float min = 0.0f;
+ float max = m_vision;
+ max *= m_engine->GetClippingDistance();
+ for (int step = 0; step < m_depth; step++)
+ {
+ CreateMosaic(x, y, 1 << step, objRank, mat, min, max);
+ min = max;
+ max *= 2;
+ if (step == m_depth-1) max = Math::HUGE_NUM;
+ }
+ }
+ else
+ {
+ CreateMosaic(x, y, 1, objRank, mat, 0.0f, Math::HUGE_NUM);
+ }
+
+ return true;
+}
+
+bool Gfx::CTerrain::CreateObjects(bool multiRes)
+{
+ AdjustRelief();
+
+ for (int y = 0; y < m_mosaic; y++)
+ {
+ for (int x = 0; x < m_mosaic; x++)
+ CreateSquare(multiRes, x, y);
+ }
+
+ return true;
+}
+
+/** ATTENTION: ok only with m_depth = 2! */
+bool Gfx::CTerrain::Terraform(const Math::Vector &p1, const Math::Vector &p2, float height)
+{
+ float dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ Math::IntPoint tp1, tp2;
+ tp1.x = static_cast<int>((p1.x+dim+m_size/2.0f)/m_size);
+ tp1.y = static_cast<int>((p1.z+dim+m_size/2.0f)/m_size);
+ tp2.x = static_cast<int>((p2.x+dim+m_size/2.0f)/m_size);
+ tp2.y = static_cast<int>((p2.z+dim+m_size/2.0f)/m_size);
+
+ if (tp1.x > tp2.x)
+ {
+ int x = tp1.x;
+ tp1.x = tp2.x;
+ tp2.x = x;
+ }
+
+ if (tp1.y > tp2.y)
+ {
+ int y = tp1.y;
+ tp1.y = tp2.y;
+ tp2.y = y;
+ }
+
+ int size = (m_mosaic*m_brick)+1;
+
+ // Calculates the current average height
+ float avg = 0.0f;
+ int nb = 0;
+ for (int y = tp1.y; y <= tp2.y; y++)
+ {
+ for (int x = tp1.x; x <= tp2.x; x++)
+ {
+ avg += m_relief[x+y*size];
+ nb ++;
+ }
+ }
+ avg /= static_cast<float>(nb);
+
+ // Changes the description of the relief
+ for (int y = tp1.y; y <= tp2.y; y++)
+ {
+ for (int x = tp1.x; x <= tp2.x; x++)
+ {
+ m_relief[x+y*size] = avg+height;
+
+ if (x % m_brick == 0 && y % m_depth != 0)
+ {
+ m_relief[(x+0)+(y-1)*size] = avg+height;
+ m_relief[(x+0)+(y+1)*size] = avg+height;
+ }
+
+ if (y % m_brick == 0 && x % m_depth != 0)
+ {
+ m_relief[(x-1)+(y+0)*size] = avg+height;
+ m_relief[(x+1)+(y+0)*size] = avg+height;
+ }
+ }
+ }
+ AdjustRelief();
+
+ Math::IntPoint pp1, pp2;
+ pp1.x = (tp1.x-2)/m_brick;
+ pp1.y = (tp1.y-2)/m_brick;
+ pp2.x = (tp2.x+1)/m_brick;
+ pp2.y = (tp2.y+1)/m_brick;
+
+ if (pp1.x < 0 ) pp1.x = 0;
+ if (pp1.x >= m_mosaic) pp1.x = m_mosaic-1;
+ if (pp1.y < 0 ) pp1.y = 0;
+ if (pp1.y >= m_mosaic) pp1.y = m_mosaic-1;
+
+ for (int y = pp1.y; y <= pp2.y; y++)
+ {
+ for (int x = pp1.x; x <= pp2.x; x++)
+ {
+ m_engine->DeleteObject(m_objRank[x+y*m_mosaic]);
+ CreateSquare(m_multiText, x, y); // recreates the square
+ }
+ }
+ m_engine->Update();
+
+ return true;
+}
+
+void Gfx::CTerrain::SetWind(Math::Vector speed)
+{
+ m_wind = speed;
+}
+
+Math::Vector Gfx::CTerrain::GetWind()
+{
+ return m_wind;
+}
+
+float Gfx::CTerrain::GetFineSlope(const Math::Vector &pos)
+{
+ Math::Vector n;
+ if (! GetNormal(n, pos)) return 0.0f;
+ return fabs(Math::RotateAngle(Math::Point(n.x, n.z).Length(), n.y) - Math::PI/2.0f);
+}
+
+float Gfx::CTerrain::GetCoarseSlope(const Math::Vector &pos)
+{
+ if (m_relief.empty()) return 0.0f;
+
+ float dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ int x = static_cast<int>((pos.x+dim)/m_size);
+ int y = static_cast<int>((pos.z+dim)/m_size);
+
+ if ( x < 0 || x >= m_mosaic*m_brick ||
+ y < 0 || y >= m_mosaic*m_brick ) return 0.0f;
+
+ float level[4] =
+ {
+ m_relief[(x+0)+(y+0)*(m_mosaic*m_brick+1)],
+ m_relief[(x+1)+(y+0)*(m_mosaic*m_brick+1)],
+ m_relief[(x+0)+(y+1)*(m_mosaic*m_brick+1)],
+ m_relief[(x+1)+(y+1)*(m_mosaic*m_brick+1)],
+ };
+
+ float min = Math::Min(level[0], level[1], level[2], level[3]);
+ float max = Math::Max(level[0], level[1], level[2], level[3]);
+
+ return atanf((max-min)/m_size);
+}
+
+bool Gfx::CTerrain::GetNormal(Math::Vector &n, const Math::Vector &p)
+{
+ float dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ int x = static_cast<int>((p.x+dim)/m_size);
+ int y = static_cast<int>((p.z+dim)/m_size);
+
+ if ( x < 0 || x > m_mosaic*m_brick ||
+ y < 0 || y > m_mosaic*m_brick ) return false;
+
+ Math::Vector p1 = GetVector(x+0, y+0);
+ Math::Vector p2 = GetVector(x+1, y+0);
+ Math::Vector p3 = GetVector(x+0, y+1);
+ Math::Vector p4 = GetVector(x+1, y+1);
+
+ if ( fabs(p.z - p2.z) < fabs(p.x - p2.x) )
+ n = Math::NormalToPlane(p1,p2,p3);
+ else
+ n = Math::NormalToPlane(p2,p4,p3);
+
+ return true;
+}
+
+float Gfx::CTerrain::GetFloorLevel(const Math::Vector &p, bool brut, bool water)
+{
+ float dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ int x = static_cast<int>((p.x+dim)/m_size);
+ int y = static_cast<int>((p.z+dim)/m_size);
+
+ if ( x < 0 || x > m_mosaic*m_brick ||
+ y < 0 || y > m_mosaic*m_brick ) return false;
+
+ Math::Vector p1 = GetVector(x+0, y+0);
+ Math::Vector p2 = GetVector(x+1, y+0);
+ Math::Vector p3 = GetVector(x+0, y+1);
+ Math::Vector p4 = GetVector(x+1, y+1);
+
+ Math::Vector ps = p;
+ if ( fabs(p.z-p2.z) < fabs(p.x-p2.x) )
+ {
+ if ( !IntersectY(p1, p2, p3, ps) ) return 0.0f;
+ }
+ else
+ {
+ if ( !IntersectY(p2, p4, p3, ps) ) return 0.0f;
+ }
+
+ if (! brut) AdjustBuildingLevel(ps);
+
+ if (water) // not going underwater?
+ {
+ float level = m_water->GetLevel();
+ if (ps.y < level) ps.y = level; // not under water
+ }
+
+ return ps.y;
+}
+
+
+/** This height is positive when you are above the ground */
+float Gfx::CTerrain::GetFloorHeight(const Math::Vector &p, bool brut, bool water)
+{
+ float dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ int x = static_cast<int>((p.x+dim)/m_size);
+ int y = static_cast<int>((p.z+dim)/m_size);
+
+ if ( x < 0 || x > m_mosaic*m_brick ||
+ y < 0 || y > m_mosaic*m_brick ) return false;
+
+ Math::Vector p1 = GetVector(x+0, y+0);
+ Math::Vector p2 = GetVector(x+1, y+0);
+ Math::Vector p3 = GetVector(x+0, y+1);
+ Math::Vector p4 = GetVector(x+1, y+1);
+
+ Math::Vector ps = p;
+ if ( fabs(p.z-p2.z) < fabs(p.x-p2.x) )
+ {
+ if ( !IntersectY(p1, p2, p3, ps) ) return 0.0f;
+ }
+ else
+ {
+ if ( !IntersectY(p2, p4, p3, ps) ) return 0.0f;
+ }
+
+ if (! brut) AdjustBuildingLevel(ps);
+
+ if (water) // not going underwater?
+ {
+ float level = m_water->GetLevel();
+ if ( ps.y < level ) ps.y = level; // not under water
+ }
+
+ return p.y-ps.y;
+}
+
+bool Gfx::CTerrain::MoveOnFloor(Math::Vector &p, bool brut, bool water)
+{
+ float dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ int x = static_cast<int>((p.x + dim) / m_size);
+ int y = static_cast<int>((p.z + dim) / m_size);
+
+ if ( x < 0 || x > m_mosaic*m_brick ||
+ y < 0 || y > m_mosaic*m_brick ) return false;
+
+ Math::Vector p1 = GetVector(x+0, y+0);
+ Math::Vector p2 = GetVector(x+1, y+0);
+ Math::Vector p3 = GetVector(x+0, y+1);
+ Math::Vector p4 = GetVector(x+1, y+1);
+
+ if (fabs(p.z - p2.z) < fabs(p.x - p2.x))
+ {
+ if (! Math::IntersectY(p1, p2, p3, p)) return false;
+ }
+ else
+ {
+ if (! Math::IntersectY(p2, p4, p3, p)) return false;
+ }
+
+ if (! brut) AdjustBuildingLevel(p);
+
+ if (water) // not going underwater?
+ {
+ float level = m_water->GetLevel();
+ if (p.y < level) p.y = level; // not under water
+ }
+
+ return true;
+}
+
+
+/** Returns false if the initial coordinate was too far */
+bool Gfx::CTerrain::ValidPosition(Math::Vector &p, float marging)
+{
+ bool ok = true;
+
+ float limit = m_mosaic*m_brick*m_size/2.0f - marging;
+
+ if (p.x < -limit)
+ {
+ p.x = -limit;
+ ok = false;
+ }
+
+ if (p.z < -limit)
+ {
+ p.z = -limit;
+ ok = false;
+ }
+
+ if (p.x > limit)
+ {
+ p.x = limit;
+ ok = false;
+ }
+
+ if (p.z > limit)
+ {
+ p.z = limit;
+ ok = false;
+ }
+
+ return ok;
+}
+
+void Gfx::CTerrain::FlushBuildingLevel()
+{
+ m_buildingLevels.clear();
+}
+
+bool Gfx::CTerrain::AddBuildingLevel(Math::Vector center, float min, float max,
+ float height, float factor)
+{
+ int i = 0;
+ for ( ; i < static_cast<int>( m_buildingLevels.size() ); i++)
+ {
+ if ( center.x == m_buildingLevels[i].center.x &&
+ center.z == m_buildingLevels[i].center.z )
+ {
+ break;
+ }
+ }
+
+ if (i == static_cast<int>( m_buildingLevels.size() ))
+ m_buildingLevels.push_back(Gfx::BuildingLevel());
+
+ m_buildingLevels[i].center = center;
+ m_buildingLevels[i].min = min;
+ m_buildingLevels[i].max = max;
+ m_buildingLevels[i].level = GetFloorLevel(center, true);
+ m_buildingLevels[i].height = height;
+ m_buildingLevels[i].factor = factor;
+ m_buildingLevels[i].bboxMinX = center.x-max;
+ m_buildingLevels[i].bboxMaxX = center.x+max;
+ m_buildingLevels[i].bboxMinZ = center.z-max;
+ m_buildingLevels[i].bboxMaxZ = center.z+max;
+
+ return true;
+}
+
+bool Gfx::CTerrain::UpdateBuildingLevel(Math::Vector center)
+{
+ for (int i = 0; i < static_cast<int>( m_buildingLevels.size() ); i++)
+ {
+ if ( center.x == m_buildingLevels[i].center.x &&
+ center.z == m_buildingLevels[i].center.z )
+ {
+ m_buildingLevels[i].center = center;
+ m_buildingLevels[i].level = GetFloorLevel(center, true);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Gfx::CTerrain::DeleteBuildingLevel(Math::Vector center)
+{
+ for (int i = 0; i < static_cast<int>( m_buildingLevels.size() ); i++)
+ {
+ if ( center.x == m_buildingLevels[i].center.x &&
+ center.z == m_buildingLevels[i].center.z )
+ {
+ for (int j = i+1; j < static_cast<int>( m_buildingLevels.size() ); j++)
+ m_buildingLevels[j-1] = m_buildingLevels[j];
+
+ m_buildingLevels.pop_back();
+ return true;
+ }
+ }
+ return false;
+}
+
+float Gfx::CTerrain::GetBuildingFactor(const Math::Vector &p)
+{
+ for (int i = 0; i < static_cast<int>( m_buildingLevels.size() ); i++)
+ {
+ if ( p.x < m_buildingLevels[i].bboxMinX ||
+ p.x > m_buildingLevels[i].bboxMaxX ||
+ p.z < m_buildingLevels[i].bboxMinZ ||
+ p.z > m_buildingLevels[i].bboxMaxZ ) continue;
+
+ float dist = Math::DistanceProjected(p, m_buildingLevels[i].center);
+
+ if (dist <= m_buildingLevels[i].max)
+ return m_buildingLevels[i].factor;
+ }
+ return 1.0f; // it is normal on the ground
+}
+
+void Gfx::CTerrain::AdjustBuildingLevel(Math::Vector &p)
+{
+ for (int i = 0; i < static_cast<int>( m_buildingLevels.size() ); i++)
+ {
+ if ( p.x < m_buildingLevels[i].bboxMinX ||
+ p.x > m_buildingLevels[i].bboxMaxX ||
+ p.z < m_buildingLevels[i].bboxMinZ ||
+ p.z > m_buildingLevels[i].bboxMaxZ ) continue;
+
+ float dist = Math::DistanceProjected(p, m_buildingLevels[i].center);
+
+ if (dist > m_buildingLevels[i].max) continue;
+
+ if (dist < m_buildingLevels[i].min)
+ {
+ p.y = m_buildingLevels[i].level + m_buildingLevels[i].height;
+ return;
+ }
+
+ Math::Vector border;
+ border.x = ((p.x - m_buildingLevels[i].center.x) * m_buildingLevels[i].max) /
+ dist + m_buildingLevels[i].center.x;
+ border.z = ((p.z - m_buildingLevels[i].center.z) * m_buildingLevels[i].max) /
+ dist + m_buildingLevels[i].center.z;
+
+ float base = GetFloorLevel(border, true);
+
+ p.y = (m_buildingLevels[i].max - dist) /
+ (m_buildingLevels[i].max - m_buildingLevels[i].min) *
+ (m_buildingLevels[i].level + m_buildingLevels[i].height-base) +
+ base;
+
+ return;
+ }
+}
+
+
+// returns the hardness of the ground in a given place.
+// The hardness determines the noise (SOUND_STEP and SOUND_BOUM).
+
+float Gfx::CTerrain::GetHardness(const Math::Vector &p)
+{
+ float factor = GetBuildingFactor(p);
+ if (factor != 1.0f) return 1.0f; // on building
+
+ if (m_levelDot.empty()) return m_defHardness;
+
+ float dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ int x, y;
+
+ x = static_cast<int>((p.x+dim)/m_size);
+ y = static_cast<int>((p.z+dim)/m_size);
+
+ if ( x < 0 || x > m_mosaic*m_brick ||
+ y < 0 || y > m_mosaic*m_brick ) return m_defHardness;
+
+ x /= m_brick/m_subdivMapping;
+ y /= m_brick/m_subdivMapping;
+
+ if ( x < 0 || x >= m_levelDotSize ||
+ y < 0 || y >= m_levelDotSize ) return m_defHardness;
+
+ int id = m_levelDot[x+y*m_levelDotSize].id;
+ TerrainMaterial* tm = LevelSearchMat(id);
+ if (tm == nullptr) return m_defHardness;
+
+ return tm->hardness;
+}
+
+void Gfx::CTerrain::GroundFlat(Math::Vector pos)
+{
+ static char table[41*41];
+
+
+ float rapport = 3200.0f/1024.0f;
+
+ for (int y = 0; y <= 40; y++)
+ {
+ for (int x = 0; x <= 40; x++)
+ {
+ int i = x + y*41;
+ table[i] = 0;
+
+ Math::Vector p;
+ p.x = (x-20)*rapport;
+ p.z = (y-20)*rapport;
+ p.y = 0.0f;
+
+ if (Math::Point(p.x, p.y).Length() > 20.0f*rapport)
+ continue;
+
+ float angle = GetFineSlope(pos+p);
+
+ if (angle < FLATLIMIT)
+ table[i] = 1;
+ else
+ table[i] = 2;
+ }
+ }
+
+ m_engine->GroundMarkCreate(pos, 40.0f, 0.001f, 15.0f, 0.001f, 41, 41, table);
+}
+
+float Gfx::CTerrain::GetFlatZoneRadius(Math::Vector center, float max)
+{
+ float angle = GetFineSlope(center);
+ if (angle >= Gfx::FLATLIMIT)
+ return 0.0f;
+
+ float ref = GetFloorLevel(center, true);
+
+ float radius = 1.0f;
+ while (radius <= max)
+ {
+ angle = 0.0f;
+ int nb = static_cast<int>(2.0f*Math::PI*radius);
+ if (nb < 8) nb = 8;
+
+ for (int i = 0; i < nb; i++)
+ {
+ Math::Point c(center.x, center.z);
+ Math::Point p (center.x+radius, center.z);
+ p = Math::RotatePoint(c, angle, p);
+ Math::Vector pos;
+ pos.x = p.x;
+ pos.z = p.y;
+ float h = GetFloorLevel(pos, true);
+ if ( fabs(h-ref) > 1.0f ) return radius;
+
+ angle += Math::PI*2.0f/8.0f;
+ }
+ radius += 1.0f;
+ }
+ return max;
+}
+
+void Gfx::CTerrain::SetFlyingMaxHeight(float height)
+{
+ m_flyingMaxHeight = height;
+}
+
+float Gfx::CTerrain::GetFlyingMaxHeight()
+{
+ return m_flyingMaxHeight;
+}
+
+void Gfx::CTerrain::FlushFlyingLimit()
+{
+ m_flyingMaxHeight = 280.0f;
+ m_flyingLimits.clear();
+}
+
+void Gfx::CTerrain::AddFlyingLimit(Math::Vector center,
+ float extRadius, float intRadius,
+ float maxHeight)
+{
+ Gfx::FlyingLimit fl;
+ fl.center = center;
+ fl.extRadius = extRadius;
+ fl.intRadius = intRadius;
+ fl.maxHeight = maxHeight;
+ m_flyingLimits.push_back(fl);
+}
+
+float Gfx::CTerrain::GetFlyingLimit(Math::Vector pos, bool noLimit)
+{
+ if (noLimit)
+ return 280.0f;
+
+ if (m_flyingLimits.empty())
+ return m_flyingMaxHeight;
+
+ for (int i = 0; i < static_cast<int>( m_flyingLimits.size() ); i++)
+ {
+ float dist = Math::DistanceProjected(pos, m_flyingLimits[i].center);
+
+ if (dist >= m_flyingLimits[i].extRadius)
+ continue;
+
+ if (dist <= m_flyingLimits[i].intRadius)
+ return m_flyingLimits[i].maxHeight;
+
+ dist -= m_flyingLimits[i].intRadius;
+
+ float h = dist * (m_flyingMaxHeight - m_flyingLimits[i].maxHeight) /
+ (m_flyingLimits[i].extRadius - m_flyingLimits[i].intRadius);
+
+ return h + m_flyingLimits[i].maxHeight;
+ }
+
+ return m_flyingMaxHeight;
+}
diff --git a/src/graphics/engine/terrain.h b/src/graphics/engine/terrain.h
index 8d8b165..41d4bbb 100644
--- a/src/graphics/engine/terrain.h
+++ b/src/graphics/engine/terrain.h
@@ -15,7 +15,10 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// terrain.h
+/**
+ * \file graphics/engine/terrain.h
+ * \brief Terrain rendering - Gfx::CTerrain class
+ */
#pragma once
@@ -40,56 +43,72 @@ enum TerrainRes
TR_STONE = 1,
TR_URANIUM = 2,
TR_POWER = 3,
- TR_KEYa = 4,
- TR_KEYb = 5,
- TR_KEYc = 6,
- TR_KEYd = 7,
+ TR_KEY_A = 4,
+ TR_KEY_B = 5,
+ TR_KEY_C = 6,
+ TR_KEY_D = 7,
};
-
-const short MAXBUILDINGLEVEL = 100;
-
struct BuildingLevel
{
- Math::Vector center;
- float factor;
- float min;
- float max;
- float level;
- float height;
- float bboxMinX;
- float bboxMaxX;
- float bboxMinZ;
- float bboxMaxZ;
+ Math::Vector center;
+ float factor;
+ float min;
+ float max;
+ float level;
+ float height;
+ float bboxMinX;
+ float bboxMaxX;
+ float bboxMinZ;
+ float bboxMaxZ;
+
+ BuildingLevel()
+ {
+ factor = min = max = level = height = 0.0f;
+ bboxMinX = bboxMaxX = bboxMinZ = bboxMaxZ = 0.0f;
+ }
};
-
-const short MAXMATTERRAIN = 100;
-
struct TerrainMaterial
{
short id;
- char texName[20];
+ std::string texName;
float u,v;
float hardness;
char mat[4]; // up, right, down, left
+
+ TerrainMaterial()
+ {
+ id = 0;
+ u = v = 0.0f;
+ hardness = 0.0f;
+ mat[0] = mat[1] = mat[2] = mat[3] = 0;
+ }
};
struct DotLevel
{
short id;
char mat[4]; // up, right, down, left
-};
-
-const short MAXFLYINGLIMIT = 10;
+ DotLevel()
+ {
+ id = 0;
+ mat[0] = mat[1] = mat[2] = mat[3] = 0;
+ }
+};
struct FlyingLimit
{
- Math::Vector center;
- float extRadius;
- float intRadius;
- float maxHeight;
+ Math::Vector center;
+ float extRadius;
+ float intRadius;
+ float maxHeight;
+
+ FlyingLimit()
+ {
+ extRadius = intRadius = maxHeight = 0.0f;
+ }
};
@@ -100,72 +119,124 @@ public:
CTerrain(CInstanceManager* iMan);
~CTerrain();
- bool Generate(int mosaic, int brickP2, float size, float vision, int depth, float hardness);
- bool InitTextures(char* baseName, int* table, int dx, int dy);
+ //! Generates a new flat terrain
+ bool Generate(int mosaic, int brickPow2, float size, float vision, int depth, float hardness);
+ //! Initializes the names of textures to use for the land
+ bool InitTextures(const std::string& baseName, int* table, int dx, int dy);
+ //! Empties level
void LevelFlush();
- bool LevelMaterial(int id, char* baseName, float u, float v, int up, int right, int down, int left, float hardness);
+ //! Initializes the names of textures to use for the land
+ void LevelMaterial(int id, std::string& baseName, float u, float v, int up, int right, int down, int left, float hardness);
+ //! Initializes all the ground with a material
bool LevelInit(int id);
+ //! Generates a level in the terrain
bool LevelGenerate(int *id, float min, float max, float slope, float freq, Math::Vector center, float radius);
+ //! Initializes a completely flat terrain
void FlushRelief();
- bool ReliefFromBMP(const char* filename, float scaleRelief, bool adjustBorder);
- bool ReliefFromDXF(const char* filename, float scaleRelief);
- bool ResFromBMP(const char* filename);
- bool CreateObjects(bool bMultiRes);
- bool Terraform(const Math::Vector &p1, const Math::Vector &p2, float height);
-
- void SetWind(Math::Vector speed);
- Math::Vector RetWind();
-
- float RetFineSlope(const Math::Vector &pos);
- float RetCoarseSlope(const Math::Vector &pos);
- bool GetNormal(Math::Vector &n, const Math::Vector &p);
- float RetFloorLevel(const Math::Vector &p, bool bBrut=false, bool bWater=false);
- float RetFloorHeight(const Math::Vector &p, bool bBrut=false, bool bWater=false);
- bool MoveOnFloor(Math::Vector &p, bool bBrut=false, bool bWater=false);
- bool ValidPosition(Math::Vector &p, float marging);
- TerrainRes RetResource(const Math::Vector &p);
+ //! Load relief from a PNG file
+ bool ReliefFromPNG(const std::string& filename, float scaleRelief, bool adjustBorder);
+ //! Load resources from a PNG file
+ bool ResFromPNG(const std::string& filename);
+ //! Creates all objects of the terrain within the 3D engine
+ bool CreateObjects(bool multiRes);
+ //! Modifies the terrain's relief
+ bool Terraform(const Math::Vector& p1, const Math::Vector& p2, float height);
+
+ //@{
+ //! Management of the wind
+ void SetWind(Math::Vector speed);
+ Math::Vector GetWind();
+ //@}
+
+ //! Gives the exact slope of the terrain of a place given
+ float GetFineSlope(const Math::Vector& pos);
+ //! Gives the approximate slope of the terrain of a specific location
+ float GetCoarseSlope(const Math::Vector& pos);
+ //! Gives the normal vector at the position p (x,-,z) of the ground
+ bool GetNormal(Math::Vector& n, const Math::Vector &p);
+ //! returns the height of the ground
+ float GetFloorLevel(const Math::Vector& p, bool brut=false, bool water=false);
+ //! Returns the height to the ground
+ float GetFloorHeight(const Math::Vector& p, bool brut=false, bool water=false);
+ //! Modifies the coordinate "y" of point "p" to rest on the ground floor
+ bool MoveOnFloor(Math::Vector& p, bool brut=false, bool water=false);
+ //! Modifies a coordinate so that it is on the ground
+ bool ValidPosition(Math::Vector& p, float marging);
+ //! Returns the resource type available underground
+ Gfx::TerrainRes GetResource(const Math::Vector& p);
+ //! Adjusts a position so that it does not exceed the boundaries
void LimitPos(Math::Vector &pos);
+ //! Empty the table of elevations
void FlushBuildingLevel();
+ //! Adds a new elevation for a building
bool AddBuildingLevel(Math::Vector center, float min, float max, float height, float factor);
+ //! Updates the elevation for a building when it was moved up (after a terraforming)
bool UpdateBuildingLevel(Math::Vector center);
+ //! Removes the elevation for a building when it was destroyed
bool DeleteBuildingLevel(Math::Vector center);
- float RetBuildingFactor(const Math::Vector &p);
- float RetHardness(const Math::Vector &p);
+ //! Returns the influence factor whether a position is on a possible rise
+ float GetBuildingFactor(const Math::Vector& p);
+ float GetHardness(const Math::Vector& p);
- int RetMosaic();
- int RetBrick();
- float RetSize();
- float RetScaleRelief();
+ int GetMosaic();
+ int GetBrick();
+ float GetSize();
+ float GetScaleRelief();
+ //! Shows the flat areas on the ground
void GroundFlat(Math::Vector pos);
- float RetFlatZoneRadius(Math::Vector center, float max);
+ //! Calculates the radius of the largest flat area available
+ float GetFlatZoneRadius(Math::Vector center, float max);
+ //@{
+ //! Management of the global max flying height
void SetFlyingMaxHeight(float height);
- float RetFlyingMaxHeight();
+ float GetFlyingMaxHeight();
+ //@}
+ //! Empty the table of flying limits
void FlushFlyingLimit();
- bool AddFlyingLimit(Math::Vector center, float extRadius, float intRadius, float maxHeight);
- float RetFlyingLimit(Math::Vector pos, bool bNoLimit);
+ //! Adds a new flying limit
+ void AddFlyingLimit(Math::Vector center, float extRadius, float intRadius, float maxHeight);
+ //! Returns the maximum height of flight
+ float GetFlyingLimit(Math::Vector pos, bool noLimit);
protected:
+ //! Adds a point of elevation in the buffer of relief
bool ReliefAddDot(Math::Vector pos, float scaleRelief);
+ //! Adjust the edges of each mosaic to be compatible with all lower resolutions
void AdjustRelief();
- Math::Vector RetVector(int x, int y);
- Gfx::VertexTex2 RetVertex(int x, int y, int step);
- bool CreateMosaic(int ox, int oy, int step, int objRank, const Gfx::Material &mat, float min, float max);
- bool CreateSquare(bool bMultiRes, int x, int y);
-
- TerrainMaterial* LevelSearchMat(int id);
- void LevelTextureName(int x, int y, char *name, Math::Point &uv);
- float LevelRetHeight(int x, int y);
+ //! Calculates a vector of the terrain
+ Math::Vector GetVector(int x, int y);
+ //! Calculates a vertex of the terrain
+ Gfx::VertexTex2 GetVertex(int x, int y, int step);
+ //! Creates all objects of a mosaic
+ bool CreateMosaic(int ox, int oy, int step, int objRank, const Gfx::Material& mat, float min, float max);
+ //! Creates all objects in a mesh square ground
+ bool CreateSquare(bool multiRes, int x, int y);
+
+ //! Seeks a materials based on theirs identifier
+ Gfx::TerrainMaterial* LevelSearchMat(int id);
+ //! Chooses texture to use for a given square
+ void LevelTextureName(int x, int y, std::string& name, Math::Point &uv);
+ //! Returns the height of the terrain
+ float LevelGetHeight(int x, int y);
+ //! Decide whether a point is using the materials
bool LevelGetDot(int x, int y, float min, float max, float slope);
+ //! Seeks if material exists
int LevelTestMat(char *mat);
+ //! Modifies the state of a point and its four neighbors, without testing if possible
void LevelSetDot(int x, int y, int id, char *mat);
+ //! Tests if a material can give a place, according to its four neighbors. If yes, puts the point.
bool LevelIfDot(int x, int y, int id, char *mat);
+ //! Modifies the state of a point
bool LevelPutDot(int x, int y, int id);
+ //! Initializes a table with empty levels
void LevelOpenTable();
+ //! Closes the level table
void LevelCloseTable();
+ //! Adjusts a position according to a possible rise
void AdjustBuildingLevel(Math::Vector &p);
protected:
@@ -173,39 +244,49 @@ protected:
CEngine* m_engine;
CWater* m_water;
- int m_mosaic; // number of mosaics
- int m_brick; // number of bricks per mosaics
- float m_size; // size of an item in an brick
- float m_vision; // vision before a change of resolution
- float* m_relief; // table of the relief
- int* m_texture; // table of textures
- int* m_objRank; // table of rows of objects
- bool m_bMultiText;
- bool m_bLevelText;
- float m_scaleMapping; // scale of the mapping
+ //! Number of mosaics
+ int m_mosaic;
+ //! Number of bricks per mosaics
+ int m_brick;
+ int m_levelDotSize;
+ //! Size of an item in a brick
+ float m_size;
+ //! Vision before a change of resolution
+ float m_vision;
+ //! Table of the relief
+ std::vector<float> m_relief;
+ //! Table of textures
+ std::vector<int> m_texture;
+ //! Table of rows of objects
+ std::vector<int> m_objRank;
+ //! Table of resources
+ std::vector<unsigned char> m_resources;
+ bool m_multiText;
+ bool m_levelText;
+ //! Scale of the mapping
+ float m_scaleMapping;
float m_scaleRelief;
- int m_subdivMapping;
- int m_depth; // number of different resolutions (1,2,3,4)
- char m_texBaseName[20];
- char m_texBaseExt[10];
+ int m_subdivMapping;
+ //! Number of different resolutions (1,2,3,4)
+ int m_depth;
+ std::string m_texBaseName;
+ std::string m_texBaseExt;
float m_defHardness;
- TerrainMaterial m_levelMat[MAXMATTERRAIN+1];
- int m_levelMatTotal;
+ std::vector<TerrainMaterial> m_levelMat;
+ std::vector<Gfx::DotLevel> m_levelDot;
int m_levelMatMax;
- int m_levelDotSize;
- DotLevel* m_levelDot;
int m_levelID;
- int m_buildingUsed;
- BuildingLevel m_buildingTable[MAXBUILDINGLEVEL];
+ std::vector<Gfx::BuildingLevel> m_buildingLevels;
- unsigned char* m_resources;
- Math::Vector m_wind; // wind speed
+ //! Wind speed
+ Math::Vector m_wind;
+ //! Global flying height limit
float m_flyingMaxHeight;
- int m_flyingLimitTotal;
- FlyingLimit m_flyingLimit[MAXFLYINGLIMIT];
+ //! List of local flight limits
+ std::vector<Gfx::FlyingLimit> m_flyingLimits;
};
}; // namespace Gfx
diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp
index 2a9543c..82abd62 100644
--- a/src/graphics/engine/text.cpp
+++ b/src/graphics/engine/text.cpp
@@ -19,5 +19,784 @@
#include "graphics/engine/text.h"
+#include "app/app.h"
+#include "common/image.h"
+#include "common/iman.h"
+#include "common/logger.h"
+#include "common/stringutils.h"
+#include "math/func.h"
-// TODO implementation
+#include <SDL/SDL.h>
+#include <SDL/SDL_ttf.h>
+
+
+namespace Gfx
+{
+
+/**
+ \struct CachedFont
+ \brief Base TTF font with UTF-8 char cache */
+struct CachedFont
+{
+ TTF_Font* font;
+ std::map<Gfx::UTF8Char, Gfx::CharTexture> cache;
+
+ CachedFont() : font(nullptr) {}
+};
+
+};
+
+
+
+Gfx::CText::CText(CInstanceManager *iMan, Gfx::CEngine* engine)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_TEXT, this);
+
+ m_device = nullptr;
+ m_engine = engine;
+
+ m_defaultSize = 12.0f;
+ m_fontPath = "fonts";
+
+ m_lastFontType = Gfx::FONT_COLOBOT;
+ m_lastFontSize = 0;
+ m_lastCachedFont = nullptr;
+}
+
+Gfx::CText::~CText()
+{
+ m_iMan->DeleteInstance(CLASS_TEXT, this);
+
+ m_iMan = nullptr;
+ m_device = nullptr;
+ m_engine = nullptr;
+}
+
+bool Gfx::CText::Create()
+{
+ if (TTF_Init() != 0)
+ {
+ m_error = std::string("TTF_Init error: ") + std::string(TTF_GetError());
+ return false;
+ }
+
+ m_fonts[Gfx::FONT_COLOBOT] = new MultisizeFont("dvu_sans.ttf");
+ m_fonts[Gfx::FONT_COLOBOT_BOLD] = new MultisizeFont("dvu_sans_bold.ttf");
+ m_fonts[Gfx::FONT_COLOBOT_ITALIC] = new MultisizeFont("dvu_sans_italic.ttf");
+
+ m_fonts[Gfx::FONT_COURIER] = new MultisizeFont("dvu_sans_mono.ttf");
+ m_fonts[Gfx::FONT_COURIER_BOLD] = new MultisizeFont("dvu_sans_mono_bold.ttf");
+
+ for (auto it = m_fonts.begin(); it != m_fonts.end(); ++it)
+ {
+ Gfx::FontType type = (*it).first;
+ CachedFont* cf = GetOrOpenFont(type, m_defaultSize);
+ if (cf == nullptr || cf->font == nullptr)
+ return false;
+ }
+
+ return true;
+}
+
+void Gfx::CText::Destroy()
+{
+ for (auto it = m_fonts.begin(); it != m_fonts.end(); ++it)
+ {
+ MultisizeFont* mf = (*it).second;
+
+ for (auto jt = mf->fonts.begin(); jt != mf->fonts.end(); ++jt)
+ {
+ CachedFont* cf = (*jt).second;
+
+ TTF_CloseFont(cf->font);
+
+ cf->font = nullptr;
+ delete cf;
+ }
+
+ mf->fonts.clear();
+ delete mf;
+ }
+
+ m_fonts.clear();
+
+ m_lastCachedFont = nullptr;
+
+ TTF_Quit();
+}
+
+void Gfx::CText::SetDevice(Gfx::CDevice* device)
+{
+ m_device = device;
+}
+
+std::string Gfx::CText::GetError()
+{
+ return m_error;
+}
+
+void Gfx::CText::FlushCache()
+{
+ for (auto it = m_fonts.begin(); it != m_fonts.end(); ++it)
+ {
+ MultisizeFont *mf = (*it).second;
+ for (auto jt = mf->fonts.begin(); jt != mf->fonts.end(); ++jt)
+ {
+ CachedFont *f = (*jt).second;
+ f->cache.clear();
+ }
+ }
+}
+
+void Gfx::CText::DrawText(const std::string &text, const std::vector<FontMetaChar> &format,
+ float size, Math::Point pos, float width, Gfx::TextAlign align,
+ int eol)
+{
+ float sw = 0.0f;
+
+ if (align == Gfx::TEXT_ALIGN_CENTER)
+ {
+ sw = GetStringWidth(text, format, size);
+ if (sw > width) sw = width;
+ pos.x -= sw / 2.0f;
+ }
+ else if (align == Gfx::TEXT_ALIGN_RIGHT)
+ {
+ sw = GetStringWidth(text, format, size);
+ if (sw > width) sw = width;
+ pos.x -= sw;
+ }
+
+ DrawString(text, format, size, pos, width, eol);
+}
+
+void Gfx::CText::DrawText(const std::string &text, Gfx::FontType font,
+ float size, Math::Point pos, float width, Gfx::TextAlign align,
+ int eol)
+{
+ float sw = 0.0f;
+
+ if (align == Gfx::TEXT_ALIGN_CENTER)
+ {
+ sw = GetStringWidth(text, font, size);
+ if (sw > width) sw = width;
+ pos.x -= sw / 2.0f;
+ }
+ else if (align == Gfx::TEXT_ALIGN_RIGHT)
+ {
+ sw = GetStringWidth(text, font, size);
+ if (sw > width) sw = width;
+ pos.x -= sw;
+ }
+
+ DrawString(text, font, size, pos, width, eol);
+}
+
+void Gfx::CText::SizeText(const std::string &text, const std::vector<FontMetaChar> &format,
+ float size, Math::Point pos, Gfx::TextAlign align,
+ Math::Point &start, Math::Point &end)
+{
+ start = end = pos;
+
+ float sw = GetStringWidth(text, format, size);
+ end.x += sw;
+ if (align == Gfx::TEXT_ALIGN_CENTER)
+ {
+ start.x -= sw/2.0f;
+ end.x -= sw/2.0f;
+ }
+ else if (align == Gfx::TEXT_ALIGN_RIGHT)
+ {
+ start.x -= sw;
+ end.x -= sw;
+ }
+
+ start.y -= GetDescent(Gfx::FONT_COLOBOT, size);
+ end.y += GetAscent(Gfx::FONT_COLOBOT, size);
+}
+
+void Gfx::CText::SizeText(const std::string &text, Gfx::FontType font,
+ float size, Math::Point pos, Gfx::TextAlign align,
+ Math::Point &start, Math::Point &end)
+{
+ start = end = pos;
+
+ float sw = GetStringWidth(text, font, size);
+ end.x += sw;
+ if (align == Gfx::TEXT_ALIGN_CENTER)
+ {
+ start.x -= sw/2.0f;
+ end.x -= sw/2.0f;
+ }
+ else if (align == Gfx::TEXT_ALIGN_RIGHT)
+ {
+ start.x -= sw;
+ end.x -= sw;
+ }
+
+ start.y -= GetDescent(font, size);
+ end.y += GetAscent(font, size);
+}
+
+float Gfx::CText::GetAscent(Gfx::FontType font, float size)
+{
+ assert(font != Gfx::FONT_BUTTON);
+
+ Gfx::CachedFont* cf = GetOrOpenFont(font, size);
+ assert(cf != nullptr);
+ Math::IntPoint wndSize;
+ wndSize.y = TTF_FontAscent(cf->font);
+ Math::Point ifSize = m_engine->WindowToInterfaceSize(wndSize);
+ return ifSize.y;
+}
+
+float Gfx::CText::GetDescent(Gfx::FontType font, float size)
+{
+ assert(font != Gfx::FONT_BUTTON);
+
+ Gfx::CachedFont* cf = GetOrOpenFont(font, size);
+ assert(cf != nullptr);
+ Math::IntPoint wndSize;
+ wndSize.y = TTF_FontDescent(cf->font);
+ Math::Point ifSize = m_engine->WindowToInterfaceSize(wndSize);
+ return ifSize.y;
+}
+
+float Gfx::CText::GetHeight(Gfx::FontType font, float size)
+{
+ assert(font != Gfx::FONT_BUTTON);
+
+ Gfx::CachedFont* cf = GetOrOpenFont(font, size);
+ assert(cf != nullptr);
+ Math::IntPoint wndSize;
+ wndSize.y = TTF_FontHeight(cf->font);
+ Math::Point ifSize = m_engine->WindowToInterfaceSize(wndSize);
+ return ifSize.y;
+}
+
+
+float Gfx::CText::GetStringWidth(const std::string &text,
+ const std::vector<FontMetaChar> &format, float size)
+{
+ assert(StrUtils::Utf8StringLength(text) == format.size());
+
+ float width = 0.0f;
+ unsigned int index = 0;
+ unsigned int fmtIndex = 0;
+ while (index < text.length())
+ {
+ Gfx::FontType font = static_cast<Gfx::FontType>(format[fmtIndex] & Gfx::FONT_MASK_FONT);
+
+ Gfx::UTF8Char ch;
+
+ int len = StrUtils::Utf8CharSizeAt(text, index);
+ if (len >= 1)
+ ch.c1 = text[index];
+ if (len >= 2)
+ ch.c2 = text[index+1];
+ if (len >= 3)
+ ch.c3 = text[index+2];
+
+ width += GetCharWidth(ch, font, size, width);
+
+ index += len;
+ fmtIndex++;
+ }
+
+ return width;
+}
+
+float Gfx::CText::GetStringWidth(const std::string &text, Gfx::FontType font, float size)
+{
+ assert(font != Gfx::FONT_BUTTON);
+
+ // TODO: special chars?
+
+ Gfx::CachedFont* cf = GetOrOpenFont(font, size);
+ assert(cf != nullptr);
+ Math::IntPoint wndSize;
+ TTF_SizeUTF8(cf->font, text.c_str(), &wndSize.x, &wndSize.y);
+ Math::Point ifSize = m_engine->WindowToInterfaceSize(wndSize);
+ return ifSize.x;
+}
+
+float Gfx::CText::GetCharWidth(Gfx::UTF8Char ch, Gfx::FontType font, float size, float offset)
+{
+ // TODO: if (font == Gfx::FONT_BUTTON)
+ if (font == Gfx::FONT_BUTTON) return 0.0f;
+
+ // TODO: special chars?
+ // TODO: tab sizing
+
+ Gfx::CachedFont* cf = GetOrOpenFont(font, size);
+ assert(cf != nullptr);
+
+ Gfx::CharTexture tex;
+ auto it = cf->cache.find(ch);
+ if (it != cf->cache.end())
+ tex = (*it).second;
+ else
+ tex = CreateCharTexture(ch, cf);
+
+ return tex.charSize.x;
+}
+
+
+int Gfx::CText::Justify(const std::string &text, const std::vector<FontMetaChar> &format,
+ float size, float width)
+{
+ assert(StrUtils::Utf8StringLength(text) == format.size());
+
+ float pos = 0.0f;
+ int cut = 0;
+ unsigned int index = 0;
+ unsigned int fmtIndex = 0;
+ while (index < text.length())
+ {
+ Gfx::FontType font = static_cast<Gfx::FontType>(format[fmtIndex] & Gfx::FONT_MASK_FONT);
+
+ Gfx::UTF8Char ch;
+
+ int len = StrUtils::Utf8CharSizeAt(text, index);
+ if (len >= 1)
+ ch.c1 = text[index];
+ if (len >= 2)
+ ch.c2 = text[index+1];
+ if (len >= 3)
+ ch.c3 = text[index+2];
+
+ if (font != Gfx::FONT_BUTTON)
+ {
+ if (ch.c1 == '\n')
+ return index+1;
+ if (ch.c1 == ' ')
+ cut = index+1;
+ }
+
+ pos += GetCharWidth(ch, font, size, pos);
+ if (pos > width)
+ {
+ if (cut == 0) return index;
+ else return cut;
+ }
+
+ index += len;
+ fmtIndex++;
+ }
+
+ return index;
+}
+
+int Gfx::CText::Justify(const std::string &text, Gfx::FontType font, float size, float width)
+{
+ assert(font != Gfx::FONT_BUTTON);
+
+ float pos = 0.0f;
+ int cut = 0;
+ unsigned int index = 0;
+ while (index < text.length())
+ {
+ Gfx::UTF8Char ch;
+
+ int len = StrUtils::Utf8CharSizeAt(text, index);
+ if (len >= 1)
+ ch.c1 = text[index];
+ if (len >= 2)
+ ch.c2 = text[index+1];
+ if (len >= 3)
+ ch.c3 = text[index+2];
+
+ index += len;
+
+ if (ch.c1 == '\n')
+ return index+1;
+
+ if (ch.c1 == ' ' )
+ cut = index+1;
+
+ pos += GetCharWidth(ch, font, size, pos);
+ if (pos > width)
+ {
+ if (cut == 0) return index;
+ else return cut;
+ }
+ }
+
+ return index;
+}
+
+int Gfx::CText::Detect(const std::string &text, const std::vector<FontMetaChar> &format,
+ float size, float offset)
+{
+ assert(StrUtils::Utf8StringLength(text) == format.size());
+
+ float pos = 0.0f;
+ unsigned int index = 0;
+ unsigned int fmtIndex = 0;
+ while (index < text.length())
+ {
+ Gfx::FontType font = static_cast<Gfx::FontType>(format[fmtIndex] & Gfx::FONT_MASK_FONT);
+
+ // TODO: if (font == Gfx::FONT_BUTTON)
+ if (font == Gfx::FONT_BUTTON) continue;
+
+ Gfx::UTF8Char ch;
+
+ int len = StrUtils::Utf8CharSizeAt(text, index);
+ if (len >= 1)
+ ch.c1 = text[index];
+ if (len >= 2)
+ ch.c2 = text[index+1];
+ if (len >= 3)
+ ch.c3 = text[index+2];
+
+ if (ch.c1 == '\n')
+ return index;
+
+ float width = GetCharWidth(ch, font, size, pos);
+ if (offset <= pos + width/2.0f)
+ return index;
+
+ pos += width;
+ index += len;
+ fmtIndex++;
+ }
+
+ return index;
+}
+
+int Gfx::CText::Detect(const std::string &text, Gfx::FontType font, float size, float offset)
+{
+ assert(font != Gfx::FONT_BUTTON);
+
+ float pos = 0.0f;
+ unsigned int index = 0;
+ while (index < text.length())
+ {
+ Gfx::UTF8Char ch;
+
+ int len = StrUtils::Utf8CharSizeAt(text, index);
+ if (len >= 1)
+ ch.c1 = text[index];
+ if (len >= 2)
+ ch.c2 = text[index+1];
+ if (len >= 3)
+ ch.c3 = text[index+2];
+
+ index += len;
+
+ if (ch.c1 == '\n')
+ return index;
+
+ float width = GetCharWidth(ch, font, size, pos);
+ if (offset <= pos + width/2.0f)
+ return index;
+
+ pos += width;
+ }
+
+ return index;
+}
+
+void Gfx::CText::DrawString(const std::string &text, const std::vector<FontMetaChar> &format,
+ float size, Math::Point pos, float width, int eol)
+{
+ assert(StrUtils::Utf8StringLength(text) == format.size());
+
+ m_engine->SetState(Gfx::ENG_RSTATE_TEXT);
+
+ Gfx::FontType font = Gfx::FONT_COLOBOT;
+ float start = pos.x;
+
+ unsigned int index = 0;
+ unsigned int fmtIndex = 0;
+ while (index < text.length())
+ {
+ font = static_cast<Gfx::FontType>(format[fmtIndex] & Gfx::FONT_MASK_FONT);
+
+ // TODO: if (font == Gfx::FONT_BUTTON)
+ if (font == Gfx::FONT_BUTTON) continue;
+
+ Gfx::UTF8Char ch;
+
+ int len = StrUtils::Utf8CharSizeAt(text, index);
+ if (len >= 1)
+ ch.c1 = text[index];
+ if (len >= 2)
+ ch.c2 = text[index+1];
+ if (len >= 3)
+ ch.c3 = text[index+2];
+
+ float offset = pos.x - start;
+ float cw = GetCharWidth(ch, font, size, offset);
+ if (offset + cw > width) // exceeds the maximum width?
+ {
+ // TODO: special end-of-line char
+ break;
+ }
+
+ Gfx::FontHighlight hl = static_cast<Gfx::FontHighlight>(format[fmtIndex] & Gfx::FONT_MASK_HIGHLIGHT);
+ if (hl != Gfx::FONT_HIGHLIGHT_NONE)
+ {
+ Math::Point charSize;
+ charSize.x = GetCharWidth(ch, font, size, offset);
+ charSize.y = GetHeight(font, size);
+ DrawHighlight(hl, pos, charSize);
+ }
+
+ DrawChar(ch, font, size, pos);
+
+ index += len;
+ fmtIndex++;
+ }
+
+ // TODO: eol
+}
+
+void Gfx::CText::DrawString(const std::string &text, Gfx::FontType font,
+ float size, Math::Point pos, float width, int eol)
+{
+ assert(font != Gfx::FONT_BUTTON);
+
+ m_engine->SetState(Gfx::ENG_RSTATE_TEXT);
+
+ unsigned int index = 0;
+ while (index < text.length())
+ {
+ Gfx::UTF8Char ch;
+
+ int len = StrUtils::Utf8CharSizeAt(text, index);
+ if (len >= 1)
+ ch.c1 = text[index];
+ if (len >= 2)
+ ch.c2 = text[index+1];
+ if (len >= 3)
+ ch.c3 = text[index+2];
+
+ index += len;
+
+ DrawChar(ch, font, size, pos);
+ }
+}
+
+void Gfx::CText::DrawHighlight(Gfx::FontHighlight hl, Math::Point pos, Math::Point size)
+{
+ // Gradient colors
+ Gfx::Color grad[4];
+
+ // TODO: switch to alpha factors
+
+ switch (hl)
+ {
+ case Gfx::FONT_HIGHLIGHT_LINK:
+ grad[0] = grad[1] = grad[2] = grad[3] = Gfx::Color(0.0f, 0.0f, 1.0f, 0.5f);
+ break;
+
+ case Gfx::FONT_HIGHLIGHT_TOKEN:
+ grad[0] = grad[1] = Gfx::Color(248.0f / 256.0f, 248.0f / 256.0f, 248.0f / 256.0f, 0.5f);
+ grad[2] = grad[3] = Gfx::Color(248.0f / 256.0f, 220.0f / 256.0f, 188.0f / 256.0f, 0.5f);
+ break;
+
+ case Gfx::FONT_HIGHLIGHT_TYPE:
+ grad[0] = grad[1] = Gfx::Color(248.0f / 256.0f, 248.0f / 256.0f, 248.0f / 256.0f, 0.5f);
+ grad[2] = grad[3] = Gfx::Color(169.0f / 256.0f, 234.0f / 256.0f, 169.0f / 256.0f, 0.5f);
+ break;
+
+ case Gfx::FONT_HIGHLIGHT_CONST:
+ grad[0] = grad[1] = Gfx::Color(248.0f / 256.0f, 248.0f / 256.0f, 248.0f / 256.0f, 0.5f);
+ grad[2] = grad[3] = Gfx::Color(248.0f / 256.0f, 176.0f / 256.0f, 169.0f / 256.0f, 0.5f);
+ break;
+
+ case Gfx::FONT_HIGHLIGHT_REM:
+ grad[0] = grad[1] = Gfx::Color(248.0f / 256.0f, 248.0f / 256.0f, 248.0f / 256.0f, 0.5f);
+ grad[2] = grad[3] = Gfx::Color(248.0f / 256.0f, 169.0f / 256.0f, 248.0f / 256.0f, 0.5f);
+ break;
+
+ case Gfx::FONT_HIGHLIGHT_KEY:
+ grad[0] = grad[1] = grad[2] = grad[3] =
+ Gfx::Color(192.0f / 256.0f, 192.0f / 256.0f, 192.0f / 256.0f, 0.5f);
+ break;
+
+ default:
+ return;
+ }
+
+ Math::IntPoint vsize = m_engine->GetWindowSize();
+ float h = 0.0f;
+ if (vsize.y <= 768.0f) // 1024x768 or less?
+ h = 1.01f / vsize.y; // 1 pixel
+ else // more than 1024x768?
+ h = 2.0f / vsize.y; // 2 pixels
+
+ Math::Point p1, p2;
+ p1.x = pos.x;
+ p2.x = pos.x + size.x;
+
+ if (hl == Gfx::FONT_HIGHLIGHT_LINK)
+ {
+ p1.y = pos.y;
+ p2.y = pos.y + h; // just emphasized
+ }
+ else
+ {
+ p1.y = pos.y;
+ p2.y = pos.y + size.y;
+ }
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, false);
+
+ Gfx::VertexCol quad[] =
+ {
+ Gfx::VertexCol(Math::Vector(p1.x, p1.y, 0.0f), grad[3]),
+ Gfx::VertexCol(Math::Vector(p1.x, p2.y, 0.0f), grad[0]),
+ Gfx::VertexCol(Math::Vector(p2.x, p1.y, 0.0f), grad[2]),
+ Gfx::VertexCol(Math::Vector(p2.x, p2.y, 0.0f), grad[1])
+ };
+
+ m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4);
+ m_engine->AddStatisticTriangle(2);
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+}
+
+void Gfx::CText::DrawChar(Gfx::UTF8Char ch, Gfx::FontType font, float size, Math::Point &pos)
+{
+ // TODO: if (font == Gfx::FONT_BUTTON)
+ if (font == Gfx::FONT_BUTTON) return;
+
+ // TODO: special chars?
+
+ CachedFont* cf = GetOrOpenFont(font, size);
+
+ if (cf == nullptr)
+ return;
+
+ auto it = cf->cache.find(ch);
+ CharTexture tex;
+ if (it != cf->cache.end())
+ {
+ tex = (*it).second;
+ }
+ else
+ {
+ tex = CreateCharTexture(ch, cf);
+
+ if (tex.id == 0) // invalid
+ return;
+
+ cf->cache[ch] = tex;
+ }
+
+ Math::Point p1(pos.x, pos.y + tex.charSize.y - tex.texSize.y);
+ Math::Point p2(pos.x + tex.texSize.x, pos.y + tex.charSize.y);
+
+ Math::Vector n(0.0f, 0.0f, -1.0f); // normal
+
+ Gfx::Vertex quad[4] =
+ {
+ Gfx::Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(0.0f, 1.0f)),
+ Gfx::Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(0.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(1.0f, 1.0f)),
+ Gfx::Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(1.0f, 0.0f))
+ };
+
+ m_device->SetTexture(0, tex.id);
+ m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4);
+ m_engine->AddStatisticTriangle(2);
+
+ pos.x += tex.charSize.x;
+}
+
+Gfx::CachedFont* Gfx::CText::GetOrOpenFont(Gfx::FontType font, float size)
+{
+ // TODO: sizing
+ int pointSize = static_cast<int>(size);
+
+ if (m_lastCachedFont != nullptr)
+ {
+ if (m_lastFontType == font && m_lastFontSize == pointSize)
+ return m_lastCachedFont;
+ }
+
+ auto it = m_fonts.find(font);
+ if (it == m_fonts.end())
+ {
+ m_error = std::string("Invalid font type ") + StrUtils::ToString<int>(static_cast<int>(font));
+ return nullptr;
+ }
+
+ MultisizeFont* mf = (*it).second;
+
+ auto jt = mf->fonts.find(pointSize);
+ if (jt != mf->fonts.end())
+ {
+ m_lastCachedFont = (*jt).second;
+ m_lastFontType = font;
+ m_lastFontSize = pointSize;
+ return m_lastCachedFont;
+ }
+
+ std::string path = CApplication::GetInstance().GetDataFilePath(m_fontPath, mf->fileName);
+
+ m_lastCachedFont = new CachedFont();
+ m_lastCachedFont->font = TTF_OpenFont(path.c_str(), pointSize);
+ if (m_lastCachedFont->font == nullptr)
+ m_error = std::string("TTF_OpenFont error ") + std::string(TTF_GetError());
+
+ mf->fonts[pointSize] = m_lastCachedFont;
+
+ return m_lastCachedFont;
+}
+
+Gfx::CharTexture Gfx::CText::CreateCharTexture(Gfx::UTF8Char ch, Gfx::CachedFont* font)
+{
+ CharTexture texture;
+
+ SDL_Surface* textSurface = nullptr;
+ SDL_Color white = {255, 255, 255, 0};
+ char str[] = { ch.c1, ch.c2, ch.c3, '\0' };
+ textSurface = TTF_RenderUTF8_Blended(font->font, str, white);
+
+ if (textSurface == nullptr)
+ {
+ m_error = "TTF_Render error";
+ return texture;
+ }
+
+ int w = Math::NextPowerOfTwo(textSurface->w);
+ int h = Math::NextPowerOfTwo(textSurface->h);
+
+ textSurface->flags = textSurface->flags & (~SDL_SRCALPHA);
+ SDL_Surface* textureSurface = SDL_CreateRGBSurface(0, w, h, 32, 0x00ff0000, 0x0000ff00,
+ 0x000000ff, 0xff000000);
+ SDL_BlitSurface(textSurface, NULL, textureSurface, NULL);
+
+ ImageData data;
+ data.surface = textureSurface;
+
+ Gfx::TextureCreateParams createParams;
+ createParams.format = Gfx::TEX_IMG_RGBA;
+ createParams.minFilter = Gfx::TEX_MIN_FILTER_NEAREST;
+ createParams.magFilter = Gfx::TEX_MAG_FILTER_NEAREST;
+ createParams.mipmap = false;
+
+ Gfx::Texture tex = m_device->CreateTexture(&data, createParams);
+
+ data.surface = nullptr;
+
+ SDL_FreeSurface(textSurface);
+ SDL_FreeSurface(textureSurface);
+
+ if (! tex.valid)
+ {
+ m_error = "Texture create error";
+ return texture;
+ }
+
+ texture.id = tex.id;
+ texture.texSize = m_engine->WindowToInterfaceSize(Math::IntPoint(textureSurface->w, textureSurface->h));
+ texture.charSize = m_engine->WindowToInterfaceSize(Math::IntPoint(textSurface->w, textSurface->h));
+
+ return texture;
+}
diff --git a/src/graphics/engine/text.h b/src/graphics/engine/text.h
index c2de220..24251ab 100644
--- a/src/graphics/engine/text.h
+++ b/src/graphics/engine/text.h
@@ -15,99 +15,287 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// text.h
+/**
+ * \file graphics/engine/text.h
+ * \brief Text rendering - Gfx::CText class
+ */
#pragma once
-#include "graphics/engine/engine.h"
-#include "graphics/core/device.h"
#include "math/point.h"
+#include <vector>
+#include <map>
class CInstanceManager;
-
namespace Gfx {
-const float SMALLFONT = 10.0f;
-const float BIGFONT = 15.0f;
+class CEngine;
+class CDevice;
+
+//! Standard small font size
+const float FONT_SIZE_SMALL = 10.0f;
+//! Standard big font size
+const float FONT_SIZE_BIG = 15.0f;
+
+/**
+ \enum TextAlign
+ \brief Type of text alignment */
+enum TextAlign
+{
+ TEXT_ALIGN_RIGHT,
+ TEXT_ALIGN_LEFT,
+ TEXT_ALIGN_CENTER
+};
-const float NORMSTRETCH = 0.8f;
+/* Font meta char constants */
+//! Type used for font character metainfo
+typedef short FontMetaChar;
+/**
+ \enum FontType
+ \brief Type of font
+ Bitmask in lower 4 bits (mask 0x00f) */
enum FontType
{
- FONT_COLOBOT = 0,
- FONT_COURIER = 1,
- FONT_BUTTON = 2,
+ //! Flag for bold font subtype
+ FONT_BOLD = 0x04,
+ //! Flag for italic font subtype
+ FONT_ITALIC = 0x08,
+
+ //! Default colobot font used for interface
+ FONT_COLOBOT = 0x00,
+ //! Alias for bold colobot font
+ FONT_COLOBOT_BOLD = FONT_COLOBOT | FONT_BOLD,
+ //! Alias for italic colobot font
+ FONT_COLOBOT_ITALIC = FONT_COLOBOT | FONT_ITALIC,
+
+ //! Courier (monospace) font used mainly in code editor (only regular & bold)
+ FONT_COURIER = 0x01,
+ //! Alias for bold courier font
+ FONT_COURIER_BOLD = FONT_COURIER | FONT_BOLD,
+
+ // 0x02 left for possible another font
+
+ //! Pseudo-font loaded from textures for buttons, icons, etc.
+ FONT_BUTTON = 0x03,
};
+/**
+ \enum FontTitle
+ \brief Size of font title
+
+ Used internally by CEdit
+
+ Bitmask in 2 bits left shifted 4 (mask 0x030) */
enum FontTitle
{
- TITLE_BIG = 0x04,
- TITLE_NORM = 0x08,
- TITLE_LITTLE = 0x0c,
+ FONT_TITLE_BIG = 0x01 << 4,
+ FONT_TITLE_NORM = 0x02 << 4,
+ FONT_TITLE_LITTLE = 0x03 << 4,
};
-enum FontColor
+/**
+ \enum FontHighlight
+ \brief Type of color highlight for text
+
+ Bitmask in 3 bits left shifted 6 (mask 0x1c0) */
+enum FontHighlight
+{
+ FONT_HIGHLIGHT_NONE = 0x00 << 6,
+ FONT_HIGHLIGHT_LINK = 0x01 << 6,
+ FONT_HIGHLIGHT_TOKEN = 0x02 << 6,
+ FONT_HIGHLIGHT_TYPE = 0x03 << 6,
+ FONT_HIGHLIGHT_CONST = 0x04 << 6,
+ FONT_HIGHLIGHT_REM = 0x05 << 6,
+ FONT_HIGHLIGHT_KEY = 0x06 << 6,
+ FONT_HIGHLIGHT_TABLE = 0x07 << 6,
+};
+
+/**
+ \enum FontMask
+ \brief Masks in FontMetaChar for different attributes */
+enum FontMask
{
- COLOR_LINK = 0x10,
- COLOR_TOKEN = 0x20,
- COLOR_TYPE = 0x30,
- COLOR_CONST = 0x40,
- COLOR_REM = 0x50,
- COLOR_KEY = 0x60,
- COLOR_TABLE = 0x70,
+ //! Mask for FontType
+ FONT_MASK_FONT = 0x00f,
+ //! Mask for FontTitle
+ FONT_MASK_TITLE = 0x030,
+ //! Mask for FontHighlight
+ FONT_MASK_HIGHLIGHT = 0x1c0,
+ //! Mask for image bit (TODO: not used?)
+ FONT_MASK_IMAGE = 0x200
};
-const short FONT_MASK = 0x03;
-const short TITLE_MASK = 0x0c;
-const short COLOR_MASK = 0x70;
-const short IMAGE_MASK = 0x80;
+/**
+ \struct UTF8Char
+ \brief UTF-8 character in font cache
+
+ Only 3-byte chars are supported */
+struct UTF8Char
+{
+ char c1, c2, c3;
+ explicit UTF8Char(char ch1 = '\0', char ch2 = '\0', char ch3 = '\0')
+ : c1(ch1), c2(ch2), c3(ch3) {}
+
+ inline bool operator<(const UTF8Char &other) const
+ {
+ if (c1 < other.c1)
+ return true;
+ else if (c1 > other.c1)
+ return false;
+
+ if (c2 < other.c2)
+ return true;
+ else if (c2 > other.c2)
+ return false;
+
+ return c3 < other.c3;
+ }
+
+ inline bool operator==(const UTF8Char &other) const
+ {
+ return c1 == other.c1 && c2 == other.c2 && c3 == other.c3;
+ }
+};
-class CText {
+/**
+ \struct CharTexture
+ \brief Texture of font character */
+struct CharTexture
+{
+ unsigned int id;
+ Math::Point texSize;
+ Math::Point charSize;
+
+ CharTexture() : id(0) {}
+};
+
+// Definition is private - in text.cpp
+struct CachedFont;
+
+/**
+ \struct MultisizeFont
+ \brief Font with multiple possible sizes */
+struct MultisizeFont
+{
+ std::string fileName;
+ std::map<int, CachedFont*> fonts;
+
+ MultisizeFont(const std::string &fn)
+ : fileName(fn) {}
+};
+
+/**
+ \class CText
+ \brief Text rendering engine
+
+ CText is responsible for drawing text in 2D interface. Font rendering is done using
+ textures generated by SDL_ttf from TTF font files.
+
+ All functions rendering text are divided into two types:
+ - single font - function takes a single Gfx::FontType argument that (along with size)
+ determines the font to be used for all characters,
+ - multi-font - function takes the text as one argument and a std::vector of FontMetaChar
+ with per-character formatting information (font, highlights and some other info used by CEdit)
+
+ All font rendering is done in UTF-8.
+*/
+class CText
+{
public:
CText(CInstanceManager *iMan, Gfx::CEngine* engine);
~CText();
+ //! Sets the device to be used
void SetDevice(Gfx::CDevice *device);
- void DrawText(char *string, char *format, int len, Math::Point pos, float width, int justif, float size, float stretch, int eol);
- void DrawText(char *string, char *format, Math::Point pos, float width, int justif, float size, float stretch, int eol);
- void DrawText(char *string, int len, Math::Point pos, float width, int justif, float size, float stretch, FontType font, int eol);
- void DrawText(char *string, Math::Point pos, float width, int justif, float size, float stretch, FontType font, int eol);
- void DimText(char *string, char *format, int len, Math::Point pos, int justif, float size, float stretch, Math::Point &start, Math::Point &end);
- void DimText(char *string, char *format, Math::Point pos, int justif, float size, float stretch, Math::Point &start, Math::Point &end);
- void DimText(char *string, int len, Math::Point pos, int justif, float size, float stretch, FontType font, Math::Point &start, Math::Point &end);
- void DimText(char *string, Math::Point pos, int justif, float size, float stretch, FontType font, Math::Point &start, Math::Point &end);
+ //! Returns the last encountered error
+ std::string GetError();
+
+ //! Initializes the font engine; must be called after SetDevice()
+ bool Create();
+ //! Frees resources before exit
+ void Destroy();
+
+ //! Flushes cached textures
+ void FlushCache();
+
+ //! Draws text (multi-format)
+ void DrawText(const std::string &text, const std::vector<Gfx::FontMetaChar> &format,
+ float size, Math::Point pos, float width, Gfx::TextAlign align,
+ int eol);
+ //! Draws text (one font)
+ void DrawText(const std::string &text, Gfx::FontType font,
+ float size, Math::Point pos, float width, Gfx::TextAlign align,
+ int eol);
- float RetAscent(float size, FontType font);
- float RetDescent(float size, FontType font);
- float RetHeight(float size, FontType font);
+ //! Calculates dimensions for text (multi-format)
+ void SizeText(const std::string &text, const std::vector<Gfx::FontMetaChar> &format,
+ float size, Math::Point pos, Gfx::TextAlign align,
+ Math::Point &start, Math::Point &end);
+ //! Calculates dimensions for text (one font)
+ void SizeText(const std::string &text, Gfx::FontType font,
+ float size, Math::Point pos, Gfx::TextAlign align,
+ Math::Point &start, Math::Point &end);
- float RetStringWidth(char *string, char *format, int len, float size, float stretch);
- float RetStringWidth(char *string, int len, float size, float stretch, FontType font);
- float RetCharWidth(int character, float offset, float size, float stretch, FontType font);
+ //! Returns the ascent font metric
+ float GetAscent(Gfx::FontType font, float size);
+ //! Returns the descent font metric
+ float GetDescent(Gfx::FontType font, float size);
+ //! Returns the height font metric
+ float GetHeight(Gfx::FontType font, float size);
- int Justif(char *string, char *format, int len, float width, float size, float stretch);
- int Justif(char *string, int len, float width, float size, float stretch, FontType font);
- int Detect(char *string, char *format, int len, float offset, float size, float stretch);
- int Detect(char *string, int len, float offset, float size, float stretch, FontType font);
+ //! Returns width of string (multi-format)
+ float GetStringWidth(const std::string &text,
+ const std::vector<Gfx::FontMetaChar> &format, float size);
+ //! Returns width of string (single font)
+ float GetStringWidth(const std::string &text, Gfx::FontType font, float size);
+ //! Returns width of single character
+ float GetCharWidth(Gfx::UTF8Char ch, Gfx::FontType font, float size, float offset);
+
+ //! Justifies a line of text (multi-format)
+ int Justify(const std::string &text, const std::vector<Gfx::FontMetaChar> &format,
+ float size, float width);
+ //! Justifies a line of text (one font)
+ int Justify(const std::string &text, Gfx::FontType font, float size, float width);
+
+ //! Returns the most suitable position to a given offset (multi-format)
+ int Detect(const std::string &text, const std::vector<Gfx::FontMetaChar> &format,
+ float size, float offset);
+ //! Returns the most suitable position to a given offset (one font)
+ int Detect(const std::string &text, Gfx::FontType font, float size, float offset);
protected:
- void DrawString(char *string, char *format, int len, Math::Point pos, float width, float size, float stretch, int eol);
- void DrawString(char *string, int len, Math::Point pos, float width, float size, float stretch, FontType font, int eol);
- void DrawColor(Math::Point pos, float size, float width, int color);
- void DrawChar(int character, Math::Point pos, float size, float stretch, FontType font);
+ Gfx::CachedFont* GetOrOpenFont(Gfx::FontType type, float size);
+ Gfx::CharTexture CreateCharTexture(Gfx::UTF8Char ch, Gfx::CachedFont* font);
+
+ void DrawString(const std::string &text, const std::vector<Gfx::FontMetaChar> &format,
+ float size, Math::Point pos, float width, int eol);
+ void DrawString(const std::string &text, Gfx::FontType font,
+ float size, Math::Point pos, float width, int eol);
+ void DrawHighlight(Gfx::FontHighlight hl, Math::Point pos, Math::Point size);
+ void DrawChar(Gfx::UTF8Char ch, Gfx::FontType font, float size, Math::Point &pos);
protected:
CInstanceManager* m_iMan;
Gfx::CEngine* m_engine;
Gfx::CDevice* m_device;
+ std::string m_error;
+ float m_defaultSize;
+ std::string m_fontPath;
+
+ std::map<Gfx::FontType, Gfx::MultisizeFont*> m_fonts;
+
+ Gfx::FontType m_lastFontType;
+ int m_lastFontSize;
+ Gfx::CachedFont* m_lastCachedFont;
};
}; // namespace Gfx
diff --git a/src/graphics/engine/water.cpp b/src/graphics/engine/water.cpp
index a157e82..8fbd1ae 100644
--- a/src/graphics/engine/water.cpp
+++ b/src/graphics/engine/water.cpp
@@ -19,5 +19,638 @@
#include "graphics/engine/water.h"
+#include "common/iman.h"
+#include "graphics/engine/engine.h"
+#include "graphics/engine/terrain.h"
+#include "sound/sound.h"
+
+
+const int WATERLINE_PREALLOCATE_COUNT = 500;
+
+// TODO: remove the limit?
+const int VAPOR_SIZE = 10;
+
+
+Gfx::CWater::CWater(CInstanceManager* iMan, Gfx::CEngine* engine)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_WATER, this);
+
+ m_engine = engine;
+ m_terrain = nullptr;
+ m_particule = nullptr;
+ m_sound = nullptr;
+
+ m_type[0] = WATER_NULL;
+ m_type[1] = WATER_NULL;
+ m_level = 0.0f;
+ m_draw = true;
+ m_lava = false;
+ m_color = 0xffffffff;
+ m_subdiv = 4;
+
+ m_line.reserve(WATERLINE_PREALLOCATE_COUNT);
+
+ std::vector<Gfx::WaterVapor>(VAPOR_SIZE).swap(m_vapor);
+}
+
+Gfx::CWater::~CWater()
+{
+ m_iMan = nullptr;
+ m_engine = nullptr;
+ m_terrain = nullptr;
+ m_particule = nullptr;
+ m_sound = nullptr;
+}
+
+
+bool Gfx::CWater::EventProcess(const Event &event)
+{
+ if (event.type == EVENT_FRAME)
+ return EventFrame(event);
+
+ return true;
+}
+
+bool Gfx::CWater::EventFrame(const Event &event)
+{
+ if (m_engine->GetPause()) return true;
+
+ m_time += event.rTime;
+
+ if (m_type[0] == WATER_NULL) return true;
+
+ if (m_lava)
+ LavaFrame(event.rTime);
+
+ return true;
+}
+
+void Gfx::CWater::LavaFrame(float rTime)
+{
+ if (m_particule == nullptr)
+ m_particule = static_cast<Gfx::CParticle*>( m_iMan->SearchInstance(CLASS_PARTICULE) );
+
+ for (int i = 0; i < static_cast<int>( m_vapor.size() ); i++)
+ VaporFrame(i, rTime);
+
+ if (m_time - m_lastLava >= 0.1f)
+ {
+ Math::Vector eye = m_engine->GetEyePt();
+ Math::Vector lookat = m_engine->GetLookatPt();
+
+ float distance = Math::Rand()*200.0f;
+ float shift = (Math::Rand()-0.5f)*200.0f;
+
+ Math::Vector dir = Normalize(lookat-eye);
+ Math::Vector pos = eye + dir*distance;
+
+ Math::Vector perp;
+ perp.x = -dir.z;
+ perp.y = dir.y;
+ perp.z = dir.x;
+ pos = pos + perp*shift;
+
+ float level = m_terrain->GetFloorLevel(pos, true);
+ if (level < m_level)
+ {
+ pos.y = m_level;
+
+ level = Math::Rand();
+ if (level < 0.8f)
+ {
+ if ( VaporCreate(Gfx::PARTIFIRE, pos, 0.02f+Math::Rand()*0.06f) )
+ m_lastLava = m_time;
+ }
+ else if (level < 0.9f)
+ {
+ if ( VaporCreate(Gfx::PARTIFLAME, pos, 0.5f+Math::Rand()*3.0f) )
+ m_lastLava = m_time;
+ }
+ else
+ {
+ if ( VaporCreate(Gfx::PARTIVAPOR, pos, 0.2f+Math::Rand()*2.0f) )
+ m_lastLava = m_time;
+ }
+ }
+ }
+}
+
+void Gfx::CWater::VaporFlush()
+{
+ m_vapor.clear();
+}
+
+bool Gfx::CWater::VaporCreate(Gfx::ParticleType type, Math::Vector pos, float delay)
+{
+ for (int i = 0; i < static_cast<int>( m_vapor.size() ); i++)
+ {
+ if (! m_vapor[i].used)
+ {
+ m_vapor[i].used = true;
+ m_vapor[i].type = type;
+ m_vapor[i].pos = pos;
+ m_vapor[i].delay = delay;
+ m_vapor[i].time = 0.0f;
+ m_vapor[i].last = 0.0f;
+
+ if (m_vapor[i].type == PARTIFIRE)
+ m_sound->Play(SOUND_BLUP, pos, 1.0f, 1.0f-Math::Rand()*0.5f);
+
+ if (m_vapor[i].type == PARTIVAPOR)
+ m_sound->Play(SOUND_PSHHH, pos, 0.3f, 2.0f);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void Gfx::CWater::VaporFrame(int i, float rTime)
+{
+ m_vapor[i].time += rTime;
+
+ if (m_sound == nullptr)
+ m_sound = static_cast<CSoundInterface*>(m_iMan->SearchInstance(CLASS_SOUND));
+
+ if (m_vapor[i].time <= m_vapor[i].delay)
+ {
+ if (m_time-m_vapor[i].last >= m_engine->ParticleAdapt(0.02f))
+ {
+ m_vapor[i].last = m_time;
+
+ if (m_vapor[i].type == PARTIFIRE)
+ {
+ for (int j = 0; j < 10; j++)
+ {
+ Math::Vector pos = m_vapor[i].pos;
+ pos.x += (Math::Rand()-0.5f)*2.0f;
+ pos.z += (Math::Rand()-0.5f)*2.0f;
+ pos.y -= 1.0f;
+ Math::Vector speed;
+ speed.x = (Math::Rand()-0.5f)*6.0f;
+ speed.z = (Math::Rand()-0.5f)*6.0f;
+ speed.y = 8.0f+Math::Rand()*5.0f;
+ Math::Point dim;
+ dim.x = Math::Rand()*1.5f+1.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticle(pos, speed, dim, PARTIERROR, 2.0f, 10.0f);
+ }
+ }
+ else if (m_vapor[i].type == PARTIFLAME)
+ {
+ Math::Vector pos = m_vapor[i].pos;
+ pos.x += (Math::Rand()-0.5f)*8.0f;
+ pos.z += (Math::Rand()-0.5f)*8.0f;
+ pos.y -= 2.0f;
+ Math::Vector speed;
+ speed.x = (Math::Rand()-0.5f)*2.0f;
+ speed.z = (Math::Rand()-0.5f)*2.0f;
+ speed.y = 4.0f+Math::Rand()*4.0f;
+ Math::Point dim;
+ dim.x = Math::Rand()*2.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticle(pos, speed, dim, PARTIFLAME);
+ }
+ else
+ {
+ Math::Vector pos = m_vapor[i].pos;
+ pos.x += (Math::Rand()-0.5f)*4.0f;
+ pos.z += (Math::Rand()-0.5f)*4.0f;
+ pos.y -= 2.0f;
+ Math::Vector speed;
+ speed.x = (Math::Rand()-0.5f)*2.0f;
+ speed.z = (Math::Rand()-0.5f)*2.0f;
+ speed.y = 8.0f+Math::Rand()*8.0f;
+ Math::Point dim;
+ dim.x = Math::Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticle(pos, speed, dim, PARTIVAPOR);
+ }
+ }
+ }
+ else
+ {
+ m_vapor[i].used = false;
+ }
+}
+
+void Gfx::CWater::AdjustLevel(Math::Vector &pos, Math::Vector &norm,
+ Math::Point &uv1, Math::Point &uv2)
+{
+ float t1 = m_time*1.5f + pos.x*0.1f * pos.z*0.2f;
+ pos.y += sinf(t1)*m_eddy.y;
+
+ t1 = m_time*1.5f;
+ uv1.x = (pos.x+10000.0f)/40.0f+sinf(t1)*m_eddy.x*0.02f;
+ uv1.y = (pos.z+10000.0f)/40.0f-cosf(t1)*m_eddy.z*0.02f;
+ uv2.x = (pos.x+10010.0f)/20.0f+cosf(-t1)*m_eddy.x*0.02f;
+ uv2.y = (pos.z+10010.0f)/20.0f-sinf(-t1)*m_eddy.z*0.02f;
+
+ t1 = m_time*0.50f + pos.x*2.1f + pos.z*1.1f;
+ float t2 = m_time*0.75f + pos.x*2.0f + pos.z*1.0f;
+ norm = Math::Vector(sinf(t1)*m_glint, 1.0f, sinf(t2)*m_glint);
+}
+
+/** This surface prevents to see the sky (background) underwater! */
+void Gfx::CWater::DrawBack()
+{
+ /* TODO!
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DMATERIAL7 material;
+ Math::Matrix matrix;
+ Math::Vector eye, lookat, n, p, p1, p2;
+ Math::Point uv1, uv2;
+ float deep, dist;
+
+ if ( !m_bDraw ) return;
+ if ( m_type[0] == WATER_NULL ) return;
+ if ( m_lineUsed == 0 ) return;
+
+ eye = m_engine->GetEyePt();
+ lookat = m_engine->GetLookatPt();
+
+ ZeroMemory( &material, sizeof(D3DMATERIAL7) );
+ material.diffuse = m_diffuse;
+ material.ambient = m_ambient;
+ m_engine->SetMaterial(material);
+
+ m_engine->SetTexture("", 0);
+
+ device = m_engine->GetD3DDevice();
+ device->SetRenderState(D3DRENDERSTATE_LIGHTING, false);
+ device->SetRenderState(D3DRENDERSTATE_ZENABLE, false);
+ device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false);
+ m_engine->SetState(D3DSTATENORMAL);
+
+ deep = m_engine->GetDeepView(0);
+ m_engine->SetDeepView(deep*2.0f, 0);
+ m_engine->SetFocus(m_engine->GetFocus());
+ m_engine->UpdateMatProj(); // twice the depth of view
+
+ matrix.LoadIdentity();
+ {
+ D3DMATRIX mat = MAT_TO_D3DMAT(matrix);
+ device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
+ }
+
+ p.x = eye.x;
+ p.z = eye.z;
+ dist = Math::DistanceProjected(eye, lookat);
+ p.x = (lookat.x-eye.x)*deep*1.0f/dist + eye.x;
+ p.z = (lookat.z-eye.z)*deep*1.0f/dist + eye.z;
+
+ p1.x = (lookat.z-eye.z)*deep*2.0f/dist + p.x;
+ p1.z = -(lookat.x-eye.x)*deep*2.0f/dist + p.z;
+ p2.x = -(lookat.z-eye.z)*deep*2.0f/dist + p.x;
+ p2.z = (lookat.x-eye.x)*deep*2.0f/dist + p.z;
+
+ p1.y = -50.0f;
+ p2.y = m_level;
+
+ n.x = (lookat.x-eye.x)/dist;
+ n.z = (lookat.z-eye.z)/dist;
+ n.y = 0.0f;
+
+ uv1.x = uv1.y = 0.0f;
+ uv2.x = uv2.y = 0.0f;
+
+ vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p2.y, p1.z), n, uv1.x,uv2.y);
+ vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p1.y, p1.z), n, uv1.x,uv1.y);
+ vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p2.y, p2.z), n, uv2.x,uv2.y);
+ vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p1.y, p2.z), n, uv2.x,uv1.y);
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+
+ m_engine->SetDeepView(deep, 0);
+ m_engine->SetFocus(m_engine->GetFocus());
+ m_engine->UpdateMatProj(); // gives the initial depth of view
+
+ device->SetRenderState(D3DRENDERSTATE_LIGHTING, true);
+ device->SetRenderState(D3DRENDERSTATE_ZENABLE, true);
+ device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false);*/
+}
+
+void Gfx::CWater::DrawSurf()
+{
+ /* TODO!
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2* vertex; // triangles
+ D3DMATERIAL7 material;
+ Math::Matrix matrix;
+ Math::Vector eye, lookat, n, pos, p;
+ Math::Point uv1, uv2;
+ bool bUnder;
+ DWORD flags;
+ float deep, size, sizez, radius;
+ int rankview, i, j, u;
+
+ if (! m_draw) return;
+ if (m_type[0] == Gfx::WATER_NULL) return;
+ if (m_line.empty()) return;
+
+ vertex = (D3DVERTEX2*)malloc(sizeof(D3DVERTEX2)*(m_brick+2)*2);
+
+ eye = m_engine->GetEyePt();
+ lookat = m_engine->GetLookatPt();
+
+ rankview = m_engine->GetRankView();
+ bUnder = ( rankview == 1);
+
+ device = m_engine->GetD3DDevice();
+ device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false);
+
+ matrix.LoadIdentity();
+ {
+ D3DMATRIX mat = MAT_TO_D3DMAT(matrix);
+ device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
+ }
+
+ ZeroMemory( &material, sizeof(D3DMATERIAL7) );
+ material.diffuse = m_diffuse;
+ material.ambient = m_ambient;
+ m_engine->SetMaterial(material);
+
+ m_engine->SetTexture(m_filename, 0);
+ m_engine->SetTexture(m_filename, 1);
+
+ if ( m_type[rankview] == WATER_TT )
+ {
+ m_engine->SetState(D3DSTATETTb|D3DSTATEDUALw|D3DSTATEWRAP, m_color);
+ }
+ if ( m_type[rankview] == WATER_TO )
+ {
+ m_engine->SetState(D3DSTATENORMAL|D3DSTATEDUALw|D3DSTATEWRAP);
+ }
+ if ( m_type[rankview] == WATER_CT )
+ {
+ m_engine->SetState(D3DSTATETTb);
+ }
+ if ( m_type[rankview] == WATER_CO )
+ {
+ m_engine->SetState(D3DSTATENORMAL);
+ }
+ device->SetRenderState(D3DRENDERSTATE_FOGENABLE, true);
+
+ size = m_size/2.0f;
+ if ( bUnder ) sizez = -size;
+ else sizez = size;
+
+ // Draws all the lines.
+ deep = m_engine->GetDeepView(0)*1.5f;
+
+ for ( i=0 ; i<m_lineUsed ; i++ )
+ {
+ pos.y = m_level;
+ pos.z = m_line[i].pz;
+ pos.x = m_line[i].px1;
+
+ // Visible line?
+ p = pos;
+ p.x += size*(m_line[i].len-1);
+ radius = sqrtf(powf(size, 2.0f)+powf(size*m_line[i].len, 2.0f));
+ if ( Math::Distance(p, eye) > deep+radius ) continue;
+
+ D3DVECTOR pD3D = VEC_TO_D3DVEC(p);
+ device->ComputeSphereVisibility(&pD3D, &radius, 1, 0, &flags);
+
+ if ( flags & D3DSTATUS_CLIPINTERSECTIONALL ) continue;
+
+ u = 0;
+ p.x = pos.x-size;
+ p.z = pos.z-sizez;
+ p.y = pos.y;
+ AdjustLevel(p, n, uv1, uv2);
+ if ( bUnder ) n.y = -n.y;
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ p.x = pos.x-size;
+ p.z = pos.z+sizez;
+ p.y = pos.y;
+ AdjustLevel(p, n, uv1, uv2);
+ if ( bUnder ) n.y = -n.y;
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ for ( j=0 ; j<m_line[i].len ; j++ )
+ {
+ p.x = pos.x+size;
+ p.z = pos.z-sizez;
+ p.y = pos.y;
+ AdjustLevel(p, n, uv1, uv2);
+ if ( bUnder ) n.y = -n.y;
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ p.x = pos.x+size;
+ p.z = pos.z+sizez;
+ p.y = pos.y;
+ AdjustLevel(p, n, uv1, uv2);
+ if ( bUnder ) n.y = -n.y;
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ pos.x += size*2.0f;
+ }
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, u, NULL);
+ m_engine->AddStatisticTriangle(u-2);
+ }
+
+ free(vertex);*/
+}
+
+bool Gfx::CWater::GetWater(int x, int y)
+{
+ x *= m_subdiv;
+ y *= m_subdiv;
+
+ float size = m_size/m_subdiv;
+ float offset = m_brick*m_size/2.0f;
+
+ for (int dy = 0; dy <= m_subdiv; dy++)
+ {
+ for (int dx = 0; dx <= m_subdiv; dx++)
+ {
+ Math::Vector pos;
+ pos.x = (x+dx)*size - offset;
+ pos.z = (y+dy)*size - offset;
+ pos.y = 0.0f;
+ float level = m_terrain->GetFloorLevel(pos, true);
+ if (level < m_level+m_eddy.y)
+ return true;
+ }
+ }
+ return false;
+}
+
+void Gfx::CWater::CreateLine(int x, int y, int len)
+{
+ Gfx::WaterLine line;
+
+ line.x = x;
+ line.y = y;
+ line.len = len;
+
+ float offset = m_brick*m_size/2.0f - m_size/2.0f;
+
+ line.px1 = m_size* line.x - offset;
+ line.px2 = m_size*(line.x+line.len) - offset;
+ line.pz = m_size* line.y - offset;
+
+ m_line.push_back(line);
+}
+
+void Gfx::CWater::Create(Gfx::WaterType type1, Gfx::WaterType type2, const std::string& fileName,
+ Gfx::Color diffuse, Gfx::Color ambient,
+ float level, float glint, Math::Vector eddy)
+{
+ m_type[0] = type1;
+ m_type[1] = type2;
+ m_diffuse = diffuse;
+ m_ambient = ambient;
+ m_level = level;
+ m_glint = glint;
+ m_eddy = eddy;
+ m_time = 0.0f;
+ m_lastLava = 0.0f;
+ m_fileName = fileName;
+
+ VaporFlush();
+
+ if (! m_fileName.empty())
+ m_engine->LoadTexture(m_fileName);
+
+ if (m_terrain == nullptr)
+ m_terrain = static_cast<CTerrain*>(m_iMan->SearchInstance(CLASS_TERRAIN));
+
+ m_brick = m_terrain->GetBrick()*m_terrain->GetMosaic();
+ m_size = m_terrain->GetSize();
+
+ m_brick /= m_subdiv;
+ m_size *= m_subdiv;
+
+ if (m_type[0] == WATER_NULL)
+ return;
+
+ m_line.clear();
+
+ for (int y = 0; y < m_brick; y++)
+ {
+ int len = 0;
+ for (int x = 0; x < m_brick; x++)
+ {
+ if (GetWater(x,y)) // water here?
+ {
+ len ++;
+ if (len >= 5)
+ {
+ CreateLine(x-len+1, y, len);
+ len = 0;
+ }
+ }
+ else // dry?
+ {
+ if (len != 0)
+ {
+ CreateLine(x-len, y, len);
+ len = 0;
+ }
+ }
+ }
+ if (len != 0)
+ CreateLine(m_brick - len, y, len);
+ }
+}
+
+void Gfx::CWater::Flush()
+{
+ m_type[0] = Gfx::WATER_NULL;
+ m_type[1] = Gfx::WATER_NULL;
+ m_level = 0.0f;
+ m_lava = false;
+}
+
+void Gfx::CWater::SetLevel(float level)
+{
+ m_level = level;
+
+ Create(m_type[0], m_type[1], m_fileName, m_diffuse, m_ambient,
+ m_level, m_glint, m_eddy);
+}
+
+float Gfx::CWater::GetLevel()
+{
+ return m_level;
+}
+
+float Gfx::CWater::GetLevel(CObject* object)
+{
+ /* TODO!
+ ObjectType type = object->GetType();
+
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH )
+ {
+ return m_level-3.0f;
+ }
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEtg ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr )
+ {
+ return m_level-2.0f;
+ }
+*/
+ return m_level;
+}
+
+void Gfx::CWater::SetLava(bool lava)
+{
+ m_lava = lava;
+}
+
+bool Gfx::CWater::GetLava()
+{
+ return m_lava;
+}
+
+void Gfx::CWater::AdjustEye(Math::Vector &eye)
+{
+ if (m_lava)
+ {
+ if (eye.y < m_level+2.0f)
+ eye.y = m_level+2.0f; // never under the lava
+ }
+ else
+ {
+ if (eye.y >= m_level-2.0f &&
+ eye.y <= m_level+2.0f) // close to the surface?
+ eye.y = m_level+2.0f; // bam, well above
+ }
+}
-// TODO implementation
diff --git a/src/graphics/engine/water.h b/src/graphics/engine/water.h
index 67be9dc..b051889 100644
--- a/src/graphics/engine/water.h
+++ b/src/graphics/engine/water.h
@@ -15,54 +15,71 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// water.h
+/**
+ * \file graphics/engine/water.h
+ * \brief Water rendering - Gfx::CWater class
+ */
#pragma once
-#include "graphics/engine/engine.h"
-#include "graphics/engine/particle.h"
#include "common/event.h"
+#include "graphics/engine/particle.h"
class CInstanceManager;
-class CSound;
+class CSoundInterface;
namespace Gfx {
+class CEngine;
class CTerrain;
-
-const short MAXWATERLINE = 500;
-
struct WaterLine
{
- short x, y; // beginning
- short len; // length by x
+ //! Beginning
+ short x, y;
+ //! Length by x
+ short len;
float px1, px2, pz;
-};
-
-const short MAXWATVAPOR = 10;
+ WaterLine()
+ {
+ x = y = 0;
+ len = 0;
+ px1 = px2 = pz = 0.0f;
+ }
+};
struct WaterVapor
{
- bool bUsed;
- ParticleType type;
- Math::Vector pos;
- float delay;
- float time;
- float last;
+ bool used;
+ Gfx::ParticleType type;
+ Math::Vector pos;
+ float delay;
+ float time;
+ float last;
+
+ WaterVapor()
+ {
+ used = false;
+ type = Gfx::PARTIWATER;
+ delay = time = last = 0.0f;
+ }
};
-
enum WaterType
{
- WATER_NULL = 0, // no water
- WATER_TT = 1, // transparent texture
- WATER_TO = 2, // opaque texture
- WATER_CT = 3, // transparent color
- WATER_CO = 4, // opaque color
+ //! No water
+ WATER_NULL = 0,
+ //! Transparent texture
+ WATER_TT = 1,
+ //! Opaque texture
+ WATER_TO = 2,
+ //! Transparent color
+ WATER_CT = 3,
+ //! Opaque color
+ WATER_CO = 4,
};
@@ -72,63 +89,88 @@ public:
CWater(CInstanceManager* iMan, Gfx::CEngine* engine);
~CWater();
- void SetGLDevice(Gfx::CDevice device);
+ void SetDevice(Gfx::CDevice* device);
bool EventProcess(const Event &event);
+ //! Removes all the water
void Flush();
- bool Create(WaterType type1, WaterType type2, const char *filename, Gfx::Color diffuse, Gfx::Color ambient, float level, float glint, Math::Vector eddy);
+ //! Creates all expanses of water
+ void Create(WaterType type1, WaterType type2, const std::string& fileName,
+ Gfx::Color diffuse, Gfx::Color ambient, float level, float glint, Math::Vector eddy);
+ //! Draw the back surface of the water
void DrawBack();
+ //! Draws the flat surface of the water
void DrawSurf();
- bool SetLevel(float level);
- float RetLevel();
- float RetLevel(CObject* object);
+ //! Changes the level of the water
+ void SetLevel(float level);
+ //! Returns the current level of water
+ float GetLevel();
+ //! Returns the current level of water for a given object
+ float GetLevel(CObject* object);
- void SetLava(bool bLava);
- bool RetLava();
+ //@{
+ //! Management of the mode of lava/water
+ void SetLava(bool lava);
+ bool GetLava();
+ //@}
+ //! Adjusts the eye of the camera, not to be in the water
void AdjustEye(Math::Vector &eye);
protected:
+ //! Makes water evolve
bool EventFrame(const Event &event);
+ //! Makes evolve the steam jets on the lava
void LavaFrame(float rTime);
+ //! Adjusts the position to normal, to imitate reflections on an expanse of water at rest
void AdjustLevel(Math::Vector &pos, Math::Vector &norm, Math::Point &uv1, Math::Point &uv2);
- bool RetWater(int x, int y);
- bool CreateLine(int x, int y, int len);
+ //! Indicates if there is water in a given position
+ bool GetWater(int x, int y);
+ //! Updates the positions, relative to the ground
+ void CreateLine(int x, int y, int len);
+ //! Removes all the steam jets
void VaporFlush();
+ //! Creates a new steam
bool VaporCreate(ParticleType type, Math::Vector pos, float delay);
+ //! Makes evolve a steam jet
void VaporFrame(int i, float rTime);
protected:
- CInstanceManager* m_iMan;
- CEngine* m_engine;
- CDevice* m_pDevice;
- CTerrain* m_terrain;
- CParticle* m_particule;
- CSound* m_sound;
+ CInstanceManager* m_iMan;
+ Gfx::CEngine* m_engine;
+ Gfx::CDevice* m_device;
+ Gfx::CTerrain* m_terrain;
+ Gfx::CParticle* m_particule;
+ CSoundInterface* m_sound;
WaterType m_type[2];
- char m_filename[100];
- float m_level; // overall level
- float m_glint; // amplitude of reflections
- Math::Vector m_eddy; // amplitude of swirls
- Gfx::Color m_diffuse; // diffuse color
- Gfx::Color m_ambient; // ambient color
+ std::string m_fileName;
+ //! Overall level
+ float m_level;
+ //! Amplitude of reflections
+ float m_glint;
+ //! Amplitude of swirls
+ Math::Vector m_eddy;
+ //! Diffuse color
+ Gfx::Color m_diffuse;
+ //! Ambient color
+ Gfx::Color m_ambient;
float m_time;
float m_lastLava;
- int m_subdiv;
-
- int m_brick; // number of brick*mosaics
- float m_size; // size of a item in an brick
+ int m_subdiv;
- int m_lineUsed;
- WaterLine m_line[MAXWATERLINE];
+ //! Number of brick*mosaics
+ int m_brick;
+ //! Size of a item in an brick
+ float m_size;
- WaterVapor m_vapor[MAXWATVAPOR];
+ std::vector<WaterLine> m_line;
+ std::vector<WaterVapor> m_vapor;
- bool m_bDraw;
- bool m_bLava;
- long m_color;
+ bool m_draw;
+ bool m_lava;
+ long m_color;
};
}; // namespace Gfx
diff --git a/src/graphics/opengl/README.txt b/src/graphics/opengl/README.txt
index 0aba0ed..596871d 100644
--- a/src/graphics/opengl/README.txt
+++ b/src/graphics/opengl/README.txt
@@ -1,6 +1,7 @@
-src/graphics/opengl
-
-OpenGL engine implementation
-
-Contains the concrete implementation using OpenGL of abstract CDevice class
-from src/graphics/core
+/**
+ * \dir graphics/opengl
+ * \brief OpenGL engine implementation
+ *
+ * Contains the concrete implementation using OpenGL of abstract CDevice class
+ * from src/graphics/core
+ */ \ No newline at end of file
diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp
index 3a255f4..caa79ee 100644
--- a/src/graphics/opengl/gldevice.cpp
+++ b/src/graphics/opengl/gldevice.cpp
@@ -64,7 +64,6 @@ void Gfx::GLDeviceConfig::LoadDefault()
Gfx::CGLDevice::CGLDevice(const Gfx::GLDeviceConfig &config)
{
m_config = config;
- m_wasInit = false;
m_lighting = false;
m_texturing = false;
}
@@ -74,9 +73,11 @@ Gfx::CGLDevice::~CGLDevice()
{
}
-bool Gfx::CGLDevice::GetWasInit()
+void Gfx::CGLDevice::DebugHook()
{
- return m_wasInit;
+ /* This function is only called here, so it can be used
+ * as a breakpoint when debugging using gDEBugger */
+ glColor3i(0, 0, 0);
}
std::string Gfx::CGLDevice::GetError()
@@ -110,8 +111,6 @@ bool Gfx::CGLDevice::Create()
/* NOTE: when not using GLEW, extension testing is not performed, as it is assumed that
glext.h is up-to-date and the OpenGL shared library has the required functions present. */
- m_wasInit = true;
-
// This is mostly done in all modern hardware by default
// DirectX doesn't even allow the option to turn off perspective correction anymore
// So turn it on permanently
@@ -130,7 +129,7 @@ bool Gfx::CGLDevice::Create()
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- glViewport(0, 0, m_config.size.w, m_config.size.h);
+ glViewport(0, 0, m_config.size.x, m_config.size.y);
m_lights = std::vector<Gfx::Light>(GL_MAX_LIGHTS, Gfx::Light());
@@ -158,8 +157,6 @@ void Gfx::CGLDevice::Destroy()
m_currentTextures.clear();
m_texturesEnabled.clear();
m_textureStageParams.clear();
-
- m_wasInit = false;
}
void Gfx::CGLDevice::ConfigChanged(const Gfx::GLDeviceConfig& newConfig)
@@ -385,18 +382,23 @@ bool Gfx::CGLDevice::GetLightEnabled(int index)
This struct must not be deleted in other way than through DeleteTexture() */
Gfx::Texture Gfx::CGLDevice::CreateTexture(CImage *image, const Gfx::TextureCreateParams &params)
{
- Gfx::Texture result;
-
ImageData *data = image->GetData();
if (data == NULL)
{
m_error = "Invalid texture data";
- return result; // invalid texture
+ return Gfx::Texture(); // invalid texture
}
+ return CreateTexture(data, params);
+}
+
+Gfx::Texture Gfx::CGLDevice::CreateTexture(ImageData *data, const Gfx::TextureCreateParams &params)
+{
+ Gfx::Texture result;
+
result.valid = true;
- result.size.w = data->surface->w;
- result.size.h = data->surface->h;
+ result.size.x = data->surface->w;
+ result.size.y = data->surface->h;
// Use & enable 1st texture stage
glActiveTexture(GL_TEXTURE0);
@@ -531,6 +533,24 @@ void Gfx::CGLDevice::SetTexture(int index, const Gfx::Texture &texture)
glDisable(GL_TEXTURE_2D);
}
+void Gfx::CGLDevice::SetTexture(int index, unsigned int textureId)
+{
+ assert(index >= 0);
+ assert(index < static_cast<int>( m_currentTextures.size() ));
+
+ // Enable the given texture stage
+ glActiveTexture(GL_TEXTURE0 + index);
+ glEnable(GL_TEXTURE_2D);
+
+ m_currentTextures[index].id = textureId;
+
+ glBindTexture(GL_TEXTURE_2D, textureId);
+
+ // Disable the stage if it is set so
+ if ( (! m_texturing) || (! m_texturesEnabled[index]) )
+ glDisable(GL_TEXTURE_2D);
+}
+
/**
Returns the previously assigned texture or invalid texture if the given stage is not enabled. */
Gfx::Texture Gfx::CGLDevice::GetTexture(int index)
@@ -1159,17 +1179,19 @@ void Gfx::CGLDevice::GetFogParams(Gfx::FogMode &mode, Gfx::Color &color, float &
void Gfx::CGLDevice::SetCullMode(Gfx::CullMode mode)
{
- if (mode == Gfx::CULL_CW) glCullFace(GL_CW);
- else if (mode == Gfx::CULL_CCW) glCullFace(GL_CCW);
+ // Cull clockwise back faces, so front face is the opposite
+ // (assuming GL_CULL_FACE is GL_BACK)
+ if (mode == Gfx::CULL_CW ) glFrontFace(GL_CCW);
+ else if (mode == Gfx::CULL_CCW) glFrontFace(GL_CW);
else assert(false);
}
Gfx::CullMode Gfx::CGLDevice::GetCullMode()
{
GLint flag = 0;
- glGetIntegerv(GL_CULL_FACE, &flag);
- if (flag == GL_CW) return Gfx::CULL_CW;
- else if (flag == GL_CCW) return Gfx::CULL_CCW;
+ glGetIntegerv(GL_FRONT_FACE, &flag);
+ if (flag == GL_CW) return Gfx::CULL_CCW;
+ else if (flag == GL_CCW) return Gfx::CULL_CW;
else assert(false);
return Gfx::CULL_CW;
}
diff --git a/src/graphics/opengl/gldevice.h b/src/graphics/opengl/gldevice.h
index 1864000..3daea8a 100644
--- a/src/graphics/opengl/gldevice.h
+++ b/src/graphics/opengl/gldevice.h
@@ -14,7 +14,10 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// gldevice.h
+/**
+ * \file graphics/opengl/gldevice.h
+ * \brief OpenGL implementation - Gfx::CGLDevice class
+ */
#pragma once
@@ -73,7 +76,8 @@ public:
CGLDevice(const Gfx::GLDeviceConfig &config);
virtual ~CGLDevice();
- virtual bool GetWasInit();
+ virtual void DebugHook();
+
virtual std::string GetError();
virtual bool Create();
@@ -100,11 +104,13 @@ public:
virtual bool GetLightEnabled(int index);
virtual Gfx::Texture CreateTexture(CImage *image, const Gfx::TextureCreateParams &params);
+ virtual Gfx::Texture CreateTexture(ImageData *data, const Gfx::TextureCreateParams &params);
virtual void DestroyTexture(const Gfx::Texture &texture);
virtual void DestroyAllTextures();
virtual int GetMaxTextureCount();
virtual void SetTexture(int index, const Gfx::Texture &texture);
+ virtual void SetTexture(int index, unsigned int textureId);
virtual Gfx::Texture GetTexture(int index);
virtual void SetTextureEnabled(int index, bool enabled);
virtual bool GetTextureEnabled(int index);
@@ -163,8 +169,6 @@ private:
private:
//! Current config
Gfx::GLDeviceConfig m_config;
- //! Was initialized?
- bool m_wasInit;
//! Last encountered error
std::string m_error;
diff --git a/src/math/README.txt b/src/math/README.txt
index 1a5ce93..fd34dcb 100644
--- a/src/math/README.txt
+++ b/src/math/README.txt
@@ -1,3 +1,12 @@
-src/math
+/**
+ * \dir math
+ * \brief Common mathematical structures and functions
+ */
-Contains common mathematical structures and functions.
+/**
+ * \namespace Math
+ * \brief Namespace for (new) math code
+ *
+ * This namespace was created to avoid clashing with old code, but now it still serves,
+ * defining a border between math and non-math-related code.
+ */ \ No newline at end of file
diff --git a/src/math/all.h b/src/math/all.h
index 13a9290..4ac9d55 100644
--- a/src/math/all.h
+++ b/src/math/all.h
@@ -14,14 +14,13 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-/** @defgroup MathAllModule math/all.h
- Includes all other math module headers.
+/**
+ * \file math/all.h
+ * \brief Includes all other math module headers
*/
#pragma once
-/* @{ */ // start of group
-
#include "const.h"
#include "func.h"
#include "point.h"
@@ -30,5 +29,3 @@
#include "geometry.h"
#include "conv.h"
-
-/* @} */ // end of group
diff --git a/src/math/const.h b/src/math/const.h
index dd7ab0f..0b6f971 100644
--- a/src/math/const.h
+++ b/src/math/const.h
@@ -14,28 +14,30 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-/** @defgroup MathConstModule math/const.h
- Contains the math constants used in math functions.
+/**
+ * \file math/const.h
+ * \brief Constants used in math functions
*/
#pragma once
+#include <cmath>
+
// Math module namespace
namespace Math
{
-/* @{ */ // start of group
//! Tolerance level -- minimum accepted float value
const float TOLERANCE = 1e-6f;
//! Very small number (used in testing/returning some values)
-const float VERY_SMALL = 1e-6f;
+const float VERY_SMALL_NUM = 1e-6f;
//! Very big number (used in testing/returning some values)
-const float VERY_BIG = 1e6f;
+const float VERY_BIG_NUM = 1e6f;
//! Huge number
-const float HUGE = 1.0e+38f;
+const float HUGE_NUM = 1.0e+38f;
//! PI
const float PI = 3.14159265358979323846f;
@@ -45,6 +47,8 @@ const float DEG_TO_RAD = 0.01745329251994329547f;
//! Radians to degrees multiplier
const float RAD_TO_DEG = 57.29577951308232286465f;
-/* @} */ // end of group
+//! Natural logarithm of 2
+const float LOG_2 = log(2.0f);
+
}; // namespace Math
diff --git a/src/math/func.h b/src/math/func.h
index 2127d1a..541b084 100644
--- a/src/math/func.h
+++ b/src/math/func.h
@@ -15,8 +15,9 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-/** @defgroup MathFuncModule math/func.h
- Contains common math functions.
+/**
+ * \file math/func.h
+ * \brief Common math functions
*/
#pragma once
@@ -31,8 +32,6 @@
namespace Math
{
-/* @{ */ // start of group
-
//! Compares \a a and \a b within \a tolerance
inline bool IsEqual(float a, float b, float tolerance = Math::TOLERANCE)
{
@@ -127,6 +126,14 @@ inline float Rand()
return static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
}
+//! Returns the next nearest power of two to \a x
+inline int NextPowerOfTwo(int x)
+{
+ double logbase2 = log(static_cast<float>(x)) / Math::LOG_2;
+ return static_cast<int>(pow(2, ceil(logbase2)) + 0.5);
+}
+
+
//! Returns a normalized angle, that is in other words between 0 and 2 * PI
inline float NormAngle(float angle)
{
@@ -180,11 +187,13 @@ inline float Direction(float a, float g)
//! Managing the dead zone of a joystick.
/**
-\verbatimin: -1 0 1
+\verbatim
+in: -1 0 1
--|-------|----o----|-------|-->
<---->
dead
-out: -1 0 0 1\endverbatim */
+out: -1 0 0 1
+\endverbatim */
inline float Neutral(float value, float dead)
{
if ( fabs(value) <= dead )
@@ -218,7 +227,8 @@ inline float Smooth(float actual, float hope, float time)
//! Bounces any movement
/**
-\verbatimout
+\verbatim
+out
|
1+------o-------o---
| o | o o | | bounce
@@ -227,7 +237,8 @@ inline float Smooth(float actual, float hope, float time)
| o | |
-o------|-------+----> progress
0| | 1
- |<---->|middle\endverbatim */
+ |<---->|middle
+\endverbatim */
inline float Bounce(float progress, float middle = 0.3f, float bounce = 0.4f)
{
if ( progress < middle )
@@ -242,6 +253,4 @@ inline float Bounce(float progress, float middle = 0.3f, float bounce = 0.4f)
}
}
-/* @} */ // end of group
-
}; // namespace Math
diff --git a/src/math/geometry.h b/src/math/geometry.h
index 61d1868..1c5f60f 100644
--- a/src/math/geometry.h
+++ b/src/math/geometry.h
@@ -15,9 +15,9 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-/** @defgroup MathGeometryModule math/geometry.h
- Contains math functions related to 3D geometry calculations,
- transformations, etc.
+/**
+ * \file math/geometry.h
+ * \brief Math functions related to 3D geometry calculations, transformations, etc.
*/
#pragma once
@@ -36,18 +36,15 @@
namespace Math
{
-/* @{ */ // start of group
-
-
//! Returns py up on the line \a a - \a b
inline float MidPoint(const Math::Point &a, const Math::Point &b, float px)
{
if (IsEqual(a.x, b.x))
{
if (a.y < b.y)
- return HUGE;
+ return Math::HUGE_NUM;
else
- return -HUGE;
+ return -Math::HUGE_NUM;
}
return (b.y-a.y) * (px-a.x) / (b.x-a.x) + a.y;
}
@@ -566,6 +563,4 @@ inline Math::Vector RotateView(Math::Vector center, float angleH, float angleV,
return eye+center;
}
-/* @} */ // end of group
-
}; // namespace Math
diff --git a/src/math/intpoint.h b/src/math/intpoint.h
index a760bc2..8e13b19 100644
--- a/src/math/intpoint.h
+++ b/src/math/intpoint.h
@@ -14,31 +14,29 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-/** @defgroup MathIntPointModule math/intpoint.h
- Contains the IntPoint struct.
+/**
+ * \file math/intpoint.h
+ * \brief IntPoint struct
*/
#pragma once
namespace Math {
-/* @{ */ // start of group
-
/**
- * \struct IntPoint 2D Point with integer coords
+ * \struct IntPoint
+ * \brief 2D Point with integer coords
*
* Analog of WinAPI's POINT struct.
*/
struct IntPoint
{
//! X coord
- long x;
+ int x;
//! Y coord
- long y;
+ int y;
- IntPoint(long aX = 0, long aY = 0) : x(aX), y(aY) {}
+ IntPoint(int aX = 0, int aY = 0) : x(aX), y(aY) {}
};
-/* @} */ // end of group
-
}; // namespace Math
diff --git a/src/math/intsize.h b/src/math/intsize.h
deleted file mode 100644
index f4b2431..0000000
--- a/src/math/intsize.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * 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/.
-
-/** @defgroup MathIntSizeModule math/intsize.h
- Contains the IntSize struct.
- */
-
-#pragma once
-
-// Math module namespace
-namespace Math
-{
-
-/* @{ */ // start of group
-
-/** \struct IntSize math/size.h
- \brief 2D size with integer dimensions */
-struct IntSize
-{
- //! Width
- int w;
- //! Height
- int h;
-
- //! Constructs a zero size: (0,0)
- inline IntSize()
- {
- LoadZero();
- }
-
- //! Constructs a size from given dimensions: (w,h)
- inline explicit IntSize(int w, int h)
- {
- this->w = w;
- this->h = h;
- }
-
- //! Sets the zero size: (0,0)
- inline void LoadZero()
- {
- w = h = 0;
- }
-}; // struct Size
-
-
-/* @} */ // end of group
-
-}; // namespace Math
diff --git a/src/math/matrix.h b/src/math/matrix.h
index 45a7d75..30e629a 100644
--- a/src/math/matrix.h
+++ b/src/math/matrix.h
@@ -14,8 +14,9 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-/** @defgroup MathMatrixModule math/matrix.h
- Contains the Matrix struct and related functions.
+/**
+ * \file math/matrix.h
+ * \brief Matrix struct and related functions
*/
#pragma once
@@ -32,8 +33,6 @@
namespace Math
{
-/* @{ */ // start of group
-
/** \struct Matrix math/matrix.h
\brief 4x4 matrix
@@ -42,11 +41,12 @@ namespace Math
The internal representation is a 16-value table in column-major order, thus:
- \verbatim
+\verbatim
m[0 ] m[4 ] m[8 ] m[12]
m[1 ] m[5 ] m[9 ] m[13]
m[2 ] m[6 ] m[10] m[14]
-m[3 ] m[7 ] m[11] m[15] \endverbatim
+m[3 ] m[7 ] m[11] m[15]
+\endverbatim
This representation is native to OpenGL; DirectX requires transposing the matrix.
@@ -405,11 +405,15 @@ inline Math::Matrix MultiplyMatrices(const Math::Matrix &left, const Math::Matri
}
//! Calculates the result of multiplying m * v
-/** The multiplication is performed thus:
-\verbatim [ m.m[0 ] m.m[4 ] m.m[8 ] m.m[12] ] [ v.x ]
+/**
+ The multiplication is performed thus:
+
+\verbatim
+[ m.m[0 ] m.m[4 ] m.m[8 ] m.m[12] ] [ v.x ]
[ m.m[1 ] m.m[5 ] m.m[9 ] m.m[13] ] [ v.y ]
[ m.m[2 ] m.m[6 ] m.m[10] m.m[14] ] * [ v.z ]
-[ m.m[3 ] m.m[7 ] m.m[11] m.m[15] ] [ 1 ] \endverbatim
+[ m.m[3 ] m.m[7 ] m.m[11] m.m[15] ] [ 1 ]
+\endverbatim
The result, a 4x1 vector is then converted to 3x1 by dividing
x,y,z coords by the fourth coord (w). */
@@ -434,6 +438,4 @@ inline Math::Vector MatrixVectorMultiply(const Math::Matrix &m, const Math::Vect
return Math::Vector(x, y, z);
}
-/* @} */ // end of group
-
}; // namespace Math
diff --git a/src/math/point.h b/src/math/point.h
index ea20db9..ecf896f 100644
--- a/src/math/point.h
+++ b/src/math/point.h
@@ -14,8 +14,9 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-/** @defgroup MathPointModule math/point.h
- Contains the Point struct and related functions.
+/**
+ * \file math/point.h
+ * \brief Point struct and related functions
*/
#pragma once
@@ -31,8 +32,6 @@
namespace Math
{
-/* @{ */ // start of group
-
/** \struct Point math/point.h
\brief 2D point
@@ -188,6 +187,4 @@ inline float Distance(const Point &a, const Point &b)
return sqrtf((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
-/* @} */ // end of group
-
}; // namespace Math
diff --git a/src/math/size.h b/src/math/size.h
deleted file mode 100644
index 781b9a4..0000000
--- a/src/math/size.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * 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/.
-
-/** @defgroup MathSizeModule math/size.h
- Contains the Size struct.
- */
-
-#pragma once
-
-// Math module namespace
-namespace Math
-{
-
-/* @{ */ // start of group
-
-/** \struct Size math/size.h
- \brief 2D size
-
- Represents a 2D size (w, h).
- Is separate from Math::Point to avoid confusion.
-
- */
-struct Size
-{
- //! Width
- float w;
- //! Height
- float h;
-
- //! Constructs a zero size: (0,0)
- inline Size()
- {
- LoadZero();
- }
-
- //! Constructs a size from given dimensions: (w,h)
- inline explicit Size(float w, float h)
- {
- this->w = w;
- this->h = h;
- }
-
- //! Sets the zero size: (0,0)
- inline void LoadZero()
- {
- w = h = 0.0f;
- }
-}; // struct Size
-
-
-/* @} */ // end of group
-
-}; // namespace Math
diff --git a/src/math/vector.h b/src/math/vector.h
index 147869f..4378e75 100644
--- a/src/math/vector.h
+++ b/src/math/vector.h
@@ -14,8 +14,9 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-/** @defgroup MathVectorModule math/vector.h
- Contains the Vector struct and related functions.
+/**
+ * \file math/vector.h
+ * \brief Vector struct and related functions
*/
#pragma once
@@ -31,8 +32,6 @@
namespace Math
{
-/* @{ */ // start of group
-
/** \struct Vector math/vector.h
\brief 3D (3x1) vector
@@ -263,6 +262,4 @@ inline float Distance(const Math::Vector &a, const Math::Vector &b)
(a.z-b.z)*(a.z-b.z) );
}
-/* @} */ // end of group
-
}; // namespace Math
diff --git a/src/object/README.txt b/src/object/README.txt
index f4c25d0..f3bad23 100644
--- a/src/object/README.txt
+++ b/src/object/README.txt
@@ -1,3 +1,7 @@
-src/object
-
-Contains modules of robots and buildings.
+/**
+ * \dir object
+ * \brief Game engine
+ *
+ * Contains the main class of game engine - CRobotMain and the various in-game objects:
+ * CObject and related auto, motion and task subclasses.
+ */ \ No newline at end of file
diff --git a/src/object/object.h b/src/object/object.h
index 75283d6..4a4dcb0 100644
--- a/src/object/object.h
+++ b/src/object/object.h
@@ -19,16 +19,12 @@
#pragma once
-#include "old/d3dengine.h"
-#include "old/camera.h"
-#include "old/sound.h"
+#include "graphics/engine/engine.h"
+#include "graphics/engine/camera.h"
+#include "sound/sound.h"
class CInstanceManager;
-class CLight;
-class CTerrain;
-class CWater;
-class CParticule;
class CPhysics;
class CBrain;
class CMotion;
@@ -40,6 +36,7 @@ class CScript;
+
// The father of all parts must always be the part number zero!
const int OBJECTMAXPART = 40;
@@ -306,7 +303,7 @@ enum ObjectMaterial
struct ObjectPart
{
char bUsed;
- int object; // number of the object in CD3DEngine
+ int object; // number of the object in CEngine
int parentPart; // number of father part
int masterParti; // master canal of the particle
Math::Vector position;
@@ -377,16 +374,16 @@ public:
int CreatePart();
void DeletePart(int part);
void SetObjectRank(int part, int objRank);
- int RetObjectRank(int part);
+ int GetObjectRank(int part);
void SetObjectParent(int part, int parent);
void SetType(ObjectType type);
- ObjectType RetType();
- char* RetName();
+ ObjectType GetType();
+ char* GetName();
void SetOption(int option);
- int RetOption();
+ int GetOption();
void SetID(int id);
- int RetID();
+ int GetID();
bool Write(char *line);
bool Read(char *line);
@@ -413,203 +410,205 @@ public:
bool WriteProgram(int rank, char* filename);
bool RunProgram(int rank);
- int RetShadowLight();
- int RetEffectLight();
+ int GetShadowLight();
+ int GetEffectLight();
void FlushCrashShere();
int CreateCrashSphere(Math::Vector pos, float radius, Sound sound, float hardness=0.45f);
- int RetCrashSphereTotal();
+ int GetCrashSphereTotal();
bool GetCrashSphere(int rank, Math::Vector &pos, float &radius);
- float RetCrashSphereHardness(int rank);
- Sound RetCrashSphereSound(int rank);
+ float GetCrashSphereHardness(int rank);
+ Sound GetCrashSphereSound(int rank);
void DeleteCrashSphere(int rank);
void SetGlobalSphere(Math::Vector pos, float radius);
void GetGlobalSphere(Math::Vector &pos, float &radius);
void SetJotlerSphere(Math::Vector pos, float radius);
void GetJotlerSphere(Math::Vector &pos, float &radius);
void SetShieldRadius(float radius);
- float RetShieldRadius();
+ float GetShieldRadius();
void SetFloorHeight(float height);
void FloorAdjust();
void SetLinVibration(Math::Vector dir);
- Math::Vector RetLinVibration();
+ Math::Vector GetLinVibration();
void SetCirVibration(Math::Vector dir);
- Math::Vector RetCirVibration();
+ Math::Vector GetCirVibration();
void SetInclinaison(Math::Vector dir);
- Math::Vector RetInclinaison();
+ Math::Vector GetInclinaison();
void SetPosition(int part, const Math::Vector &pos);
- Math::Vector RetPosition(int part);
+ Math::Vector GetPosition(int part);
void SetAngle(int part, const Math::Vector &angle);
- Math::Vector RetAngle(int part);
+ Math::Vector GetAngle(int part);
void SetAngleY(int part, float angle);
void SetAngleX(int part, float angle);
void SetAngleZ(int part, float angle);
- float RetAngleY(int part);
- float RetAngleX(int part);
- float RetAngleZ(int part);
+ float GetAngleY(int part);
+ float GetAngleX(int part);
+ float GetAngleZ(int part);
void SetZoom(int part, float zoom);
void SetZoom(int part, Math::Vector zoom);
- Math::Vector RetZoom(int part);
+ Math::Vector GetZoom(int part);
void SetZoomX(int part, float zoom);
- float RetZoomX(int part);
+ float GetZoomX(int part);
void SetZoomY(int part, float zoom);
- float RetZoomY(int part);
+ float GetZoomY(int part);
void SetZoomZ(int part, float zoom);
- float RetZoomZ(int part);
+ float GetZoomZ(int part);
- float RetWaterLevel();
+ float GetWaterLevel();
void SetTrainer(bool bEnable);
- bool RetTrainer();
+ bool GetTrainer();
void SetToy(bool bEnable);
- bool RetToy();
+ bool GetToy();
void SetManual(bool bManual);
- bool RetManual();
+ bool GetManual();
void SetResetCap(ResetCap cap);
- ResetCap RetResetCap();
+ ResetCap GetResetCap();
void SetResetBusy(bool bBusy);
- bool RetResetBusy();
+ bool GetResetBusy();
void SetResetPosition(const Math::Vector &pos);
- Math::Vector RetResetPosition();
+ Math::Vector GetResetPosition();
void SetResetAngle(const Math::Vector &angle);
- Math::Vector RetResetAngle();
+ Math::Vector GetResetAngle();
void SetResetRun(int run);
- int RetResetRun();
+ int GetResetRun();
void SetMasterParticule(int part, int parti);
- int RetMasterParticule(int part);
+ int GetMasterParticule(int part);
void SetPower(CObject* power);
- CObject* RetPower();
+ CObject* GetPower();
void SetFret(CObject* fret);
- CObject* RetFret();
+ CObject* GetFret();
void SetTruck(CObject* truck);
- CObject* RetTruck();
+ CObject* GetTruck();
void SetTruckPart(int part);
- int RetTruckPart();
+ int GetTruckPart();
void InfoFlush();
void DeleteInfo(int rank);
void SetInfo(int rank, Info info);
- Info RetInfo(int rank);
- int RetInfoTotal();
- void SetInfoReturn(float value);
- float RetInfoReturn();
+ Info GetInfo(int rank);
+ int GetInfoTotal();
+ void SetInfoGeturn(float value);
+ float GetInfoGeturn();
void SetInfoUpdate(bool bUpdate);
- bool RetInfoUpdate();
+ bool GetInfoUpdate();
bool SetCmdLine(int rank, float value);
- float RetCmdLine(int rank);
+ float GetCmdLine(int rank);
- Math::Matrix* RetRotateMatrix(int part);
- Math::Matrix* RetTranslateMatrix(int part);
- Math::Matrix* RetTransformMatrix(int part);
- Math::Matrix* RetWorldMatrix(int part);
+ Math::Matrix* GetRotateMatrix(int part);
+ Math::Matrix* GetTranslateMatrix(int part);
+ Math::Matrix* GetTransformMatrix(int part);
+ Math::Matrix* GetWorldMatrix(int part);
- void SetViewFromHere(Math::Vector &eye, float &dirH, float &dirV, Math::Vector &lookat, Math::Vector &upVec, CameraType type);
+ void SetViewFromHere(Math::Vector &eye, float &dirH, float &dirV,
+ Math::Vector &lookat, Math::Vector &upVec,
+ Gfx::CameraType type);
void SetCharacter(Character* character);
void GetCharacter(Character* character);
- Character* RetCharacter();
+ Character* GetCharacter();
- float RetAbsTime();
+ float GetAbsTime();
void SetEnergy(float level);
- float RetEnergy();
+ float GetEnergy();
void SetCapacity(float capacity);
- float RetCapacity();
+ float GetCapacity();
void SetShield(float level);
- float RetShield();
+ float GetShield();
void SetRange(float delay);
- float RetRange();
+ float GetRange();
void SetTransparency(float value);
- float RetTransparency();
+ float GetTransparency();
- ObjectMaterial RetMaterial();
+ ObjectMaterial GetMaterial();
void SetGadget(bool bMode);
- bool RetGadget();
+ bool GetGadget();
void SetFixed(bool bFixed);
- bool RetFixed();
+ bool GetFixed();
void SetClip(bool bClip);
- bool RetClip();
+ bool GetClip();
bool JostleObject(float force);
void StartDetectEffect(CObject *target, bool bFound);
void SetVirusMode(bool bEnable);
- bool RetVirusMode();
- float RetVirusTime();
+ bool GetVirusMode();
+ float GetVirusTime();
- void SetCameraType(CameraType type);
- CameraType RetCameraType();
+ void SetCameraType(Gfx::CameraType type);
+ Gfx::CameraType GetCameraType();
void SetCameraDist(float dist);
- float RetCameraDist();
+ float GetCameraDist();
void SetCameraLock(bool bLock);
- bool RetCameraLock();
+ bool GetCameraLock();
void SetHilite(bool bMode);
- bool RetHilite();
+ bool GetHilite();
void SetSelect(bool bMode, bool bDisplayError=true);
- bool RetSelect(bool bReal=false);
+ bool GetSelect(bool bReal=false);
void SetSelectable(bool bMode);
- bool RetSelectable();
+ bool GetSelectable();
void SetActivity(bool bMode);
- bool RetActivity();
+ bool GetActivity();
void SetVisible(bool bVisible);
- bool RetVisible();
+ bool GetVisible();
void SetEnable(bool bEnable);
- bool RetEnable();
+ bool GetEnable();
void SetCheckToken(bool bMode);
- bool RetCheckToken();
+ bool GetCheckToken();
void SetProxyActivate(bool bActivate);
- bool RetProxyActivate();
+ bool GetProxyActivate();
void SetProxyDistance(float distance);
- float RetProxyDistance();
+ float GetProxyDistance();
void SetMagnifyDamage(float factor);
- float RetMagnifyDamage();
+ float GetMagnifyDamage();
void SetParam(float value);
- float RetParam();
+ float GetParam();
void SetExplo(bool bExplo);
- bool RetExplo();
+ bool GetExplo();
void SetLock(bool bLock);
- bool RetLock();
+ bool GetLock();
void SetCargo(bool bCargo);
- bool RetCargo();
+ bool GetCargo();
void SetBurn(bool bBurn);
- bool RetBurn();
+ bool GetBurn();
void SetDead(bool bDead);
- bool RetDead();
- bool RetRuin();
- bool RetActif();
+ bool GetDead();
+ bool GetRuin();
+ bool GetActif();
void SetGunGoalV(float gunGoal);
void SetGunGoalH(float gunGoal);
- float RetGunGoalV();
- float RetGunGoalH();
+ float GetGunGoalV();
+ float GetGunGoalH();
bool StartShowLimit();
void StopShowLimit();
@@ -618,16 +617,16 @@ public:
void CreateSelectParticule();
void SetRunScript(CScript* script);
- CScript* RetRunScript();
- CBotVar* RetBotVar();
- CPhysics* RetPhysics();
- CBrain* RetBrain();
- CMotion* RetMotion();
- CAuto* RetAuto();
+ CScript* GetRunScript();
+ CBotVar* GetBotVar();
+ CPhysics* GetPhysics();
+ CBrain* GetBrain();
+ CMotion* GetMotion();
+ CAuto* GetAuto();
void SetAuto(CAuto* automat);
void SetDefRank(int rank);
- int RetDefRank();
+ int GetDefRank();
bool GetTooltipName(char* name);
@@ -635,17 +634,17 @@ public:
CObject* SubDeselList();
void DeleteDeselList(CObject* pObj);
- bool CreateShadowCircle(float radius, float intensity, D3DShadowType type=D3DSHADOWNORM);
- bool CreateShadowLight(float height, D3DCOLORVALUE color);
- bool CreateEffectLight(float height, D3DCOLORVALUE color);
+ bool CreateShadowCircle(float radius, float intensity, Gfx::EngineShadowType type = Gfx::ENG_SHADOW_NORM);
+ bool CreateShadowLight(float height, Gfx::Color color);
+ bool CreateEffectLight(float height, Gfx::Color color);
void FlatParent();
- bool RetTraceDown();
+ bool GetTraceDown();
void SetTraceDown(bool bDown);
- int RetTraceColor();
+ int GetTraceColor();
void SetTraceColor(int color);
- float RetTraceWidth();
+ float GetTraceWidth();
void SetTraceWidth(float width);
protected:
@@ -663,19 +662,19 @@ protected:
protected:
CInstanceManager* m_iMan;
- CD3DEngine* m_engine;
- CLight* m_light;
- CTerrain* m_terrain;
- CWater* m_water;
- CCamera* m_camera;
- CParticule* m_particule;
+ Gfx::CEngine* m_engine;
+ Gfx::CLightManager* m_lightMan;
+ Gfx::CTerrain* m_terrain;
+ Gfx::CWater* m_water;
+ Gfx::CCamera* m_camera;
+ Gfx::CParticle* m_particle;
CPhysics* m_physics;
CBrain* m_brain;
CMotion* m_motion;
CAuto* m_auto;
CDisplayText* m_displayText;
CRobotMain* m_main;
- CSound* m_sound;
+ CSoundInterface* m_sound;
CBotVar* m_botVar;
CScript* m_runScript;
@@ -732,7 +731,7 @@ protected:
float m_showLimitRadius;
float m_gunGoalV;
float m_gunGoalH;
- CameraType m_cameraType;
+ Gfx::CameraType m_cameraType;
float m_cameraDist;
bool m_bCameraLock;
int m_defRank;
@@ -767,7 +766,7 @@ protected:
int m_infoTotal;
Info m_info[OBJECTMAXINFO];
- float m_infoReturn;
+ float m_infoGeturn;
bool m_bInfoUpdate;
float m_cmdLine[OBJECTMAXCMDLINE];
diff --git a/src/object/robotmain.cpp b/src/object/robotmain.cpp
index fb68152..668be87 100644
--- a/src/object/robotmain.cpp
+++ b/src/object/robotmain.cpp
@@ -722,7 +722,7 @@ CRobotMain::CRobotMain(CInstanceManager* iMan)
g_unit = 4.0f;
m_gamerName[0] = 0;
- GetLocalProfileString("Gamer", "LastName", m_gamerName, 100);
+ GetProfile()->GetLocalProfileString("Gamer", "LastName", m_gamerName, 100);
SetGlobalGamerName(m_gamerName);
ReadFreeParam();
m_dialog->SetupRecall();
diff --git a/src/physics/README.txt b/src/physics/README.txt
index 0003956..4ad5989 100644
--- a/src/physics/README.txt
+++ b/src/physics/README.txt
@@ -1,3 +1,4 @@
-src/physics
-
-Contains the physics module.
+/**
+ * \dir physics
+ * \brief Physics engine
+ */ \ No newline at end of file
diff --git a/src/physics/physics.h b/src/physics/physics.h
index 6865b6a..2e1f5eb 100644
--- a/src/physics/physics.h
+++ b/src/physics/physics.h
@@ -19,23 +19,27 @@
#pragma once
-#include "old/d3dengine.h"
#include "common/misc.h"
#include "object/object.h"
+#include "math/vector.h"
class CInstanceManager;
-class CD3DEngine;
-class CLight;
-class CParticule;
-class CTerrain;
-class CWater;
class CCamera;
class CObject;
class CBrain;
class CMotion;
class CSound;
+namespace Gfx
+{
+class CEngine;
+class CLight;
+class CParticule;
+class CTerrain;
+class CWater;
+};
+
enum PhysicsType
{
@@ -98,64 +102,64 @@ public:
void SetMotion(CMotion* motion);
void SetType(PhysicsType type);
- PhysicsType RetType();
+ PhysicsType GetType();
bool Write(char *line);
bool Read(char *line);
void SetGravity(float value);
- float RetGravity();
+ float GetGravity();
- float RetFloorHeight();
+ float GetFloorHeight();
void SetLinMotion(PhysicsMode mode, Math::Vector value);
- Math::Vector RetLinMotion(PhysicsMode mode);
+ Math::Vector GetLinMotion(PhysicsMode mode);
void SetLinMotionX(PhysicsMode mode, float value);
void SetLinMotionY(PhysicsMode mode, float value);
void SetLinMotionZ(PhysicsMode mode, float value);
- float RetLinMotionX(PhysicsMode mode);
- float RetLinMotionY(PhysicsMode mode);
- float RetLinMotionZ(PhysicsMode mode);
+ float GetLinMotionX(PhysicsMode mode);
+ float GetLinMotionY(PhysicsMode mode);
+ float GetLinMotionZ(PhysicsMode mode);
void SetCirMotion(PhysicsMode mode, Math::Vector value);
- Math::Vector RetCirMotion(PhysicsMode mode);
+ Math::Vector GetCirMotion(PhysicsMode mode);
void SetCirMotionX(PhysicsMode mode, float value);
void SetCirMotionY(PhysicsMode mode, float value);
void SetCirMotionZ(PhysicsMode mode, float value);
- float RetCirMotionX(PhysicsMode mode);
- float RetCirMotionY(PhysicsMode mode);
- float RetCirMotionZ(PhysicsMode mode);
+ float GetCirMotionX(PhysicsMode mode);
+ float GetCirMotionY(PhysicsMode mode);
+ float GetCirMotionZ(PhysicsMode mode);
- float RetLinStopLength(PhysicsMode sMode=MO_ADVSPEED, PhysicsMode aMode=MO_STOACCEL);
- float RetCirStopLength();
- float RetLinMaxLength(float dir);
- float RetLinTimeLength(float dist, float dir=1.0f);
- float RetLinLength(float dist);
+ float GetLinStopLength(PhysicsMode sMode=MO_ADVSPEED, PhysicsMode aMode=MO_STOACCEL);
+ float GetCirStopLength();
+ float GetLinMaxLength(float dir);
+ float GetLinTimeLength(float dist, float dir=1.0f);
+ float GetLinLength(float dist);
void SetMotor(bool bState);
- bool RetMotor();
+ bool GetMotor();
void SetLand(bool bState);
- bool RetLand();
+ bool GetLand();
void SetSwim(bool bState);
- bool RetSwim();
+ bool GetSwim();
void SetCollision(bool bCollision);
- bool RetCollision();
+ bool GetCollision();
void SetFreeze(bool bFreeze);
- bool RetFreeze();
+ bool GetFreeze();
void SetReactorRange(float range);
- float RetReactorRange();
+ float GetReactorRange();
void SetMotorSpeed(Math::Vector speed);
void SetMotorSpeedX(float speed);
void SetMotorSpeedY(float speed);
void SetMotorSpeedZ(float speed);
- Math::Vector RetMotorSpeed();
- float RetMotorSpeedX();
- float RetMotorSpeedY();
- float RetMotorSpeedZ();
+ Math::Vector GetMotorSpeed();
+ float GetMotorSpeedX();
+ float GetMotorSpeedY();
+ float GetMotorSpeedZ();
void CreateInterface(bool bSelect);
- Error RetError();
+ Error GetError();
protected:
bool EventFrame(const Event &event);
@@ -186,12 +190,12 @@ protected:
protected:
CInstanceManager* m_iMan;
- CD3DEngine* m_engine;
- CLight* m_light;
- CParticule* m_particule;
- CTerrain* m_terrain;
- CWater* m_water;
- CCamera* m_camera;
+ Gfx::CEngine* m_engine;
+ Gfx::CLightManager* m_lightMan;
+ Gfx::CParticle* m_particle;
+ Gfx::CTerrain* m_terrain;
+ Gfx::CWater* m_water;
+ Gfx::CCamera* m_camera;
CObject* m_object;
CBrain* m_brain;
CMotion* m_motion;
diff --git a/src/plugins/plugininterface.h b/src/plugins/plugininterface.h
new file mode 100644
index 0000000..b8adddc
--- /dev/null
+++ b/src/plugins/plugininterface.h
@@ -0,0 +1,65 @@
+// * This file is part of the COLOBOT source code
+// * 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/.
+
+// plugininterface.h
+
+/**
+ * @file plugin/plugininterface.h
+ * @brief Generic plugin interface
+ */
+
+#pragma once
+
+#include <string>
+
+#define PLUGIN_INTERFACE(class_type) \
+ static class_type* Plugin##class_type; \
+ extern "C" void InstallPluginEntry() { Plugin##class_type = new class_type(); Plugin##class_type->InstallPlugin(); } \
+ extern "C" bool UninstallPluginEntry(std::string &reason) { bool result = Plugin##class_type->UninstallPlugin(reason); \
+ if (!result) \
+ return false; \
+ delete Plugin##class_type; \
+ return true; } \
+ extern "C" CPluginInterface* GetPluginInterfaceEntry() { return static_cast<CPluginInterface*>(Plugin##class_type); }
+
+
+/**
+* @class CPluginInterface
+*
+* @brief Generic plugin interface. All plugins that will be managed by plugin manager have to derive from this class.
+*
+*/
+class CPluginInterface {
+ public:
+ /** Function to get plugin name or description
+ * @return returns plugin name
+ */
+ virtual std::string PluginName() = 0;
+
+ /** Function to get plugin version. 1 means version 0.01, 2 means 0.02 etc.
+ * @return number indicating plugin version
+ */
+ virtual int PluginVersion() = 0;
+
+ /** Function to initialize plugin
+ */
+ virtual void InstallPlugin() = 0;
+
+ /** Function called before removing plugin
+ */
+ virtual bool UninstallPlugin(std::string &) = 0;
+};
+
diff --git a/src/plugins/pluginloader.cpp b/src/plugins/pluginloader.cpp
new file mode 100644
index 0000000..fd8ce74
--- /dev/null
+++ b/src/plugins/pluginloader.cpp
@@ -0,0 +1,126 @@
+// * This file is part of the COLOBOT source code
+// * 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/.
+
+// pluginloader.cpp
+
+
+#include "pluginloader.h"
+
+
+CPluginLoader::CPluginLoader(std::string filename)
+{
+ mInterface = nullptr;
+ mFilename = filename;
+ mLoaded = false;
+}
+
+
+std::string CPluginLoader::GetName()
+{
+ if (mLoaded)
+ return mInterface->PluginName();
+ return "(not loaded)";
+}
+
+
+int CPluginLoader::GetVersion()
+{
+ if (mLoaded)
+ return mInterface->PluginVersion();
+ return 0;
+}
+
+
+bool CPluginLoader::IsLoaded()
+{
+ return mLoaded;
+}
+
+
+bool CPluginLoader::UnloadPlugin()
+{
+ if (!mLoaded) {
+ GetLogger()->Warn("Plugin %s is not loaded.\n");
+ return true;
+ }
+
+ bool (*uninstall)(std::string &) = (bool (*)(std::string &)) lt_dlsym(mHandle, "UninstallPluginEntry");
+ if (!uninstall) {
+ GetLogger()->Error("Error getting UninstallPluginEntry for plugin %s: %s\n", mFilename.c_str(), lt_dlerror());
+ return false;
+ }
+
+ std::string reason;
+ if (!uninstall(reason)) {
+ GetLogger()->Error("Could not unload plugin %s: %s\n", mFilename.c_str(), reason.c_str());
+ return false;
+ }
+
+ lt_dlclose(mHandle);
+ mLoaded = false;
+ return true;
+}
+
+
+bool CPluginLoader::LoadPlugin()
+{
+ if (mFilename.length() == 0) {
+ GetLogger()->Warn("No plugin filename specified.\n");
+ return false;
+ }
+
+ mHandle = lt_dlopenext(mFilename.c_str());
+ if (!mHandle) {
+ GetLogger()->Error("Error loading plugin %s: %s\n", mFilename.c_str(), lt_dlerror());
+ return false;
+ }
+
+ void (*install)() = (void (*)()) lt_dlsym(mHandle, "InstallPluginEntry");
+ if (!install) {
+ GetLogger()->Error("Error getting InstallPluginEntry for plugin %s: %s\n", mFilename.c_str(), lt_dlerror());
+ return false;
+ }
+
+ CPluginInterface* (*getInterface)() = (CPluginInterface* (*)()) lt_dlsym(mHandle, "GetPluginInterfaceEntry");
+
+ if (!getInterface) {
+ GetLogger()->Error("Error getting GetPluginInterfaceEntry for plugin %s: %s\n", mFilename.c_str(), lt_dlerror());
+ return false;
+ }
+
+ install();
+ mInterface = getInterface();
+ mLoaded = true;
+ return true;
+}
+
+
+bool CPluginLoader::SetFilename(std::string filename)
+{
+ bool ok = true;
+ if (mLoaded)
+ ok = UnloadPlugin();
+
+ if (ok)
+ mFilename = filename;
+ return ok;
+}
+
+
+std::string CPluginLoader::GetFilename()
+{
+ return mFilename;
+}
diff --git a/src/plugins/pluginloader.h b/src/plugins/pluginloader.h
new file mode 100644
index 0000000..40b19da
--- /dev/null
+++ b/src/plugins/pluginloader.h
@@ -0,0 +1,88 @@
+// * This file is part of the COLOBOT source code
+// * 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/.
+
+// pluginloader.h
+
+/**
+ * @file plugin/pluginloader.h
+ * @brief Plugin loader interface
+ */
+
+#pragma once
+
+#include <ltdl.h>
+#include <string>
+
+#include <common/logger.h>
+
+#include "plugininterface.h"
+
+
+/**
+* @class CPluginLoader
+*
+* @brief Plugin loader interface. Plugin manager uses this class to load plugins.
+*
+*/
+class CPluginLoader {
+ public:
+ /** Class contructor
+ * @param std::string plugin filename
+ */
+ CPluginLoader(std::string);
+
+ /** Function to get plugin name or description
+ * @return returns plugin name
+ */
+ std::string GetName();
+
+ /** Function to get plugin version
+ * @return returns plugin version
+ */
+ int GetVersion();
+
+ /** Function to unload plugin
+ * @return returns true on success
+ */
+ bool UnloadPlugin();
+
+ /** Function to load plugin
+ * @return returns true on success
+ */
+ bool LoadPlugin();
+
+ /** Function to check if plugin is loaded
+ * @return returns true if plugin is loaded
+ */
+ bool IsLoaded();
+
+ /** Function to set plugin filename
+ * @return returns true on success. Action can fail if plugin was loaded and cannot be unloaded
+ */
+ bool SetFilename(std::string);
+
+ /** Function to get plugin filename
+ * @return returns plugin filename
+ */
+ std::string GetFilename();
+
+
+ private:
+ CPluginInterface* mInterface;
+ std::string mFilename;
+ lt_dlhandle mHandle;
+ bool mLoaded;
+};
diff --git a/src/plugins/pluginmanager.cpp b/src/plugins/pluginmanager.cpp
new file mode 100644
index 0000000..470ac2f
--- /dev/null
+++ b/src/plugins/pluginmanager.cpp
@@ -0,0 +1,132 @@
+// * This file is part of the COLOBOT source code
+// * 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/.
+
+// pluginmanager.cpp
+
+
+#include "pluginmanager.h"
+
+
+template<> CPluginManager* CSingleton<CPluginManager>::mInstance = nullptr;
+
+
+CPluginManager::CPluginManager()
+{
+ lt_dlinit();
+}
+
+
+CPluginManager::~CPluginManager()
+{
+ UnloadAllPlugins();
+ lt_dlexit();
+}
+
+
+
+void CPluginManager::LoadFromProfile()
+{
+ std::vector< std::string > dirs = GetProfile()->GetLocalProfileSection("Plugins", "Path");
+ std::vector< std::string > plugins = GetProfile()->GetLocalProfileSection("Plugins", "File");
+
+ for (std::string dir : dirs)
+ m_folders.insert(dir);
+
+ for (std::string plugin : plugins) {
+ GetLogger()->Info("Trying to load plugin %s...\n", plugin.c_str());
+ LoadPlugin(plugin);
+ }
+}
+
+
+bool CPluginManager::LoadPlugin(std::string filename)
+{
+ bool result = false;
+ CPluginLoader *loader = new CPluginLoader("");
+ for (std::string dir : m_folders) {
+ loader->SetFilename(dir + "/" + filename);
+ result = loader->LoadPlugin();
+ if (result) {
+ GetLogger()->Info("Plugin %s (%s) version %0.2f loaded!\n", filename.c_str(), loader->GetName().c_str(), loader->GetVersion() / 100.0f);
+ m_plugins.push_back(loader);
+ break;
+ }
+ }
+ return result;
+}
+
+
+bool CPluginManager::UnloadPlugin(std::string filename)
+{
+ std::vector<CPluginLoader *>::iterator it;
+ GetLogger()->Info("Trying to unload plugin %s...\n", filename.c_str());
+ for (it = m_plugins.begin(); it != m_plugins.end(); it++) {
+ CPluginLoader *plugin = *it;
+ if (NameEndsWith(plugin->GetFilename(), filename)) {
+ m_plugins.erase(it);
+ plugin->UnloadPlugin();
+ delete plugin;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool CPluginManager::AddSearchDirectory(std::string dir)
+{
+ m_folders.insert(dir);
+ return true;
+}
+
+
+bool CPluginManager::RemoveSearchDirectory(std::string dir)
+{
+ m_folders.erase(dir);
+ return false;
+}
+
+
+bool CPluginManager::UnloadAllPlugins()
+{
+ bool allOk = true;
+ std::vector<CPluginLoader *>::iterator it;
+ for (it = m_plugins.begin(); it != m_plugins.end(); it++) {
+ CPluginLoader *plugin = *it;
+ bool result;
+
+ GetLogger()->Info("Trying to unload plugin %s (%s)...\n", plugin->GetFilename().c_str(), plugin->GetName().c_str());
+ result = plugin->UnloadPlugin();
+ if (!result) {
+ allOk = false;
+ continue;
+ }
+ delete plugin;
+ m_plugins.erase(it);
+ }
+
+ return allOk;
+}
+
+
+bool CPluginManager::NameEndsWith(std::string filename, std::string ending)
+{
+ if (filename.length() > ending.length()) {
+ std::string fileEnd = filename.substr(filename.length() - ending.length());
+ return (fileEnd == ending);
+ }
+ return false;
+}
diff --git a/src/plugins/pluginmanager.h b/src/plugins/pluginmanager.h
new file mode 100644
index 0000000..e425c62
--- /dev/null
+++ b/src/plugins/pluginmanager.h
@@ -0,0 +1,88 @@
+// * This file is part of the COLOBOT source code
+// * 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/.
+
+// pluginmanager.h
+
+/**
+ * @file plugin/pluginmanager.h
+ * @brief Plugin manager class.
+ */
+
+#pragma once
+
+#include <string>
+#include <set>
+#include <vector>
+
+#include <common/logger.h>
+#include <common/profile.h>
+
+#include <common/singleton.h>
+
+#include "pluginloader.h"
+
+
+/**
+* @class CPluginManager
+*
+* @brief Plugin manager class. Plugin manager can load plugins from colobot.ini or manually specified files.
+*
+*/
+class CPluginManager : public CSingleton<CPluginManager> {
+ public:
+ CPluginManager();
+ ~CPluginManager();
+
+ /** Function loads plugin list and path list from profile file
+ */
+ void LoadFromProfile();
+
+ /** Function loads specified plugin
+ * @param std::string plugin filename
+ * @return returns true on success
+ */
+ bool LoadPlugin(std::string);
+
+ /** Function unloads specified plugin
+ * @param std::string plugin filename
+ * @return returns true on success
+ */
+ bool UnloadPlugin(std::string);
+
+ /** Function adds path to be checked when searching for plugin file. If path was already added it will be ignored
+ * @param std::string plugin search path
+ * @return returns true on success
+ */
+ bool AddSearchDirectory(std::string);
+
+ /** Function removes path from list
+ * @param std::string plugin search path
+ * @return returns true on success
+ */
+ bool RemoveSearchDirectory(std::string);
+
+ /** Function tries to unload all plugins
+ * @return returns true on success
+ */
+ bool UnloadAllPlugins();
+
+ private:
+ bool NameEndsWith(std::string, std::string);
+
+ std::set< std::string > m_folders;
+ std::vector<CPluginLoader *> m_plugins;
+};
+
diff --git a/src/plugins/test/CMakeLists.txt b/src/plugins/test/CMakeLists.txt
new file mode 100644
index 0000000..5f86b6f
--- /dev/null
+++ b/src/plugins/test/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(CMAKE_BUILD_TYPE debug)
+set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0 -std=c++11 -rdynamic")
+
+add_executable(manager_test manager_test.cpp ../../common/logger.cpp ../../common/profile.cpp ../../common/iman.cpp ../pluginmanager.cpp ../pluginloader.cpp)
+
+include_directories(".")
+include_directories("../../")
+include_directories("../../../")
+
+target_link_libraries(manager_test ltdl)
diff --git a/src/plugins/test/colobot.ini b/src/plugins/test/colobot.ini
new file mode 100644
index 0000000..08956be
--- /dev/null
+++ b/src/plugins/test/colobot.ini
@@ -0,0 +1,3 @@
+[Plugins]
+Path=.
+File=libopenalsound.so
diff --git a/src/plugins/test/manager_test.cpp b/src/plugins/test/manager_test.cpp
new file mode 100644
index 0000000..d921c1d
--- /dev/null
+++ b/src/plugins/test/manager_test.cpp
@@ -0,0 +1,31 @@
+#include <common/logger.h>
+#include <common/profile.h>
+#include <common/iman.h>
+#include <plugins/pluginmanager.h>
+#include <sound/sound.h>
+
+
+int main() {
+ new CLogger();
+ new CProfile();
+ new CInstanceManager();
+ CPluginManager *mgr = new CPluginManager();
+
+ if (!GetProfile()->InitCurrentDirectory()) {
+ GetLogger()->Error("Config not found!\n");
+ return 1;
+ }
+
+ mgr->LoadFromProfile();
+ CSoundInterface *sound = static_cast<CSoundInterface*>(CInstanceManager::GetInstancePointer()->SearchInstance(CLASS_SOUND));
+
+ if (!sound) {
+ GetLogger()->Error("Sound not loaded!\n");
+ return 2;
+ }
+
+ sound->Create(true);
+ mgr->UnloadAllPlugins();
+
+ return 0;
+}
diff --git a/src/sound/README.txt b/src/sound/README.txt
index d6ac0bd..fa7bbad 100644
--- a/src/sound/README.txt
+++ b/src/sound/README.txt
@@ -1,3 +1,4 @@
-src/sound
-
-Contains the sound module - for playing sounds and music.
+/**
+ * \dir sound
+ * \brief Sound module - playing sounds and music
+ */ \ No newline at end of file
diff --git a/src/sound/plugins/oalsound/CMakeLists.txt b/src/sound/plugins/oalsound/CMakeLists.txt
new file mode 100644
index 0000000..e36f3ac
--- /dev/null
+++ b/src/sound/plugins/oalsound/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(SOURCES
+ alsound.cpp
+ buffer.cpp
+ channel.cpp
+)
+
+SET (CMAKE_CXX_FLAGS "-Wall -g -std=c++0x -fPIC")
+
+include(FindPkgConfig)
+include(FindOpenAL)
+pkg_check_modules(OPENAL_LIB REQUIRED openal)
+
+set(OPENAL_LIBRARIES
+ openal
+ alut
+)
+
+
+include_directories(../../..)
+include_directories(.)
+add_library(openalsound SHARED ${SOURCES})
+target_link_libraries(openalsound ${OPENAL_LIBRARIES})
diff --git a/src/sound/plugins/oalsound/alsound.cpp b/src/sound/plugins/oalsound/alsound.cpp
new file mode 100644
index 0000000..8cd8221
--- /dev/null
+++ b/src/sound/plugins/oalsound/alsound.cpp
@@ -0,0 +1,553 @@
+// * 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/.
+
+// alsound.cpp
+
+
+#include "alsound.h"
+
+
+#define MIN(a, b) (a > b ? b : a)
+
+
+PLUGIN_INTERFACE(ALSound)
+
+
+std::string ALSound::PluginName()
+{
+ return "Sound plugin using OpenAL library to play sounds.";
+}
+
+
+int ALSound::PluginVersion()
+{
+ return 2;
+}
+
+
+void ALSound::InstallPlugin()
+{
+ auto pointer = CInstanceManager::GetInstancePointer();
+ if (pointer != nullptr)
+ CInstanceManager::GetInstancePointer()->AddInstance(CLASS_SOUND, this);
+}
+
+
+bool ALSound::UninstallPlugin(std::string &reason)
+{
+ auto pointer = CInstanceManager::GetInstancePointer();
+ if (pointer != nullptr)
+ CInstanceManager::GetInstancePointer()->DeleteInstance(CLASS_SOUND, this);
+ CleanUp();
+ return true;
+}
+
+
+ALSound::ALSound()
+{
+ mEnabled = false;
+ m3D = false;
+ mAudioVolume = MAXVOLUME;
+ mMute = false;
+}
+
+
+ALSound::~ALSound()
+{
+ CleanUp();
+}
+
+
+void ALSound::CleanUp()
+{
+ if (mEnabled) {
+ GetLogger()->Info("Unloading files and closing device...\n");
+ StopAll();
+
+ for (auto item : mSounds)
+ delete item.second;
+
+ mEnabled = false;
+ alutExit();
+ }
+}
+
+
+bool ALSound::Create(bool b3D)
+{
+ CleanUp();
+
+ if (mEnabled)
+ return true;
+
+ GetLogger()->Info("Opening audio device...\n");
+ if (!alutInit(NULL, NULL)) {
+ ALenum error = alutGetError();
+ GetLogger()->Error("Could not open audio device! Reason: %s\n", alutGetErrorString(error));
+ return false;
+ }
+ GetLogger()->Info("Done.\n");
+
+ mEnabled = true;
+ return true;
+}
+
+
+void ALSound::SetSound3D(bool bMode)
+{
+ // TODO stub! need to be implemented
+ m3D = bMode;
+}
+
+
+bool ALSound::RetSound3D()
+{
+ // TODO stub! need to be implemented
+ return true;
+}
+
+
+bool ALSound::RetSound3DCap()
+{
+ // TODO stub! need to be implemented
+ return true;
+}
+
+
+bool ALSound::RetEnable()
+{
+ return mEnabled;
+}
+
+
+void ALSound::SetAudioVolume(int volume)
+{
+ alListenerf(AL_GAIN, MIN(volume, MAXVOLUME) * 0.01f);
+ mAudioVolume = MIN(volume, MAXVOLUME);
+}
+
+
+int ALSound::RetAudioVolume()
+{
+ float volume;
+ if ( !mEnabled )
+ return 0;
+
+ alGetListenerf(AL_GAIN, &volume);
+ return volume * MAXVOLUME;
+}
+
+
+void ALSound::SetMusicVolume(int volume)
+{
+ // TODO stub! Add music support
+}
+
+
+int ALSound::RetMusicVolume()
+{
+ // TODO stub! Add music support
+ if ( !mEnabled )
+ return 0;
+
+ return 0;
+}
+
+
+bool ALSound::Cache(Sound sound, std::string filename)
+{
+ Buffer *buffer = new Buffer();
+ if (buffer->LoadFromFile(filename, sound)) {
+ mSounds[sound] = buffer;
+ return true;
+ }
+ return false;
+}
+
+
+void ALSound::CacheAll()
+{
+ char filename[100];
+ for ( int i = 1; i < 69; i++ )
+ {
+ sprintf(filename, "high/sound%.3d.wav", i);
+ if ( !Cache((Sound) i, std::string(filename)) )
+ {
+ fprintf(stderr, "Unable to load audio: %s\n", filename);
+ }
+ }
+}
+
+
+int ALSound::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;
+}
+
+
+bool ALSound::SearchFreeBuffer(Sound sound, int &channel, bool &bAlreadyLoaded)
+{
+ int priority = RetPriority(sound);
+
+ // Seeks a channel used which sound is stopped.
+ for (auto it : mChannels) {
+ if (it.second->IsPlaying())
+ continue;
+ if (it.second->GetSoundType() != sound)
+ continue;
+
+ it.second->SetPriority(priority);
+ channel = it.first;
+ bAlreadyLoaded = true;
+ return true;
+ }
+
+ // just add a new channel if we dont have any
+ if (mChannels.size() == 0) {
+ Channel *chn = new Channel();
+ // check if we channel ready to play music, if not report error
+ if (chn->IsReady()) {
+ chn->SetPriority(priority);
+ mChannels[1] = chn;
+ channel = 1;
+ bAlreadyLoaded = false;
+ return true;
+ }
+ delete chn;
+ GetLogger()->Error("Could not open channel to play sound!");
+ return false;
+ }
+
+ // Seeks a channel completely free.
+ auto it = mChannels.end();
+ it--;
+ int i = (*it).first;
+ while (++i)
+ {
+ if (mChannels.find(i) == mChannels.end()) {
+ Channel *chn = new Channel();
+ // check if we channel ready to play music, if not destroy it and seek free one
+ if (chn->IsReady()) {
+ chn->SetPriority(priority);
+ mChannels[1] = chn;
+ channel = 1;
+ bAlreadyLoaded = false;
+ return true;
+ }
+ delete chn;
+ GetLogger()->Warn("Could not open additional channel to play sound!");
+ }
+ }
+
+ int lowerOrEqual = -1;
+ for (auto it : mChannels) {
+ if (it.second->GetPriority() < priority) {
+ GetLogger()->Info("Sound channel with lower priority will be reused.");
+ channel = it.first;
+ return true;
+ }
+ if (it.second->GetPriority() <= priority)
+ lowerOrEqual = it.first;
+ }
+
+ if (lowerOrEqual != -1) {
+ channel = lowerOrEqual;
+ GetLogger()->Info("Sound channel with lower or equal priority will be reused.");
+ return true;
+ }
+
+ GetLogger()->Warn("Could not find free buffer to use.\n");
+ return false;
+}
+
+
+int ALSound::Play(Sound sound, float amplitude, float frequency, bool bLoop)
+{
+ return Play(sound, Math::Vector(), amplitude, frequency, bLoop);
+}
+
+
+int ALSound::Play(Sound sound, Math::Vector pos, float amplitude, float frequency, bool bLoop)
+{
+ if (!mEnabled)
+ return -1;
+
+ if (mAudioVolume <= 0.0f)
+ return -1;
+
+ if (mSounds.find(sound) == mSounds.end()) {
+ GetLogger()->Warn("Sound %d was not loaded!\n", sound);
+ return -1;
+ }
+
+ int channel;
+ bool bAlreadyLoaded;
+ if (!SearchFreeBuffer(sound, channel, bAlreadyLoaded))
+ return -1;
+ if ( !bAlreadyLoaded ) {
+ mChannels[channel]->SetBuffer(mSounds[sound]);
+ }
+
+ Position(channel, pos);
+
+ // setting initial values
+ mChannels[channel]->SetStartAmplitude(amplitude);
+ mChannels[channel]->SetStartFrequency(frequency);
+ mChannels[channel]->SetChangeFrequency(1.0f);
+ mChannels[channel]->ResetOper();
+ mChannels[channel]->AdjustFrequency(frequency);
+ mChannels[channel]->AdjustVolume(mAudioVolume);
+ mChannels[channel]->Play();
+ return channel;
+}
+
+
+bool ALSound::FlushEnvelope(int channel)
+{
+ if (mChannels.find(channel) == mChannels.end()) {
+ return false;
+ }
+
+ mChannels[channel]->ResetOper();
+ return true;
+}
+
+
+bool ALSound::AddEnvelope(int channel, float amplitude, float frequency, float time, SoundNext oper)
+{
+ if (!mEnabled)
+ return false;
+
+ if (mChannels.find(channel) == mChannels.end()) {
+ return false;
+ }
+
+ SoundOper op;
+ op.finalAmplitude = amplitude;
+ op.finalFrequency = frequency;
+ op.totalTime = time;
+ op.nextOper = oper;
+ mChannels[channel]->AddOper(op);
+
+ return false;
+}
+
+
+bool ALSound::Position(int channel, Math::Vector pos)
+{
+ if (!mEnabled)
+ return false;
+
+ if (mChannels.find(channel) == mChannels.end()) {
+ return false;
+ }
+
+ mChannels[channel]->SetPosition(pos);
+ return true;
+}
+
+
+bool ALSound::Frequency(int channel, float frequency)
+{
+ if (!mEnabled)
+ return false;
+
+ if (mChannels.find(channel) == mChannels.end()) {
+ return false;
+ }
+
+ mChannels[channel]->SetFrequency(frequency);
+ return true;
+}
+
+bool ALSound::Stop(int channel)
+{
+ if (!mEnabled)
+ return false;
+
+ if (mChannels.find(channel) == mChannels.end()) {
+ return false;
+ }
+
+ mChannels[channel]->Stop();
+ mChannels[channel]->ResetOper();
+
+ return true;
+}
+
+
+bool ALSound::StopAll()
+{
+ if (!mEnabled)
+ return false;
+
+ for (auto channel : mChannels) {
+ channel.second->Stop();
+ channel.second->ResetOper();
+ }
+
+ return true;
+}
+
+
+bool ALSound::MuteAll(bool bMute)
+{
+ if (!mEnabled)
+ return false;
+
+ float volume;
+ mMute = bMute;
+ if (mMute)
+ volume = 0;
+ else
+ volume = mAudioVolume;
+
+ for (auto channel : mChannels) {
+ channel.second->SetVolume(volume);
+ }
+
+ return true;
+}
+
+
+void ALSound::FrameMove(float delta)
+{
+ if (!mEnabled)
+ return;
+
+ float progress;
+ float volume, frequency;
+ for (auto it : mChannels) {
+ if (!it.second->IsPlaying())
+ continue;
+
+ if (!it.second->HasEnvelope())
+ continue;
+
+ //it.second->GetEnvelope().currentTime += delta;
+ SoundOper oper = it.second->GetEnvelope();
+ progress = it.second->GetCurrentTime() / oper.totalTime;
+ progress = MIN(progress, 1.0f);
+
+ // setting volume
+ volume = progress * abs(oper.finalAmplitude - it.second->GetStartAmplitude());
+ it.second->AdjustVolume(volume * mAudioVolume);
+
+ // setting frequency
+ frequency = progress * (oper.finalFrequency - it.second->GetStartFrequency()) * it.second->GetStartFrequency() * it.second->GetChangeFrequency();
+ it.second->AdjustFrequency(frequency);
+
+ if (it.second->GetEnvelope().totalTime <= it.second->GetCurrentTime()) {
+
+ if (oper.nextOper == SOPER_LOOP) {
+ GetLogger()->Info("Replay.\n");
+ it.second->SetCurrentTime(0.0f);
+ it.second->Play();
+ } else {
+ GetLogger()->Info("Next.\n");
+ it.second->SetStartAmplitude(oper.finalAmplitude);
+ it.second->SetStartFrequency(oper.finalFrequency);
+ it.second->PopEnvelope();
+ }
+ }
+ }
+}
+
+
+void ALSound::SetListener(Math::Vector eye, Math::Vector lookat)
+{
+ GetLogger()->Info("Setting listener position.\n");
+ float orientation[] = {lookat.x, lookat.y, lookat.z, 0.f, 1.f, 0.f};
+ alListener3f(AL_POSITION, eye.x, eye.y, eye.z);
+ alListenerfv(AL_ORIENTATION, orientation);
+}
+
+
+bool ALSound::PlayMusic(int rank, bool bRepeat)
+{
+ // TODO stub! Add music support
+ return true;
+}
+
+
+bool ALSound::RestartMusic()
+{
+ // TODO stub! Add music support
+ return true;
+}
+
+void ALSound::StopMusic()
+{
+ // TODO stub! Add music support
+ SuspendMusic();
+}
+
+
+bool ALSound::IsPlayingMusic()
+{
+ // TODO stub! Add music support
+ return true;
+}
+
+
+void ALSound::SuspendMusic()
+{
+ // TODO stub! Add music support
+}
diff --git a/src/sound/plugins/oalsound/alsound.h b/src/sound/plugins/oalsound/alsound.h
new file mode 100644
index 0000000..c1cdb81
--- /dev/null
+++ b/src/sound/plugins/oalsound/alsound.h
@@ -0,0 +1,95 @@
+// * 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/.
+
+// alsound.h
+
+#pragma once
+
+#include <map>
+#include <string>
+
+#include <AL/alut.h>
+
+#include <common/iman.h>
+#include <common/logger.h>
+#include <sound/sound.h>
+
+#include "buffer.h"
+#include "channel.h"
+#include "check.h"
+
+
+class ALSound : public CSoundInterface
+{
+ public:
+ ALSound();
+ ~ALSound();
+
+ bool Create(bool b3D);
+ void CacheAll();
+ bool Cache(Sound, std::string);
+
+ bool RetEnable();
+
+ void SetSound3D(bool bMode);
+ bool RetSound3D();
+ bool RetSound3DCap();
+
+ void SetAudioVolume(int volume);
+ int RetAudioVolume();
+ void SetMusicVolume(int volume);
+ int RetMusicVolume();
+
+ 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();
+
+ // plugin interface
+ std::string PluginName();
+ int PluginVersion();
+ void InstallPlugin();
+ bool UninstallPlugin(std::string &);
+
+ private:
+ void CleanUp();
+ int RetPriority(Sound);
+ bool SearchFreeBuffer(Sound sound, int &channel, bool &bAlreadyLoaded);
+
+ bool mEnabled;
+ bool m3D;
+ bool mMute;
+ int mAudioVolume;
+ ALCdevice* audioDevice;
+ ALCcontext* audioContext;
+ std::map<Sound, Buffer*> mSounds;
+ std::map<int, Channel*> mChannels;
+};
diff --git a/src/sound/plugins/oalsound/buffer.cpp b/src/sound/plugins/oalsound/buffer.cpp
new file mode 100644
index 0000000..37211e9
--- /dev/null
+++ b/src/sound/plugins/oalsound/buffer.cpp
@@ -0,0 +1,80 @@
+// * This file is part of the COLOBOT source code
+// * 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/.
+
+// buffer.cpp
+
+#include "buffer.h"
+
+Buffer::Buffer() {
+ mLoaded = false;
+ mDuration = 0;
+}
+
+
+Buffer::~Buffer() {
+ if (mLoaded) {
+ alDeleteBuffers(1, &mBuffer);
+ if (alCheck())
+ GetLogger()->Warn("Failed to unload buffer. Code %d\n", alGetCode());
+ }
+}
+
+
+bool Buffer::LoadFromFile(std::string filename, Sound sound) {
+ mSound = sound;
+
+ GetLogger()->Info("Loading audio file: %s\n", filename.c_str());
+ mBuffer = alutCreateBufferFromFile(filename.c_str());
+
+ ALenum error = alutGetError();
+ if (error) {
+ GetLogger()->Warn("Failed to load file. Reason: %s\n", alutGetErrorString(error));
+ mLoaded = false;
+ return false;
+ }
+
+ ALint size, bits, channels, freq;
+
+ alGetBufferi(mBuffer, AL_SIZE, &size);
+ alGetBufferi(mBuffer, AL_BITS, &bits);
+ alGetBufferi(mBuffer, AL_CHANNELS, &channels);
+ alGetBufferi(mBuffer, AL_FREQUENCY, &freq);
+
+ mDuration = (ALfloat)size / channels / bits / 8 / (ALfloat)freq;
+
+ mLoaded = true;
+ return true;
+}
+
+
+Sound Buffer::GetSoundType() {
+ return mSound;
+}
+
+
+ALuint Buffer::GetBuffer() {
+ return mBuffer;
+}
+
+
+bool Buffer::IsLoaded() {
+ return mLoaded;
+}
+
+
+float Buffer::GetDuration() {
+ return mDuration;
+}
diff --git a/src/sound/plugins/oalsound/buffer.h b/src/sound/plugins/oalsound/buffer.h
new file mode 100644
index 0000000..6eefe72
--- /dev/null
+++ b/src/sound/plugins/oalsound/buffer.h
@@ -0,0 +1,48 @@
+// * This file is part of the COLOBOT source code
+// * 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/.
+
+// buffer.h
+
+#pragma once
+
+#include <string>
+
+#include <AL/alut.h>
+
+#include <sound/sound.h>
+#include <common/logger.h>
+
+#include "check.h"
+
+class Buffer
+{
+ public:
+ Buffer();
+ ~Buffer();
+
+ bool LoadFromFile(std::string, Sound);
+ bool IsLoaded();
+
+ Sound GetSoundType();
+ ALuint GetBuffer();
+ float GetDuration();
+
+ private:
+ ALuint mBuffer;
+ Sound mSound;
+ bool mLoaded;
+ float mDuration;
+};
diff --git a/src/sound/plugins/oalsound/channel.cpp b/src/sound/plugins/oalsound/channel.cpp
new file mode 100644
index 0000000..4476dee
--- /dev/null
+++ b/src/sound/plugins/oalsound/channel.cpp
@@ -0,0 +1,304 @@
+// * This file is part of the COLOBOT source code
+// * 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/.
+
+// channel.cpp
+
+#include "channel.h"
+
+
+Channel::Channel() {
+ alGenSources(1, &mSource);
+
+ if (alCheck()) {
+ GetLogger()->Warn("Failed to create sound source. Code: %d\n", alGetCode());
+ mReady = false;
+ } else {
+ mReady = true;
+ }
+
+ mPriority = 0;
+ mBuffer = nullptr;
+}
+
+
+Channel::~Channel() {
+ if (mReady) {
+ alSourcei(mSource, AL_BUFFER, 0);
+ alDeleteSources(1, &mSource);
+ if (alCheck())
+ GetLogger()->Warn("Failed to delete sound source. Code: %s\n", alGetCode());
+ }
+}
+
+
+bool Channel::Play() {
+ if (!mReady)
+ return false;
+
+ alSourcePlay(mSource);
+ if (alCheck())
+ GetLogger()->Warn("Could not play audio sound source. Code: %s\n", alGetCode());
+ return true;
+}
+
+
+bool Channel::SetPosition(Math::Vector pos) {
+ if (!mReady)
+ return false;
+
+ alSource3f(mSource, AL_POSITION, pos.x, pos.y, pos.z);
+ if (alCheck()) {
+ GetLogger()->Warn("Could not set sound position. Code: %s\n", alGetCode());
+ return false;
+ }
+ return true;
+}
+
+
+bool Channel::SetFrequency(float freq)
+{
+ if (!mReady)
+ return false;
+
+ alSourcef(mSource, AL_PITCH, freq);
+ if (alCheck()) {
+ GetLogger()->Warn("Could not set sound pitch. Code: %s\n", alGetCode());
+ return false;
+ }
+ return true;
+}
+
+
+float Channel::GetFrequency()
+{
+ ALfloat freq;
+ if (!mReady)
+ return 0;
+
+ alGetSourcef(mSource, AL_PITCH, &freq);
+ if (alCheck()) {
+ GetLogger()->Warn("Could not get sound pitch. Code: %s\n", alGetCode());
+ return 0;
+ }
+
+ return freq;
+}
+
+
+bool Channel::SetVolume(float vol)
+{
+ if (!mReady || vol < 0)
+ return false;
+
+ alSourcef(mSource, AL_GAIN, vol / MAXVOLUME);
+ if (alCheck()) {
+ GetLogger()->Warn("Could not set sound volume. Code: %s\n", alGetCode());
+ return false;
+ }
+ return true;
+}
+
+
+float Channel::GetVolume()
+{
+ ALfloat vol;
+ if (!mReady)
+ return 0;
+
+ alGetSourcef(mSource, AL_GAIN, &vol);
+ if (alCheck()) {
+ GetLogger()->Warn("Could not get sound volume. Code: %s\n", alGetCode());
+ return 0;
+ }
+
+ return vol * MAXVOLUME;
+}
+
+
+int Channel::GetPriority()
+{
+ return mPriority;
+}
+
+
+void Channel::SetPriority(int pri)
+{
+ mPriority = pri;
+}
+
+
+void Channel::SetStartAmplitude(float gain)
+{
+ mStartAmplitude = gain;
+}
+
+
+void Channel::SetStartFrequency(float freq)
+{
+ mStartFrequency = freq;
+}
+
+
+void Channel::SetChangeFrequency(float freq)
+{
+ mChangeFrequency = freq;
+}
+
+
+void Channel::SetInitFrequency(float freq)
+{
+ mInitFrequency = freq;
+}
+
+
+float Channel::GetStartAmplitude()
+{
+ return mStartAmplitude;
+}
+
+
+float Channel::GetStartFrequency()
+{
+ return mStartFrequency;
+}
+
+
+float Channel::GetChangeFrequency()
+{
+ return mChangeFrequency;
+}
+
+
+float Channel::GetInitFrequency()
+{
+ return mInitFrequency;
+}
+
+
+void Channel::AddOper(SoundOper oper)
+{
+ mOper.push_back(oper);
+}
+
+
+void Channel::ResetOper()
+{
+ mOper.clear();
+}
+
+
+Sound Channel::GetSoundType() {
+ return mBuffer->GetSoundType();
+}
+
+
+bool Channel::SetBuffer(Buffer *buffer) {
+ if (!mReady)
+ return false;
+
+ assert(buffer);
+ mBuffer = buffer;
+ alSourcei(mSource, AL_BUFFER, buffer->GetBuffer());
+ if (alCheck()) {
+ GetLogger()->Warn("Could not set sound buffer. Code: %s\n", alGetCode());
+ return false;
+ }
+ mInitFrequency = GetFrequency();
+ return true;
+}
+
+
+void Channel::AdjustFrequency(float freq) {
+ SetFrequency(freq * mInitFrequency);
+}
+
+
+void Channel::AdjustVolume(float volume) {
+ SetVolume(mStartAmplitude * (float) volume);
+}
+
+
+bool Channel::IsPlaying() {
+ ALint status;
+ if (!mReady) return false;
+
+ alGetSourcei(mSource, AL_SOURCE_STATE, &status);
+ if (alCheck()) {
+ GetLogger()->Warn("Could not get sound status. Code: %s\n", alGetCode());
+ return false;
+ }
+
+ return status == AL_PLAYING;
+}
+
+
+bool Channel::IsReady() {
+ return mReady;
+}
+
+
+bool Channel::Stop() {
+ alSourceStop(mSource);
+ if (alCheck()) {
+ GetLogger()->Warn("Could not stop sound. Code: %s\n", alGetCode());
+ return false;
+ }
+ return true;
+}
+
+
+float Channel::GetCurrentTime()
+{
+ ALfloat current;
+ alGetSourcef(mSource, AL_SEC_OFFSET, &current);
+ if (alCheck()) {
+ GetLogger()->Warn("Could not get source current play time. Code: %s\n", alGetCode());
+ return 0.0f;
+ }
+ return current;
+}
+
+
+void Channel::SetCurrentTime(float current)
+{
+ alSourcef(mSource, AL_SEC_OFFSET, current);
+ if (alCheck())
+ GetLogger()->Warn("Could not get source current play time. Code: %s\n", alGetCode());
+}
+
+
+float Channel::GetDuration()
+{
+ return mBuffer->GetDuration();
+}
+
+
+bool Channel::HasEnvelope()
+{
+ return mOper.size() > 0;
+}
+
+
+SoundOper& Channel::GetEnvelope()
+{
+ return mOper.front();
+}
+
+
+void Channel::PopEnvelope()
+{
+ mOper.pop_front();
+}
diff --git a/src/sound/plugins/oalsound/channel.h b/src/sound/plugins/oalsound/channel.h
new file mode 100644
index 0000000..3099931
--- /dev/null
+++ b/src/sound/plugins/oalsound/channel.h
@@ -0,0 +1,99 @@
+// * This file is part of the COLOBOT source code
+// * 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/.
+
+// channel.h
+
+#pragma once
+
+#include <string>
+#include <deque>
+#include <cassert>
+
+#include <AL/al.h>
+#include <AL/alc.h>
+
+#include <sound/sound.h>
+
+#include "buffer.h"
+#include "check.h"
+
+struct SoundOper
+{
+ float finalAmplitude;
+ float finalFrequency;
+ float totalTime;
+ SoundNext nextOper;
+};
+
+
+class Channel
+{
+ public:
+ Channel();
+ ~Channel();
+
+ bool Play();
+ bool Stop();
+ bool SetPosition(Math::Vector);
+
+ bool SetFrequency(float);
+ float GetFrequency();
+
+ float GetCurrentTime();
+ void SetCurrentTime(float);
+ float GetDuration();
+
+ bool SetVolume(float);
+ float GetVolume();
+ bool IsPlaying();
+ bool IsReady();
+
+ bool SetBuffer(Buffer *);
+ bool HasEnvelope();
+ SoundOper& GetEnvelope();
+ void PopEnvelope();
+
+ int GetPriority();
+ void SetPriority(int);
+
+ void SetStartAmplitude(float);
+ void SetStartFrequency(float);
+ void SetChangeFrequency(float);
+ void SetInitFrequency(float);
+
+ float GetStartAmplitude();
+ float GetStartFrequency();
+ float GetChangeFrequency();
+ float GetInitFrequency();
+
+ void AddOper(SoundOper);
+ void ResetOper();
+ Sound GetSoundType();
+ void AdjustFrequency(float);
+ void AdjustVolume(float);
+
+ private:
+ Buffer *mBuffer;
+ ALuint mSource;
+
+ int mPriority;
+ float mStartAmplitude;
+ float mStartFrequency;
+ float mChangeFrequency;
+ float mInitFrequency;
+ std::deque<SoundOper> mOper;
+ bool mReady;
+};
diff --git a/src/plugins/plugin.h b/src/sound/plugins/oalsound/check.h
index f238122..cb6b4a1 100644
--- a/src/plugins/plugin.h
+++ b/src/sound/plugins/oalsound/check.h
@@ -14,20 +14,26 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// plugin.h
-
+// check.h
#pragma once
+#include <AL/al.h>
+#include <AL/alc.h>
-#define PLUGIN_INTERFACE(class_type, interface_type) \
- extern "C" interface_type* installPlugin() { return (interface_type *)new class_type(); } \
- extern "C" void uninstallPlugin(class_type *_class) { delete _class; }
+#include <common/logger.h>
+static ALenum CODE = AL_NO_ERROR;
-class CPlugin {
- public:
- virtual char* PluginName() = 0;
- virtual int PluginVersion() = 0;
-};
+inline bool alCheck()
+{
+ CODE = alGetError();
+ return CODE != AL_NO_ERROR;
+}
+inline ALenum alGetCode()
+{
+ ALenum ret = CODE;
+ CODE = AL_NO_ERROR;
+ return ret;
+}
diff --git a/src/sound/plugins/oalsound/test/CMakeLists.txt b/src/sound/plugins/oalsound/test/CMakeLists.txt
new file mode 100644
index 0000000..d10169b
--- /dev/null
+++ b/src/sound/plugins/oalsound/test/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(CMAKE_BUILD_TYPE debug)
+set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0 -std=c++11 -rdynamic")
+
+add_executable(plugin_test plugin_test.cpp ../../../../common/iman.cpp ../../../../common/logger.cpp ../../../../plugins/pluginloader.cpp)
+
+include_directories(".")
+include_directories("../../../../")
+
+target_link_libraries(plugin_test ltdl)
diff --git a/src/sound/plugins/oalsound/test/plugin_test.cpp b/src/sound/plugins/oalsound/test/plugin_test.cpp
new file mode 100644
index 0000000..40c1cd2
--- /dev/null
+++ b/src/sound/plugins/oalsound/test/plugin_test.cpp
@@ -0,0 +1,40 @@
+#include <string>
+#include <cstdio>
+#include <unistd.h>
+
+#include <common/logger.h>
+#include <common/iman.h>
+#include <sound/sound.h>
+#include <plugins/pluginloader.h>
+
+
+int main() {
+ new CLogger();
+ new CInstanceManager();
+
+ lt_dlinit();
+
+ CPluginLoader *plugin = new CPluginLoader("libopenalsound");
+ if (plugin->LoadPlugin()) {
+ CSoundInterface *sound = static_cast<CSoundInterface*>(CInstanceManager::GetInstancePointer()->SearchInstance(CLASS_SOUND));
+
+ sound->Create(true);
+ sound->CacheAll();
+ sound->Play((Sound)8);
+ sound->Play((Sound)18);
+
+ sleep(10);
+ /*
+ while (1)
+ {
+ // just a test, very slow
+ plugin->FrameMove(0);
+ //if ('n' == getchar())
+ // break;
+ }*/
+ plugin->UnloadPlugin();
+ }
+
+ lt_dlexit();
+ return 0;
+}
diff --git a/src/sound/sound.h b/src/sound/sound.h
index a1b8fe3..45ec7e1 100644
--- a/src/sound/sound.h
+++ b/src/sound/sound.h
@@ -15,10 +15,10 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// soundinterface.h
+// sound.h
/**
- * @file sound/soundinterface.h
+ * @file sound/sound.h
* @brief Sound plugin interface
*/
@@ -26,7 +26,7 @@
#include <math/vector.h>
-#include <plugins/plugin.h>
+#include <plugins/plugininterface.h>
#include <string>
@@ -39,7 +39,7 @@
/**
* \public
- * \enum Sound sound/soundinterface.h
+ * \enum Sound sound/sound.h
* \brief Sound enum representing sound file
**/
enum Sound
@@ -131,7 +131,7 @@ enum Sound
/**
* \public
- * \enum SoundNext sound/soundinterface.h
+ * \enum SoundNext sound/sound.h
* \brief Enum representing operation that will be performend on a sound at given time
**/
enum SoundNext
@@ -148,7 +148,7 @@ enum SoundNext
* @brief Sound plugin interface
*
*/
-class CSoundInterface : public CPlugin
+class CSoundInterface : public CPluginInterface
{
public:
CSoundInterface() {
@@ -319,3 +319,4 @@ class CSoundInterface : public CPlugin
*/
virtual bool IsPlayingMusic() = 0;
};
+
diff --git a/src/ui/README.txt b/src/ui/README.txt
index 4ffd8ec..9814ef0 100644
--- a/src/ui/README.txt
+++ b/src/ui/README.txt
@@ -1,3 +1,4 @@
-src/ui
-
-Contains modules responsible for displaying the user interface controls (from game menus and HUD).
+/**
+ * \dir ui
+ * \brief 2D user interface controls
+ */ \ No newline at end of file