summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
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.cpp40
-rw-r--r--src/common/logger.h38
-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.h15
-rw-r--r--src/graphics/core/texture.h36
-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.cpp3722
-rw-r--r--src/graphics/engine/engine.h917
-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.h79
-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.cpp638
-rw-r--r--src/graphics/engine/water.h152
-rw-r--r--src/graphics/opengl/README.txt13
-rw-r--r--src/graphics/opengl/gldevice.cpp65
-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, 11600 insertions, 1630 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..ed8df8c 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()
@@ -57,8 +43,10 @@ void CLogger::Log(LogType type, const char *str, va_list args)
return;
switch (type) {
- case LOG_WARN: fprintf(IsOpened() ? mFile : stderr, "[WARN]: "); break;
- case LOG_INFO: fprintf(IsOpened() ? mFile : stderr, "[INFO]: "); break;
+ case LOG_TRACE: fprintf(IsOpened() ? mFile : stderr, "[TRACE]: "); break;
+ case LOG_DEBUG: fprintf(IsOpened() ? mFile : stderr, "[DEBUG]: "); break;
+ case LOG_WARN: fprintf(IsOpened() ? mFile : stderr, "[WARN]: "); break;
+ case LOG_INFO: fprintf(IsOpened() ? mFile : stderr, "[INFO]: "); break;
case LOG_ERROR: fprintf(IsOpened() ? mFile : stderr, "[ERROR]: "); break;
default: break;
}
@@ -67,6 +55,24 @@ void CLogger::Log(LogType type, const char *str, va_list args)
}
+void CLogger::Trace(const char *str, ...)
+{
+ va_list args;
+ va_start(args, str);
+ Log(LOG_TRACE, str, args);
+ va_end(args);
+}
+
+
+void CLogger::Debug(const char *str, ...)
+{
+ va_list args;
+ va_start(args, str);
+ Log(LOG_DEBUG, str, args);
+ va_end(args);
+}
+
+
void CLogger::Info(const char *str, ...)
{
va_list args;
diff --git a/src/common/logger.h b/src/common/logger.h
index a67aefe..fc43735 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>
@@ -37,10 +38,12 @@
**/
enum LogType
{
- LOG_INFO = 1, /*!< lowest level, information */
- LOG_WARN = 2, /*!< warning */
- LOG_ERROR = 3, /*!< error */
- LOG_NONE = 4 /*!< none level, used for custom messages */
+ LOG_TRACE = 1, /*!< lowest level, execution tracing */
+ LOG_DEBUG = 2, /*!< debugging messages */
+ LOG_INFO = 3, /*!< information */
+ LOG_WARN = 4, /*!< warning */
+ LOG_ERROR = 5, /*!< error */
+ LOG_NONE = 6 /*!< none level, used for custom messages */
};
@@ -57,42 +60,51 @@ 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_TRACE level
+ * @param str - message to write
+ * @param ... - additional arguments
+ */
+ void Trace(const char *str, ...);
+
+ /** Write message to console or file with LOG_DEBUG level
+ * @param str - message to write
+ * @param ... - additional arguments
+ */
+ void Debug(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..156ff36 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
@@ -42,6 +45,16 @@ struct Material
Gfx::Color ambient;
//! Specular color
Gfx::Color specular;
+
+ bool operator==(const Gfx::Material &mat) const
+ {
+ return diffuse == mat.diffuse && ambient == mat.ambient && specular == mat.specular;
+ }
+
+ bool operator!=(const Gfx::Material &mat) const
+ {
+ return ! operator==(mat);
+ }
};
}; // namespace Gfx
diff --git a/src/graphics/core/texture.h b/src/graphics/core/texture.h
index 8d6b082..8abe86a 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 {
@@ -189,34 +192,43 @@ struct TextureStageParams
Also contains some additional data. */
struct Texture
{
- //! Whether the texture (ID) is valid
- bool valid;
- //! ID of the texture in graphics engine
+ //! ID of the texture in graphics engine; 0 = invalid texture
unsigned int id;
//! Size of texture
- Math::IntSize size;
+ Math::IntPoint size;
//! Whether the texture has alpha channel
bool alpha;
Texture()
{
- valid = false;
id = 0;
alpha = false;
}
+ //! Returns whether the texture is valid (ID != 0)
+ bool Valid() const
+ {
+ return id != 0;
+ }
+
+ //! Sets the ID to invalid value (0)
+ void SetInvalid()
+ {
+ id = 0;
+ }
+
//! Comparator for use in texture maps and sets
inline bool operator<(const Gfx::Texture &other) const
{
// Invalid textures are always "less than" every other texture
- if ( (!valid) && (!other.valid) )
+ if ( (! Valid()) && (! other.Valid()) )
return false;
- if (!valid)
+ if (! Valid())
return true;
- if (!other.valid)
+ if (! other.Valid())
return false;
return id < other.id;
@@ -225,9 +237,9 @@ struct Texture
//! Comparator
inline bool operator==(const Gfx::Texture &other) const
{
- if (valid != other.valid)
+ if (Valid() != other.Valid())
return false;
- if ( (!valid) && (!other.valid) )
+ if ( (! Valid()) && (! other.Valid()) )
return true;
return id == other.id;
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..d7bac0f 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_lines.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_linesUsed == 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_linesUsed ; i++ )
+ {
+ pos.y = m_level;
+ pos.z = m_lines[i].pz;
+ pos.x = m_lines[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_lines[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_lines.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_lines.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..079f77b 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_lines;
- bool m_bEnable;
+ bool m_enable;
};
diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp
index e544ee3..ddc6b23 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;
@@ -35,37 +47,77 @@ const int GROUNDSPOT_PREALLOCATE_COUNT = 100;
const int LEVEL1_PREALLOCATE_COUNT = 50;
const int LEVEL2_PREALLOCATE_COUNT = 100;
const int LEVEL3_PREALLOCATE_COUNT = 5;
-const int LEVEL4_PREALLOCATE_COUNT = 10;
-const int LEVEL5_PREALLOCATE_COUNT = 100;
-const int LEVEL5_VERTEX_PREALLOCATE_COUNT = 200;
+const int LEVEL4_PREALLOCATE_COUNT = 100;
+const int LEVEL4_VERTEX_PREALLOCATE_COUNT = 200;
+
+
+Gfx::EngineObjLevel1::EngineObjLevel1(bool used, const std::string& tex1Name, const std::string& tex2Name)
+{
+ this->used = used;
+ this->tex1Name = tex1Name;
+ this->tex2Name = tex2Name;
+
+ next.reserve(LEVEL2_PREALLOCATE_COUNT);
+}
+
+Gfx::EngineObjLevel2::EngineObjLevel2(bool used, int objRank)
+{
+ this->used = used;
+ this->objRank = objRank;
+
+ next.reserve(LEVEL3_PREALLOCATE_COUNT);
+}
+
+Gfx::EngineObjLevel3::EngineObjLevel3(bool used, float min, float max)
+{
+ this->used = used;
+ this->min = min;
+ this->max = max;
+
+ next.reserve(LEVEL4_PREALLOCATE_COUNT);
+}
+
+Gfx::EngineObjLevel4::EngineObjLevel4(bool used, Gfx::EngineTriangleType type, const Gfx::Material& material, int state)
+{
+ this->used = used;
+ this->type = type;
+ this->material = material;
+ this->state = state;
+
+ vertices.reserve(LEVEL4_VERTEX_PREALLOCATE_COUNT);
+}
+
+// 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 +151,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 +171,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 +183,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 +208,1634 @@ 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;
+}
+
+void Gfx::CEngine::SetDevice(Gfx::CDevice *device)
+{
+ m_device = device;
+}
- m_sound = NULL;
- m_terrain = NULL;
+Gfx::CDevice* Gfx::CEngine::GetDevice()
+{
+ return m_device;
}
-bool Gfx::CEngine::GetWasInit()
+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 = LoadTexture("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))
+ {
+ bool bq = !m_backgroundQuarter;
+ SetBackground(bq ? "geneda.png" : "", Gfx::Color(), Gfx::Color(), Gfx::Color(), Gfx::Color(), true, bq);
+ }
+ else if (event.key.key == KEY(F4))
+ {
+ m_skyMode = !m_skyMode;
+ if (! m_skyMode)
+ {
+ 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 write screenshot: not very important for now
+ GetLogger()->Trace("CEngine::WriteSceenShot(): stub!\n");
+ 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: when INI reading is completed
+ return true;
+}
+bool Gfx::CEngine::WriteSettings()
+{
+ // TODO: when INI writing is completed
return true;
}
-void Gfx::CEngine::ResetAfterDeviceChanged()
+void Gfx::CEngine::SetPause(bool pause)
+{
+ m_pause = pause;
+}
+
+bool Gfx::CEngine::GetPause()
{
- // TODO
+ return m_pause;
}
+void Gfx::CEngine::SetMovieLock(bool lock)
+{
+ m_movieLock = lock;
+}
-Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName, const Gfx::TextureCreateParams &params)
+bool Gfx::CEngine::GetMovieLock()
{
- CImage img;
- if (! img.Load(m_app->GetDataFilePath(m_texPath, texName)))
+ 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()
+{
+ int i = 0;
+ for ( ; i < static_cast<int>( m_objects.size() ); i++)
{
- std::stringstream str;
- str << "Couldn't load texture '" << texName << "': " << img.GetError();
- m_error = str.str();
- return Gfx::Texture(); // invalid texture
+ if (! m_objects[i].used)
+ {
+ m_objects[i].LoadDefault();
+ break;
+ }
}
- Gfx::Texture result = m_device->CreateTexture(&img, params);
+ if (i == static_cast<int>( m_objects.size() ))
+ m_objects.push_back(Gfx::EngineObject());
+
+
+ m_objects[i].used = true;
- if (! result.valid)
+ Math::Matrix mat;
+ mat.LoadIdentity();
+ SetObjectTransform(i, mat);
+
+ m_objects[i].drawWorld = true;
+ m_objects[i].distance = 0.0f;
+ m_objects[i].bboxMin = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_objects[i].bboxMax = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_objects[i].shadowRank = -1;
+
+ return i;
+}
+
+void Gfx::CEngine::FlushObject()
+{
+ m_objectTree.clear();
+ m_objects.clear();
+
+ m_shadows.clear();
+
+ FlushGroundSpot();
+}
+
+bool Gfx::CEngine::DeleteObject(int objRank)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ // Delete object's triangles
+ for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++)
{
- std::stringstream str;
- str << "Couldn't load texture '" << texName << "': " << m_device->GetError();
- m_error = str.str();
- return result;
+ Gfx::EngineObjLevel1& p1 = m_objectTree[l1];
+ if (! p1.used) continue;
+
+ for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
+ {
+ Gfx::EngineObjLevel2& p2 = p1.next[l2];
+ if (! p2.used) continue;
+
+ if (p2.objRank == objRank)
+ {
+ p2.used = false;
+ p2.next.clear();
+ }
+ }
}
- m_texNameMap[texName] = result;
- m_revTexNameMap[result] = texName;
+ // Mark object as deleted
+ m_objects[objRank].used = false;
- return result;
+ // Delete associated shadows
+ DeleteShadow(objRank);
+
+ return true;
}
-Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName)
+bool Gfx::CEngine::SetObjectType(int objRank, Gfx::EngineObjectType type)
{
- return CreateTexture(texName, m_defaultTexParams);
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ m_objects[objRank].type = type;
+ return true;
}
-void Gfx::CEngine::DestroyTexture(const std::string &texName)
+Gfx::EngineObjectType Gfx::CEngine::GetObjectType(int objRank)
{
- std::map<std::string, Gfx::Texture>::iterator it = m_texNameMap.find(texName);
- if (it == m_texNameMap.end())
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return Gfx::ENG_OBJTYPE_NULL;
+
+ return m_objects[objRank].type;
+}
+
+
+bool Gfx::CEngine::SetObjectTransform(int objRank, const Math::Matrix& transform)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ m_objects[objRank].transform = transform;
+ return true;
+}
+
+bool Gfx::CEngine::GetObjectTransform(int objRank, Math::Matrix& transform)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ transform = m_objects[objRank].transform;
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectDrawWorld(int objRank, bool draw)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ m_objects[objRank].drawWorld = draw;
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectDrawFront(int objRank, bool draw)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ m_objects[objRank].drawFront = draw;
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectTransparency(int objRank, float value)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ m_objects[objRank].transparency = value;
+ return true;
+}
+
+bool Gfx::CEngine::GetObjectBBox(int objRank, Math::Vector& min, Math::Vector& max)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return 0;
+
+ min = m_objects[objRank].bboxMin;
+ max = m_objects[objRank].bboxMax;
+ return true;
+}
+
+
+int Gfx::CEngine::GetObjectTotalTriangles(int objRank)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return 0;
+
+ return m_objects[objRank].totalTriangles;
+}
+
+
+Gfx::EngineObjLevel1& Gfx::CEngine::AddLevel1(const std::string& tex1Name, const std::string& tex2Name)
+{
+ bool unusedPresent = false;
+ for (int i = 0; i < static_cast<int>( m_objectTree.size() ); i++)
+ {
+ if (! m_objectTree[i].used)
+ {
+ unusedPresent = true;
+ continue;
+ }
+
+ if (m_objectTree[i].tex1Name == tex1Name && m_objectTree[i].tex2Name == tex2Name)
+ return m_objectTree[i];
+ }
+
+ if (unusedPresent)
+ {
+ for (int i = 0; i < static_cast<int>( m_objectTree.size() ); i++)
+ {
+ if (! m_objectTree[i].used)
+ {
+ m_objectTree[i].used = true;
+ m_objectTree[i].tex1Name = tex1Name;
+ m_objectTree[i].tex2Name = tex2Name;
+ return m_objectTree[i];
+ }
+ }
+ }
+
+ m_objectTree.push_back(Gfx::EngineObjLevel1(true, tex1Name, tex2Name));
+ return m_objectTree.back();
+}
+
+Gfx::EngineObjLevel2& Gfx::CEngine::AddLevel2(Gfx::EngineObjLevel1& p1, int objRank)
+{
+ bool unusedPresent = false;
+ for (int i = 0; i < static_cast<int>( p1.next.size() ); i++)
+ {
+ if (! p1.next[i].used)
+ {
+ unusedPresent = true;
+ continue;
+ }
+
+ if (p1.next[i].objRank == objRank)
+ return p1.next[i];
+ }
+
+ if (unusedPresent)
+ {
+ for (int i = 0; i < static_cast<int>( p1.next.size() ); i++)
+ {
+ if (! p1.next[i].used)
+ {
+ p1.next[i].used = true;
+ p1.next[i].objRank = objRank;
+ return p1.next[i];
+ }
+ }
+ }
+
+ p1.next.push_back(Gfx::EngineObjLevel2(true, objRank));
+ return p1.next.back();
+}
+
+Gfx::EngineObjLevel3& Gfx::CEngine::AddLevel3(Gfx::EngineObjLevel2& p2, float min, float max)
+{
+ bool unusedPresent = false;
+ for (int i = 0; i < static_cast<int>( p2.next.size() ); i++)
+ {
+ if (! p2.next[i].used)
+ {
+ unusedPresent = true;
+ continue;
+ }
+
+ if ( (p2.next[i].min == min) && (p2.next[i].max == max) )
+ return p2.next[i];
+ }
+
+ if (unusedPresent)
+ {
+ for (int i = 0; i < static_cast<int>( p2.next.size() ); i++)
+ {
+ if (! p2.next[i].used)
+ {
+ p2.next[i].used = true;
+ p2.next[i].min = min;
+ p2.next[i].max = max;
+ return p2.next[i];
+ }
+ }
+ }
+
+ p2.next.push_back(Gfx::EngineObjLevel3(true, min, max));
+ return p2.next.back();
+}
+
+Gfx::EngineObjLevel4& Gfx::CEngine::AddLevel4(Gfx::EngineObjLevel3& p3, Gfx::EngineTriangleType type,
+ const Gfx::Material& material, int state)
+{
+ bool unusedPresent = false;
+ for (int i = 0; i < static_cast<int>( p3.next.size() ); i++)
+ {
+ if (! p3.next[i].used)
+ {
+ unusedPresent = true;
+ continue;
+ }
+
+ if ( (p3.next[i].type == type) && (p3.next[i].material == material) && (p3.next[i].state == state) )
+ return p3.next[i];
+ }
+
+ if (unusedPresent)
+ {
+ for (int i = 0; i < static_cast<int>( p3.next.size() ); i++)
+ {
+ if (! p3.next[i].used)
+ {
+ p3.next[i].used = true;
+ p3.next[i].type = type;
+ p3.next[i].material = material;
+ p3.next[i].state = state;
+ return p3.next[i];
+ }
+ }
+ }
+
+ p3.next.push_back(Gfx::EngineObjLevel4(true, type, material, state));
+ return p3.next.back();
+}
+
+bool Gfx::CEngine::AddTriangles(int objRank, const std::vector<Gfx::VertexTex2>& vertices,
+ const Gfx::Material& material, int state,
+ std::string tex1Name, std::string tex2Name,
+ float min, float max, bool globalUpdate)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ {
+ GetLogger()->Error("AddTriangle(): invalid object rank %d\n", objRank);
+ return false;
+ }
+
+ m_lastSize = m_size;
+ m_lastObjectDetail = m_objectDetail;
+ m_lastClippingDistance = m_clippingDistance;
+
+ Gfx::EngineObjLevel1& p1 = AddLevel1(tex1Name, tex2Name);
+ Gfx::EngineObjLevel2& p2 = AddLevel2(p1, objRank);
+ Gfx::EngineObjLevel3& p3 = AddLevel3(p2, min, max);
+ Gfx::EngineObjLevel4& p4 = AddLevel4(p3, Gfx::ENG_TRIANGLE_TYPE_TRIANGLES, material, state);
+
+ p4.vertices.insert(p4.vertices.end(), vertices.begin(), vertices.end());
+
+ if (globalUpdate)
+ {
+ m_updateGeometry = true;
+ }
+ else
+ {
+ for (int i = 0; i < static_cast<int>( vertices.size() ); i++)
+ {
+ m_objects[objRank].bboxMin.x = Math::Min(vertices[i].coord.x, m_objects[objRank].bboxMin.x);
+ m_objects[objRank].bboxMin.y = Math::Min(vertices[i].coord.y, m_objects[objRank].bboxMin.y);
+ m_objects[objRank].bboxMin.z = Math::Min(vertices[i].coord.z, m_objects[objRank].bboxMin.z);
+ m_objects[objRank].bboxMax.x = Math::Max(vertices[i].coord.x, m_objects[objRank].bboxMax.x);
+ m_objects[objRank].bboxMax.y = Math::Max(vertices[i].coord.y, m_objects[objRank].bboxMax.y);
+ m_objects[objRank].bboxMax.z = Math::Max(vertices[i].coord.z, m_objects[objRank].bboxMax.z);
+ }
+
+ m_objects[objRank].radius = Math::Max(m_objects[objRank].bboxMin.Length(),
+ m_objects[objRank].bboxMax.Length());
+ }
+
+ m_objects[objRank].totalTriangles += vertices.size() / 3;
+
+ return true;
+}
+
+bool Gfx::CEngine::AddSurface(int objRank, const std::vector<Gfx::VertexTex2>& vertices,
+ const Gfx::Material& material, int state,
+ std::string tex1Name, std::string tex2Name,
+ float min, float max, bool globalUpdate)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ {
+ GetLogger()->Error("AddSurface(): invalid object rank %d\n", objRank);
+ return false;
+ }
+
+ m_lastSize = m_size;
+ m_lastObjectDetail = m_objectDetail;
+ m_lastClippingDistance = m_clippingDistance;
+
+ Gfx::EngineObjLevel1& p1 = AddLevel1(tex1Name, tex2Name);
+ Gfx::EngineObjLevel2& p2 = AddLevel2(p1, objRank);
+ Gfx::EngineObjLevel3& p3 = AddLevel3(p2, min, max);
+ Gfx::EngineObjLevel4& p4 = AddLevel4(p3, Gfx::ENG_TRIANGLE_TYPE_SURFACE, material, state);
+
+ p4.vertices.insert(p4.vertices.end(), vertices.begin(), vertices.end());
+
+ if (globalUpdate)
+ {
+ m_updateGeometry = true;
+ }
+ else
+ {
+ for (int i = 0; i < static_cast<int>( vertices.size() ); i++)
+ {
+ m_objects[objRank].bboxMin.x = Math::Min(vertices[i].coord.x, m_objects[objRank].bboxMin.x);
+ m_objects[objRank].bboxMin.y = Math::Min(vertices[i].coord.y, m_objects[objRank].bboxMin.y);
+ m_objects[objRank].bboxMin.z = Math::Min(vertices[i].coord.z, m_objects[objRank].bboxMin.z);
+ m_objects[objRank].bboxMax.x = Math::Max(vertices[i].coord.x, m_objects[objRank].bboxMax.x);
+ m_objects[objRank].bboxMax.y = Math::Max(vertices[i].coord.y, m_objects[objRank].bboxMax.y);
+ m_objects[objRank].bboxMax.z = Math::Max(vertices[i].coord.z, m_objects[objRank].bboxMax.z);
+ }
+
+ m_objects[objRank].radius = Math::Max(m_objects[objRank].bboxMin.Length(),
+ m_objects[objRank].bboxMax.Length());
+ }
+
+ m_objects[objRank].totalTriangles += vertices.size() - 2;
+
+ return true;
+}
+
+bool Gfx::CEngine::AddQuick(int objRank, const Gfx::EngineObjLevel4& buffer,
+ std::string tex1Name, std::string tex2Name,
+ float min, float max, bool globalUpdate)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ {
+ GetLogger()->Error("AddQuick(): invalid object rank %d\n", objRank);
+ return false;
+ }
+
+ Gfx::EngineObjLevel1& p1 = AddLevel1(tex1Name, tex2Name);
+ Gfx::EngineObjLevel2& p2 = AddLevel2(p1, objRank);
+ Gfx::EngineObjLevel3& p3 = AddLevel3(p2, min, max);
+
+ p3.next.push_back(buffer);
+ p3.next.back().used = true; // ensure that it is used
+
+ if (globalUpdate)
+ {
+ m_updateGeometry = true;
+ }
+ else
+ {
+ for (int i = 0; i < static_cast<int>( buffer.vertices.size() ); i++)
+ {
+ m_objects[objRank].bboxMin.x = Math::Min(buffer.vertices[i].coord.x, m_objects[objRank].bboxMin.x);
+ m_objects[objRank].bboxMin.y = Math::Min(buffer.vertices[i].coord.y, m_objects[objRank].bboxMin.y);
+ m_objects[objRank].bboxMin.z = Math::Min(buffer.vertices[i].coord.z, m_objects[objRank].bboxMin.z);
+ m_objects[objRank].bboxMax.x = Math::Max(buffer.vertices[i].coord.x, m_objects[objRank].bboxMax.x);
+ m_objects[objRank].bboxMax.y = Math::Max(buffer.vertices[i].coord.y, m_objects[objRank].bboxMax.y);
+ m_objects[objRank].bboxMax.z = Math::Max(buffer.vertices[i].coord.z, m_objects[objRank].bboxMax.z);
+ }
+
+ m_objects[objRank].radius = Math::Max(m_objects[objRank].bboxMin.Length(),
+ m_objects[objRank].bboxMax.Length());
+ }
+
+ if (buffer.type == Gfx::ENG_TRIANGLE_TYPE_TRIANGLES)
+ m_objects[objRank].totalTriangles += buffer.vertices.size() / 3;
+ else // surfaces
+ m_objects[objRank].totalTriangles += buffer.vertices.size() - 2;
+
+ return true;
+}
+
+Gfx::EngineObjLevel4* Gfx::CEngine::FindTriangles(int objRank, const Gfx::Material& material,
+ int state, std::string tex1Name,
+ std::string tex2Name, float min, float max)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ {
+ GetLogger()->Error("FindTriangles(): invalid object rank %d\n", objRank);
+ return nullptr;
+ }
+
+ for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++)
+ {
+ Gfx::EngineObjLevel1& p1 = m_objectTree[l1];
+ if (! p1.used) continue;
+
+ if (p1.tex1Name != tex1Name) continue;
+ // TODO: tex2Name compare?
+
+ for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
+ {
+ Gfx::EngineObjLevel2& p2 = p1.next[l2];
+ if (! p2.used) continue;
+
+ if (p2.objRank != objRank) continue;
+
+ for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
+ {
+ Gfx::EngineObjLevel3& p3 = p2.next[l1];
+ if (! p3.used) continue;
+
+ if (p3.min != min || p3.max != max) continue;
+
+ for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
+ {
+ Gfx::EngineObjLevel4& p4 = p3.next[l4];
+ if (! p4.used) continue;
+
+ if ( (p4.state & (~(Gfx::ENG_RSTATE_DUAL_BLACK|Gfx::ENG_RSTATE_DUAL_WHITE))) != state ||
+ p4.material != material )
+ continue;
+
+ return &p4;
+ }
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+int Gfx::CEngine::GetPartialTriangles(int objRank, float min, float max, float percent, int maxCount,
+ std::vector<Gfx::EngineTriangle>& triangles)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ {
+ GetLogger()->Error("GetPartialTriangles(): invalid object rank %d\n", objRank);
+ return 0;
+ }
+
+ int total = m_objects[objRank].totalTriangles;
+ int expectedCount = static_cast<int>(percent * total);
+ triangles.reserve(Math::Min(maxCount, expectedCount));
+
+ int actualCount = 0;
+
+ for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++)
+ {
+ Gfx::EngineObjLevel1& p1 = m_objectTree[l1];
+ if (! p1.used) continue;
+
+ for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
+ {
+ Gfx::EngineObjLevel2& p2 = p1.next[l2];
+ if (! p2.used) continue;
+
+ if (p2.objRank != objRank) continue;
+
+ for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
+ {
+ Gfx::EngineObjLevel3& p3 = p2.next[l1];
+ if (! p3.used) continue;
+
+ if (p3.min != min || p3.max != max) continue;
+
+ for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
+ {
+ Gfx::EngineObjLevel4& p4 = p3.next[l4];
+ if (! p4.used) continue;
+
+ if (p4.type == Gfx::ENG_TRIANGLE_TYPE_TRIANGLES)
+ {
+ for (int i = 0; i < static_cast<int>( p4.vertices.size() ); i += 3)
+ {
+ if (static_cast<float>(actualCount) / total >= percent)
+ break;
+
+ if (actualCount >= maxCount)
+ break;
+
+ Gfx::EngineTriangle t;
+ t.triangle[0] = p4.vertices[i];
+ t.triangle[1] = p4.vertices[i+1];
+ t.triangle[2] = p4.vertices[i+2];
+ t.material = p4.material;
+ t.state = p4.state;
+ t.tex1Name = p1.tex1Name;
+ t.tex2Name = p1.tex2Name;
+
+ triangles.push_back(t);
+
+ ++actualCount;
+ }
+ }
+ else if (p4.type == Gfx::ENG_TRIANGLE_TYPE_SURFACE)
+ {
+ for (int i = 0; i < static_cast<int>( p4.vertices.size() ); i += 1)
+ {
+ if (static_cast<float>(actualCount) / total >= percent)
+ break;
+
+ if (actualCount >= maxCount)
+ break;
+
+ Gfx::EngineTriangle t;
+ t.triangle[0] = p4.vertices[i];
+ t.triangle[1] = p4.vertices[i+1];
+ t.triangle[2] = p4.vertices[i+2];
+ t.material = p4.material;
+ t.state = p4.state;
+ t.tex1Name = p1.tex1Name;
+ t.tex2Name = p1.tex2Name;
+
+ triangles.push_back(t);
+
+ ++actualCount;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return actualCount;
+}
+
+void Gfx::CEngine::ChangeLOD()
+{
+ float oldLimit[2] =
+ {
+ GetLimitLOD(0, true),
+ GetLimitLOD(1, true)
+ };
+
+ float newLimit[2] =
+ {
+ GetLimitLOD(0, false),
+ GetLimitLOD(1, false)
+ };
+
+ float oldTerrain = m_terrainVision * m_lastClippingDistance;
+ float newTerrain = m_terrainVision * m_clippingDistance;
+
+ for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++)
+ {
+ Gfx::EngineObjLevel1& p1 = m_objectTree[l1];
+ if (! p1.used) continue;
+
+ for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
+ {
+ Gfx::EngineObjLevel2& p2 = p1.next[l2];
+ if (! p2.used) continue;
+
+ for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
+ {
+ Gfx::EngineObjLevel3& p3 = p2.next[l1];
+ if (! p3.used) continue;
+
+ if ( Math::IsEqual(p3.min, 0.0f ) &&
+ Math::IsEqual(p3.max, oldLimit[0]) )
+ {
+ p3.max = newLimit[0];
+ }
+ else if ( Math::IsEqual(p3.min, oldLimit[0]) &&
+ Math::IsEqual(p3.max, oldLimit[1]) )
+ {
+ p3.min = newLimit[0];
+ p3.max = newLimit[1];
+ }
+ else if ( Math::IsEqual(p3.min, oldLimit[1]) &&
+ Math::IsEqual(p3.max, 1000000.0f ) )
+ {
+ p3.min = newLimit[1];
+ }
+ else if ( Math::IsEqual(p3.min, 0.0f ) &&
+ Math::IsEqual(p3.max, oldTerrain) )
+ {
+ p3.max = newTerrain;
+ }
+ }
+ }
+ }
+
+ m_lastSize = m_size;
+ m_lastObjectDetail = m_objectDetail;
+ m_lastClippingDistance = m_clippingDistance;
+}
+
+bool Gfx::CEngine::ChangeSecondTexture(int objRank, const std::string& tex2Name)
+{
+ for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++)
+ {
+ Gfx::EngineObjLevel1& p1 = m_objectTree[l1];
+ if (! p1.used) continue;
+
+ if (p1.tex2Name == tex2Name) continue; // already new
+
+ for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
+ {
+ Gfx::EngineObjLevel2& p2 = p1.next[l2];
+ if (! p2.used) continue;
+
+ if (p2.objRank != objRank) continue;
+
+ Gfx::EngineObjLevel1& newP1 = AddLevel1(p1.tex1Name, tex2Name);
+
+ newP1.next.push_back(Gfx::EngineObjLevel2(true, objRank));
+
+ Gfx::EngineObjLevel2& newP2 = newP1.next.back();
+ newP2.next.swap(p2.next);
+
+ p2.used = false;
+ }
+ }
+ return true;
+}
+
+bool Gfx::CEngine::ChangeTextureMapping(int objRank, const Gfx::Material& mat, int state,
+ const std::string& tex1Name, const std::string& tex2Name,
+ float min, float max, Gfx::EngineTextureMapping mode,
+ float au, float bu, float av, float bv)
+{
+ Gfx::EngineObjLevel4* p4 = FindTriangles(objRank, mat, state, tex1Name, tex2Name, min, max);
+ if (p4 == nullptr)
+ return false;
+
+ int nb = p4->vertices.size();
+
+ if (mode == Gfx::ENG_TEX_MAPPING_X)
+ {
+ for (int i = 0; i < nb; i++)
+ {
+ p4->vertices[i].texCoord.x = p4->vertices[i].coord.z * au + bu;
+ p4->vertices[i].texCoord.y = p4->vertices[i].coord.y * av + bv;
+ }
+ }
+ else if (mode == Gfx::ENG_TEX_MAPPING_Y)
+ {
+ for (int i = 0; i < nb; i++)
+ {
+ p4->vertices[i].texCoord.x = p4->vertices[i].coord.x * au + bu;
+ p4->vertices[i].texCoord.y = p4->vertices[i].coord.z * av + bv;
+ }
+ }
+ else if (mode == Gfx::ENG_TEX_MAPPING_Z)
+ {
+ for (int i = 0; i < nb; i++)
+ {
+ p4->vertices[i].texCoord.x = p4->vertices[i].coord.x * au + bu;
+ p4->vertices[i].texCoord.y = p4->vertices[i].coord.y * av + bv;
+ }
+ }
+ else if (mode == Gfx::ENG_TEX_MAPPING_1X)
+ {
+ for (int i = 0; i < nb; i++)
+ {
+ p4->vertices[i].texCoord.x = p4->vertices[i].coord.x * au + bu;
+ }
+ }
+ else if (mode == Gfx::ENG_TEX_MAPPING_1Y)
+ {
+ for (int i = 0; i < nb; i++)
+ {
+ p4->vertices[i].texCoord.y = p4->vertices[i].coord.y * au + bu;
+ }
+ }
+ else if (mode == Gfx::ENG_TEX_MAPPING_1Z)
+ {
+ for (int i = 0; i < nb; i++)
+ {
+ p4->vertices[i].texCoord.x = p4->vertices[i].coord.z * au + bu;
+ }
+ }
+
+ return true;
+}
+
+bool Gfx::CEngine::TrackTextureMapping(int objRank, const Gfx::Material& mat, int state,
+ const std::string& tex1Name, const std::string& tex2Name,
+ float min, float max, Gfx::EngineTextureMapping mode,
+ float pos, float factor, float tl, float ts, float tt)
+{
+ // TODO track texture mapping: pretty complex code, so leaving it for now
+ GetLogger()->Trace("CEngine::TrackTextureMapping(): stub!\n");
+ return true;
+}
+
+
+bool Gfx::CEngine::CreateShadow(int objRank)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ // Already allocated?
+ if (m_objects[objRank].shadowRank != -1) return true;
+
+ int index = 0;
+ for ( ; index < static_cast<int>( m_shadows.size() ); index++)
+ {
+ if (! m_shadows[index].used)
+ {
+ m_shadows[index].LoadDefault();
+ break;
+ }
+ }
+
+ m_shadows.push_back(Gfx::EngineShadow());
+
+ m_shadows[index].used = true;
+ m_shadows[index].objRank = objRank;
+ m_shadows[index].height = 0.0f;
+
+ m_objects[objRank].shadowRank = index;
+
+ return true;
+}
+
+void Gfx::CEngine::DeleteShadow(int objRank)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
return;
- std::map<Gfx::Texture, std::string>::iterator revIt = m_revTexNameMap.find((*it).second);
+ int i = m_objects[objRank].shadowRank;
+ if (i == -1)
+ return;
- m_device->DestroyTexture((*it).second);
+ m_shadows[i].used = false;
+ m_shadows[i].objRank = -1;
- m_revTexNameMap.erase(revIt);
- m_texNameMap.erase(it);
+ m_objects[objRank].shadowRank = -1;
}
-void Gfx::CEngine::SetTexture(const std::string &name, int stage)
+bool Gfx::CEngine::SetObjectShadowHide(int objRank, bool hide)
{
- std::map<std::string, Gfx::Texture>::iterator it = m_texNameMap.find(name);
- if (it != m_texNameMap.end())
- m_device->SetTexture(stage, (*it).second);
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ int i = m_objects[objRank].shadowRank;
+ if (i == -1)
+ return false;
- // TODO if not present...
+ m_shadows[i].hide = hide;
+ return true;
}
-void Gfx::CEngine::SetMaterial(const Gfx::Material &mat)
+bool Gfx::CEngine::SetObjectShadowType(int objRank, Gfx::EngineShadowType type)
{
- m_device->SetMaterial(mat);
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ int i = m_objects[objRank].shadowRank;
+ if (i == -1)
+ return false;
+
+ m_shadows[i].type = type;
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectShadowPos(int objRank, const Math::Vector& pos)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ int i = m_objects[objRank].shadowRank;
+ if (i == -1)
+ return false;
+
+ m_shadows[i].pos = pos;
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectShadowNormal(int objRank, const Math::Vector& normal)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ int i = m_objects[objRank].shadowRank;
+ if (i == -1)
+ return false;
+
+ m_shadows[i].normal = normal;
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectShadowAngle(int objRank, float angle)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ int i = m_objects[objRank].shadowRank;
+ if (i == -1)
+ return false;
+
+ m_shadows[i].angle = angle;
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectShadowRadius(int objRank, float radius)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ int i = m_objects[objRank].shadowRank;
+ if (i == -1)
+ return false;
+
+ m_shadows[i].radius = radius;
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectShadowIntensity(int objRank, float intensity)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ int i = m_objects[objRank].shadowRank;
+ if (i == -1)
+ return false;
+
+ m_shadows[i].intensity = intensity;
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectShadowHeight(int objRank, float height)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return false;
+
+ int i = m_objects[objRank].shadowRank;
+ if (i == -1)
+ return false;
+
+ m_shadows[i].height = height;
+ return true;
+}
+
+float Gfx::CEngine::GetObjectShadowRadius(int objRank)
+{
+ if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
+ return 0.0f;
+
+ int i = m_objects[objRank].shadowRank;
+ if (i == -1)
+ return 0.0f;
+
+ return m_shadows[i].radius;
+}
+
+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 )
+ {
+ m_highlightRank[i++] = *rankList++;
+ }
+ m_highlightRank[i] = -1; // terminator
+}
+
+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;
+
+ for (int i = 0; i < 8; i++)
+ {
+ 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;
+ }
+ }
+
+ if ( min.x == 1000000.0f ||
+ min.y == 1000000.0f ||
+ max.x == -1000000.0f ||
+ max.y == -1000000.0f ) return false;
+
+ return true;
+}
+
+void Gfx::CEngine::FlushGroundSpot()
+{
+ m_groundSpots.clear();
+ m_firstGroundSpot = true;
+
+ // TODO: blank all shadow textures
}
-void Gfx::CEngine::SetState(int state, Gfx::Color color)
+int Gfx::CEngine::CreateGroundSpot()
{
- if ( state == m_lastState && color == m_lastColor )
+ int index = 0;
+ for ( ; index < static_cast<int>( m_groundSpots.size() ); index++)
+ {
+ if (! m_groundSpots[index].used)
+ {
+ m_groundSpots[index].LoadDefault();
+ break;
+ }
+ }
+
+ m_groundSpots.push_back(Gfx::EngineGroundSpot());
+
+ m_groundSpots[index].used = true;
+ m_groundSpots[index].smooth = 1.0f;
+
+ return index;
+}
+
+void Gfx::CEngine::DeleteGroundSpot(int rank)
+{
+ m_groundSpots[rank].used = false;
+ m_groundSpots[rank].pos = Math::Vector(0.0f, 0.0f, 0.0f);
+}
+
+bool Gfx::CEngine::SetObjectGroundSpotPos(int rank, const Math::Vector& pos)
+{
+ if ( rank < 0 || rank >= static_cast<int>( m_groundSpots.size() ) )
+ return 0.0f;
+
+ m_groundSpots[rank].pos = pos;
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectGroundSpotRadius(int rank, float radius)
+{
+ if ( rank < 0 || rank >= static_cast<int>( m_groundSpots.size() ) )
+ return 0.0f;
+
+ m_groundSpots[rank].radius = radius;
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectGroundSpotColor(int rank, const Gfx::Color& color)
+{
+ if ( rank < 0 || rank >= static_cast<int>( m_groundSpots.size() ) )
+ return 0.0f;
+
+ m_groundSpots[rank].color = color;
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectGroundSpotMinMax(int rank, float min, float max)
+{
+ if ( rank < 0 || rank >= static_cast<int>( m_groundSpots.size() ) )
+ return 0.0f;
+
+ m_groundSpots[rank].min = min;
+ m_groundSpots[rank].max = max;
+ return true;
+}
+
+bool Gfx::CEngine::SetObjectGroundSpotSmooth(int rank, float smooth)
+{
+ if ( rank < 0 || rank >= static_cast<int>( m_groundSpots.size() ) )
+ return 0.0f;
+
+ m_groundSpots[rank].smooth = smooth;
+ return true;
+}
+
+void Gfx::CEngine::CreateGroundMark(Math::Vector pos, float radius,
+ float delay1, float delay2, float delay3,
+ int dx, int dy, char* table)
+{
+ m_groundMark.LoadDefault();
+
+ m_groundMark.phase = Gfx::ENG_GR_MARK_PHASE_INC;
+ m_groundMark.delay[0] = delay1;
+ m_groundMark.delay[1] = delay2;
+ m_groundMark.delay[2] = delay3;
+ m_groundMark.pos = pos;
+ m_groundMark.radius = radius;
+ m_groundMark.intensity = 0.0f;
+ m_groundMark.dx = dx;
+ m_groundMark.dy = dy;
+ m_groundMark.table = table;
+}
+
+void Gfx::CEngine::DeleteGroundMark(int rank)
+{
+ m_groundMark.LoadDefault();
+}
+
+void Gfx::CEngine::ComputeDistance()
+{
+ // TODO: s_resol???
+
+ for (int i = 0; i < static_cast<int>( m_objects.size() ); i++)
+ {
+ if (! m_objects[i].used)
+ continue;
+
+ Math::Vector v;
+ v.x = m_eyePt.x - m_objects[i].transform.Get(1, 4);
+ v.y = m_eyePt.y - m_objects[i].transform.Get(2, 4);
+ v.z = m_eyePt.z - m_objects[i].transform.Get(3, 4);
+ m_objects[i].distance = v.Length();
+ }
+}
+
+void Gfx::CEngine::UpdateGeometry()
+{
+ if (! m_updateGeometry)
+ return;
+
+ for (int i = 0; i < static_cast<int>( m_objects.size() ); i++)
+ {
+ m_objects[i].bboxMin.x = 0;
+ m_objects[i].bboxMin.y = 0;
+ m_objects[i].bboxMin.z = 0;
+ m_objects[i].bboxMax.x = 0;
+ m_objects[i].bboxMax.y = 0;
+ m_objects[i].bboxMax.z = 0;
+ m_objects[i].radius = 0;
+ }
+
+ for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++)
+ {
+ Gfx::EngineObjLevel1& p1 = m_objectTree[l1];
+ if (! p1.used) continue;
+
+ for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
+ {
+ Gfx::EngineObjLevel2& p2 = p1.next[l2];
+ if (! p2.used) continue;
+
+ for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
+ {
+ Gfx::EngineObjLevel3& p3 = p2.next[l1];
+ if (! p3.used) continue;
+
+ for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
+ {
+ Gfx::EngineObjLevel4& p4 = p3.next[l4];
+ if (! p4.used) continue;
+
+ int objRank = p2.objRank;
+
+ for (int i = 0; i < static_cast<int>( p4.vertices.size() ); i++)
+ {
+ m_objects[objRank].bboxMin.x = Math::Min(p4.vertices[i].coord.x, m_objects[objRank].bboxMin.x);
+ m_objects[objRank].bboxMin.y = Math::Min(p4.vertices[i].coord.y, m_objects[objRank].bboxMin.y);
+ m_objects[objRank].bboxMin.z = Math::Min(p4.vertices[i].coord.z, m_objects[objRank].bboxMin.z);
+ m_objects[objRank].bboxMax.x = Math::Max(p4.vertices[i].coord.x, m_objects[objRank].bboxMax.x);
+ m_objects[objRank].bboxMax.y = Math::Max(p4.vertices[i].coord.y, m_objects[objRank].bboxMax.y);
+ m_objects[objRank].bboxMax.z = Math::Max(p4.vertices[i].coord.z, m_objects[objRank].bboxMax.z);
+ }
+
+ m_objects[objRank].radius = Math::Max(m_objects[objRank].bboxMin.Length(),
+ m_objects[objRank].bboxMax.Length());
+ }
+ }
+ }
+ }
+
+ m_updateGeometry = false;
+}
+
+void Gfx::CEngine::Update()
+{
+ ComputeDistance();
+ UpdateGeometry();
+}
+
+bool Gfx::CEngine::DetectBBox(int objRank, Math::Point mouse)
+{
+ Math::Point min, max;
+ min.x = 1000000.0f;
+ min.y = 1000000.0f;
+ max.x = -1000000.0f;
+ max.y = -1000000.0f;
+
+ for (int i = 0; i < 8; i++)
+ {
+ 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;
+ }
+ }
+
+ return ( mouse.x >= min.x &&
+ mouse.x <= max.x &&
+ mouse.y >= min.y &&
+ mouse.y <= max.y );
+}
+
+int Gfx::CEngine::DetectObject(Math::Point mouse)
+{
+ float min = 1000000.0f;
+ int nearest = -1;
+
+ for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++)
+ {
+ Gfx::EngineObjLevel1& p1 = m_objectTree[l1];
+ if (! p1.used) continue;
+
+ for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
+ {
+ Gfx::EngineObjLevel2& p2 = p1.next[l2];
+ if (! p2.used) continue;
+
+ if (m_objects[p2.objRank].type == Gfx::ENG_OBJTYPE_TERRAIN) continue;
+
+ if (! DetectBBox(p2.objRank, mouse)) continue;
+
+ for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
+ {
+ Gfx::EngineObjLevel3& p3 = p2.next[l1];
+ if (! p3.used) continue;
+
+ if (p3.min != 0.0f) continue; // LOD B or C?
+
+ for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
+ {
+ Gfx::EngineObjLevel4& p4 = p3.next[l4];
+ if (! p4.used) continue;
+
+ if (p4.type == Gfx::ENG_TRIANGLE_TYPE_TRIANGLES)
+ {
+ for (int i = 0; i < static_cast<int>( p4.vertices.size() ); i += 3)
+ {
+ float dist = 0.0f;
+ if (DetectTriangle(mouse, &p4.vertices[i], p2.objRank, dist) && dist < min)
+ {
+ min = dist;
+ nearest = p2.objRank;
+ }
+ }
+ }
+ else if (p4.type == Gfx::ENG_TRIANGLE_TYPE_SURFACE)
+ {
+ for (int i = 0; i < static_cast<int>( p4.vertices.size() ) - 2; i += 1)
+ {
+ float dist = 0.0f;
+ if (DetectTriangle(mouse, &p4.vertices[i], p2.objRank, dist) && dist < min)
+ {
+ min = dist;
+ nearest = p2.objRank;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return nearest;
+}
+
+bool Gfx::CEngine::DetectTriangle(Math::Point mouse, Gfx::VertexTex2* triangle, int objRank, float& dist)
+{
+ Math::Vector p2D[3], p3D;
+
+ for (int i = 0; i < 3; i++)
+ {
+ p3D.x = triangle[i].coord.x;
+ p3D.y = triangle[i].coord.y;
+ p3D.z = triangle[i].coord.z;
+
+ if (! TransformPoint(p2D[i], objRank, p3D))
+ return false;
+ }
+
+ if ( mouse.x < p2D[0].x &&
+ mouse.x < p2D[1].x &&
+ mouse.x < p2D[2].x ) return false;
+ if ( mouse.x > p2D[0].x &&
+ mouse.x > p2D[1].x &&
+ mouse.x > p2D[2].x ) return false;
+ if ( mouse.y < p2D[0].y &&
+ mouse.y < p2D[1].y &&
+ mouse.y < p2D[2].y ) return false;
+ if ( mouse.y > p2D[0].y &&
+ mouse.y > p2D[1].y &&
+ mouse.y > p2D[2].y ) return false;
+
+ Math::Point a, b, c;
+ a.x = p2D[0].x;
+ a.y = p2D[0].y;
+ b.x = p2D[1].x;
+ b.y = p2D[1].y;
+ c.x = p2D[2].x;
+ c.y = p2D[2].y;
+
+ if (! Math::IsInsideTriangle(a, b, c, mouse))
+ return false;
+
+ dist = (p2D[0].z + p2D[1].z + p2D[2].z) / 3.0f;
+ return true;
+}
+
+bool Gfx::CEngine::IsVisible(int objRank)
+{
+ // TODO: use ComputeSphereVisiblity() after tested OK
+ 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 +1843,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->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, true);
- /*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_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 +2016,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 +2043,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,171 +2080,668 @@ 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 tex = m_device->CreateTexture(&img, params);
+
+ if (! tex.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 tex;
+ }
- if (event.key.key == KEY(F1))
+ m_texNameMap[texName] = tex;
+ m_revTexNameMap[tex] = texName;
+
+ return tex;
+}
+
+Gfx::Texture Gfx::CEngine::LoadTexture(const std::string& name)
+{
+ return LoadTexture(name, m_defaultTexParams);
+}
+
+Gfx::Texture Gfx::CEngine::LoadTexture(const std::string& name, const Gfx::TextureCreateParams& params)
+{
+ if (m_texBlacklist.find(name) != m_texBlacklist.end())
+ return Gfx::Texture();
+
+ std::map<std::string, Gfx::Texture>::iterator it = m_texNameMap.find(name);
+ if (it != m_texNameMap.end())
+ return (*it).second;
+
+ Gfx::Texture tex = CreateTexture(name, params);
+ return tex;
+}
+
+bool Gfx::CEngine::LoadAllTextures()
+{
+ LoadTexture("text.png");
+ m_miceTexture = 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_backgroundQuarter) // image into 4 pieces?
+ {
+ if (! m_backgroundName.empty())
{
- m_mouseVisible = !m_mouseVisible;
- m_app->SetSystemMouseVisible(! m_app->GetSystemMouseVisibile());
+ for (int i = 0; i < 4; i++)
+ m_backgroundQuarterTexs[i] = LoadTexture(m_backgroundQuarterNames[i]);
}
- 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 );
+ for (int i = 0; i < 4; i++)
+ m_backgroundQuarterTexs[i].SetInvalid();
}
}
+ else
+ {
+ if (! m_backgroundName.empty())
+ m_backgroundFullTex = LoadTexture(m_backgroundName);
+ else
+ m_backgroundFullTex.SetInvalid();
+ }
- // By default, pass on all events
- return true;
+ if (! m_foregroundName.empty())
+ m_foregroundTex = LoadTexture(m_foregroundName);
+ else
+ m_foregroundTex.SetInvalid();
+
+ m_planet->LoadTexture();
+
+ bool ok = true;
+
+ for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++)
+ {
+ Gfx::EngineObjLevel1& p1 = m_objectTree[l1];
+ if (! p1.used) continue;
+
+ if (! p1.tex1Name.empty())
+ {
+ if (! LoadTexture(p1.tex1Name).Valid())
+ ok = false;
+ }
+
+ if (! p1.tex2Name.empty())
+ {
+ if (! LoadTexture(p1.tex2Name).Valid())
+ ok = false;
+ }
+ }
+
+ return ok;
}
-bool Gfx::CEngine::Render()
+void Gfx::CEngine::DeleteTexture(const std::string& texName)
{
- m_statisticTriangle = 0;
+ auto it = m_texNameMap.find(texName);
+ if (it == m_texNameMap.end())
+ return;
- m_lastState = -1;
- SetState(Gfx::ENG_RSTATE_NORMAL);
+ auto revIt = m_revTexNameMap.find((*it).second);
- m_device->BeginScene();
+ m_device->DestroyTexture((*it).second);
+
+ m_revTexNameMap.erase(revIt);
+ m_texNameMap.erase(it);
+}
+
+void Gfx::CEngine::DeleteTexture(const Gfx::Texture& tex)
+{
+ if (! tex.Valid())
+ return;
- SetUp3DView();
+ auto revIt = m_revTexNameMap.find(tex);
+ if (revIt == m_revTexNameMap.end())
+ return;
- if (! Draw3DScene() )
- return false;
+ m_device->DestroyTexture(tex);
- SetUpInterfaceView();
+ auto it = m_texNameMap.find((*revIt).second);
- if (! DrawInterface() )
+ m_revTexNameMap.erase(revIt);
+ m_texNameMap.erase(it);
+}
+
+bool Gfx::CEngine::SetTexture(const std::string& name, int stage)
+{
+ auto it = m_texNameMap.find(name);
+ if (it != m_texNameMap.end())
+ {
+ m_device->SetTexture(stage, (*it).second);
+ return true;
+ }
+
+ if (! LoadTexture(name).Valid())
+ {
+ m_device->SetTexture(stage, 0); // invalid texture
return false;
+ }
- m_device->EndScene();
+ it = m_texNameMap.find(name);
+ if (it != m_texNameMap.end())
+ {
+ m_device->SetTexture(stage, (*it).second);
+ return true;
+ }
- return true;
+ m_device->SetTexture(stage, 0); // invalid texture
+ return false; // should not happen normally
}
-void Gfx::CEngine::SetUp3DView()
+void Gfx::CEngine::SetTexture(const Gfx::Texture& tex, int stage)
{
- // TODO
+ m_device->SetTexture(stage, tex);
}
-bool Gfx::CEngine::Draw3DScene()
+void Gfx::CEngine::SetLimitLOD(int rank, float limit)
{
- // TODO
- return true;
+ m_limitLOD[rank] = limit;
}
-void Gfx::CEngine::SetUpInterfaceView()
+float Gfx::CEngine::GetLimitLOD(int rank, bool last)
{
- m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_matWorldInterface);
- m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matViewInterface);
- m_device->SetTransform(Gfx::TRANSFORM_PROJECTION, m_matProjInterface);
+ 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;
}
-bool Gfx::CEngine::DrawInterface()
+void Gfx::CEngine::SetShadow(bool mode)
{
- Gfx::VertexCol vertices[3] =
+ 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];
+}
+
+std::string QuarterName(const std::string& name, int quarter)
+{
+ size_t pos = name.find('.');
+ if (pos == std::string::npos)
+ return name;
+
+ return name.substr(0, pos) + std::string(1, static_cast<char>('a' + quarter)) + name.substr(pos);
+}
+
+void Gfx::CEngine::SetBackground(const std::string& name, Gfx::Color up, Gfx::Color down,
+ Gfx::Color cloudUp, Gfx::Color cloudDown,
+ bool full, bool quarter)
+{
+ if (m_backgroundFullTex.Valid())
{
- 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))
- };
+ DeleteTexture(m_backgroundFullTex);
+ m_backgroundFullTex.SetInvalid();
+ }
- m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, vertices, 3);
+ for (int i = 0; i < 4; i++)
+ {
+ DeleteTexture(m_backgroundQuarterTexs[i]);
+ m_backgroundQuarterTexs[i].SetInvalid();
+ }
- DrawMouse();
+ m_backgroundName = name;
+ m_backgroundColorUp = up;
+ m_backgroundColorDown = down;
+ m_backgroundCloudUp = cloudUp;
+ m_backgroundCloudDown = cloudDown;
+ m_backgroundFull = full;
+ m_backgroundQuarter = quarter;
- return true;
+ if (! m_backgroundName.empty())
+ {
+ if (m_backgroundQuarter)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ m_backgroundQuarterNames[i] = QuarterName(name, i);
+ m_backgroundQuarterTexs[i] = LoadTexture(m_backgroundQuarterNames[i]);
+ }
+ }
+ else
+ {
+ m_backgroundFullTex = LoadTexture(m_backgroundName);
+ }
+ }
}
-void Gfx::CEngine::DrawMouse()
+void Gfx::CEngine::GetBackground(std::string& name, Gfx::Color& up, Gfx::Color& down,
+ Gfx::Color& cloudUp, Gfx::Color& cloudDown,
+ bool &full, bool &quarter)
{
- if (! m_mouseVisible)
- return;
+ name = m_backgroundName;
+ up = m_backgroundColorUp;
+ down = m_backgroundColorDown;
+ cloudUp = m_backgroundCloudUp;
+ cloudDown = m_backgroundCloudDown;
+ full = m_backgroundFull;
+ quarter = m_backgroundQuarter;
+}
- if (m_app->GetSystemMouseVisibile())
- return;
+void Gfx::CEngine::SetForegroundName(const std::string& name)
+{
+ if (m_foregroundTex.Valid())
+ {
+ DeleteTexture(m_foregroundTex);
+ m_foregroundTex.SetInvalid();
+ }
- Gfx::Material material;
- material.diffuse = Gfx::Color(1.0f, 1.0f, 1.0f);
- material.ambient = Gfx::Color(0.5f, 0.5f, 0.5f);
+ m_foregroundName = name;
- m_device->SetMaterial(material);
- m_device->SetTexture(0, m_miceTexture);
+ if (! m_foregroundName.empty())
+ m_foregroundTex = LoadTexture(m_foregroundName);
+}
- int index = static_cast<int>(m_mouseType);
+void Gfx::CEngine::SetOverFront(bool front)
+{
+ m_overFront = front;
+}
- Math::Point pos = m_mousePos;
- pos.x = m_mousePos.x - (m_mice[index].hotPoint.x * m_mouseSize.x) / 32.0f;
- pos.y = m_mousePos.y - ((32.0f - m_mice[index].hotPoint.y) * m_mouseSize.y) / 32.0f;
+void Gfx::CEngine::SetOverColor(const Gfx::Color& color, int mode)
+{
+ m_overColor = color;
+ m_overMode = mode;
+}
- Math::Point shadowPos;
- shadowPos.x = pos.x + (4.0f/800.0f);
- shadowPos.y = pos.y - (3.0f/600.0f);
+void Gfx::CEngine::SetParticleDensity(float value)
+{
+ if (value < 0.0f) value = 0.0f;
+ if (value > 2.0f) value = 2.0f;
+ m_particleDensity = value;
+}
- SetState(Gfx::ENG_RSTATE_TCOLOR_WHITE);
- DrawMouseSprite(shadowPos, m_mouseSize, m_mice[index].iconShadow);
+float Gfx::CEngine::GetParticleDensity()
+{
+ return m_particleDensity;
+}
- SetState(m_mice[index].mode1);
- DrawMouseSprite(pos, m_mouseSize, m_mice[index].icon1);
+float Gfx::CEngine::ParticleAdapt(float factor)
+{
+ if (m_particleDensity == 0.0f)
+ return 1000000.0f;
- SetState(m_mice[index].mode2);
- DrawMouseSprite(pos, m_mouseSize, m_mice[index].icon2);
+ return factor / m_particleDensity;
}
-void Gfx::CEngine::DrawMouseSprite(Math::Point pos, Math::Point size, int icon)
+void Gfx::CEngine::SetClippingDistance(float value)
{
- if (icon == -1)
- return;
+ if (value < 0.5f) value = 0.5f;
+ if (value > 2.0f) value = 2.0f;
+ m_clippingDistance = value;
+}
- Math::Point p1 = pos;
- Math::Point p2 = p1 + size;
+float Gfx::CEngine::GetClippingDistance()
+{
+ return m_clippingDistance;
+}
- float u1 = (32.0f / 256.0f) * (icon % 8);
- float v1 = (32.0f / 256.0f) * (icon / 8);
- float u2 = u1 + (32.0f / 256.0f);
- float v2 = v1 + (32.0f / 256.0f);
+void Gfx::CEngine::SetObjectDetail(float value)
+{
+ if ( value < 0.0f ) value = 0.0f;
+ if ( value > 2.0f ) value = 2.0f;
+ m_objectDetail = value;
+}
- float dp = 0.5f / 256.0f;
- u1 += dp;
- v1 += dp;
- u2 -= dp;
- v2 -= dp;
+float Gfx::CEngine::GetObjectDetail()
+{
+ return m_objectDetail;
+}
- Math::Vector normal(0.0f, 0.0f, -1.0f);
+void Gfx::CEngine::SetGadgetQuantity(float value)
+{
+ if (value < 0.0f) value = 0.0f;
+ if (value > 1.0f) value = 1.0f;
- Gfx::Vertex vertex[4] =
+ 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)
{
- 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, p2.y, 0.0f), normal, Math::Point(u2, v1))
- };
+ m_textureQuality = value;
+ LoadAllTextures();
+ }
+}
- m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertex, 4);
- AddStatisticTriangle(2);
+int Gfx::CEngine::GetTextureQuality()
+{
+ return m_textureQuality;
}
-bool Gfx::CEngine::GetPause()
+void Gfx::CEngine::SetTotoMode(bool present)
{
- return m_pause;
+ m_totoMode = present;
}
-Math::Vector Gfx::CEngine::GetLookatPt()
+bool Gfx::CEngine::GetTotoMode()
{
- return m_lookatPt;
+ return m_totoMode;
}
-Math::Vector Gfx::CEngine::GetEyePt()
+void Gfx::CEngine::SetLensMode(bool present)
{
- return m_eyePt;
+ 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)
@@ -726,18 +2774,1080 @@ Gfx::EngineMouseType Gfx::CEngine::GetMouseType()
return m_mouseType;
}
-void Gfx::CEngine::AddStatisticTriangle(int count)
+const Math::Matrix& Gfx::CEngine::GetMatView()
{
- m_statisticTriangle += count;
+ return m_matView;
}
-void Gfx::CEngine::SetShowStat(bool show)
+Math::Vector Gfx::CEngine::GetEyePt()
{
- m_showStats = show;
+ return m_eyePt;
}
-bool Gfx::CEngine::GetShowStat()
+Math::Vector Gfx::CEngine::GetLookatPt()
{
- return m_showStats;
+ 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;
+ m_lastColor = 999;
+ m_lastMaterial = Gfx::Material();
+
+ m_lightMan->UpdateLights();
+
+ Gfx::Color color;
+ if (m_skyMode && m_cloud->GetLevel() != 0.0f) // clouds?
+ color = m_backgroundCloudDown;
+ else
+ color = m_backgroundColorDown;
+
+ m_device->SetClearColor(color);
+
+ // Begin the scene
+ m_device->BeginScene();
+
+ if (m_drawWorld)
+ Draw3DScene();
+
+ DrawInterface();
+
+ // End the scene
+ m_device->EndScene();
+}
+
+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->tex1Name, 0);
+ SetTexture(p2->tex2Name, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( m_objects[objRank].type != TYPETERRAIN ) continue;
+ if ( !m_objects[objRank].bDrawWorld ) continue;
+
+ {
+ D3DMATRIX mat = MAT_TO_D3DMAT(m_objects[objRank].transform);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
+ }
+
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objects[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objects[objRank].distance < p4->min ||
+ m_objects[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->tex1Name, 0);
+ SetTexture(p2->tex2Name, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( m_bShadow && m_objects[objRank].type == TYPETERRAIN ) continue;
+ if ( !m_objects[objRank].bDrawWorld ) continue;
+
+ {
+ D3DMATRIX mat = MAT_TO_D3DMAT(m_objects[objRank].transform);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
+ }
+
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objects[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objects[objRank].distance < p4->min ||
+ m_objects[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_objects[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->tex1Name, 0);
+ SetTexture(p2->tex2Name, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( m_bShadow && m_objects[objRank].type == TYPETERRAIN ) continue;
+ if ( !m_objects[objRank].bDrawWorld ) continue;
+
+ {
+ D3DMATRIX mat = MAT_TO_D3DMAT(m_objects[objRank].transform);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
+ }
+
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objects[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objects[objRank].distance < p4->min ||
+ m_objects[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_objects[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::DrawInterface()
+{
+ 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->tex1Name, 0);
+ SetTexture(p2->tex2Name, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( !m_objects[objRank].bDrawFront ) continue;
+
+ {
+ D3DMATRIX mat = MAT_TO_D3DMAT(m_objects[objRank].transform);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
+ }
+
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objects[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objects[objRank].distance < p4->min ||
+ m_objects[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();
+}
+
+void Gfx::CEngine::UpdateGroundSpotTextures()
+{
+ // TODO the original code modifying the textures is very complex, so stub for now
+ GetLogger()->Trace("CEngine::UpdateGroundSpotTextures(): stub!\n");
+}
+
+void Gfx::CEngine::DrawShadow()
+{
+ 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);
+}
+
+// Status: PART_TESTED
+void Gfx::CEngine::DrawBackgroundImageQuarter(Math::Point p1, Math::Point p2, const Gfx::Texture &tex)
+{
+ 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
+ {
+ 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(tex);
+ 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_TRIANGLE_STRIP, vertex, 4);
+ AddStatisticTriangle(2);
}
+// Status: TESTED, VERIFIED
+void Gfx::CEngine::DrawBackgroundImage()
+{
+ Math::Point p1, p2;
+ std::string name;
+
+ if (m_backgroundQuarter)
+ {
+ p1.x = 0.0f;
+ p1.y = 0.5f;
+ p2.x = 0.5f;
+ p2.y = 1.0f;
+ DrawBackgroundImageQuarter(p1, p2, m_backgroundQuarterTexs[0]);
+
+ p1.x = 0.5f;
+ p1.y = 0.5f;
+ p2.x = 1.0f;
+ p2.y = 1.0f;
+ DrawBackgroundImageQuarter(p1, p2, m_backgroundQuarterTexs[1]);
+
+ p1.x = 0.0f;
+ p1.y = 0.0f;
+ p2.x = 0.5f;
+ p2.y = 0.5f;
+ DrawBackgroundImageQuarter(p1, p2, m_backgroundQuarterTexs[2]);
+
+ p1.x = 0.5f;
+ p1.y = 0.0f;
+ p2.x = 1.0f;
+ p2.y = 0.5f;
+ DrawBackgroundImageQuarter(p1, p2, m_backgroundQuarterTexs[3]);
+ }
+ else
+ {
+ p1.x = 0.0f;
+ p1.y = 0.0f;
+ p2.x = 1.0f;
+ p2.y = 1.0f;
+ DrawBackgroundImageQuarter(p1, p2, m_backgroundFullTex);
+ }
+}
+
+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_foregroundTex);
+ 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)
+ return;
+
+ if (m_app->GetSystemMouseVisibile())
+ return;
+
+ Gfx::Material material;
+ material.diffuse = Gfx::Color(1.0f, 1.0f, 1.0f);
+ material.ambient = Gfx::Color(0.5f, 0.5f, 0.5f);
+
+ m_device->SetMaterial(material);
+ m_device->SetTexture(0, m_miceTexture);
+
+ int index = static_cast<int>(m_mouseType);
+
+ Math::Point pos = m_mousePos;
+ pos.x = m_mousePos.x - (m_mice[index].hotPoint.x * m_mouseSize.x) / 32.0f;
+ pos.y = m_mousePos.y - ((32.0f - m_mice[index].hotPoint.y) * m_mouseSize.y) / 32.0f;
+
+ Math::Point shadowPos;
+ shadowPos.x = pos.x + (4.0f/800.0f);
+ shadowPos.y = pos.y - (3.0f/600.0f);
+
+ SetState(Gfx::ENG_RSTATE_TCOLOR_WHITE);
+ DrawMouseSprite(shadowPos, m_mouseSize, m_mice[index].iconShadow);
+
+ SetState(m_mice[index].mode1);
+ DrawMouseSprite(pos, m_mouseSize, m_mice[index].icon1);
+
+ SetState(m_mice[index].mode2);
+ 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)
+ return;
+
+ Math::Point p1 = pos;
+ Math::Point p2 = p1 + size;
+
+ float u1 = (32.0f / 256.0f) * (icon % 8);
+ float v1 = (32.0f / 256.0f) * (icon / 8);
+ float u2 = u1 + (32.0f / 256.0f);
+ float v2 = v1 + (32.0f / 256.0f);
+
+ float dp = 0.5f / 256.0f;
+ u1 += dp;
+ v1 += dp;
+ u2 -= dp;
+ v2 -= dp;
+
+ Math::Vector normal(0.0f, 0.0f, -1.0f);
+
+ Gfx::Vertex vertex[4] =
+ {
+ Gfx::Vertex(Math::Vector(p1.x, p1.y, 0.0f), normal, Math::Point(u1, 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);
+}
diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h
index 25c5e5d..3f21e0d 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 {
@@ -57,14 +60,69 @@ class CTerrain;
/**
+ \enum EngineRenderState
+ \brief Render state of graphics engine
+
+ States are used for settings certain modes, for instance texturing and blending.
+ The enum is a bitmask and some of the states can be OR'd together. */
+enum EngineRenderState
+{
+ //! Normal opaque materials
+ ENG_RSTATE_NORMAL = 0,
+ //! The transparent texture (black = no)
+ ENG_RSTATE_TTEXTURE_BLACK = (1<<0),
+ //! The transparent texture (white = no)
+ ENG_RSTATE_TTEXTURE_WHITE = (1<<1),
+ //! The transparent diffuse color
+ ENG_RSTATE_TDIFFUSE = (1<<2),
+ //! Texture wrap
+ ENG_RSTATE_WRAP = (1<<3),
+ //! Texture borders with solid color
+ ENG_RSTATE_CLAMP = (1<<4),
+ //! Light texture (ambient max)
+ ENG_RSTATE_LIGHT = (1<<5),
+ //! Double black texturing
+ ENG_RSTATE_DUAL_BLACK = (1<<6),
+ //! Double white texturing
+ ENG_RSTATE_DUAL_WHITE = (1<<7),
+ //! Part 1 (no change in. MOD!)
+ ENG_RSTATE_PART1 = (1<<8),
+ //! Part 2
+ ENG_RSTATE_PART2 = (1<<9),
+ //! Part 3
+ ENG_RSTATE_PART3 = (1<<10),
+ //! Part 4
+ ENG_RSTATE_PART4 = (1<<11),
+ //! Double-sided face
+ ENG_RSTATE_2FACE = (1<<12),
+ //! Image using alpha channel
+ ENG_RSTATE_ALPHA = (1<<13),
+ //! Always use 2nd floor texturing
+ ENG_RSTATE_SECOND = (1<<14),
+ //! Causes the fog
+ ENG_RSTATE_FOG = (1<<15),
+ //! The transparent color (black = no)
+ ENG_RSTATE_TCOLOR_BLACK = (1<<16),
+ //! The transparent color (white = no)
+ 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)
+};
+
+
+/**
\enum EngineTriangleType
\brief Type of triangles drawn for engine objects */
enum EngineTriangleType
{
//! Triangles
- ENG_TRIANGLE_TYPE_6T = 1,
+ ENG_TRIANGLE_TYPE_TRIANGLES = 1,
//! Surfaces
- ENG_TRIANGLE_TYPE_6S = 2
+ ENG_TRIANGLE_TYPE_SURFACE = 2
};
/**
@@ -76,16 +134,16 @@ struct EngineTriangle
Gfx::VertexTex2 triangle[3];
//! Material
Gfx::Material material;
- //! Render state (TODO: ?)
+ //! Render state
int state;
//! 1st texture
- Gfx::Texture tex1;
+ std::string tex1Name;
//! 2nd texture
- Gfx::Texture tex2;
+ std::string tex2Name;
EngineTriangle()
{
- state = 0;
+ state = Gfx::ENG_RSTATE_NORMAL;
}
};
@@ -115,6 +173,8 @@ enum EngineObjectType
\brief Object drawn by the graphics engine */
struct EngineObject
{
+ //! If true, object is valid in objects vector
+ bool used;
//! If true, the object is drawn
bool visible;
//! If true, object is behind the 2D interface
@@ -127,7 +187,7 @@ struct EngineObject
Gfx::EngineObjectType type;
//! Transformation matrix
Math::Matrix transform;
- //! Distance view - origin (TODO: ?)
+ //! Distance to object from eye point
float distance;
//! Bounding box min (origin 0,0,0 always included)
Math::Vector bboxMin;
@@ -140,15 +200,27 @@ struct EngineObject
//! Transparency of the object [0, 1]
float transparency;
+ //! Calls LoadDefault()
EngineObject()
{
+ LoadDefault();
+ }
+
+ //! Loads default values
+ inline void LoadDefault()
+ {
+ used = false;
visible = false;
drawWorld = false;
drawFront = false;
totalTriangles = 0;
+ type = Gfx::ENG_OBJTYPE_NULL;
+ transform.LoadIdentity();
+ bboxMax.LoadZero();
+ bboxMin.LoadZero();
distance = 0.0f;
radius = 0.0f;
- shadowRank = 0;
+ shadowRank = -1;
transparency = 0.0f;
}
};
@@ -157,31 +229,22 @@ struct EngineObjLevel1;
struct EngineObjLevel2;
struct EngineObjLevel3;
struct EngineObjLevel4;
-struct EngineObjLevel5;
-
-/**
- \struct EngineObjLevel5
- \brief Tier 5 of object tree */
-struct EngineObjLevel5
-{
- Gfx::Material material;
- int state;
- Gfx::EngineTriangleType type;
- std::vector<Gfx::VertexTex2> vertices;
-
- EngineObjLevel5();
-};
/**
\struct EngineObjLevel4
\brief Tier 4 of object tree */
struct EngineObjLevel4
{
- int reserved;
- std::vector<Gfx::EngineObjLevel5> up;
- Gfx::EngineObjLevel3* down;
+ bool used;
+ Gfx::EngineTriangleType type;
+ Gfx::Material material;
+ int state;
+ std::vector<Gfx::VertexTex2> vertices;
- EngineObjLevel4();
+ EngineObjLevel4(bool used = false,
+ Gfx::EngineTriangleType type = Gfx::ENG_TRIANGLE_TYPE_TRIANGLES,
+ const Gfx::Material& material = Gfx::Material(),
+ int state = Gfx::ENG_RSTATE_NORMAL);
};
/**
@@ -189,12 +252,12 @@ struct EngineObjLevel4
\brief Tier 3 of object tree */
struct EngineObjLevel3
{
+ bool used;
float min;
float max;
- std::vector<Gfx::EngineObjLevel4> up;
- Gfx::EngineObjLevel2* down;
+ std::vector<Gfx::EngineObjLevel4> next;
- EngineObjLevel3();
+ EngineObjLevel3(bool used = false, float min = 0.0f, float max = 0.0f);
};
/**
@@ -202,11 +265,11 @@ struct EngineObjLevel3
\brief Tier 2 of object tree */
struct EngineObjLevel2
{
+ bool used;
int objRank;
- std::vector<Gfx::EngineObjLevel3> up;
- Gfx::EngineObjLevel1* down;
+ std::vector<Gfx::EngineObjLevel3> next;
- EngineObjLevel2();
+ EngineObjLevel2(bool used = false, int objRank = -1);
};
/**
@@ -214,11 +277,15 @@ struct EngineObjLevel2
\brief Tier 1 of object tree */
struct EngineObjLevel1
{
+ bool used;
+ std::string tex1Name;
Gfx::Texture tex1;
+ std::string tex2Name;
Gfx::Texture tex2;
- std::vector<Gfx::EngineObjLevel2> up;
+ std::vector<Gfx::EngineObjLevel2> next;
- EngineObjLevel1();
+ EngineObjLevel1(bool used = false, const std::string& tex1Name = "",
+ const std::string& tex2Name = "");
};
/**
@@ -237,6 +304,8 @@ enum EngineShadowType
\brief Shadow drawn by the graphics engine */
struct EngineShadow
{
+ //! If true, shadow is valid
+ bool used;
//! If true, shadow is invisible (object being carried for example)
bool hide;
//! Rank of the associated object
@@ -258,8 +327,17 @@ struct EngineShadow
EngineShadow()
{
+ LoadDefault();
+ }
+
+ void LoadDefault()
+ {
+ used = false;
hide = false;
objRank = 0;
+ type = Gfx::ENG_SHADOW_NORM;
+ pos.LoadZero();
+ normal.LoadZero();
angle = radius = intensity = height = 0.0f;
}
};
@@ -269,6 +347,8 @@ struct EngineShadow
\brief A spot (large shadow) drawn on the ground by the graphics engine */
struct EngineGroundSpot
{
+ //! If true, ground spot is valid
+ bool used;
//! Color of the shadow
Gfx::Color color;
//! Min altitude
@@ -288,6 +368,15 @@ struct EngineGroundSpot
EngineGroundSpot()
{
+ LoadDefault();
+ }
+
+ void LoadDefault()
+ {
+ used = false;
+ color = Gfx::Color();
+ pos.LoadZero();
+ drawPos.LoadZero();
min = max = smooth = radius = drawRadius = 0.0f;
}
};
@@ -297,12 +386,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
};
/**
@@ -339,11 +430,19 @@ struct EngineGroundMark
EngineGroundMark()
{
+ LoadDefault();
+ }
+
+ void LoadDefault()
+ {
draw = false;
+ phase = ENG_GR_MARK_PHASE_NULL;
+ pos = Math::Vector();
+ drawPos = Math::Vector();
delay[0] = delay[1] = delay[2] = 0.0f;
fix = radius = intensity = drawRadius = drawIntensity = 0.0f;
dx = dy = 0;
- table = NULL;
+ table = nullptr;
}
};
@@ -363,55 +462,6 @@ enum EngineTextureMapping
/**
- \enum EngineRenderState
- \brief Render state of graphics engine
-
- States are used for settings certain modes, for instance texturing and blending.
- The enum is a bitmask and some of the states can be OR'd together. */
-enum EngineRenderState
-{
- //! Normal opaque materials
- ENG_RSTATE_NORMAL = 0,
- //! The transparent texture (black = no)
- ENG_RSTATE_TTEXTURE_BLACK = (1<<0),
- //! The transparent texture (white = no)
- ENG_RSTATE_TTEXTURE_WHITE = (1<<1),
- //! The transparent diffuse color
- ENG_RSTATE_TDIFFUSE = (1<<2),
- //! Texture wrap
- ENG_RSTATE_WRAP = (1<<3),
- //! Texture borders with solid color
- ENG_RSTATE_CLAMP = (1<<4),
- //! Light texture (ambient max)
- ENG_RSTATE_LIGHT = (1<<5),
- //! Double black texturing
- ENG_RSTATE_DUAL_BLACK = (1<<6),
- //! Double white texturing
- ENG_RSTATE_DUAL_WHITE = (1<<7),
- //! Part 1 (no change in. MOD!)
- ENG_RSTATE_PART1 = (1<<8),
- //! Part 2
- ENG_RSTATE_PART2 = (1<<9),
- //! Part 3
- ENG_RSTATE_PART3 = (1<<10),
- //! Part 4
- ENG_RSTATE_PART4 = (1<<11),
- //! Double-sided face
- ENG_RSTATE_2FACE = (1<<12),
- //! Image using alpha channel
- ENG_RSTATE_ALPHA = (1<<13),
- //! Always use 2nd floor texturing
- ENG_RSTATE_SECOND = (1<<14),
- //! Causes the fog
- ENG_RSTATE_FOG = (1<<15),
- //! The transparent color (black = no)
- ENG_RSTATE_TCOLOR_BLACK = (1<<16),
- //! The transparent color (white = no)
- ENG_RSTATE_TCOLOR_WHITE = (1<<17)
-};
-
-
-/**
\enum EngineMouseType
\brief Type of mouse cursor displayed in-game */
enum EngineMouseType
@@ -501,7 +551,7 @@ struct EngineMouse
The 3D scene is composed of objects which are basically collections of triangles forming
a surface or simply independent triangles in space. Objects are stored in the engine
- as a tree structure which is composed of 5 tiers (EngineObjLevel1, EngineObjLevel2 and so on).
+ as a tree structure which is composed of 4 tiers (EngineObjLevel1, EngineObjLevel2 and so on).
Each tier stores some data about object triangle, like textures or materials used.
Additional information on objects stored are in EngineObject structure.
Each object is uniquely identified by its rank.
@@ -511,354 +561,592 @@ 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);
+
+ //! 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);
- //! Renders a single frame
- bool Render();
+ //! Writes a screenshot containing the current frame
+ bool WriteScreenShot(const std::string& fileName, int width, int height);
- bool WriteProfile();
+ //! 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();
+ //! Creates a new object and returns its rank
int CreateObject();
+ //! Deletes all objects, shadows and ground spots
void FlushObject();
+ //! Deletes the given object
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,
- 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,
- int state, std::string texName1, std::string texName2,
+
+ //@{
+ //! Management of engine object type
+ bool SetObjectType(int objRank, Gfx::EngineObjectType type);
+ Gfx::EngineObjectType GetObjectType(int objRank);
+ //@}
+
+ //@{
+ //! Management of object transform
+ bool SetObjectTransform(int objRank, const Math::Matrix& transform);
+ bool GetObjectTransform(int objRank, Math::Matrix& transform);
+ //@}
+
+ //! Sets drawWorld for given object
+ bool SetObjectDrawWorld(int objRank, bool draw);
+ //! Sets drawFront for given object
+ bool SetObjectDrawFront(int objRank, bool draw);
+
+ //! Sets the transparency level for given object
+ bool SetObjectTransparency(int objRank, float value);
+
+ //! Returns the bounding box for an object
+ bool GetObjectBBox(int objRank, Math::Vector& min, Math::Vector& max);
+
+ //! Returns the total number of triangles of given object
+ int GetObjectTotalTriangles(int objRank);
+
+ //! Adds triangles to given object with the specified params
+ bool AddTriangles(int objRank, const std::vector<Gfx::VertexTex2>& vertices,
+ const Gfx::Material& material, int state,
+ std::string tex1Name, std::string tex2Name,
+ float min, float max, bool globalUpdate);
+
+ //! Adds a surface to given object with the specified params
+ bool AddSurface(int objRank, const std::vector<Gfx::VertexTex2>& vertices,
+ const Gfx::Material& material, int state,
+ std::string tex1Name, std::string tex2Name,
float min, float max, bool globalUpdate);
- bool AddQuick(int objRank, Gfx::EngineObjLevel5* buffer,
- std::string texName1, std::string texName2,
+
+ //! Adds a tier 4 engine object directly
+ bool AddQuick(int objRank, const Gfx::EngineObjLevel4& buffer,
+ std::string tex1Name, std::string tex2Name,
float min, float max, bool globalUpdate);
- Gfx::EngineObjLevel5* SearchTriangle(int objRank, const Gfx::Material &mat,
- int state, std::string texName1, std::string texName2,
- float min, float max);
+ //! Returns the first found tier 4 engine object for the given params or nullptr if not found
+ Gfx::EngineObjLevel4* FindTriangles(int objRank, const Gfx::Material& material,
+ int state, std::string tex1Name, std::string tex2Name,
+ float min, float max);
+
+ //! Returns a partial list of triangles for given object
+ int GetPartialTriangles(int objRank, float min, float max, float percent, int maxCount,
+ std::vector<Gfx::EngineTriangle>& triangles);
+
+ //! Updates LOD after parameter or resolution change
void ChangeLOD();
- bool ChangeSecondTexture(int objRank, char* 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,
+
+ //! Changes the 2nd texure for given object
+ bool ChangeSecondTexture(int objRank, const std::string& tex2Name);
+
+ //! Changes (recalculates) texture mapping for given object
+ bool ChangeTextureMapping(int objRank, const Gfx::Material& mat, int state,
+ const std::string& tex1Name, const std::string& tex2Name,
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,
+
+ //! Changes texture mapping for robot tracks
+ bool TrackTextureMapping(int objRank, const Gfx::Material& mat, int state,
+ const std::string& tex1Name, const std::string& tex2Name,
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 SetObjectType(int objRank, Gfx::EngineObjectType type);
- Gfx::EngineObjectType GetObjectType(int objRank);
- bool SetObjectTransparency(int objRank, float value);
- bool ShadowCreate(int objRank);
- void ShadowDelete(int objRank);
+
+ //! Creates a shadow for the given object
+ bool CreateShadow(int objRank);
+ //! Deletes the shadow for given object
+ void DeleteShadow(int objRank);
+
+ //@{
+ //! Management of different shadow params
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& normal);
bool SetObjectShadowAngle(int objRank, float angle);
bool SetObjectShadowRadius(int objRank, float radius);
bool SetObjectShadowIntensity(int objRank, float intensity);
- bool SetObjectShadowHeight(int objRank, float h);
+ bool SetObjectShadowHeight(int objRank, float height);
float GetObjectShadowRadius(int objRank);
-
- void GroundSpotFlush();
- int GroundSpotCreate();
- void GroundSpotDelete(int rank);
- bool SetObjectGroundSpotPos(int rank, const Math::Vector &pos);
+ //@}
+
+ //! Lists the ranks of objects and subobjects selected
+ void SetHighlightRank(int* rankList);
+ //! Returns the highlighted rectangle
+ bool GetHighlight(Math::Point& p1, Math::Point& p2);
+
+ //! Deletes all ground spots
+ void FlushGroundSpot();
+ //! Creates a new ground spot and returns its rank
+ int CreateGroundSpot();
+ //! Deletes the given ground spot
+ void DeleteGroundSpot(int rank);
+
+ //@{
+ //! Management of different ground spot params
+ 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);
+ //@}
- int GroundMarkCreate(Math::Vector pos, float radius,
+ //! Creates the ground mark with the given params
+ void CreateGroundMark(Math::Vector pos, float radius,
float delay1, float delay2, float delay3,
int dx, int dy, char* table);
- bool GroundMarkDelete(int rank);
+ //! Deletes the ground mark
+ void DeleteGroundMark(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 *************** */
- bool LoadTexture(const std::string &name, int stage = 0);
+ //! 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);
+
+ //! Loads texture, creating it if not already present
+ Gfx::Texture LoadTexture(const std::string& name);
+ //! Loads texture, creating it with given params if not already present
+ Gfx::Texture LoadTexture(const std::string& name, const Gfx::TextureCreateParams& params);
+ //! Loads all necessary textures
bool LoadAllTextures();
+ //! Sets texture for given stage; if not present in cache, the texture is loaded
+ /** If loading fails, returns false. */
+ bool SetTexture(const std::string& name, int stage = 0);
+ //! Sets texture for given stage
+ void SetTexture(const Gfx::Texture& tex, int stage = 0);
+
+ //! Deletes the given texture, unloading it and removing from cache
+ void DeleteTexture(const std::string& name);
+ //! Deletes the given texture, unloading it and removing from cache
+ void DeleteTexture(const Gfx::Texture& tex);
+
+ //@{
+ //! 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);
- 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);
+ //! Resets the projection matrix after changes
+ void UpdateMatProj();
-protected:
+ //! Updates the scene after a change of parameters
+ void ApplyChange();
- void SetUp3DView();
- bool Draw3DScene();
+protected:
+ //! Prepares the interface for 3D scene
+ void Draw3DScene();
+ //! Draws the user interface over the scene
+ void DrawInterface();
- 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 Gfx::Texture &tex);
+ //! 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);*/
+ //! Creates new tier 1 object
+ Gfx::EngineObjLevel1& AddLevel1(const std::string& tex1Name, const std::string& tex2Name);
+ //! Creates a new tier 2 object
+ Gfx::EngineObjLevel2& AddLevel2(Gfx::EngineObjLevel1 &p1, int objRank);
+ //! Creates a new tier 3 object
+ Gfx::EngineObjLevel3& AddLevel3(Gfx::EngineObjLevel2 &p2, float min, float max);
+ //! Creates a new tier 4 object
+ Gfx::EngineObjLevel4& AddLevel4(Gfx::EngineObjLevel3 &p3, Gfx::EngineTriangleType type,
+ const Gfx::Material& mat, int state);
+ //! Create texture and add it to cache
+ Gfx::Texture CreateTexture(const std::string &texName, const Gfx::TextureCreateParams &params);
+
+ //! 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 geometric parameters of objects (bounding box and radius)
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 +1157,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 +1217,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;
@@ -936,21 +1226,25 @@ protected:
bool m_fog;
bool m_firstGroundSpot;
int m_secondTexNum;
+ bool m_backgroundFull;
+ bool m_backgroundQuarter;
std::string m_backgroundName;
+ std::string m_backgroundQuarterNames[4];
+ Gfx::Texture m_backgroundFullTex;
+ Gfx::Texture m_backgroundQuarterTexs[4];
Gfx::Color m_backgroundColorUp;
Gfx::Color m_backgroundColorDown;
Gfx::Color m_backgroundCloudUp;
Gfx::Color m_backgroundCloudDown;
- bool m_backgroundFull;
- bool m_backgroundQuarter;
bool m_overFront;
Gfx::Color m_overColor;
int m_overMode;
- std::string m_frontsizeName;
+ std::string m_foregroundName;
+ Gfx::Texture m_foregroundTex;
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 +1263,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..b6b111a 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()->Trace("CLightning::CLightning() stub!\n");
+ // TODO!
+}
+
+Gfx::CLightning::~CLightning()
+{
+ GetLogger()->Trace("CLightning::~CLightning() stub!\n");
+ // TODO!
+}
+
+void Gfx::CLightning::Flush()
+{
+ GetLogger()->Trace("CLightning::Flush() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CLightning::EventProcess(const Event &event)
+{
+ GetLogger()->Trace("CLightning::EventProcess() stub!\n");
+ // TODO!
+ return true;
+}
+
+bool Gfx::CLightning::Create(float sleep, float delay, float magnetic)
+{
+ GetLogger()->Trace("CLightning::Create() stub!\n");
+ // TODO!
+ return true;
+}
+
+bool Gfx::CLightning::GetStatus(float &sleep, float &delay, float &magnetic, float &progress)
+{
+ GetLogger()->Trace("CLightning::GetStatus() stub!\n");
+ // TODO!
+ return true;
+}
+
+bool Gfx::CLightning::SetStatus(float sleep, float delay, float magnetic, float progress)
+{
+ GetLogger()->Trace("CLightning::SetStatus() stub!\n");
+ // TODO!
+ return true;
+}
+
+void Gfx::CLightning::Draw()
+{
+ GetLogger()->Trace("CLightning::Draw() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CLightning::EventFrame(const Event &event)
+{
+ GetLogger()->Trace("CLightning::EventFrame() stub!\n");
+ // TODO!
+ return true;
+}
+
+CObject* Gfx::CLightning::SearchObject(Math::Vector pos)
+{
+ GetLogger()->Trace("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..37a3975 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()->Trace("CParticle::CParticle() stub!\n");
+ // TODO!
+}
+
+Gfx::CParticle::~CParticle()
+{
+ GetLogger()->Trace("CParticle::~CParticle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetDevice(Gfx::CDevice* device)
+{
+ GetLogger()->Trace("CParticle::SetDevice() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::FlushParticle()
+{
+ GetLogger()->Trace("CParticle::FlushParticle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::FlushParticle(int sheet)
+{
+ GetLogger()->Trace("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()->Trace("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()->Trace("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()->Trace("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()->Trace("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()->Trace("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()->Trace("CParticle::CreateWheelTrace() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DeleteParticle(Gfx::ParticleType type)
+{
+ GetLogger()->Trace("CParticle::DeleteParticle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DeleteParticle(int channel)
+{
+ GetLogger()->Trace("CParticle::DeleteParticle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetObjectLink(int channel, CObject *object)
+{
+ GetLogger()->Trace("CParticle::SetObjectLink() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetObjectFather(int channel, CObject *object)
+{
+ GetLogger()->Trace("CParticle::SetObjectFather() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetPosition(int channel, Math::Vector pos)
+{
+ GetLogger()->Trace("CParticle::SetPosition() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetDimension(int channel, Math::Point dim)
+{
+ GetLogger()->Trace("CParticle::SetDimension() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetZoom(int channel, float zoom)
+{
+ GetLogger()->Trace("CParticle::SetZoom() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetAngle(int channel, float angle)
+{
+ GetLogger()->Trace("CParticle::SetAngle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetIntensity(int channel, float intensity)
+{
+ GetLogger()->Trace("CParticle::SetIntensity() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, float angle, float intensity)
+{
+ GetLogger()->Trace("CParticle::SetParam() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::SetPhase(int channel, Gfx::ParticlePhase phase, float duration)
+{
+ GetLogger()->Trace("CParticle::SetPhase() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CParticle::GetPosition(int channel, Math::Vector &pos)
+{
+ GetLogger()->Trace("CParticle::GetPosition() stub!\n");
+ // TODO!
+ return true;
+}
+
+Gfx::Color Gfx::CParticle::GetFogColor(Math::Vector pos)
+{
+ GetLogger()->Trace("CParticle::GetFogColor() stub!\n");
+ // TODO!
+ return Gfx::Color();
+}
+
+void Gfx::CParticle::SetFrameUpdate(int sheet, bool update)
+{
+ GetLogger()->Trace("CParticle::SetFrameUpdate() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::FrameParticle(float rTime)
+{
+ GetLogger()->Trace("CParticle::FrameParticle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticle(int sheet)
+{
+ GetLogger()->Trace("CParticle::DrawParticle() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CParticle::WriteWheelTrace(char *filename, int width, int height, Math::Vector dl, Math::Vector ur)
+{
+ GetLogger()->Trace("CParticle::WriteWheelTrace() stub!\n");
+ // TODO!
+ return true;
+}
+
+void Gfx::CParticle::DeleteRank(int rank)
+{
+ GetLogger()->Trace("CParticle::DeleteRank() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CParticle::CheckChannel(int &channel)
+{
+ GetLogger()->Trace("CParticle::CheckChannel() stub!\n");
+ // TODO!
+ return true;
+}
+
+void Gfx::CParticle::DrawParticleTriangle(int i)
+{
+ GetLogger()->Trace("CParticle::DrawParticleTriangle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticleNorm(int i)
+{
+ GetLogger()->Trace("CParticle::DrawParticleNorm() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticleFlat(int i)
+{
+ GetLogger()->Trace("CParticle::DrawParticleFlat() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticleFog(int i)
+{
+ GetLogger()->Trace("CParticle::DrawParticleFog() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticleRay(int i)
+{
+ GetLogger()->Trace("CParticle::DrawParticleRay() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticleSphere(int i)
+{
+ GetLogger()->Trace("CParticle::DrawParticleSphere() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticleCylinder(int i)
+{
+ GetLogger()->Trace("CParticle::DrawParticleCylinder() stub!\n");
+ // TODO!
+}
+
+void Gfx::CParticle::DrawParticleWheel(int i)
+{
+ GetLogger()->Trace("CParticle::DrawParticleWheel() stub!\n");
+ // TODO!
+}
+
+CObject* Gfx::CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos, Gfx::ParticleType type, CObject *father)
+{
+ GetLogger()->Trace("CParticle::SearchObjectGun() stub!\n");
+ // TODO!
+ return nullptr;
+}
+
+CObject* Gfx::CParticle::SearchObjectRay(Math::Vector pos, Math::Vector goal, Gfx::ParticleType type, CObject *father)
+{
+ GetLogger()->Trace("CParticle::SearchObjectRay() stub!\n");
+ // TODO!
+ return nullptr;
+}
+
+void Gfx::CParticle::Play(Sound sound, Math::Vector pos, float amplitude)
+{
+ GetLogger()->Trace("CParticle::Play() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CParticle::TrackMove(int i, Math::Vector pos, float progress)
+{
+ GetLogger()->Trace("CParticle::TrackMove() stub!\n");
+ // TODO!
+ return true;
+}
+
+void Gfx::CParticle::TrackDraw(int i, Gfx::ParticleType type)
+{
+ GetLogger()->Trace("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..e859cd7 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,71 @@ 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;
+
+ // TODO: make all textures transparent?
+ //! 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..c97131e 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()->Trace("CParticle::CPyro() stub!\n");
+ // TODO!
+}
+
+Gfx::CPyro::~CPyro()
+{
+ GetLogger()->Trace("CPyro::~CPyro() stub!");
+ // TODO!
+}
+
+void Gfx::CPyro::DeleteObject(bool all)
+{
+ GetLogger()->Trace("CPyro::DeleteObject() stub!");
+ // TODO!
+}
+
+bool Gfx::CPyro::Create(Gfx::PyroType type, CObject* pObj, float force)
+{
+ GetLogger()->Trace("CPyro::Create() stub!");
+ // TODO!
+ return true;
+}
+
+bool Gfx::CPyro::EventProcess(const Event &event)
+{
+ GetLogger()->Trace("CPyro::EventProcess() stub!\n");
+ // TODO!
+ return true;
+}
+
+Error Gfx::CPyro::IsEnded()
+{
+ GetLogger()->Trace("CPyro::IsEnded() stub!\n");
+ // TODO!
+ return ERR_OK;
+}
+
+void Gfx::CPyro::CutObjectLink(CObject* pObj)
+{
+ GetLogger()->Trace("CPyro::CutObjectLink() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::DisplayError(PyroType type, CObject* pObj)
+{
+ GetLogger()->Trace("CPyro::DisplayError() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CPyro::CreateLight(Math::Vector pos, float height)
+{
+ GetLogger()->Trace("CPyro::CreateLight() stub!\n");
+ // TODO!
+ return true;
+}
+
+void Gfx::CPyro::DeleteObject(bool primary, bool secondary)
+{
+ GetLogger()->Trace("CPyro::DeleteObject() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::CreateTriangle(CObject* pObj, ObjectType oType, int part)
+{
+ GetLogger()->Trace("CPyro::CreateTriangle() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::ExploStart()
+{
+ GetLogger()->Trace("CPyro::ExploStart() stub!\n");
+ // TODO!
+}
+void Gfx::CPyro::ExploTerminate()
+{
+ GetLogger()->Trace("CPyro::ExploTerminate() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::BurnStart()
+{
+ GetLogger()->Trace("CPyro::BurnStart() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::BurnAddPart(int part, Math::Vector pos, Math::Vector angle)
+{
+ GetLogger()->Trace("CPyro::BurnAddPart() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::BurnProgress()
+{
+ GetLogger()->Trace("CPyro::BurnProgress() stub!\n");
+ // TODO!
+}
+
+bool Gfx::CPyro::BurnIsKeepPart(int part)
+{
+ GetLogger()->Trace("CPyro::BurnIsKeepPart() stub!\n");
+ // TODO!
+ return true;
+}
+
+void Gfx::CPyro::BurnTerminate()
+{
+ GetLogger()->Trace("CPyro::BurnTerminate() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::FallStart()
+{
+ GetLogger()->Trace("CPyro::FallStart() stub!\n");
+ // TODO!
+}
+
+CObject* Gfx::CPyro::FallSearchBeeExplo()
+{
+ GetLogger()->Trace("CPyro::FallSearchBeeExplo() stub!\n");
+ // TODO!
+ return nullptr;
+}
+
+void Gfx::CPyro::FallProgress(float rTime)
+{
+ GetLogger()->Trace("CPyro::FallProgress() stub!\n");
+ // TODO!
+}
+
+Error Gfx::CPyro::FallIsEnded()
+{
+ GetLogger()->Trace("CPyro::FallIsEnded() stub!\n");
+ // TODO!
+ return ERR_OK;
+}
+
+void Gfx::CPyro::LightOperFlush()
+{
+ GetLogger()->Trace("CPyro::LightOperFlush() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::LightOperAdd(float progress, float intensity, float r, float g, float b)
+{
+ GetLogger()->Trace("CPyro::LightOperAdd() stub!\n");
+ // TODO!
+}
+
+void Gfx::CPyro::LightOperFrame(float rTime)
+{
+ GetLogger()->Trace("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..6b26281 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_levelMats.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_levelMats.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_levelMats.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::EngineObjLevel4 buffer;
+ buffer.vertices.reserve(total);
+
+ buffer.type = Gfx::ENG_TRIANGLE_TYPE_SURFACE;
+ 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_levelMats.size() ); i++)
+ {
+ if (id == m_levelMats[i].id)
+ return &m_levelMats[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_levelDots[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_levelMats or -1 if there is not.
+ m_levelMats[i].id gives the identifier. */
+int Gfx::CTerrain::LevelTestMat(char *mat)
+{
+ for (int i = 0; i < static_cast<int>( m_levelMats.size() ); i++)
+ {
+ if ( m_levelMats[i].mat[0] == mat[0] &&
+ m_levelMats[i].mat[1] == mat[1] &&
+ m_levelMats[i].mat[2] == mat[2] &&
+ m_levelMats[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_levelMats[ii].id; // looking for a id compatible with mat
+ }
+
+ // Changes the point
+ m_levelDots[x+y*m_levelDotSize].id = id;
+ m_levelDots[x+y*m_levelDotSize].mat[0] = mat[0];
+ m_levelDots[x+y*m_levelDotSize].mat[1] = mat[1];
+ m_levelDots[x+y*m_levelDotSize].mat[2] = mat[2];
+ m_levelDots[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_levelDots[i].mat[0] != mat[2])
+ {
+ m_levelDots[i].mat[0] = mat[2];
+ int ii = LevelTestMat(m_levelDots[i].mat);
+ if (ii != -1)
+ m_levelDots[i].id = m_levelMats[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_levelDots[i].mat[1] != mat[3])
+ {
+ m_levelDots[i].mat[1] = mat[3];
+ int ii = LevelTestMat(m_levelDots[i].mat);
+ if (ii != -1)
+ m_levelDots[i].id = m_levelMats[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_levelDots[i].mat[2] != mat[0])
+ {
+ m_levelDots[i].mat[2] = mat[0];
+ int ii = LevelTestMat(m_levelDots[i].mat);
+ if (ii != -1)
+ m_levelDots[i].id = m_levelMats[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_levelDots[i].mat[3] != mat[1] )
+ {
+ m_levelDots[i].mat[3] = mat[1];
+ int ii = LevelTestMat(m_levelDots[i].mat);
+ if (ii != -1)
+ m_levelDots[i].id = m_levelMats[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_levelDots[(x+0)+(y-1)*m_levelDotSize].mat[1];
+ test[2] = m_levelDots[(x+0)+(y-1)*m_levelDotSize].mat[2];
+ test[3] = m_levelDots[(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_levelDots[(x-1)+(y+0)*m_levelDotSize].mat[0];
+ test[1] = mat[3];
+ test[2] = m_levelDots[(x-1)+(y+0)*m_levelDotSize].mat[2];
+ test[3] = m_levelDots[(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_levelDots[(x+0)+(y+1)*m_levelDotSize].mat[0];
+ test[1] = m_levelDots[(x+0)+(y+1)*m_levelDotSize].mat[1];
+ test[2] = mat[0];
+ test[3] = m_levelDots[(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_levelDots[(x+1)+(y+0)*m_levelDotSize].mat[0];
+ test[1] = m_levelDots[(x+1)+(y+0)*m_levelDotSize].mat[1];
+ test[2] = m_levelDots[(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_levelDots[i].id = id;
+
+ for (int j = 0; j < 4; j++)
+ m_levelDots[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_levelDots.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_levelDots);
+
+ for (int i = 0; i < m_levelDotSize * m_levelDotSize; i++)
+ {
+ for (int j = 0; j < 4; j++)
+ m_levelDots[i].mat[j] = 0;
+ }
+}
+
+void Gfx::CTerrain::LevelCloseTable()
+{
+ m_levelDots.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_levelDots.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_levelDots[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->CreateGroundMark(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..0c7e3cf 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_levelMats;
+ std::vector<Gfx::DotLevel> m_levelDots;
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..19ef57b 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..2a7c6d2 100644
--- a/src/graphics/engine/water.cpp
+++ b/src/graphics/engine/water.cpp
@@ -19,5 +19,641 @@
#include "graphics/engine/water.h"
+#include "common/iman.h"
+#include "common/logger.h"
+#include "graphics/engine/engine.h"
+#include "graphics/engine/terrain.h"
+#include "object/object.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_lines.reserve(WATERLINE_PREALLOCATE_COUNT);
+
+ std::vector<Gfx::WaterVapor>(VAPOR_SIZE).swap(m_vapors);
+}
+
+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_vapors.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_vapors.clear();
+}
+
+bool Gfx::CWater::VaporCreate(Gfx::ParticleType type, Math::Vector pos, float delay)
+{
+ for (int i = 0; i < static_cast<int>( m_vapors.size() ); i++)
+ {
+ if (! m_vapors[i].used)
+ {
+ m_vapors[i].used = true;
+ m_vapors[i].type = type;
+ m_vapors[i].pos = pos;
+ m_vapors[i].delay = delay;
+ m_vapors[i].time = 0.0f;
+ m_vapors[i].last = 0.0f;
+
+ if (m_vapors[i].type == PARTIFIRE)
+ m_sound->Play(SOUND_BLUP, pos, 1.0f, 1.0f-Math::Rand()*0.5f);
+
+ if (m_vapors[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_vapors[i].time += rTime;
+
+ if (m_sound == nullptr)
+ m_sound = static_cast<CSoundInterface*>(m_iMan->SearchInstance(CLASS_SOUND));
+
+ if (m_vapors[i].time <= m_vapors[i].delay)
+ {
+ if (m_time-m_vapors[i].last >= m_engine->ParticleAdapt(0.02f))
+ {
+ m_vapors[i].last = m_time;
+
+ if (m_vapors[i].type == PARTIFIRE)
+ {
+ for (int j = 0; j < 10; j++)
+ {
+ Math::Vector pos = m_vapors[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_vapors[i].type == PARTIFLAME)
+ {
+ Math::Vector pos = m_vapors[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_vapors[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_vapors[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()
+{
+ GetLogger()->Trace("CWater::DrawBack(): stub!\n");
+ /* 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()
+{
+ GetLogger()->Trace("CWater::DrawSurf(): stub!\n");
+ /* 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_lines.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_lines.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)
+{
+ 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..f20f992 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_lines;
+ std::vector<WaterVapor> m_vapors;
- 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..3526b13 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,22 @@ 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
}
- result.valid = true;
- result.size.w = data->surface->w;
- result.size.h = data->surface->h;
+ return CreateTexture(data, params);
+}
+
+Gfx::Texture Gfx::CGLDevice::CreateTexture(ImageData *data, const Gfx::TextureCreateParams &params)
+{
+ Gfx::Texture result;
+
+ result.size.x = data->surface->w;
+ result.size.y = data->surface->h;
// Use & enable 1st texture stage
glActiveTexture(GL_TEXTURE0);
@@ -461,7 +462,7 @@ Gfx::Texture Gfx::CGLDevice::CreateTexture(CImage *image, const Gfx::TextureCrea
// Restore the previous state of 1st stage
- if (m_currentTextures[0].valid)
+ if (m_currentTextures[0].Valid())
glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
else
glBindTexture(GL_TEXTURE_2D, 0);
@@ -516,7 +517,7 @@ void Gfx::CGLDevice::SetTexture(int index, const Gfx::Texture &texture)
m_currentTextures[index] = texture; // remember the change
- if (! texture.valid)
+ if (! texture.Valid())
{
glBindTexture(GL_TEXTURE_2D, 0); // unbind texture
}
@@ -531,6 +532,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)
@@ -576,7 +595,7 @@ void Gfx::CGLDevice::SetTextureStageParams(int index, const Gfx::TextureStagePar
m_textureStageParams[index] = params;
// Don't actually do anything if texture not set
- if (! m_currentTextures[index].valid)
+ if (! m_currentTextures[index].Valid())
return;
// Enable the given stage
@@ -1159,17 +1178,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 7a8c3df..83eca52 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