summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt44
-rw-r--r--src/app/app.cpp688
-rw-r--r--src/app/app.h153
-rw-r--r--src/app/main.cpp41
-rw-r--r--src/app/system.cpp270
-rw-r--r--src/app/system.h46
-rw-r--r--src/app/system_linux.h101
-rw-r--r--src/app/system_other.h146
-rw-r--r--src/app/system_windows.h122
-rw-r--r--src/common/event.cpp164
-rw-r--r--src/common/event.h261
-rw-r--r--src/common/image.cpp221
-rw-r--r--src/common/image.h84
-rw-r--r--src/common/ioutils.h81
-rw-r--r--src/common/key.h (renamed from src/graphics/common/device.h)40
-rw-r--r--src/common/logger.cpp2
-rw-r--r--src/common/misc.h2
-rw-r--r--src/common/modfile.cpp695
-rw-r--r--src/common/modfile.h115
-rw-r--r--src/common/singleton.h12
-rw-r--r--src/common/stringutils.cpp149
-rw-r--r--src/common/stringutils.h77
-rw-r--r--src/common/test/CMakeLists.txt6
-rw-r--r--src/common/test/image_test.cpp34
-rw-r--r--src/graphics/common/README.txt5
-rw-r--r--src/graphics/common/color.cpp150
-rw-r--r--src/graphics/common/color.h50
-rw-r--r--src/graphics/common/device.cpp14
-rw-r--r--src/graphics/common/engine.cpp73
-rw-r--r--src/graphics/common/engine.h715
-rw-r--r--src/graphics/common/light.cpp22
-rw-r--r--src/graphics/common/light.h115
-rw-r--r--src/graphics/common/model.cpp23
-rw-r--r--src/graphics/common/model.h141
-rw-r--r--src/graphics/common/modfile.cpp23
-rw-r--r--src/graphics/common/modfile.h114
-rw-r--r--src/graphics/common/vertex.h68
-rw-r--r--src/graphics/core/README.txt6
-rw-r--r--src/graphics/core/color.cpp103
-rw-r--r--src/graphics/core/color.h98
-rw-r--r--src/graphics/core/device.h414
-rw-r--r--src/graphics/core/light.h91
-rw-r--r--src/graphics/core/material.h (renamed from src/graphics/common/material.h)3
-rw-r--r--src/graphics/core/texture.h237
-rw-r--r--src/graphics/core/vertex.h141
-rw-r--r--src/graphics/engine/README.txt8
-rw-r--r--src/graphics/engine/camera.cpp (renamed from src/graphics/common/camera.cpp)2
-rw-r--r--src/graphics/engine/camera.h (renamed from src/graphics/common/camera.h)5
-rw-r--r--src/graphics/engine/cloud.cpp (renamed from src/graphics/common/cloud.cpp)2
-rw-r--r--src/graphics/engine/cloud.h (renamed from src/graphics/common/cloud.h)2
-rw-r--r--src/graphics/engine/engine.cpp729
-rw-r--r--src/graphics/engine/engine.h985
-rw-r--r--src/graphics/engine/lightman.cpp416
-rw-r--r--src/graphics/engine/lightman.h181
-rw-r--r--src/graphics/engine/lightning.cpp (renamed from src/graphics/common/lightning.cpp)2
-rw-r--r--src/graphics/engine/lightning.h (renamed from src/graphics/common/lightning.h)0
-rw-r--r--src/graphics/engine/modelfile.cpp841
-rw-r--r--src/graphics/engine/modelfile.h120
-rw-r--r--src/graphics/engine/particle.cpp (renamed from src/graphics/common/particle.cpp)2
-rw-r--r--src/graphics/engine/particle.h (renamed from src/graphics/common/particle.h)107
-rw-r--r--src/graphics/engine/planet.cpp (renamed from src/graphics/common/planet.cpp)2
-rw-r--r--src/graphics/engine/planet.h (renamed from src/graphics/common/planet.h)0
-rw-r--r--src/graphics/engine/pyro.cpp (renamed from src/graphics/common/pyro.cpp)2
-rw-r--r--src/graphics/engine/pyro.h (renamed from src/graphics/common/pyro.h)2
-rw-r--r--src/graphics/engine/terrain.cpp (renamed from src/graphics/common/terrain.cpp)2
-rw-r--r--src/graphics/engine/terrain.h (renamed from src/graphics/common/terrain.h)2
-rw-r--r--src/graphics/engine/test/CMakeLists.txt7
-rw-r--r--src/graphics/engine/test/modelfile_test.cpp48
-rw-r--r--src/graphics/engine/text.cpp (renamed from src/graphics/common/text.cpp)2
-rw-r--r--src/graphics/engine/text.h (renamed from src/graphics/common/text.h)8
-rw-r--r--src/graphics/engine/water.cpp (renamed from src/graphics/common/water.cpp)2
-rw-r--r--src/graphics/engine/water.h (renamed from src/graphics/common/water.h)8
-rw-r--r--src/graphics/opengl/README.txt4
-rw-r--r--src/graphics/opengl/gldevice.cpp1146
-rw-r--r--src/graphics/opengl/gldevice.h172
-rw-r--r--src/graphics/opengl/glengine.cpp21
-rw-r--r--src/graphics/opengl/glengine.h32
-rw-r--r--src/graphics/opengl/test/CMakeLists.txt87
-rw-r--r--src/graphics/opengl/test/README.txt9
-rw-r--r--src/graphics/opengl/test/light_test.cpp437
-rw-r--r--src/graphics/opengl/test/model_test.cpp377
-rw-r--r--src/graphics/opengl/test/tex1.pngbin0 -> 151263 bytes
-rw-r--r--src/graphics/opengl/test/tex2.pngbin0 -> 57503 bytes
-rw-r--r--src/graphics/opengl/test/texture_test.cpp193
-rw-r--r--src/graphics/opengl/test/transform_test.cpp339
-rw-r--r--src/math/func.h28
-rw-r--r--src/math/geometry.h141
-rw-r--r--src/math/matrix.h20
-rw-r--r--src/math/point.h22
-rw-r--r--src/math/vector.h35
-rw-r--r--src/sound/sound.h1
91 files changed, 9517 insertions, 3194 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d7bd0bf..da8463b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -5,6 +5,8 @@ add_subdirectory(CBot)
# Configure options
option(DEBUG "Enable debug output" ON)
+set(PLATFORM_LIBS "")
+
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(PLATFORM_WINDOWS 1)
set(PLATFORM_LINUX 0)
@@ -13,6 +15,8 @@ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(PLATFORM_WINDOWS 0)
set(PLATFORM_LINUX 1)
set(PLATFORM_OTHER 0)
+ # for clock_gettime
+ set(PLATFORM_LIBS "-lrt")
else()
set(PLATFORM_WINDOWS 0)
set(PLATFORM_LINUX 0)
@@ -31,6 +35,7 @@ app/app.cpp
app/main.cpp
app/system.cpp
common/event.cpp
+common/image.cpp
common/logger.cpp
common/iman.cpp
# common/metafile.cpp
@@ -38,23 +43,21 @@ common/iman.cpp
# common/modfile.cpp
# common/profile.cpp
# common/restext.cpp
-graphics/common/camera.cpp
-graphics/common/cloud.cpp
-graphics/common/color.cpp
-graphics/common/device.cpp
-graphics/common/engine.cpp
-graphics/common/light.cpp
-graphics/common/lightning.cpp
-graphics/common/model.cpp
-graphics/common/modfile.cpp
-graphics/common/particle.cpp
-graphics/common/planet.cpp
-graphics/common/pyro.cpp
-graphics/common/terrain.cpp
-graphics/common/text.cpp
-graphics/common/water.cpp
+common/stringutils.cpp
+graphics/core/color.cpp
+graphics/engine/camera.cpp
+graphics/engine/cloud.cpp
+graphics/engine/engine.cpp
+graphics/engine/lightman.cpp
+graphics/engine/lightning.cpp
+graphics/engine/modelfile.cpp
+graphics/engine/particle.cpp
+graphics/engine/planet.cpp
+graphics/engine/pyro.cpp
+graphics/engine/terrain.cpp
+graphics/engine/text.cpp
+graphics/engine/water.cpp
graphics/opengl/gldevice.cpp
-graphics/opengl/glengine.cpp
# object/auto/auto.cpp
# object/auto/autobase.cpp
# object/auto/autoconvert.cpp
@@ -152,10 +155,17 @@ set(LIBS
${SDL_LIBRARY}
${SDLIMAGE_LIBRARY}
${OPENGL_LIBRARY}
+${PNG_LIBRARIES}
+${PLATFORM_LIBS}
CBot
)
-include_directories(. ${CMAKE_CURRENT_BINARY_DIR})
+include_directories(. ${CMAKE_CURRENT_BINARY_DIR}
+${SDL_INCLUDE_DIR}
+${SDL_IMAGE_INCLUDE_DIR}
+${SDLTTF_INCLUDE_DIR}
+${PNG_INCLUDE_DIRS}
+)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/CBot)
diff --git a/src/app/app.cpp b/src/app/app.cpp
index 68131fc..c778a63 100644
--- a/src/app/app.cpp
+++ b/src/app/app.cpp
@@ -20,12 +20,27 @@
#include "app/app.h"
#include "app/system.h"
+#include "common/logger.h"
#include "common/iman.h"
+#include "common/image.h"
+#include "graphics/opengl/gldevice.h"
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
+#include <stdio.h>
+
+
+template<> CApplication* CSingleton<CApplication>::mInstance = NULL;
+
+
+//! Interval of timer called to update joystick state
+const int JOYSTICK_TIMER_INTERVAL = 1000/30;
+
+//! Function called by the timer
+Uint32 JoystickTimerCallback(Uint32 interval, void *);
+
/**
* \struct ApplicationPrivate
@@ -42,57 +57,57 @@ struct ApplicationPrivate
//! Joystick
SDL_Joystick *joystick;
//! Index of joystick device
- int joystickDevice;
+ int joystickIndex;
+ //! Id of joystick timer
+ SDL_TimerID joystickTimer;
+ //! Current configuration of OpenGL display device
+ Gfx::GLDeviceConfig deviceConfig;
ApplicationPrivate()
{
memset(&currentEvent, 0, sizeof(SDL_Event));
surface = NULL;
joystick = NULL;
- joystickDevice = 0;
+ joystickIndex = 0;
+ joystickTimer = 0;
}
};
+
CApplication::CApplication()
{
m_private = new ApplicationPrivate();
m_exitCode = 0;
m_iMan = new CInstanceManager();
- m_event = new CEvent(m_iMan);
- m_engine = 0;
- m_robotMain = 0;
- m_sound = 0;
+ m_eventQueue = new CEventQueue(m_iMan);
+
+ m_engine = NULL;
+ m_device = NULL;
+ m_robotMain = NULL;
+ m_sound = NULL;
m_keyState = 0;
m_axeKey = Math::Vector(0.0f, 0.0f, 0.0f);
m_axeJoy = Math::Vector(0.0f, 0.0f, 0.0f);
- m_vidMemTotal = 0;
- m_active = false;
- m_activateApp = false;
- m_ready = false;
- m_joystick = false;
- m_time = 0.0f;
+ m_active = false;
+ m_activateApp = false;
+ m_ready = false;
+ m_joystickEnabled = false;
- for (int i = 0; i < 32; i++)
- {
- m_joyButton[i] = false;
- }
+ m_time = 0.0f;
m_windowTitle = "COLOBOT";
- m_appUseZBuffer = true;
- m_appUseStereo = true;
m_showStats = false;
m_debugMode = false;
- m_audioState = true;
- m_audioTrack = true;
- m_niceMouse = false;
m_setupMode = true;
+ m_dataPath = "./data";
+
ResetKey();
}
@@ -101,91 +116,102 @@ CApplication::~CApplication()
delete m_private;
m_private = NULL;
+ delete m_eventQueue;
+ m_eventQueue = NULL;
+
delete m_iMan;
m_iMan = NULL;
}
-Error CApplication::ParseArguments(int argc, char *argv[])
+bool CApplication::ParseArguments(int argc, char *argv[])
{
+ bool waitDataDir = false;
+
for (int i = 1; i < argc; ++i)
{
std::string arg = argv[i];
+ if (waitDataDir)
+ {
+ waitDataDir = false;
+ m_dataPath = arg;
+ }
+
if (arg == "-debug")
{
m_showStats = true;
SetDebugMode(true);
}
- else if (arg == "-audiostate")
+ else if (arg == "-datadir")
{
- m_audioState = false;
+ waitDataDir = true;
}
- else if (arg == "-audiotrack")
+ else
{
- m_audioTrack = false;
+ m_exitCode = 1;
+ return false;
}
- // TODO else {} report invalid argument
}
- return ERR_OK;
+ // Data dir not given?
+ if (waitDataDir)
+ return false;
+
+ return true;
}
bool CApplication::Create()
{
-/*
-TODO
- Full screen by default unless in debug mode
- if (! m_debugMode)
- m_deviceConfig.fullScreen = true;
-
- int full = 0;
- if (GetProfileInt("Device", "FullScreen", full))
- m_deviceConfig.fullScreen = full == 1;
-*/
+ // TODO: verify that data directory exists
// Temporarily -- only in windowed mode
- m_deviceConfig.fullScreen = false;
+ m_private->deviceConfig.fullScreen = false;
-/*
-TODO
- // Create the 3D engine.
- m_engine = new CEngine(m_iMan, this);
+ // Create the 3D engine
+ m_engine = new Gfx::CEngine(m_iMan, this);
- // Initialize the app's custom scene stuff
- if (! m_engine->OneTimeSceneInit())
- {
- SystemDialog(SDT_ERROR, "COLOBOT - Error", m_engine->RetError());
- return false;
- }
- // Create the sound instance.
+/* // Create the sound instance.
m_sound = new CSound(m_iMan);
// Create the robot application.
- m_robotMain = new CRobotMain(m_iMan);
-*/
+ m_robotMain = new CRobotMain(m_iMan); */
- Uint32 initFlags = SDL_INIT_VIDEO;
- if (m_joystick)
- initFlags |= SDL_INIT_JOYSTICK;
+
+ /* SDL initialization sequence */
+
+
+ Uint32 initFlags = SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_TIMER;
if (SDL_Init(initFlags) < 0)
{
- SystemDialog( SDT_ERROR, "COLOBOT - Error", "SDL initialization error:\n" + std::string(SDL_GetError()) );
+ SystemDialog( SDT_ERROR, "COLOBOT - Error", "SDL initialization error:\n" +
+ std::string(SDL_GetError()) );
+ m_exitCode = 2;
+ return false;
+ }
+
+ if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) == 0)
+ {
+ SystemDialog( SDT_ERROR, "COLOBOT - Error", std::string("SDL_Image initialization error:\n") +
+ std::string(IMG_GetError()) );
+ m_exitCode = 3;
return false;
}
const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
- if (! videoInfo)
+ if (videoInfo == NULL)
{
- SystemDialog( SDT_ERROR, "COLOBOT - Error", "SDL error while getting video info:\n " + std::string(SDL_GetError()) );
+ SystemDialog( SDT_ERROR, "COLOBOT - Error", "SDL error while getting video info:\n " +
+ std::string(SDL_GetError()) );
+ m_exitCode = 2;
return false;
}
Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
- if (m_deviceConfig.resizeable)
+ if (m_private->deviceConfig.resizeable)
videoFlags |= SDL_RESIZABLE;
// Use hardware surface if available
@@ -198,68 +224,77 @@ TODO
if (videoInfo->blit_hw)
videoFlags |= SDL_HWACCEL;
- if (m_deviceConfig.fullScreen)
+ if (m_private->deviceConfig.fullScreen)
videoFlags |= SDL_FULLSCREEN;
- SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+ // Set OpenGL attributes
- SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
- SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, m_private->deviceConfig.redSize);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, m_private->deviceConfig.greenSize);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, m_private->deviceConfig.blueSize);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, m_private->deviceConfig.alphaSize);
- if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) == 0)
- {
- SystemDialog( SDT_ERROR, "COLOBOT - Error", std::string("SDL_Image initialization error:\n") +
- std::string(IMG_GetError()) );
- return false;
- }
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, m_private->deviceConfig.depthSize);
- m_private->surface = SDL_SetVideoMode(m_deviceConfig.width, m_deviceConfig.height,
- m_deviceConfig.bpp, videoFlags);
+ if (m_private->deviceConfig.doubleBuf)
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
- if (! m_private->surface)
+ /* If hardware acceleration specifically requested, this will force the hw accel
+ and fail with error if not available */
+ if (m_private->deviceConfig.hardwareAccel)
+ SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
+
+ m_private->surface = SDL_SetVideoMode(m_private->deviceConfig.width, m_private->deviceConfig.height,
+ m_private->deviceConfig.bpp, videoFlags);
+
+ if (m_private->surface == NULL)
{
SystemDialog( SDT_ERROR, "COLOBT - Error", std::string("SDL error while setting video mode:\n") +
std::string(SDL_GetError()) );
+ m_exitCode = 2;
return false;
}
SDL_WM_SetCaption(m_windowTitle.c_str(), m_windowTitle.c_str());
+ // Enable translating key codes of key press events to unicode chars
SDL_EnableUNICODE(1);
+ // Don't generate joystick events
+ SDL_JoystickEventState(SDL_IGNORE);
+
-/*
-TODO
+ // For now, enable joystick for testing
+ SetJoystickEnabled(true);
- InitJoystick();
- if ( !GetProfileInt("Setup", "Sound3D", b3D) )
+ // The video is ready, we can create and initalize the graphics device
+ m_device = new Gfx::CGLDevice();
+ if (! m_device->Create() )
{
- b3D = true;
+ SystemDialog( SDT_ERROR, "COLOBT - Error", std::string("Error in CDevice::Create() :\n") +
+ std::string(m_device->GetError()) );
+ m_exitCode = 1;
+ return false;
}
- m_pSound->SetDebugMode(m_bDebugMode);
- m_pSound->Create(m_hWnd, b3D);
- m_pSound->CacheAll();
- m_pSound->SetState(m_bAudioState);
- m_pSound->SetAudioTrack(m_bAudioTrack);
- m_pSound->SetCDpath(m_CDpath);
-
- // First execution?
- if ( !GetProfileInt("Setup", "ObjectDirty", iValue) )
+
+ m_engine->SetDevice(m_device);
+ if (! m_engine->Create() )
{
- m_pD3DEngine->FirstExecuteAdapt(true);
+ SystemDialog( SDT_ERROR, "COLOBT - Error", std::string("Error in CEngine::Create() :\n") +
+ std::string(m_engine->GetError()) );
+ m_exitCode = 1;
+ return false;
}
- // Creates the file colobot.ini at the first execution.
- m_pRobotMain->CreateIni();
-
- m_pRobotMain->ChangePhase(PHASE_WELCOME2);
+ if (! m_engine->AfterDeviceSetInit() )
+ {
+ SystemDialog( SDT_ERROR, "COLOBT - Error", std::string("Error in CEngine::AfterDeviceSetInit() :\n") +
+ std::string(m_engine->GetError()) );
+ m_exitCode = 1;
+ return false;
+ }
- m_engine->TimeInit();
-*/
// The app is ready to go
m_ready = true;
@@ -269,66 +304,222 @@ TODO
void CApplication::Destroy()
{
+ /*if (m_robotMain != NULL)
+ {
+ delete m_robotMain;
+ m_robotMain = NULL;
+ }
+
+ if (m_sound != NULL)
+ {
+ delete m_sound;
+ m_sound = NULL;
+ }*/
+
+ if (m_engine != NULL)
+ {
+ if (m_engine->GetWasInit())
+ m_engine->Destroy();
+
+ delete m_engine;
+ m_engine = NULL;
+ }
+
+ if (m_device != NULL)
+ {
+ if (m_device->GetWasInit())
+ m_device->Destroy();
+
+ delete m_device;
+ m_device = NULL;
+ }
+
if (m_private->joystick != NULL)
{
SDL_JoystickClose(m_private->joystick);
m_private->joystick = NULL;
}
- SDL_FreeSurface(m_private->surface);
- m_private->surface = NULL;
+ if (m_private->surface != NULL)
+ {
+ SDL_FreeSurface(m_private->surface);
+ m_private->surface = NULL;
+ }
IMG_Quit();
SDL_Quit();
}
-int CApplication::Run()
+bool CApplication::OpenJoystick()
{
- m_active = true;
+ m_private->joystick = SDL_JoystickOpen(m_private->joystickIndex);
+ if (m_private->joystick == NULL)
+ return false;
+
+ // Create the vectors with joystick axis & button states to exactly the required size
+ m_joyAxeState = std::vector<int>(SDL_JoystickNumAxes(m_private->joystick), 0);
+ m_joyButtonState = std::vector<bool>(SDL_JoystickNumButtons(m_private->joystick), false);
+
+ // Create a timer for polling joystick state
+ m_private->joystickTimer = SDL_AddTimer(JOYSTICK_TIMER_INTERVAL, JoystickTimerCallback, NULL);
+
+ return true;
+}
+
- while (m_private->currentEvent.type != SDL_QUIT)
+void CApplication::CloseJoystick()
+{
+ // Timer will remove itself automatically
+
+ SDL_JoystickClose(m_private->joystick);
+ m_private->joystick = NULL;
+}
+
+Uint32 JoystickTimerCallback(Uint32 interval, void *)
+{
+ CApplication *app = CApplication::GetInstancePointer();
+ if ((app == NULL) || (! app->GetJoystickEnabled()))
+ return 0; // don't run the timer again
+
+ app->UpdateJoystick();
+
+ return interval; // run for the same interval again
+}
+
+/** Updates the state info in CApplication and on change, creates SDL events and pushes them to SDL event queue.
+ This way, the events get handled properly in the main event loop and besides, SDL_PushEvent() ensures thread-safety. */
+void CApplication::UpdateJoystick()
+{
+ if (! m_joystickEnabled)
+ return;
+
+ SDL_JoystickUpdate();
+
+ for (int axis = 0; axis < (int) m_joyAxeState.size(); ++axis)
{
- // Use SDL_PeepEvents() if the app is active, so we can use idle time to
- // render the scene. Else, use SDL_PollEvent() to avoid eating CPU time.
- int count = 0;
- if (m_active)
+ int newValue = SDL_JoystickGetAxis(m_private->joystick, axis);
+
+ if (m_joyAxeState[axis] != newValue)
{
- SDL_PumpEvents();
- count = SDL_PeepEvents(&m_private->currentEvent, 1, SDL_GETEVENT, SDL_ALLEVENTS);
+ m_joyAxeState[axis] = newValue;
+
+ SDL_Event joyAxisEvent;
+
+ joyAxisEvent.jaxis.type = SDL_JOYAXISMOTION;
+ joyAxisEvent.jaxis.which = 0;
+ joyAxisEvent.jaxis.axis = axis;
+ joyAxisEvent.jaxis.value = newValue;
+
+ SDL_PushEvent(&joyAxisEvent);
}
- else
+ }
+
+ for (int button = 0; button < (int) m_joyButtonState.size(); ++button)
+ {
+ bool newValue = SDL_JoystickGetButton(m_private->joystick, button) == 1;
+
+ if (m_joyButtonState[button] != newValue)
{
- SDL_PollEvent(&m_private->currentEvent);
+ m_joyButtonState[button] = newValue;
+
+ SDL_Event joyButtonEvent;
+
+ if (newValue)
+ {
+ joyButtonEvent.jbutton.type = SDL_JOYBUTTONDOWN;
+ joyButtonEvent.jbutton.state = SDL_PRESSED;
+ }
+ else
+ {
+ joyButtonEvent.jbutton.type = SDL_JOYBUTTONUP;
+ joyButtonEvent.jbutton.state = SDL_RELEASED;
+ }
+ joyButtonEvent.jbutton.which = 0;
+ joyButtonEvent.jbutton.button = button;
+
+ SDL_PushEvent(&joyButtonEvent);
}
+ }
+}
+
+int CApplication::Run()
+{
+ m_active = true;
+
+ while (true)
+ {
+ // To be sure no old event remains
+ m_private->currentEvent.type = SDL_NOEVENT;
- // If received an event
- if ((m_active && count > 0) || (!m_active))
+ if (m_active)
+ SDL_PumpEvents();
+
+ bool haveEvent = true;
+ while (haveEvent)
{
- ParseEvent();
+ haveEvent = false;
+
+ int count = 0;
+ // Use SDL_PeepEvents() if the app is active, so we can use idle time to
+ // render the scene. Else, use SDL_PollEvent() to avoid eating CPU time.
+ if (m_active)
+ count = SDL_PeepEvents(&m_private->currentEvent, 1, SDL_GETEVENT, SDL_ALLEVENTS);
+ else
+ count = SDL_PollEvent(&m_private->currentEvent);
+
+ // If received an event
+ if (count > 0)
+ {
+ haveEvent = true;
+
+ Event event = ParseEvent();
+
+ if (event.type == EVENT_QUIT)
+ goto end; // exit the loop
+
+ if (event.type != EVENT_NULL)
+ {
+ bool passOn = ProcessEvent(event);
+
+ if (m_engine != NULL && passOn)
+ passOn = m_engine->ProcessEvent(event);
+
+ if (passOn)
+ m_eventQueue->AddEvent(event);
+ }
+ }
}
- // Render a frame during idle time (no messages are waiting)
+ // Enter game update & frame rendering only if active
if (m_active && m_ready)
{
Event event;
- while (m_event->GetEvent(event))
+ while (m_eventQueue->GetEvent(event))
{
- if (event.event == EVENT_QUIT)
- {
+ if (event.type == EVENT_QUIT)
goto end; // exit both loops
+
+ bool passOn = true;
+
+ // Skip system events (they have been processed earlier)
+ if (! event.systemEvent)
+ {
+ passOn = ProcessEvent(event);
+
+ if (passOn && m_engine != NULL)
+ passOn = m_engine->ProcessEvent(event);
}
- //m_robotMain->EventProcess(event);
+ /*if (passOn && m_robotMain != NULL)
+ m_robotMain->ProcessEvent(event); */
}
- //if ( !RetNiceMouse())
- //{
- // SetMouseType(m_engine->RetMouseType());
- //}
+ // Update game and render a frame during idle time (no messages are waiting)
+ bool ok = Render();
// If an error occurs, push quit event to the queue
- if (! Render())
+ if (! ok)
{
SDL_Event quitEvent;
memset(&quitEvent, 0, sizeof(SDL_Event));
@@ -339,7 +530,6 @@ int CApplication::Run()
}
end:
- //m_sound->StopMusic();
Destroy();
return m_exitCode;
@@ -350,74 +540,181 @@ int CApplication::GetExitCode()
return m_exitCode;
}
-void CApplication::ParseEvent()
+//! Translates SDL press state to PressState
+PressState TranslatePressState(unsigned char state)
{
-/* Event event;
+ if (state == SDL_PRESSED)
+ return STATE_PRESSED;
+ else
+ return STATE_RELEASED;
+}
- if (m_private->currentEvent.type == SDL_MOUSEBUTTONDOWN)
+/** 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( (float)pos.x / (float)m_private->deviceConfig.width,
+ 1.0f - (float)pos.y / (float)m_private->deviceConfig.height);
+}
+
+Math::IntPoint CApplication::InterfaceToWindowCoords(Math::Point pos)
+{
+ return Math::IntPoint((int)(pos.x * m_private->deviceConfig.width),
+ (int)((1.0f - pos.y) * m_private->deviceConfig.height));
+}
+
+/** 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()
+{
+ Event event;
+
+ event.systemEvent = true;
+
+ if (m_private->currentEvent.type == SDL_QUIT)
{
- if (m_private->currentEvent.button.button == SDL_BUTTON_LEFT)
- event.event = EVENT_LBUTTONDOWN;
- else if (m_private->currentEvent.button.button == SDL_BUTTON_RIGHT)
- event.event = EVENT_RBUTTONDOWN;
+ event.type = EVENT_QUIT;
}
- else if (m_private->currentEvent.type == SDL_MOUSEBUTTONUP)
+ else if ( (m_private->currentEvent.type == SDL_KEYDOWN) ||
+ (m_private->currentEvent.type == SDL_KEYUP) )
{
- if (m_private->currentEvent.button.button == SDL_BUTTON_LEFT)
- event.event = EVENT_LBUTTONUP;
- else if (m_private->currentEvent.button.button == SDL_BUTTON_RIGHT)
- event.event = EVENT_RBUTTONUP;
+ if (m_private->currentEvent.type == SDL_KEYDOWN)
+ event.type = EVENT_KEY_DOWN;
+ else
+ event.type = EVENT_KEY_UP;
+
+ event.key.key = m_private->currentEvent.key.keysym.sym;
+ event.key.mod = m_private->currentEvent.key.keysym.mod;
+ event.key.state = TranslatePressState(m_private->currentEvent.key.state);
+ event.key.unicode = m_private->currentEvent.key.keysym.unicode;
}
- else if (m_private->currentEvent.type == SDL_MOUSEMOTION)
+ else if ( (m_private->currentEvent.type == SDL_MOUSEBUTTONDOWN) ||
+ (m_private->currentEvent.type == SDL_MOUSEBUTTONUP) )
{
- event.event = EVENT_MOUSEMOVE;
+ if (m_private->currentEvent.type == SDL_MOUSEBUTTONDOWN)
+ event.type = EVENT_MOUSE_BUTTON_DOWN;
+ else
+ event.type = EVENT_MOUSE_BUTTON_UP;
+
+ 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));
}
- else if (m_private->currentEvent.type == SDL_KEYDOWN)
+ else if (m_private->currentEvent.type == SDL_MOUSEMOTION)
{
- event.event = EVENT_KEYDOWN;
+ 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));
}
- else if (m_private->currentEvent.type == SDL_KEYUP)
+ else if (m_private->currentEvent.type == SDL_JOYAXISMOTION)
{
- event.event = EVENT_KEYUP;
- }
+ event.type = EVENT_JOY_AXIS;
- if (m_robotMain != NULL && event.event != EVENT_NULL)
- {
- m_robotMain->EventProcess(event);
+ event.joyAxis.axis = m_private->currentEvent.jaxis.axis;
+ event.joyAxis.value = m_private->currentEvent.jaxis.value;
}
- if (m_engine != NULL)
+ else if ( (m_private->currentEvent.type == SDL_JOYBUTTONDOWN) ||
+ (m_private->currentEvent.type == SDL_JOYBUTTONUP) )
{
- m_engine->MsgProc( hWnd, uMsg, wParam, lParam );
+ if (m_private->currentEvent.type == SDL_JOYBUTTONDOWN)
+ event.type = EVENT_JOY_BUTTON_DOWN;
+ else
+ event.type = EVENT_JOY_BUTTON_UP;
+
+ event.joyButton.button = m_private->currentEvent.jbutton.button;
+ event.joyButton.state = TranslatePressState(m_private->currentEvent.jbutton.state);
}
- ProcessEvent(event);*/
+ return event;
}
-void CApplication::ProcessEvent(Event event)
+/** Processes incoming events. It is the first function called after an event is captures.
+ Function returns \c true if the event is to be passed on to other processing functions
+ or \c false if not. */
+bool CApplication::ProcessEvent(const Event &event)
{
+ CLogger *l = GetLogger();
+ // Print the events in debug mode to test the code
+ if (m_debugMode)
+ {
+ switch (event.type)
+ {
+ case EVENT_KEY_DOWN:
+ case EVENT_KEY_UP:
+ l->Info("EVENT_KEY_%s:\n", (event.type == EVENT_KEY_DOWN) ? "DOWN" : "UP");
+ l->Info(" key = %4x\n", event.key.key);
+ l->Info(" state = %s\n", (event.key.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED");
+ l->Info(" mod = %4x\n", event.key.mod);
+ l->Info(" unicode = %4x\n", event.key.unicode);
+ break;
+ case EVENT_MOUSE_MOVE:
+ l->Info("EVENT_MOUSE_MOVE:\n");
+ l->Info(" state = %s\n", (event.mouseMove.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED");
+ l->Info(" pos = (%f, %f)\n", event.mouseMove.pos.x, event.mouseMove.pos.y);
+ break;
+ case EVENT_MOUSE_BUTTON_DOWN:
+ case EVENT_MOUSE_BUTTON_UP:
+ l->Info("EVENT_MOUSE_BUTTON_%s:\n", (event.type == EVENT_MOUSE_BUTTON_DOWN) ? "DOWN" : "UP");
+ l->Info(" button = %d\n", event.mouseButton.button);
+ l->Info(" state = %s\n", (event.mouseButton.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED");
+ l->Info(" pos = (%f, %f)\n", event.mouseButton.pos.x, event.mouseButton.pos.y);
+ break;
+ case EVENT_JOY_AXIS:
+ l->Info("EVENT_JOY_AXIS:\n");
+ l->Info(" axis = %d\n", event.joyAxis.axis);
+ l->Info(" value = %d\n", event.joyAxis.value);
+ break;
+ case EVENT_JOY_BUTTON_DOWN:
+ case EVENT_JOY_BUTTON_UP:
+ l->Info("EVENT_JOY_BUTTON_%s:\n", (event.type == EVENT_JOY_BUTTON_DOWN) ? "DOWN" : "UP");
+ l->Info(" button = %d\n", event.joyButton.button);
+ l->Info(" state = %s\n", (event.joyButton.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED");
+ break;
+ default:
+ break;
+ }
+ }
+ // By default, pass on all events
+ return true;
}
+/** Renders the frame and swaps buffers as necessary. Returns \c false on error. */
bool CApplication::Render()
{
bool result = m_engine->Render();
if (! result)
return false;
- if (m_deviceConfig.doubleBuf)
+ if (m_private->deviceConfig.doubleBuf)
SDL_GL_SwapBuffers();
return true;
}
+/** Called in to toggle the pause state of the app. */
void CApplication::Pause(bool pause)
{
- // TODO
-}
+ static long appPausedCount = 0L;
-void CApplication::SetMousePos(Math::Point pos)
-{
- // TODO
+ appPausedCount += ( pause ? +1 : -1 );
+ m_ready = appPausedCount == 0;
+
+ // Handle the first pause request (of many, nestable pause requests)
+ if( pause && ( 1 == appPausedCount ) )
+ {
+ // Stop the scene from animating
+ //m_engine->TimeEnterGel();
+ }
+
+ // Final pause request done
+ if (appPausedCount == 0)
+ {
+ // Restart the scene
+ //m_engine->TimeExitGel();
+ }
}
void CApplication::StepSimulation(float rTime)
@@ -425,32 +722,29 @@ void CApplication::StepSimulation(float rTime)
// TODO
}
-void SetShowStat(bool show)
+void CApplication::SetShowStat(bool show)
{
- // TODO
+ m_showStats = show;
}
-bool CApplication::RetShowStat()
+bool CApplication::GetShowStat()
{
- // TODO
- return false;
+ return m_showStats;
}
void CApplication::SetDebugMode(bool mode)
{
- // TODO
+ m_debugMode = mode;
}
-bool CApplication::RetDebugMode()
+bool CApplication::GetDebugMode()
{
- // TODO
- return false;
+ return m_debugMode;
}
-bool CApplication::RetSetupMode()
+bool CApplication::GetSetupMode()
{
- // TODO
- return false;
+ return m_setupMode;
}
void CApplication::FlushPressKey()
@@ -468,46 +762,73 @@ void CApplication::SetKey(int keyRank, int option, int key)
// TODO
}
-int CApplication::RetKey(int keyRank, int option)
+int CApplication::GetKey(int keyRank, int option)
{
// TODO
return 0;
}
-void CApplication::SetJoystick(bool enable)
+void CApplication::SetGrabInput(bool grab)
{
- // TODO
+ SDL_WM_GrabInput(grab ? SDL_GRAB_ON : SDL_GRAB_OFF);
}
-bool CApplication::RetJoystick()
+bool CApplication::GetGrabInput()
{
- // TODO
- return false;
+ int result = SDL_WM_GrabInput(SDL_GRAB_QUERY);
+ return result == SDL_GRAB_ON;
}
-void SetMouseType(Gfx::MouseType type)
+void CApplication::SetSystemMouseVisible(bool visible)
{
- // TODO
+ SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE);
}
-void SetNiceMouse(bool nice)
+bool CApplication::GetSystemMouseVisibile()
{
- // TODO
+ int result = SDL_ShowCursor(SDL_QUERY);
+ return result == SDL_ENABLE;
}
-bool CApplication::RetNiceMouse()
+
+void CApplication::SetSystemMousePos(Math::Point pos)
{
- return false;
+ Math::IntPoint windowPos = InterfaceToWindowCoords(pos);
+ SDL_WarpMouse(windowPos.x, windowPos.y);
+ m_systemMousePos = pos;
}
-bool CApplication::RetNiceMouseCap()
+Math::Point CApplication::GetSystemMousePos()
{
- return false;
+ return m_systemMousePos;
+}
+
+void CApplication::SetJoystickEnabled(bool enable)
+{
+ m_joystickEnabled = enable;
+
+ if (m_joystickEnabled)
+ {
+ if (! OpenJoystick())
+ {
+ m_joystickEnabled = false;
+ }
+ }
+ else
+ {
+ CloseJoystick();
+ }
+}
+
+bool CApplication::GetJoystickEnabled()
+{
+ return m_joystickEnabled;
}
bool CApplication::WriteScreenShot(char *filename, int width, int height)
{
// TODO
+ return false;
}
void CApplication::InitText()
@@ -529,3 +850,8 @@ void CApplication::OutputText(long x, long y, char* str)
{
// TODO
}
+
+std::string CApplication::GetDataFilePath(const std::string& dirName, const std::string& fileName)
+{
+ return m_dataPath + "/" + dirName + "/" + fileName;
+}
diff --git a/src/app/app.h b/src/app/app.h
index f776b10..956eab8 100644
--- a/src/app/app.h
+++ b/src/app/app.h
@@ -21,10 +21,12 @@
#include "common/misc.h"
-#include "graphics/common/device.h"
-#include "graphics/common/engine.h"
+#include "common/singleton.h"
+#include "graphics/core/device.h"
+#include "graphics/engine/engine.h"
#include <string>
+#include <vector>
class CInstanceManager;
@@ -32,19 +34,41 @@ class CEvent;
class CRobotMain;
class CSound;
-struct ApplicationPrivate;
+struct ApplicationPrivate;
/**
* \class CApplication
* \brief Main application
*
- * This class is responsible for creating and handling main application window,
- * receiving events, etc.
+ * This class is responsible for main application execution, including creating
+ * and handling main application window, receiving events, etc.
+ *
+ * It is a singleton class with only one instance that can be created.
+ *
+ * Creation of other main objects
+ *
+ * The class creates the only instance of CInstanceManager, CEventQueue, CEngine,
+ * CRobotMain and CSound classes.
+ *
+ * Window management
+ *
+ * The class is responsible for creating app window, setting and changing the video mode,
+ * setting the position of mouse and changing the cursor, grabbing and writing screenshots.
+ *
+ * Events
+ *
+ * Events are taken from SDL event queue and either handled by CApplication or translated
+ * to common events from src/common.h and pushed to global event queue CEventQueue.
+ * Joystick events are generated somewhat differently, by running a separate timer,
+ * polling the device for changes and synthesising events on change. It avoids flooding
+ * the event queue with too many joystick events and the granularity of the timer can be
+ * adjusted.
+ *
+ * The events are further handled in CRobotMain class.
*
- * ...
*/
-class CApplication
+class CApplication : public CSingleton<CApplication>
{
public:
//! Constructor (can only be called once!)
@@ -54,61 +78,79 @@ public:
public:
//! Parses commandline arguments
- Error ParseArguments(int argc, char *argv[]);
+ bool ParseArguments(int argc, char *argv[]);
//! Initializes the application
bool Create();
//! Main event loop
int Run();
-
//! Returns the code to be returned at main() exit
int GetExitCode();
-protected:
//! Cleans up before exit
void Destroy();
- //! Processes an SDL event to Event struct
- void ParseEvent();
- //! Handles some incoming events
- void ProcessEvent(Event event);
- //! Renders the image in window
- bool Render();
-public:
+ //! Enters the pause mode
void Pause(bool pause);
+
+ //! Updates the simulation state
void StepSimulation(float rTime);
- void SetMousePos(Math::Point pos);
+ //! Polls the state of joystick axes and buttons
+ void UpdateJoystick();
void SetShowStat(bool show);
- bool RetShowStat();
+ bool GetShowStat();
+
void SetDebugMode(bool mode);
- bool RetDebugMode();
- bool RetSetupMode();
+ bool GetDebugMode();
+
+ bool GetSetupMode();
+
+ void SetJoystickEnabled(bool enable);
+ bool GetJoystickEnabled();
void FlushPressKey();
void ResetKey();
void SetKey(int keyRank, int option, int key);
- int RetKey(int keyRank, int option);
+ int GetKey(int keyRank, int option);
+
+ //! Sets the grab mode for input (keyboard & mouse)
+ void SetGrabInput(bool grab);
+ //! Returns the grab mode
+ bool GetGrabInput();
- void SetJoystick(bool enable);
- bool RetJoystick();
+ //! Sets the visiblity of system mouse cursor
+ void SetSystemMouseVisible(bool visible);
+ //! Returns the visiblity of system mouse cursor
+ bool GetSystemMouseVisibile();
- void SetMouseType(Gfx::MouseType type);
- void SetNiceMouse(bool nice);
- bool RetNiceMouse();
- bool RetNiceMouseCap();
+ //! Sets the position of system mouse cursor (in interface coords)
+ void SetSystemMousePos(Math::Point pos);
+ //! Returns the position of system mouse cursor (in interface coords)
+ Math::Point GetSystemMousePos();
bool WriteScreenShot(char *filename, int width, int height);
+ //! Returns the full path to a file in data directory
+ std::string GetDataFilePath(const std::string &dirName, const std::string &fileName);
+
protected:
- //HRESULT ConfirmDevice( DDCAPS* pddDriverCaps, D3DDEVICEDESC7* pd3dDeviceDesc );
- //HRESULT Initialize3DEnvironment();
- //HRESULT Change3DEnvironment();
- //HRESULT CreateZBuffer(GUID* pDeviceGUID);
- //HRESULT Render3DEnvironment();
- //VOID Cleanup3DEnvironment();
- //VOID DeleteDeviceObjects();
- //VOID DisplayFrameworkError( HRESULT, DWORD );
+ //! Processes the captured SDL event to Event struct
+ Event ParseEvent();
+ //! Handles some incoming events
+ bool ProcessEvent(const Event &event);
+ //! Renders the image in window
+ bool 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);
void InitText();
void DrawSuppl();
@@ -116,14 +158,20 @@ protected:
void OutputText(long x, long y, char* str);
protected:
+ //! Instance manager
+ CInstanceManager* m_iMan;
//! Private (SDL-dependent data)
ApplicationPrivate* m_private;
- CInstanceManager* m_iMan;
- Gfx::DeviceConfig m_deviceConfig;
+ //! Global event queue
+ CEventQueue* m_eventQueue;
+ //! Graphics engine
Gfx::CEngine* m_engine;
- CEvent* m_event;
- CRobotMain* m_robotMain;
+ //! Graphics device
+ Gfx::CDevice* m_device;
+ //! Sound subsystem
CSound* m_sound;
+ //! Main class of the proper game engine
+ CRobotMain* m_robotMain;
//! Code to return at exit
int m_exitCode;
@@ -131,27 +179,32 @@ protected:
bool m_active;
bool m_activateApp;
bool m_ready;
- bool m_joystick;
- std::string m_windowTitle;
- long m_vidMemTotal;
- bool m_appUseZBuffer;
- bool m_appUseStereo;
bool m_showStats;
bool m_debugMode;
- bool m_audioState;
- bool m_audioTrack;
- bool m_niceMouse;
bool m_setupMode;
+ //! Whether joystick is enabled
+ bool m_joystickEnabled;
+
+ //! Text set as window title
+ std::string m_windowTitle;
+
int m_keyState;
Math::Vector m_axeKey;
Math::Vector m_axeJoy;
- bool m_joyButton[32];
- Math::Point m_mousePos;
+ Math::Point m_systemMousePos;
long m_mouseWheel;
+ //! Current state of joystick axes; may be updated from another thread
+ std::vector<int> m_joyAxeState;
+ //! Current state of joystick buttons; may be updated from another thread
+ std::vector<bool> m_joyButtonState;
+
float m_time;
long m_key[50][2];
+
+ //! Path to directory with data files
+ std::string m_dataPath;
};
diff --git a/src/app/main.cpp b/src/app/main.cpp
index 151cd20..9eea6e4 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -24,6 +24,42 @@
#include "common/restext.h"
+/* Doxygen main page */
+
+/**
+
+\mainpage
+
+Doxygen documentation of Colobot project
+
+\section Intro Introduction
+
+The source code released by Epitec was sparsely documented. This documentation, written from scratch,
+will aim to describe the various components of the code.
+
+Currently, the only documented classes are the ones written from scratch or the old ones rewritten to match the new code.
+In time, the documentation will be extended to cover every major part of the code.
+
+\section Structure Code structure
+
+The source code was split from the original all-in-one directory to subdirectories, each containing one major part of the project.
+The current layout is this:
+ - src/CBot - separate library with CBot language
+ - src/app - class CApplication and everything concerned with SDL plus other system-dependent code such as displaying a message box, finding files, etc.
+ - src/common - shared structs, enums, defines, etc.; should not have any external dependencies
+ - src/graphics/common - interface of graphics engine (CEngine) and device (CDevice), without concrete implementation, shared structs such as Vertex, Material, etc., “effects” classes: CCamera, CLight, CParticle that will use the graphics engine interface
+ - src/graphics/opengl - concrete implementation of CEngine and CDevice classes in OpenGL: CGLEngine and CGLDevice
+ - src/graphics/d3d - in (far) future - perhaps a newer implementation in DirectX (9? 10?)
+ - src/math - mathematical structures and functions
+ - src/object - non-graphical game engine, that is robots, buildings, etc.; dependent only on interface of graphics engine, not on concrete implementation
+ - src/ui - 2D user interface (menu, buttons, check boxes, etc.); also without dependencies to concrete implementation of graphics engine
+ - src/sound - sound and music engine written using fmod library
+ - src/physics - physics engine
+ - src/script - link with the CBot library
+ - src/metafile - separate program for packing data files to .dat format
+*/
+
+
//! Entry point to the program
int main(int argc, char *argv[])
{
@@ -33,16 +69,17 @@ int main(int argc, char *argv[])
CApplication app; // single instance of the application
- Error err = app.ParseArguments(argc, argv);
- if (err != ERR_OK)
+ if (! app.ParseArguments(argc, argv))
{
SystemDialog(SDT_ERROR, "COLOBOT", "Invalid commandline arguments!\n");
+ return app.GetExitCode();
}
int code = 0;
if (! app.Create())
{
+ app.Destroy(); // ensure a clean exit
code = app.GetExitCode();
logger.Info("Didn't run main loop. Exiting with code %d\n", code);
return code;
diff --git a/src/app/system.cpp b/src/app/system.cpp
index a765e11..eb0321b 100644
--- a/src/app/system.cpp
+++ b/src/app/system.cpp
@@ -21,19 +21,21 @@
#include "common/config.h"
+
#if defined(PLATFORM_WINDOWS)
-#include <windows.h>
+#include "system_windows.h"
+
#elif defined(PLATFORM_LINUX)
-#include <cstdlib>
+#include "system_linux.h"
+
#else
-#include <iostream>
+#include "system_other.h"
+
#endif
+#include <cassert>
-SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message);
-SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message);
-SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message);
/**
* Displays a system dialog with info, error, question etc. message.
@@ -45,209 +47,103 @@ SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string&
*/
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message)
{
- #if defined(PLATFORM_WINDOWS)
+#if defined(PLATFORM_WINDOWS)
return SystemDialog_Windows(type, title, message);
- #elif defined(PLATFORM_LINUX)
+#elif defined(PLATFORM_LINUX)
return SystemDialog_Linux(type, title, message);
- #else
+#else
return SystemDialog_Other(type, title, message);
- #endif
+#endif
}
-
-
-#if defined(PLATFORM_WINDOWS)
-
-// Convert a wide Unicode string to an UTF8 string
-std::string UTF8_Encode_Windows(const std::wstring &wstr)
+SystemTimeStamp* CreateTimeStamp()
{
- int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
- std::string strTo(size_needed, 0);
- WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
- return strTo;
+ return new SystemTimeStamp();
}
-// Convert an UTF8 string to a wide Unicode String
-std::wstring UTF8_Decode_Windows(const std::string &str)
+void DestroyTimeStamp(SystemTimeStamp *stamp)
{
- int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
- std::wstring wstrTo(size_needed, 0);
- MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
- return wstrTo;
+ delete stamp;
}
-SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message)
+void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src)
{
- unsigned int windowsType = 0;
- std::wstring windowsMessage = UTF8_Decode_Windows(message);
- std::wstring windowsTitle = UTF8_Decode_Windows(title);
-
- switch (type)
- {
- case SDT_INFO:
- default:
- windowsType = MB_ICONINFORMATION|MB_OK;
- break;
- case SDT_WARNING:
- windowsType = MB_ICONWARNING|MB_OK;
- break;
- case SDT_ERROR:
- windowsType = MB_ICONERROR|MB_OK;
- break;
- case SDT_YES_NO:
- windowsType = MB_ICONQUESTION|MB_YESNO;
- break;
- case SDT_OK_CANCEL:
- windowsType = MB_ICONWARNING|MB_OKCANCEL;
- break;
- }
-
- switch (MessageBoxW(NULL, windowsMessage.c_str(), windowsTitle.c_str(), windowsType))
- {
- case IDOK:
- return SDR_OK;
- case IDCANCEL:
- return SDR_CANCEL;
- case IDYES:
- return SDR_YES;
- case IDNO:
- return SDR_NO;
- default:
- break;
- }
-
- return SDR_OK;
+ *dst = *src;
}
+void GetCurrentTimeStamp(SystemTimeStamp *stamp)
+{
+#if defined(PLATFORM_WINDOWS)
+ GetCurrentTimeStamp_Windows(stamp);
#elif defined(PLATFORM_LINUX)
+ GetCurrentTimeStamp_Linux(stamp);
+#else
+ GetCurrentTimeStamp_Other(stamp);
+#endif
+}
-SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message)
+float GetTimeStampResolution(SystemTimeUnit unit)
{
- std::string options = "";
- switch (type)
- {
- case SDT_INFO:
- default:
- options = "--info";
- break;
- case SDT_WARNING:
- options = "--warning";
- break;
- case SDT_ERROR:
- options = "--error";
- break;
- case SDT_YES_NO:
- options = "--question --ok-label=\"Yes\" --cancel-label=\"No\"";
- break;
- case SDT_OK_CANCEL:
- options = "--question --ok-label=\"OK\" --cancel-label=\"Cancel\"";
- break;
- }
-
- std::string command = "zenity " + options + " --text=\"" + message + "\" --title=\"" + title + "\"";
- int code = system(command.c_str());
-
- SystemDialogResult result = SDR_OK;
- switch (type)
- {
- case SDT_YES_NO:
- result = code ? SDR_NO : SDR_YES;
- break;
- case SDT_OK_CANCEL:
- result = code ? SDR_CANCEL : SDR_OK;
- break;
- default:
- break;
- }
-
+ unsigned long long exact = 0;
+#if defined(PLATFORM_WINDOWS)
+ exact = GetTimeStampExactResolution_Windows();
+#elif defined(PLATFORM_LINUX)
+ exact = GetTimeStampExactResolution_Linux();
+#else
+ exact = GetTimeStampExactResolution_Other();
+#endif
+ float result = 0.0f;
+ if (unit == STU_SEC)
+ result = exact * 1e-9;
+ else if (unit == STU_MSEC)
+ result = exact * 1e-6;
+ else if (unit == STU_USEC)
+ result = exact * 1e-3;
+ else
+ assert(false);
return result;
}
+long long GetTimeStampExactResolution()
+{
+#if defined(PLATFORM_WINDOWS)
+ return GetTimeStampExactResolution_Windows();
+#elif defined(PLATFORM_LINUX)
+ return GetTimeStampExactResolution_Linux();
#else
+ return GetTimeStampExactResolution_Other();
+#endif
+}
-SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message)
+float TimeStampDiff(SystemTimeStamp *before, SystemTimeStamp *after, SystemTimeUnit unit)
{
- switch (type)
- {
- case SDT_INFO:
- std::cout << "INFO: ";
- break;
- case SDT_WARNING:
- std::cout << "WARNING:";
- break;
- case SDT_ERROR:
- std::cout << "ERROR: ";
- break;
- case SDT_YES_NO:
- case SDT_OK_CANCEL:
- std::cout << "QUESTION: ";
- break;
- }
-
- std::cout << message << std::endl;
-
- std::string line;
-
- SystemDialogResult result = SDR_OK;
-
- bool done = false;
- while (!done)
- {
- switch (type)
- {
- case SDT_INFO:
- case SDT_WARNING:
- case SDT_ERROR:
- std::cout << "Press ENTER to continue";
- break;
-
- case SDT_YES_NO:
- std::cout << "Type 'Y' for Yes or 'N' for No";
- break;
-
- case SDT_OK_CANCEL:
- std::cout << "Type 'O' for OK or 'C' for Cancel";
- break;
- }
-
- std::getline(std::cin, line);
-
- switch (type)
- {
- case SDT_INFO:
- case SDT_WARNING:
- case SDT_ERROR:
- done = true;
- break;
-
- case SDT_YES_NO:
- if (line == "Y" || line == "y")
- {
- result = SDR_YES;
- done = true;
- }
- else if (line == "N" || line == "n")
- {
- result = SDR_NO;
- done = true;
- }
- break;
-
- case SDT_OK_CANCEL:
- if (line == "O" || line == "o")
- {
- done = true;
- result = SDR_OK;
- }
- else if (line == "C" || line == "c")
- {
- done = true;
- result = SDR_CANCEL;
- }
- break;
- }
- }
-
+ long long exact = 0;
+#if defined(PLATFORM_WINDOWS)
+ exact = TimeStampExactDiff_Windows(before, after);
+#elif defined(PLATFORM_LINUX)
+ exact = TimeStampExactDiff_Linux(before, after);
+#else
+ exact = TimeStampExactDiff_Other(before, after);
+#endif
+ float result = 0.0f;
+ if (unit == STU_SEC)
+ result = exact * 1e-9;
+ else if (unit == STU_MSEC)
+ result = exact * 1e-6;
+ else if (unit == STU_USEC)
+ result = exact * 1e-3;
+ else
+ assert(false);
return result;
}
-#endif // if defined(PLATFORM_WINDOWS)
+
+long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after)
+{
+#if defined(PLATFORM_WINDOWS)
+ return TimeStampExactDiff_Windows(before, after);
+#elif defined(PLATFORM_LINUX)
+ return TimeStampExactDiff_Linux(before, after);
+#else
+ return TimeStampExactDiff_Other(before, after);
+#endif
+}
diff --git a/src/app/system.h b/src/app/system.h
index 3bf6457..3c04760 100644
--- a/src/app/system.h
+++ b/src/app/system.h
@@ -23,6 +23,8 @@
#include <string>
+/* Dialog utils */
+
/**
* \enum SysDialogType
* \brief Type of system dialog
@@ -57,3 +59,47 @@ enum SystemDialogResult
//! Displays a system dialog
SystemDialogResult SystemDialog(SystemDialogType, const std::string &title, const std::string &message);
+
+
+/* Time utils */
+
+enum SystemTimeUnit
+{
+ //! seconds
+ STU_SEC,
+ //! milliseconds
+ STU_MSEC,
+ //! microseconds
+ STU_USEC
+};
+
+/* Forward declaration of time stamp struct
+ * SystemTimeStamp should be used in a pointer context.
+ * The implementation details are hidden because of platform dependence. */
+struct SystemTimeStamp;
+
+//! Creates a new time stamp object
+SystemTimeStamp* CreateTimeStamp();
+
+//! Destroys a time stamp object
+void DestroyTimeStamp(SystemTimeStamp *stamp);
+
+//! Copies the time stamp from \a src to \a dst
+void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src);
+
+//! Returns a time stamp associated with current time
+void GetCurrentTimeStamp(SystemTimeStamp *stamp);
+
+//! Returns the platform's expected time stamp resolution
+float GetTimeStampResolution(SystemTimeUnit unit = STU_SEC);
+
+//! Returns the platform's exact (in nanosecond units) expected time stamp resolution
+long long GetTimeStampExactResolution();
+
+//! Returns a difference between two timestamps in given time unit
+/** The difference is \a after - \a before. */
+float TimeStampDiff(SystemTimeStamp *before, SystemTimeStamp *after, SystemTimeUnit unit = STU_SEC);
+
+//! Returns the exact (in nanosecond units) difference between two timestamps
+/** The difference is \a after - \a before. */
+long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after);
diff --git a/src/app/system_linux.h b/src/app/system_linux.h
new file mode 100644
index 0000000..f58c9a1
--- /dev/null
+++ b/src/app/system_linux.h
@@ -0,0 +1,101 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+// system_linux.h
+
+/* This header contains Linux-specific code for system utils
+ from system.h. There is no separate .cpp module for simplicity.*/
+
+#include <sys/time.h>
+#include <time.h>
+#include <stdlib.h>
+
+
+SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message);
+
+void GetCurrentTimeStamp_Linux(SystemTimeStamp *stamp);
+long long GetTimeStampExactResolution_Linux();
+long long TimeStampExactDiff_Linux(SystemTimeStamp *before, SystemTimeStamp *after);
+
+struct SystemTimeStamp
+{
+ timespec clockTime;
+
+ SystemTimeStamp()
+ {
+ clockTime.tv_sec = clockTime.tv_nsec = 0;
+ }
+};
+
+
+SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message)
+{
+ std::string options = "";
+ switch (type)
+ {
+ case SDT_INFO:
+ default:
+ options = "--info";
+ break;
+ case SDT_WARNING:
+ options = "--warning";
+ break;
+ case SDT_ERROR:
+ options = "--error";
+ break;
+ case SDT_YES_NO:
+ options = "--question --ok-label=\"Yes\" --cancel-label=\"No\"";
+ break;
+ case SDT_OK_CANCEL:
+ options = "--question --ok-label=\"OK\" --cancel-label=\"Cancel\"";
+ break;
+ }
+
+ std::string command = "zenity " + options + " --text=\"" + message + "\" --title=\"" + title + "\"";
+ int code = system(command.c_str());
+
+ SystemDialogResult result = SDR_OK;
+ switch (type)
+ {
+ case SDT_YES_NO:
+ result = code ? SDR_NO : SDR_YES;
+ break;
+ case SDT_OK_CANCEL:
+ result = code ? SDR_CANCEL : SDR_OK;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+void GetCurrentTimeStamp_Linux(SystemTimeStamp *stamp)
+{
+ clock_gettime(CLOCK_MONOTONIC, &stamp->clockTime);
+}
+
+long long GetTimeStampExactResolution_Linux()
+{
+ return 1ll;
+}
+
+long long TimeStampExactDiff_Linux(SystemTimeStamp *before, SystemTimeStamp *after)
+{
+ return (after->clockTime.tv_nsec - before->clockTime.tv_nsec) +
+ (after->clockTime.tv_sec - before->clockTime.tv_sec) * 1000000000ll;
+}
diff --git a/src/app/system_other.h b/src/app/system_other.h
new file mode 100644
index 0000000..9f13ffa
--- /dev/null
+++ b/src/app/system_other.h
@@ -0,0 +1,146 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+// system_other.h
+
+/* This header contains fallback code for other platforms for system utils
+ from system.h. There is no separate .cpp module for simplicity.*/
+
+#include <SDL/SDL.h>
+
+#include <iostream>
+
+
+SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message);
+
+void GetCurrentTimeStamp_Other(SystemTimeStamp *stamp);
+long long GetTimeStampExactResolution_Other();
+long long TimeStampExactDiff_Other(SystemTimeStamp *before, SystemTimeStamp *after);
+
+struct SystemTimeStamp
+{
+ Uint32 sdlTicks;
+
+ SystemTimeStamp()
+ {
+ sdlTicks = 0;
+ }
+};
+
+
+SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message)
+{
+ switch (type)
+ {
+ case SDT_INFO:
+ std::cout << "INFO: ";
+ break;
+ case SDT_WARNING:
+ std::cout << "WARNING:";
+ break;
+ case SDT_ERROR:
+ std::cout << "ERROR: ";
+ break;
+ case SDT_YES_NO:
+ case SDT_OK_CANCEL:
+ std::cout << "QUESTION: ";
+ break;
+ }
+
+ std::cout << message << std::endl;
+
+ std::string line;
+
+ SystemDialogResult result = SDR_OK;
+
+ bool done = false;
+ while (!done)
+ {
+ switch (type)
+ {
+ case SDT_INFO:
+ case SDT_WARNING:
+ case SDT_ERROR:
+ std::cout << "Press ENTER to continue";
+ break;
+
+ case SDT_YES_NO:
+ std::cout << "Type 'Y' for Yes or 'N' for No";
+ break;
+
+ case SDT_OK_CANCEL:
+ std::cout << "Type 'O' for OK or 'C' for Cancel";
+ break;
+ }
+
+ std::getline(std::cin, line);
+
+ switch (type)
+ {
+ case SDT_INFO:
+ case SDT_WARNING:
+ case SDT_ERROR:
+ done = true;
+ break;
+
+ case SDT_YES_NO:
+ if (line == "Y" || line == "y")
+ {
+ result = SDR_YES;
+ done = true;
+ }
+ else if (line == "N" || line == "n")
+ {
+ result = SDR_NO;
+ done = true;
+ }
+ break;
+
+ case SDT_OK_CANCEL:
+ if (line == "O" || line == "o")
+ {
+ done = true;
+ result = SDR_OK;
+ }
+ else if (line == "C" || line == "c")
+ {
+ done = true;
+ result = SDR_CANCEL;
+ }
+ break;
+ }
+ }
+
+ return result;
+}
+
+
+
+void GetCurrentTimeStamp_Other(SystemTimeStamp *stamp)
+{
+ stamp->sdlTicks = SDL_GetTicks();
+}
+
+long long GetTimeStampExactResolution_Other()
+{
+ return 1000000ll;
+}
+
+long long TimeStampExactDiff_Other(SystemTimeStamp *before, SystemTimeStamp *after)
+{
+ return (after->sdlTicks - before->sdlTicks) * 1000000ll;
+}
diff --git a/src/app/system_windows.h b/src/app/system_windows.h
new file mode 100644
index 0000000..eb6beec
--- /dev/null
+++ b/src/app/system_windows.h
@@ -0,0 +1,122 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+// system_windows.h
+
+/* This header contains Windows-specific code for system utils
+ from system.h. There is no separate .cpp module for simplicity.*/
+
+#include <windows.h>
+
+
+std::string UTF8_Encode_Windows(const std::wstring &wstr);
+std::wstring UTF8_Decode_Windows(const std::string &str);
+SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message);
+
+void GetCurrentTimeStamp_Windows(SystemTimeStamp *stamp);
+long long GetTimeStampExactResolution_Windows();
+long long TimeStampExactDiff_Windows(SystemTimeStamp *before, SystemTimeStamp *after);
+
+struct SystemTimeStamp
+{
+ FILETIME fileTime;
+
+ SystemTimeStamp()
+ {
+ fileTime.dwHighDateTime = fileTime.dwLowDateTime = 0;
+ }
+};
+
+
+// Convert a wide Unicode string to an UTF8 string
+std::string UTF8_Encode_Windows(const std::wstring &wstr)
+{
+ int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
+ std::string strTo(size_needed, 0);
+ WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
+ return strTo;
+}
+
+// Convert an UTF8 string to a wide Unicode String
+std::wstring UTF8_Decode_Windows(const std::string &str)
+{
+ int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
+ std::wstring wstrTo(size_needed, 0);
+ MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
+ return wstrTo;
+}
+
+SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message)
+{
+ unsigned int windowsType = 0;
+ std::wstring windowsMessage = UTF8_Decode_Windows(message);
+ std::wstring windowsTitle = UTF8_Decode_Windows(title);
+
+ switch (type)
+ {
+ case SDT_INFO:
+ default:
+ windowsType = MB_ICONINFORMATION|MB_OK;
+ break;
+ case SDT_WARNING:
+ windowsType = MB_ICONWARNING|MB_OK;
+ break;
+ case SDT_ERROR:
+ windowsType = MB_ICONERROR|MB_OK;
+ break;
+ case SDT_YES_NO:
+ windowsType = MB_ICONQUESTION|MB_YESNO;
+ break;
+ case SDT_OK_CANCEL:
+ windowsType = MB_ICONWARNING|MB_OKCANCEL;
+ break;
+ }
+
+ switch (MessageBoxW(NULL, windowsMessage.c_str(), windowsTitle.c_str(), windowsType))
+ {
+ case IDOK:
+ return SDR_OK;
+ case IDCANCEL:
+ return SDR_CANCEL;
+ case IDYES:
+ return SDR_YES;
+ case IDNO:
+ return SDR_NO;
+ default:
+ break;
+ }
+
+ return SDR_OK;
+}
+
+
+void GetCurrentTimeStamp_Windows(SystemTimeStamp *stamp)
+{
+ GetSystemTimeAsFileTime(&stamp->fileTime);
+}
+
+long long GetTimeStampExactResolution_Windows()
+{
+ return 100ll;
+}
+
+long long TimeStampExactDiff_Windows(SystemTimeStamp *before, SystemTimeStamp *after)
+{
+ long long tH = (1ll << 32) * (after->fileTime.dwHighDateTime - before->fileTime.dwHighDateTime);
+ long long tL = after->fileTime.dwLowDateTime - before->fileTime.dwLowDateTime;
+ return (tH + tL) * 100ll;
+}
diff --git a/src/common/event.cpp b/src/common/event.cpp
index 9af4691..e8595d0 100644
--- a/src/common/event.cpp
+++ b/src/common/event.cpp
@@ -1,96 +1,68 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.
-
-// event.cpp
-
-#include "common/iman.h"
-#include "common/event.h"
-
-#include <string.h>
-
-
-Event::Event()
-{
- event = EVENT_NULL;
- param = 0;
- axeX = 0.0f;
- axeY = 0.0f;
- axeZ = 0.0f;
- keyState = 0;
- rTime = 0.0f;
-}
-
-
-// Object's constructor.
-
-CEvent::CEvent(CInstanceManager* iMan)
-{
- m_iMan = iMan;
- m_iMan->AddInstance(CLASS_EVENT, this);
-
- Flush();
-}
-
-// Object's destructor.
-
-CEvent::~CEvent()
-{
-}
-
-
-// Empty the FIFO of events.
-
-void CEvent::Flush()
-{
- m_head = 0;
- m_tail = 0;
- m_total = 0;
-}
-
-// Produces an event.
-
-void CEvent::MakeEvent(Event &event, EventMsg msg)
-{
- memset(&event, 0, sizeof(Event));
- event.event = msg;
-}
-
-// Adds an event in the FIFO.
-
-bool CEvent::AddEvent(const Event &event)
-{
- if ( m_total >= MAXEVENT ) return false;
-
- m_fifo[m_head++] = event;
- if ( m_head >= MAXEVENT ) m_head = 0;
- m_total ++;
-
- return true;
-}
-
-// Removes an event from the FIFO.
-
-bool CEvent::GetEvent(Event &event)
-{
- if ( m_head == m_tail ) return false;
-
- event = m_fifo[m_tail++];
- if ( m_tail >= MAXEVENT ) m_tail = 0;
- m_total --;
-
- return true;
-}
-
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+// event.cpp
+
+#include "common/event.h"
+#include "common/iman.h"
+
+
+
+CEventQueue::CEventQueue(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_EVENT, this);
+
+ Flush();
+}
+
+CEventQueue::~CEventQueue()
+{
+}
+
+void CEventQueue::Flush()
+{
+ m_head = 0;
+ m_tail = 0;
+ m_total = 0;
+}
+
+/** If the maximum size of queue has been reached, returns \c false.
+ Else, adds the event to the queue and returns \c true. */
+bool CEventQueue::AddEvent(const Event &event)
+{
+ if ( m_total >= MAX_EVENT_QUEUE ) return false;
+
+ m_fifo[m_head++] = event;
+ if ( m_head >= MAX_EVENT_QUEUE ) m_head = 0;
+ m_total ++;
+
+ return true;
+}
+
+/** If the queue is empty, returns \c false.
+ Else, gets the event from the front, puts it into \a event and returns \c true. */
+bool CEventQueue::GetEvent(Event &event)
+{
+ if ( m_head == m_tail ) return false;
+
+ event = m_fifo[m_tail++];
+ if ( m_tail >= MAX_EVENT_QUEUE ) m_tail = 0;
+ m_total --;
+
+ return true;
+}
+
diff --git a/src/common/event.h b/src/common/event.h
index 8174fab..6ce1a79 100644
--- a/src/common/event.h
+++ b/src/common/event.h
@@ -19,40 +19,51 @@
#pragma once
+#include "common/key.h"
#include "math/point.h"
+#include <string.h>
-#if !defined (WM_XBUTTONDOWN)
-#define WM_XBUTTONDOWN 0x020B
-#define WM_XBUTTONUP 0x020C
-#define XBUTTON1 0x0001
-#define XBUTTON2 0x0002
-#endif
+class CInstanceManager;
+/**
+ \enum EventType
+ \brief Type of event message
+ */
+enum EventType
+{
-class CInstanceManager;
+// TODO: document the meaning of each value
+ //! Invalid event / no event
+ EVENT_NULL = 0,
-const int MAXEVENT = 100;
+ //! Event sent on user or system quit request
+ EVENT_QUIT = 1,
-// Events.
+ //? EVENT_FRAME = 2,
-enum EventMsg
-{
- EVENT_NULL = 0,
+ //! Event sent after pressing a mouse button
+ EVENT_MOUSE_BUTTON_DOWN = 3,
+ //! Event sent after releasing a mouse button
+ EVENT_MOUSE_BUTTON_UP = 4,
+ //! Event sent after moving the mouse
+ EVENT_MOUSE_MOVE = 7,
+ //! Event sent after pressing a key
+ EVENT_KEY_DOWN = 8,
+ //! Event sent after releasing a key
+ EVENT_KEY_UP = 9,
+
+ //? EVENT_CHAR = 10,
+ //? EVENT_FOCUS = 11,
- EVENT_QUIT = 1,
- EVENT_FRAME = 2,
- EVENT_LBUTTONDOWN = 3,
- EVENT_RBUTTONDOWN = 4,
- EVENT_LBUTTONUP = 5,
- EVENT_RBUTTONUP = 6,
- EVENT_MOUSEMOVE = 7,
- EVENT_KEYDOWN = 8,
- EVENT_KEYUP = 9,
- EVENT_CHAR = 10,
- EVENT_FOCUS = 11,
+ //! Event sent after moving joystick axes
+ EVENT_JOY_AXIS = 12,
+ //! Event sent after pressing a joystick button
+ EVENT_JOY_BUTTON_DOWN = 13,
+ //! Event sent after releasing a joystick button
+ EVENT_JOY_BUTTON_UP = 14,
EVENT_UPDINTERFACE = 20,
EVENT_WIN = 30,
@@ -525,60 +536,142 @@ enum EventMsg
EVENT_STUDIO_STEP = 2053,
EVENT_USER = 10000,
- EVENT_FORCE_DWORD = 0x7fffffff
+ EVENT_FORCE_LONG = 0x7fffffff
+};
+
+
+/** \enum PressState
+ \brief State of key/mouse button */
+enum PressState
+{
+ STATE_PRESSED,
+ STATE_RELEASED
+};
+
+
+/** \struct KeyEventData
+ \brief Additional data for keyboard event */
+struct KeyEventData
+{
+ //! STATE_PRESSED or STATE_RELEASED */
+ PressState state;
+ //! Key symbol: KEY(...) macro value (from common/key.h)
+ unsigned int key;
+ //! Keyboard modifiers: a bitmask made of KEY_MOD(...) macro values (from common/key.h)
+ unsigned int mod;
+ //! Unicode character
+ unsigned int unicode;
+
+ KeyEventData()
+ : state(STATE_PRESSED), key(0), mod(0), unicode(0) {}
+};
+
+/** \struct MouseMotionEventData
+ \brief Additional data for mouse move event */
+struct MouseMoveEventData
+{
+ //! Current button state
+ unsigned char state;
+ //! Position of mouse in normalized coordinates (0..1)
+ Math::Point pos;
+
+ MouseMoveEventData()
+ : state(STATE_PRESSED) {}
+};
+
+/** \struct MouseButtonEventData
+ \brief Additional data mouse button event */
+struct MouseButtonEventData
+{
+ //! The mouse button index
+ unsigned char button;
+ //! STATE_PRESSED or STATE_RELEASED
+ PressState state;
+ //! Position of mouse in normalized coordinates (0..1)
+ Math::Point pos;
+
+ MouseButtonEventData()
+ : button(0), state(STATE_PRESSED) {}
+};
+
+/** \struct JoyAxisEventData
+ \brief Additional data for joystick axis event */
+struct JoyAxisEventData
+{
+ //! The joystick axis index
+ unsigned char axis;
+ //! The axis value (range: -32768 to 32767)
+ int value;
+
+ JoyAxisEventData()
+ : axis(axis), value(value) {}
+};
+
+/** \struct JoyButtonEventData
+ \brief Joystick button event structure */
+struct JoyButtonEventData
+{
+ //! The joystick button index
+ unsigned char button;
+ //! STATE_PRESSED or STATE_RELEASED
+ PressState state;
+
+ JoyButtonEventData()
+ : button(0), state(STATE_PRESSED) {}
};
+// TODO: JoyHatEventData? JoyBallEventData?
+
+
+/**
+ \struct Event
+ \brief Event sent by system, interface or game
+
+ Event is described by its type (EventType) and the union
+ \a data contains additional data about the event.
+ Different members of the union are filled with different event types.
+ With some events, nothing is filled (it's zeroed out).
+ The union contains roughly the same information as SDL_Event struct
+ but packaged to independent structs and fields.
+ **/
struct Event
{
- EventMsg event; // event (EVENT *)
- 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();
+ //! Type of event (EVENT_*)
+ EventType type;
+
+ //! 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;
+
+ //? 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) {}
};
-const int VK_BUTTON1 = (0x100+1); // joystick button 1
-const int VK_BUTTON2 = (0x100+2); // joystick button 2
-const int VK_BUTTON3 = (0x100+3); // joystick button 3
-const int VK_BUTTON4 = (0x100+4); // joystick button 4
-const int VK_BUTTON5 = (0x100+5); // joystick button 5
-const int VK_BUTTON6 = (0x100+6); // joystick button 6
-const int VK_BUTTON7 = (0x100+7); // joystick button 7
-const int VK_BUTTON8 = (0x100+8); // joystick button 8
-const int VK_BUTTON9 = (0x100+9); // joystick button 9
-const int VK_BUTTON10 = (0x100+10); // joystick button 10
-const int VK_BUTTON11 = (0x100+11); // joystick button 11
-const int VK_BUTTON12 = (0x100+12); // joystick button 12
-const int VK_BUTTON13 = (0x100+13); // joystick button 13
-const int VK_BUTTON14 = (0x100+14); // joystick button 14
-const int VK_BUTTON15 = (0x100+15); // joystick button 15
-const int VK_BUTTON16 = (0x100+16); // joystick button 16
-const int VK_BUTTON17 = (0x100+17); // joystick button 17
-const int VK_BUTTON18 = (0x100+18); // joystick button 18
-const int VK_BUTTON19 = (0x100+19); // joystick button 19
-const int VK_BUTTON20 = (0x100+20); // joystick button 20
-const int VK_BUTTON21 = (0x100+21); // joystick button 21
-const int VK_BUTTON22 = (0x100+22); // joystick button 22
-const int VK_BUTTON23 = (0x100+23); // joystick button 23
-const int VK_BUTTON24 = (0x100+24); // joystick button 24
-const int VK_BUTTON25 = (0x100+25); // joystick button 25
-const int VK_BUTTON26 = (0x100+26); // joystick button 26
-const int VK_BUTTON27 = (0x100+27); // joystick button 27
-const int VK_BUTTON28 = (0x100+28); // joystick button 28
-const int VK_BUTTON29 = (0x100+29); // joystick button 29
-const int VK_BUTTON30 = (0x100+30); // joystick button 30
-const int VK_BUTTON31 = (0x100+31); // joystick button 31
-const int VK_BUTTON32 = (0x100+32); // joystick button 32
-
-const int VK_WHEELUP = (0x200+1); // Mousewheel up
-const int VK_WHEELDOWN = (0x200+2); // Mousewheel down
+/**
+ \enum KeyRank
+ \brief Slots for key assignment of user controls
+ */
+// TODO: move to global.h ?
enum KeyRank
{
@@ -609,25 +702,37 @@ enum KeyRank
};
+/**
+ \class CEventQueue
+ \brief Global event queue
-class CEvent
+ Provides an interface to a global FIFO queue with events (both system- and user-generated).
+ The queue has a fixed maximum size but it should not be a problem.
+ */
+class CEventQueue
{
public:
- CEvent(CInstanceManager* iMan);
- ~CEvent();
+ //! Constant maximum size of queue
+ static const int MAX_EVENT_QUEUE = 100;
+
+public:
+ //! Object's constructor
+ CEventQueue(CInstanceManager* iMan);
+ //! Object's destructor
+ ~CEventQueue();
+ //! Empties the FIFO of events
void Flush();
- void MakeEvent(Event &event, EventMsg msg);
+ //! Adds an event to the queue
bool AddEvent(const Event &event);
bool GetEvent(Event &event);
protected:
CInstanceManager* m_iMan;
-
- Event m_fifo[MAXEVENT];
- int m_head;
- int m_tail;
- int m_total;
+ Event m_fifo[MAX_EVENT_QUEUE];
+ int m_head;
+ int m_tail;
+ int m_total;
};
diff --git a/src/common/image.cpp b/src/common/image.cpp
new file mode 100644
index 0000000..78834b4
--- /dev/null
+++ b/src/common/image.cpp
@@ -0,0 +1,221 @@
+// * 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/.
+
+// image.cpp
+
+#include "image.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+#include <png.h>
+
+
+/* <---------------------------------------------------------------> */
+
+/* The following code is from savesurf program by Angelo "Encelo" Theodorou
+ Source: http://encelo.netsons.org/old/sdl/
+ The code was refactored and modified slightly to fit the needs.
+ The copyright information below is kept unchanged. */
+
+
+/* SaveSurf: an example on how to save a SDLSurface in PNG
+ Copyright (C) 2006 Angelo "Encelo" Theodorou
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ NOTE:
+
+ This program is part of "Mars, Land of No Mercy" SDL examples,
+ you can find other examples on http://marsnomercy.org
+*/
+
+std::string PNG_ERROR = "";
+
+void PNGUserError(png_structp ctx, png_const_charp str)
+{
+ PNG_ERROR = std::string(str);
+}
+
+int PNGColortypeFromSurface(SDL_Surface *surface)
+{
+ int colortype = PNG_COLOR_MASK_COLOR; /* grayscale not supported */
+
+ if (surface->format->palette)
+ colortype |= PNG_COLOR_MASK_PALETTE;
+ else if (surface->format->Amask)
+ colortype |= PNG_COLOR_MASK_ALPHA;
+
+ return colortype;
+}
+
+bool PNGSaveSurface(const char *filename, SDL_Surface *surf)
+{
+ FILE *fp;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ int i, colortype;
+ png_bytep *row_pointers;
+
+ PNG_ERROR = "";
+
+ /* Opening output file */
+ fp = fopen(filename, "wb");
+ if (fp == NULL)
+ {
+ PNG_ERROR = std::string("Could not open file '") + std::string(filename) + std::string("' for saving");
+ return false;
+ }
+
+ /* Initializing png structures and callbacks */
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, PNGUserError, NULL);
+ if (png_ptr == NULL)
+ return false;
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ {
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ PNG_ERROR = "png_create_info_struct() error!";
+ return false;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+ return false;
+ }
+
+ png_init_io(png_ptr, fp);
+
+ colortype = PNGColortypeFromSurface(surf);
+ png_set_IHDR(png_ptr, info_ptr, surf->w, surf->h, 8, colortype, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+ /* Writing the image */
+ png_write_info(png_ptr, info_ptr);
+ png_set_packing(png_ptr);
+
+ row_pointers = (png_bytep*) malloc(sizeof(png_bytep)*surf->h);
+ for (i = 0; i < surf->h; i++)
+ row_pointers[i] = (png_bytep)(Uint8 *)surf->pixels + i*surf->pitch;
+ png_write_image(png_ptr, row_pointers);
+ png_write_end(png_ptr, info_ptr);
+
+ /* Cleaning out... */
+ free(row_pointers);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+
+ return true;
+}
+
+/* <---------------------------------------------------------------> */
+
+
+CImage::CImage()
+{
+ m_data = NULL;
+}
+
+CImage::~CImage()
+{
+ Free();
+}
+
+bool CImage::IsEmpty()
+{
+ return m_data == NULL;
+}
+
+void CImage::Free()
+{
+ if (m_data != NULL)
+ {
+ if (m_data->surface != NULL)
+ {
+ SDL_FreeSurface(m_data->surface);
+ m_data->surface = NULL;
+ }
+ delete m_data;
+ m_data = NULL;
+ }
+}
+
+ImageData* CImage::GetData()
+{
+ return m_data;
+}
+
+std::string CImage::GetError()
+{
+ return m_error;
+}
+
+bool CImage::Load(const std::string& fileName)
+{
+ if (! IsEmpty() )
+ Free();
+
+ m_data = new ImageData();
+
+ m_error = "";
+
+ m_data->surface = IMG_Load(fileName.c_str());
+ if (m_data->surface == NULL)
+ {
+ delete m_data;
+ m_data = NULL;
+
+ m_error = std::string(IMG_GetError());
+ return false;
+ }
+
+ return true;
+}
+
+bool CImage::SavePNG(const std::string& fileName)
+{
+ if (IsEmpty())
+ {
+ m_error = "Empty image!";
+ return false;
+ }
+
+ m_error = "";
+
+ if (! PNGSaveSurface(fileName.c_str(), m_data->surface) )
+ {
+ m_error = PNG_ERROR;
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/common/image.h b/src/common/image.h
new file mode 100644
index 0000000..4d86d31
--- /dev/null
+++ b/src/common/image.h
@@ -0,0 +1,84 @@
+// * 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/.
+
+// image.h
+
+#pragma once
+
+
+#include <stddef.h>
+#include <string>
+
+
+// Forward declaration without including headers to clutter the code
+struct SDL_Surface;
+
+//! Implementation-specific image data
+/** Note that the struct has no destructor and the surface
+ will not be freed at destruction. */
+struct ImageData
+{
+ //! SDL surface with image data
+ SDL_Surface* surface;
+
+ ImageData() { surface = NULL; }
+};
+
+/**
+ \class CImage
+ \brief Image loaded from file
+
+ Wrapper around SDL_Image library to load images. Also contains
+ function for saving images to PNG.
+ */
+class CImage
+{
+private:
+ //! Blocked!
+ CImage(const CImage &other) {}
+ //! Blocked!
+ void operator=(const CImage &other) {}
+
+public:
+ //! Constructs empty image (with NULL data)
+ CImage();
+ //! Destroys image, calling Free()
+ virtual ~CImage();
+
+ //! Frees the allocated image data
+ void Free();
+
+ //! Returns whether the image is empty (has NULL data)
+ bool IsEmpty();
+
+ //! Returns the image data; if empty - returns NULL
+ ImageData* GetData();
+
+ //! Loads an image from the specified file
+ bool Load(const std::string &fileName);
+
+ //! Saves the image to the specified file in PNG format
+ bool SavePNG(const std::string &fileName);
+
+ //! Returns the last error
+ std::string GetError();
+
+private:
+ //! Last encountered error
+ std::string m_error;
+ //! Image data
+ ImageData* m_data;
+};
diff --git a/src/common/ioutils.h b/src/common/ioutils.h
new file mode 100644
index 0000000..f17c961
--- /dev/null
+++ b/src/common/ioutils.h
@@ -0,0 +1,81 @@
+// * 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/.
+
+// ioutils.h
+
+#pragma once
+
+
+#include <iostream>
+
+
+namespace IOUtils {
+
+//! Writes a binary number to output stream
+/**
+ \c T is a numeric type (int, unsigned int, etc.)
+ \c N is number of bytes
+ Write order is little-endian */
+template<int N, typename T>
+void WriteBinary(T value, std::ostream &ostr)
+{
+ for (int i = 0; i < N; ++i)
+ {
+ unsigned char byte = (value >> (i*8)) & 0xFF;
+ ostr.write((char*)&byte, 1);
+ }
+}
+
+//! Reads a binary number from input stream
+/**
+ \c T is a numeric type (int, unsigned int, etc.)
+ \c N is number of bytes
+ Read order is little-endian */
+template<int N, typename T>
+T ReadBinary(std::istream &istr)
+{
+ T value = 0;
+ for (int i = 0; i < N; ++i)
+ {
+ unsigned char byte = 0;
+ istr.read((char*)&byte, 1);
+ value |= byte << (i*8);
+ }
+ return value;
+}
+
+//! Writes a binary 32-bit float to output stream
+/**
+ Write order is little-endian
+ NOTE: code is probably not portable as there are platforms with other float representations. */
+void WriteBinaryFloat(float value, std::ostream &ostr)
+{
+ unsigned int iValue = *( (unsigned int*)( (void*)(&value) ) );
+ IOUtils::WriteBinary<4, unsigned int>(iValue, ostr);
+}
+
+//! Reads a binary 32-bit float from input stream
+/**
+ Read order is little-endian
+ NOTE: code is probably not portable as there are platforms with other float representations. */
+float ReadBinaryFloat(std::istream &istr)
+{
+ unsigned int iValue = IOUtils::ReadBinary<4, unsigned int>(istr);
+ float result = *( (float*)( (void*)(&iValue) ) );
+ return result;
+}
+
+}; // namespace IOUtils
diff --git a/src/graphics/common/device.h b/src/common/key.h
index 5900570..de31c09 100644
--- a/src/graphics/common/device.h
+++ b/src/common/key.h
@@ -1,5 +1,4 @@
// * 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
@@ -15,38 +14,21 @@
// * 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
+// key.h
#pragma once
-namespace Gfx {
+#include "SDL/SDL_keysym.h"
-struct DeviceConfig
-{
- //! Screen width
- int width;
- //! Screen height
- int height;
- //! Bits per pixel
- int bpp;
- //! Full screen
- bool fullScreen;
- //! Resizeable window
- bool resizeable;
- //! Hardware acceleration
- bool hardwareAccel;
- //! Double buffering
- bool doubleBuf;
- //! No window frame (also set with full screen)
- bool noFrame;
+/* Key definitions are specially defined here so that it is clear in other parts of the code
+ that these are used. It is to avoid having SDL-related enum values or #defines lying around
+ unchecked. With this approach it will be easier to maintain the code later on. */
- DeviceConfig();
-};
+// Key symbol defined as concatenation to SDLK_...
+// If need arises, it can be changed to custom function or anything else
+#define KEY(x) SDLK_ ## x
-class CDevice
-{
- // TODO
-};
-
-}; // namespace Gfx
+// Key modifier defined as concatenation to KMOD_...
+// If need arises, it can be changed to custom function or anything else
+#define KEY_MOD(x) KMOD_ ## x
diff --git a/src/common/logger.cpp b/src/common/logger.cpp
index acd1d27..41d60eb 100644
--- a/src/common/logger.cpp
+++ b/src/common/logger.cpp
@@ -18,6 +18,8 @@
#include <common/logger.h>
+#include <stdio.h>
+
template<> CLogger* CSingleton<CLogger>::mInstance = 0;
diff --git a/src/common/misc.h b/src/common/misc.h
index e863b69..4853856 100644
--- a/src/common/misc.h
+++ b/src/common/misc.h
@@ -219,7 +219,7 @@ const int KS_NUMMINUS = (1<<15);
// Procedures.
-extern EventMsg GetUniqueEventMsg();
+extern EventType GetUniqueEventType();
extern char RetNoAccent(char letter);
extern char RetToUpper(char letter);
diff --git a/src/common/modfile.cpp b/src/common/modfile.cpp
deleted file mode 100644
index fc202b7..0000000
--- a/src/common/modfile.cpp
+++ /dev/null
@@ -1,695 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.
-
-// modfile.cpp
-
-
-#include <windows.h>
-#include <stdio.h>
-#include <d3d.h>
-
-#include "common/struct.h"
-#include "math/geometry.h"
-#include "old/d3dengine.h"
-#include "old/d3dmath.h"
-#include "common/language.h"
-#include "common/event.h"
-#include "common/misc.h"
-#include "common/iman.h"
-#include "old/math3d.h"
-#include "common/modfile.h"
-
-
-
-const int MAX_VERTICES = 2000;
-
-
-
-// Object's constructor.
-
-CModFile::CModFile(CInstanceManager* iMan)
-{
- m_iMan = iMan;
-
- m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
-
- m_triangleUsed = 0;
- m_triangleTable = (ModelTriangle*)malloc(sizeof(ModelTriangle)*MAX_VERTICES);
- ZeroMemory(m_triangleTable, sizeof(ModelTriangle)*MAX_VERTICES);
-}
-
-// Object's destructor.
-
-CModFile::~CModFile()
-{
- free(m_triangleTable);
-}
-
-
-
-
-// Creates a triangle in the internal structure.
-
-bool CModFile::CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3,
- float min, float max)
-{
- Math::Vector n;
- int i;
-
- if ( m_triangleUsed >= MAX_VERTICES )
- {
- OutputDebugString("ERROR: CreateTriangle::Too many triangles\n");
- return false;
- }
-
- i = m_triangleUsed++;
-
- ZeroMemory(&m_triangleTable[i], sizeof(ModelTriangle));
-
- m_triangleTable[i].bUsed = true;
- m_triangleTable[i].bSelect = false;
-
- n = Math::NormalToPlane(p3, p2, p1);
- m_triangleTable[i].p1 = D3DVERTEX2( p1, n);
- m_triangleTable[i].p2 = D3DVERTEX2( p2, n);
- m_triangleTable[i].p3 = D3DVERTEX2( p3, n);
-
- m_triangleTable[i].material.diffuse.r = 1.0f;
- m_triangleTable[i].material.diffuse.g = 1.0f;
- m_triangleTable[i].material.diffuse.b = 1.0f; // white
- m_triangleTable[i].material.ambient.r = 0.5f;
- m_triangleTable[i].material.ambient.g = 0.5f;
- m_triangleTable[i].material.ambient.b = 0.5f;
-
- m_triangleTable[i].min = min;
- m_triangleTable[i].max = max;
-
- return true;
-}
-
-// Reads a DXF file.
-
-bool CModFile::ReadDXF(char *filename, float min, float max)
-{
- FILE* file = NULL;
- char line[100];
- int command, rankSommet, nbSommet, nbFace;
- Math::Vector table[MAX_VERTICES];
- bool bWaitNbSommet;
- bool bWaitNbFace;
- bool bWaitSommetX;
- bool bWaitSommetY;
- bool bWaitSommetZ;
- bool bWaitFaceX;
- bool bWaitFaceY;
- bool bWaitFaceZ;
- float x,y,z;
- int p1,p2,p3;
-
- file = fopen(filename, "r");
- if ( file == NULL ) return false;
-
- m_triangleUsed = 0;
-
- rankSommet = 0;
- bWaitNbSommet = false;
- bWaitNbFace = false;
- bWaitSommetX = false;
- bWaitSommetY = false;
- bWaitSommetZ = false;
- bWaitFaceX = false;
- bWaitFaceY = false;
- bWaitFaceZ = false;
-
- while ( fgets(line, 100, file) != NULL )
- {
- sscanf(line, "%d", &command);
- if ( fgets(line, 100, file) == NULL ) break;
-
- if ( command == 66 )
- {
- bWaitNbSommet = true;
- }
-
- if ( command == 71 && bWaitNbSommet )
- {
- bWaitNbSommet = false;
- sscanf(line, "%d", &nbSommet);
- if ( nbSommet > MAX_VERTICES ) nbSommet = MAX_VERTICES;
- rankSommet = 0;
- bWaitNbFace = true;
-
-//? sprintf(s, "Waiting for %d sommets\n", nbSommet);
-//? OutputDebugString(s);
- }
-
- if ( command == 72 && bWaitNbFace )
- {
- bWaitNbFace = false;
- sscanf(line, "%d", &nbFace);
- bWaitSommetX = true;
-
-//? sprintf(s, "Waiting for %d faces\n", nbFace);
-//? OutputDebugString(s);
- }
-
- if ( command == 10 && bWaitSommetX )
- {
- bWaitSommetX = false;
- sscanf(line, "%f", &x);
- bWaitSommetY = true;
- }
-
- if ( command == 20 && bWaitSommetY )
- {
- bWaitSommetY = false;
- sscanf(line, "%f", &y);
- bWaitSommetZ = true;
- }
-
- if ( command == 30 && bWaitSommetZ )
- {
- bWaitSommetZ = false;
- sscanf(line, "%f", &z);
-
- nbSommet --;
- if ( nbSommet >= 0 )
- {
- Math::Vector p(x,z,y); // permutation of Y and Z!
- table[rankSommet++] = p;
- bWaitSommetX = true;
-
-//? sprintf(s, "Sommet[%d]=%f;%f;%f\n", rankSommet, p.x,p.y,p.z);
-//? OutputDebugString(s);
- }
- else
- {
- bWaitFaceX = true;
- }
- }
-
- if ( command == 71 && bWaitFaceX )
- {
- bWaitFaceX = false;
- sscanf(line, "%d", &p1);
- if ( p1 < 0 ) p1 = -p1;
- bWaitFaceY = true;
- }
-
- if ( command == 72 && bWaitFaceY )
- {
- bWaitFaceY = false;
- sscanf(line, "%d", &p2);
- if ( p2 < 0 ) p2 = -p2;
- bWaitFaceZ = true;
- }
-
- if ( command == 73 && bWaitFaceZ )
- {
- bWaitFaceZ = false;
- sscanf(line, "%d", &p3);
- if ( p3 < 0 ) p3 = -p3;
-
- nbFace --;
- if ( nbFace >= 0 )
- {
- CreateTriangle( table[p3-1], table[p2-1], table[p1-1], min,max );
- bWaitFaceX = true;
-
-//? sprintf(s, "Face=%d;%d;%d\n", p1,p2,p3);
-//? OutputDebugString(s);
- }
- }
-
- }
-
- fclose(file);
- return true;
-}
-
-
-
-struct InfoMOD
-{
- int rev;
- int vers;
- int total;
- int reserve[10];
-};
-
-
-// Change nom.bmp to nom.tga
-
-void ChangeBMPtoTGA(char *filename)
-{
- char* p;
-
- p = strstr(filename, ".bmp");
- if ( p != 0 ) strcpy(p, ".tga");
-}
-
-
-// Reads a MOD file.
-
-bool CModFile::AddModel(char *filename, int first, bool bEdit, bool bMeta)
-{
- FILE* file;
- InfoMOD info;
- float limit[2];
- int i, nb, err;
- char* p;
-
- if ( m_engine->RetDebugMode() )
- {
- bMeta = false;
- }
-
- if ( bMeta )
- {
- p = strchr(filename, '\\');
- if ( p == 0 )
- {
-#if _SCHOOL
- err = g_metafile.Open("ceebot2.dat", filename);
-#else
- err = g_metafile.Open("colobot2.dat", filename);
-#endif
- }
- else
- {
-#if _SCHOOL
- err = g_metafile.Open("ceebot2.dat", p+1);
-#else
- err = g_metafile.Open("colobot2.dat", p+1);
-#endif
- }
- if ( err != 0 ) bMeta = false;
- }
- if ( !bMeta )
- {
- file = fopen(filename, "rb");
- if ( file == NULL ) return false;
- }
-
- if ( bMeta )
- {
- g_metafile.Read(&info, sizeof(InfoMOD));
- }
- else
- {
- fread(&info, sizeof(InfoMOD), 1, file);
- }
- nb = info.total;
- m_triangleUsed += nb;
-
- if ( info.rev == 1 && info.vers == 0 )
- {
- OldModelTriangle1 old;
-
- for ( i=first ; i<m_triangleUsed ; i++ )
- {
- if ( bMeta )
- {
- g_metafile.Read(&old, sizeof(OldModelTriangle1));
- }
- else
- {
- fread(&old, sizeof(OldModelTriangle1), 1, file);
- }
-
- ZeroMemory(&m_triangleTable[i], sizeof(ModelTriangle));
- m_triangleTable[i].bUsed = old.bUsed;
- m_triangleTable[i].bSelect = old.bSelect;
-
- m_triangleTable[i].p1.x = old.p1.x;
- m_triangleTable[i].p1.y = old.p1.y;
- m_triangleTable[i].p1.z = old.p1.z;
- m_triangleTable[i].p1.nx = old.p1.nx;
- m_triangleTable[i].p1.ny = old.p1.ny;
- m_triangleTable[i].p1.nz = old.p1.nz;
- m_triangleTable[i].p1.tu = old.p1.tu;
- m_triangleTable[i].p1.tv = old.p1.tv;
-
- m_triangleTable[i].p2.x = old.p2.x;
- m_triangleTable[i].p2.y = old.p2.y;
- m_triangleTable[i].p2.z = old.p2.z;
- m_triangleTable[i].p2.nx = old.p2.nx;
- m_triangleTable[i].p2.ny = old.p2.ny;
- m_triangleTable[i].p2.nz = old.p2.nz;
- m_triangleTable[i].p2.tu = old.p2.tu;
- m_triangleTable[i].p2.tv = old.p2.tv;
-
- m_triangleTable[i].p3.x = old.p3.x;
- m_triangleTable[i].p3.y = old.p3.y;
- m_triangleTable[i].p3.z = old.p3.z;
- m_triangleTable[i].p3.nx = old.p3.nx;
- m_triangleTable[i].p3.ny = old.p3.ny;
- m_triangleTable[i].p3.nz = old.p3.nz;
- m_triangleTable[i].p3.tu = old.p3.tu;
- m_triangleTable[i].p3.tv = old.p3.tv;
-
- m_triangleTable[i].material = old.material;
- strcpy(m_triangleTable[i].texName, old.texName);
- m_triangleTable[i].min = old.min;
- m_triangleTable[i].max = old.max;
- }
- }
- else if ( info.rev == 1 && info.vers == 1 )
- {
- OldModelTriangle2 old;
-
- for ( i=first ; i<m_triangleUsed ; i++ )
- {
- if ( bMeta )
- {
- g_metafile.Read(&old, sizeof(OldModelTriangle2));
- }
- else
- {
- fread(&old, sizeof(OldModelTriangle2), 1, file);
- }
-
- ZeroMemory(&m_triangleTable[i], sizeof(ModelTriangle));
- m_triangleTable[i].bUsed = old.bUsed;
- m_triangleTable[i].bSelect = old.bSelect;
-
- m_triangleTable[i].p1.x = old.p1.x;
- m_triangleTable[i].p1.y = old.p1.y;
- m_triangleTable[i].p1.z = old.p1.z;
- m_triangleTable[i].p1.nx = old.p1.nx;
- m_triangleTable[i].p1.ny = old.p1.ny;
- m_triangleTable[i].p1.nz = old.p1.nz;
- m_triangleTable[i].p1.tu = old.p1.tu;
- m_triangleTable[i].p1.tv = old.p1.tv;
-
- m_triangleTable[i].p2.x = old.p2.x;
- m_triangleTable[i].p2.y = old.p2.y;
- m_triangleTable[i].p2.z = old.p2.z;
- m_triangleTable[i].p2.nx = old.p2.nx;
- m_triangleTable[i].p2.ny = old.p2.ny;
- m_triangleTable[i].p2.nz = old.p2.nz;
- m_triangleTable[i].p2.tu = old.p2.tu;
- m_triangleTable[i].p2.tv = old.p2.tv;
-
- m_triangleTable[i].p3.x = old.p3.x;
- m_triangleTable[i].p3.y = old.p3.y;
- m_triangleTable[i].p3.z = old.p3.z;
- m_triangleTable[i].p3.nx = old.p3.nx;
- m_triangleTable[i].p3.ny = old.p3.ny;
- m_triangleTable[i].p3.nz = old.p3.nz;
- m_triangleTable[i].p3.tu = old.p3.tu;
- m_triangleTable[i].p3.tv = old.p3.tv;
-
- m_triangleTable[i].material = old.material;
- strcpy(m_triangleTable[i].texName, old.texName);
- m_triangleTable[i].min = old.min;
- m_triangleTable[i].max = old.max;
- m_triangleTable[i].state = old.state;
- m_triangleTable[i].reserve2 = old.reserve2;
- m_triangleTable[i].reserve3 = old.reserve3;
- m_triangleTable[i].reserve4 = old.reserve4;
- }
- }
- else
- {
- if ( bMeta )
- {
- g_metafile.Read(m_triangleTable+first, sizeof(ModelTriangle)*nb);
- }
- else
- {
- fread(m_triangleTable+first, sizeof(ModelTriangle), nb, file);
- }
- }
-
- for ( i=first ; i<m_triangleUsed ; i++ )
- {
- ChangeBMPtoTGA(m_triangleTable[i].texName);
- }
-
- if ( !bEdit )
- {
- limit[0] = m_engine->RetLimitLOD(0); // frontier AB as config
- limit[1] = m_engine->RetLimitLOD(1); // frontier BC as config
-
- // Standard frontiers -> config.
- for ( i=first ; i<m_triangleUsed ; i++ )
- {
- if ( m_triangleTable[i].min == 0.0f &&
- m_triangleTable[i].max == 100.0f ) // resolution A ?
- {
- m_triangleTable[i].max = limit[0];
- }
- else if ( m_triangleTable[i].min == 100.0f &&
- m_triangleTable[i].max == 200.0f ) // resolution B ?
- {
- m_triangleTable[i].min = limit[0];
- m_triangleTable[i].max = limit[1];
- }
- else if ( m_triangleTable[i].min == 200.0f &&
- m_triangleTable[i].max == 1000000.0f ) // resolution C ?
- {
- m_triangleTable[i].min = limit[1];
- }
- }
- }
-
- if ( bMeta )
- {
- g_metafile.Close();
- }
- else
- {
- fclose(file);
- }
- return true;
-}
-
-// Reads a MOD file.
-
-bool CModFile::ReadModel(char *filename, bool bEdit, bool bMeta)
-{
- m_triangleUsed = 0;
- return AddModel(filename, 0, bEdit, bMeta);
-}
-
-
-// Writes a MOD file.
-
-bool CModFile::WriteModel(char *filename)
-{
- FILE* file;
- InfoMOD info;
-
- if ( m_triangleUsed == 0 ) return false;
-
- file = fopen(filename, "wb");
- if ( file == NULL ) return false;
-
- ZeroMemory(&info, sizeof(InfoMOD));
- info.rev = 1;
- info.vers = 2;
- info.total = m_triangleUsed;
- fwrite(&info, sizeof(InfoMOD), 1, file);
-
- fwrite(m_triangleTable, sizeof(ModelTriangle), m_triangleUsed, file);
-
- fclose(file);
- return true;
-}
-
-
-// Creates the object in the 3D engine.
-
-bool CModFile::CreateEngineObject(int objRank, int addState)
-{
-#if 0
- char texName2[20];
- int texNum, i, state;
-
- for ( i=0 ; i<m_triangleUsed ; i++ )
- {
- if ( !m_triangleTable[i].bUsed ) continue;
-
- state = m_triangleTable[i].state;
- texName2[0] = 0;
-
- if ( m_triangleTable[i].texNum2 != 0 )
- {
- if ( m_triangleTable[i].texNum2 == 1 )
- {
- texNum = m_engine->RetSecondTexture();
- }
- else
- {
- texNum = m_triangleTable[i].texNum2;
- }
-
- if ( texNum >= 1 && texNum <= 10 )
- {
- state = m_triangleTable[i].state|D3DSTATEDUALb;
- }
- if ( texNum >= 11 && texNum <= 20 )
- {
- state = m_triangleTable[i].state|D3DSTATEDUALw;
- }
- sprintf(texName2, "dirty%.2d.bmp", texNum);
- }
-
- m_engine->AddTriangle(objRank, &m_triangleTable[i].p1, 3,
- m_triangleTable[i].material,
- state+addState,
- m_triangleTable[i].texName, texName2,
- m_triangleTable[i].min,
- m_triangleTable[i].max, false);
- }
- return true;
-#else
- char texName1[20];
- char texName2[20];
- int texNum, i, state;
-
- for ( i=0 ; i<m_triangleUsed ; i++ )
- {
- if ( !m_triangleTable[i].bUsed ) continue;
-
- state = m_triangleTable[i].state;
- strcpy(texName1, m_triangleTable[i].texName);
- texName2[0] = 0;
-
- if ( strcmp(texName1, "plant.tga") == 0 )
- {
- state |= D3DSTATEALPHA;
- }
-
- if ( m_triangleTable[i].texNum2 != 0 )
- {
- if ( m_triangleTable[i].texNum2 == 1 )
- {
- texNum = m_engine->RetSecondTexture();
- }
- else
- {
- texNum = m_triangleTable[i].texNum2;
- }
-
- if ( texNum >= 1 && texNum <= 10 )
- {
- state |= D3DSTATEDUALb;
- }
- if ( texNum >= 11 && texNum <= 20 )
- {
- state |= D3DSTATEDUALw;
- }
- sprintf(texName2, "dirty%.2d.tga", texNum);
- }
-
- m_engine->AddTriangle(objRank, &m_triangleTable[i].p1, 3,
- m_triangleTable[i].material,
- state+addState,
- texName1, texName2,
- m_triangleTable[i].min,
- m_triangleTable[i].max, false);
- }
- return true;
-#endif
-}
-
-
-// Performs a mirror according to Z.
-
-void CModFile::Mirror()
-{
- D3DVERTEX2 t;
- int i;
-
- for ( i=0 ; i<m_triangleUsed ; i++ )
- {
- t = m_triangleTable[i].p1;
- m_triangleTable[i].p1 = m_triangleTable[i].p2;
- m_triangleTable[i].p2 = t;
-
- m_triangleTable[i].p1.z = -m_triangleTable[i].p1.z;
- m_triangleTable[i].p2.z = -m_triangleTable[i].p2.z;
- m_triangleTable[i].p3.z = -m_triangleTable[i].p3.z;
-
- m_triangleTable[i].p1.nz = -m_triangleTable[i].p1.nz;
- m_triangleTable[i].p2.nz = -m_triangleTable[i].p2.nz;
- m_triangleTable[i].p3.nz = -m_triangleTable[i].p3.nz;
- }
-}
-
-
-// Returns the pointer to the list of triangles.
-
-void CModFile::SetTriangleUsed(int total)
-{
- m_triangleUsed = total;
-}
-
-int CModFile::RetTriangleUsed()
-{
- return m_triangleUsed;
-}
-
-int CModFile::RetTriangleMax()
-{
- return MAX_VERTICES;
-}
-
-ModelTriangle* CModFile::RetTriangleList()
-{
- return m_triangleTable;
-}
-
-
-// Returns the height according to a position (x - z);
-
-float CModFile::RetHeight(Math::Vector pos)
-{
- Math::Vector p1, p2, p3;
- float limit;
- int i;
-
- limit = 5.0f;
-
- for ( i=0 ; i<m_triangleUsed ; i++ )
- {
- if ( !m_triangleTable[i].bUsed ) continue;
-
- if ( fabs(pos.x-m_triangleTable[i].p1.x) < limit &&
- fabs(pos.z-m_triangleTable[i].p1.z) < limit )
- {
- return m_triangleTable[i].p1.y;
- }
-
- if ( fabs(pos.x-m_triangleTable[i].p2.x) < limit &&
- fabs(pos.z-m_triangleTable[i].p2.z) < limit )
- {
- return m_triangleTable[i].p2.y;
- }
-
- if ( fabs(pos.x-m_triangleTable[i].p3.x) < limit &&
- fabs(pos.z-m_triangleTable[i].p3.z) < limit )
- {
- return m_triangleTable[i].p3.y;
- }
- }
-
- return 0.0f;
-}
-
-
diff --git a/src/common/modfile.h b/src/common/modfile.h
deleted file mode 100644
index c852c1e..0000000
--- a/src/common/modfile.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.
-
-// modfile.h
-
-#pragma once
-
-
-#include "math/vector.h"
-#include "old/d3dengine.h"
-
-
-class CInstanceManager;
-
-
-
-
-struct OldModelTriangle1
-{
- char bUsed; // true -> using
- char bSelect; // true -> selected
- D3DVERTEX p1;
- D3DVERTEX p2;
- D3DVERTEX p3;
- D3DMATERIAL7 material;
- char texName[20];
- float min;
- float max;
-}; // length = 196 bytes
-
-struct OldModelTriangle2
-{
- char bUsed; // true -> used
- char bSelect; // true -> selected
- D3DVERTEX p1;
- D3DVERTEX p2;
- D3DVERTEX p3;
- D3DMATERIAL7 material;
- char texName[20];
- float min;
- float max;
- long state;
- short reserve1;
- short reserve2;
- short reserve3;
- short reserve4;
-};
-
-struct ModelTriangle
-{
- char bUsed; // true -> used
- char bSelect; // true -> selected
- D3DVERTEX2 p1;
- D3DVERTEX2 p2;
- D3DVERTEX2 p3;
- D3DMATERIAL7 material;
- char texName[20];
- float min;
- float max;
- long state;
- short texNum2;
- short reserve2;
- short reserve3;
- short reserve4;
-}; // length = 208 bytes
-
-
-
-
-class CModFile
-{
-public:
- CModFile(CInstanceManager* iMan);
- ~CModFile();
-
- bool ReadDXF(char *filename, float min, float max);
- bool AddModel(char *filename, int first, bool bEdit=false, bool bMeta=true);
- bool ReadModel(char *filename, bool bEdit=false, bool bMeta=true);
- bool WriteModel(char *filename);
-
- bool CreateEngineObject(int objRank, int addState=0);
- void Mirror();
-
- void SetTriangleUsed(int total);
- int RetTriangleUsed();
- int RetTriangleMax();
- ModelTriangle* RetTriangleList();
-
- float RetHeight(Math::Vector pos);
-
-protected:
- bool CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max);
-
-protected:
- CInstanceManager* m_iMan;
- CD3DEngine* m_engine;
-
- ModelTriangle* m_triangleTable;
- int m_triangleUsed;
-};
-
-
diff --git a/src/common/singleton.h b/src/common/singleton.h
index dc09645..4df7878 100644
--- a/src/common/singleton.h
+++ b/src/common/singleton.h
@@ -29,25 +29,25 @@ template<typename T> class CSingleton
public:
static T& GetInstance() {
- aserrt(mInstance);
+ assert(mInstance != NULL);
return *mInstance;
}
- static T& GetInstancePointer() {
- aserrt(mInstance);
+ static T* GetInstancePointer() {
+ assert(mInstance != NULL);
return mInstance;
}
static bool IsCreated() {
- return mInstance != NULL;
+ return mInstance != NULL;
}
CSingleton() {
- assert(!mInstance);
+ assert(mInstance == NULL);
mInstance = static_cast<T *>(this);
}
- ~CSingleton() {
+ virtual ~CSingleton() {
mInstance = NULL;
}
diff --git a/src/common/stringutils.cpp b/src/common/stringutils.cpp
new file mode 100644
index 0000000..9a7aa61
--- /dev/null
+++ b/src/common/stringutils.cpp
@@ -0,0 +1,149 @@
+// * 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/.
+
+// stringutils.cpp
+
+#include "stringutils.h"
+
+
+std::string StrUtils::Replace(const std::string &str, const std::string &oldStr, const std::string &newStr)
+{
+ std::string result = str;
+ size_t pos = 0;
+ while ((pos = str.find(oldStr, pos)) != std::string::npos)
+ {
+ result.replace(pos, oldStr.length(), newStr);
+ pos += newStr.length();
+ }
+ return result;
+}
+
+std::string StrUtils::UnicodeCharToUtf8(unsigned int ch)
+{
+ std::string result;
+ if (ch < 0x0080)
+ {
+ result += (char)(ch);
+ }
+ else if (ch < 0x0800)
+ {
+ char ch1 = 0xC0 | ((ch & 0x07C0) >> 6);
+ char ch2 = 0x80 | (ch & 0x3F);
+ result += ch1;
+ result += ch2;
+ }
+ else
+ {
+ char ch1 = 0xE0 | ((ch & 0xF000) >> 12);
+ char ch2 = 0x80 | ((ch & 0x07C0) >> 6);
+ char ch3 = 0x80 | (ch & 0x3F);
+ result += ch1;
+ result += ch2;
+ result += ch3;
+ }
+ return result;
+}
+
+std::string StrUtils::UnicodeStringToUtf8(const std::wstring &str)
+{
+ std::string result;
+ for (unsigned int i = 0; i < str.size(); ++i)
+ result += StrUtils::UnicodeCharToUtf8((unsigned int)str[i]);
+
+ return result;
+}
+
+unsigned int StrUtils::Utf8CharToUnicode(const std::string &ch)
+{
+ if (ch.empty())
+ return 0;
+
+ unsigned int result = 0;
+ if ((ch[0] & 0x80) == 0)
+ {
+ if (ch.size() == 1)
+ result = (unsigned int)ch[0];
+ }
+ else if ((ch[0] & 0xC0) == 0xC0)
+ {
+ if (ch.size() == 2)
+ {
+ unsigned int ch1 = (ch[0] & 0x1F) << 6;
+ unsigned int ch2 = (ch[1] & 0x3F);
+ result = ch1 | ch2;
+ }
+ }
+ else
+ {
+ if (ch.size() == 3)
+ {
+ unsigned int ch1 = (ch[0] & 0xF0) << 12;
+ unsigned int ch2 = (ch[1] & 0xC0) << 6;
+ unsigned int ch3 = (ch[2] & 0xC0);
+ result = ch1 | ch2 | ch3;
+ }
+ }
+
+ return result;
+}
+
+std::wstring StrUtils::Utf8StringToUnicode(const std::string &str)
+{
+ std::wstring result;
+ unsigned int pos = 0;
+ while (pos < str.size())
+ {
+ int len = StrUtils::Utf8CharSizeAt(str, pos);
+ if (len == 0)
+ break;
+
+ std::string ch = str.substr(pos, len);
+ result += (wchar_t)(StrUtils::Utf8CharToUnicode(ch));
+ pos += len;
+ }
+ return result;
+}
+
+int StrUtils::Utf8CharSizeAt(const std::string &str, unsigned int pos)
+{
+ if (pos >= str.size())
+ return 0;
+
+ if ((str[pos] & 0x80) == 0)
+ return 1;
+ else if ((str[pos] & 0xC0) == 0xC0)
+ return 2;
+ else
+ return 3;
+
+ return 0;
+}
+
+size_t StrUtils::Utf8StringLength(const std::string &str)
+{
+ size_t result = 0;
+ for (unsigned int i = 0; i < str.size(); ++i)
+ {
+ char ch = str[i];
+ if ((ch & 0x80) == 0)
+ ++result;
+ else if ((ch & 0xC0) == 0xC0)
+ result += 2;
+ else
+ result += 3;
+ }
+ return result;
+}
diff --git a/src/common/stringutils.h b/src/common/stringutils.h
new file mode 100644
index 0000000..a0cae70
--- /dev/null
+++ b/src/common/stringutils.h
@@ -0,0 +1,77 @@
+// * 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/.
+
+// stringutils.h
+
+#pragma once
+
+
+#include <string>
+#include <sstream>
+
+namespace StrUtils {
+
+//! Converts a value to string
+/** If given, \a ok is set to true/false on success/failure.
+ Warning: To avoid unnecessary problems, *always* give full template qualifier e.g. ToString\<int\> */
+template<class T>
+std::string ToString(T value, bool *ok = NULL)
+{
+ std::ostringstream s;
+ s << value;
+ if (ok != NULL)
+ *ok = !s.fail();
+ return s.str();
+}
+
+//! Converts a value to string
+/** If given, \a ok is set to true/false on success/failure.
+ Warning: To avoid unnecessary problems, *always* give full template qualifier e.g. FromString\<int\> */
+template<class T>
+T FromString(const std::string &str, bool *ok = NULL)
+{
+ std::istringstream s;
+ s.str(str);
+ T value;
+ s >> value;
+ if (ok != NULL)
+ *ok = !s.fail();
+ return value;
+}
+
+//! Returns a string with every occurence of \a oldStr in \a str replaced to \a newStr
+std::string Replace(const std::string &str, const std::string &oldStr, const std::string &newStr);
+
+
+//! Converts a wide Unicode char to a single UTF-8 encoded char
+std::string UnicodeCharToUtf8(unsigned int ch);
+
+//! Converts a wide Unicode string to a UTF-8 encoded string
+std::string UnicodeStringToUtf8(const std::wstring &str);
+
+//! Converts a UTF-8 encoded single character to wide Unicode char
+unsigned int Utf8CharToUnicode(const std::string &ch);
+
+//! Converts a UTF-8 encoded string to wide Unicode string
+std::wstring Utf8StringToUnicode(const std::string &str);
+
+//! Returns the size in bytes of UTF-8 character at given \a pos in a UTF-8 \a str
+int Utf8CharSizeAt(const std::string &str, unsigned int pos);
+
+//! Returns the length in characters of UTF-8 string \a str
+size_t Utf8StringLength(const std::string &str);
+
+}; // namespace StrUtil
diff --git a/src/common/test/CMakeLists.txt b/src/common/test/CMakeLists.txt
new file mode 100644
index 0000000..680116c
--- /dev/null
+++ b/src/common/test/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(CMAKE_BUILD_TYPE debug)
+set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0")
+
+add_executable(image_test ../image.cpp image_test.cpp)
diff --git a/src/common/test/image_test.cpp b/src/common/test/image_test.cpp
new file mode 100644
index 0000000..0ad1ee2
--- /dev/null
+++ b/src/common/test/image_test.cpp
@@ -0,0 +1,34 @@
+#include "../image.h"
+
+#include <SDL/SDL.h>
+#include <stdio.h>
+
+/* For now, just a simple test: loading a file from image
+ * and saving it to another in PNG. */
+
+int main(int argc, char *argv[])
+{
+ if (argc != 3)
+ {
+ printf("Usage: %s in_image out_image\n", argv[0]);
+ return 0;
+ }
+
+ CImage image;
+
+ if (! image.Load(argv[1]))
+ {
+ std::string err = image.GetError();
+ printf("Error loading '%s': %s\n", err.c_str());
+ return 1;
+ }
+
+ if (! image.SavePNG(argv[2]))
+ {
+ std::string err = image.GetError();
+ printf("Error saving PNG '%s': %s\n", err.c_str());
+ return 2;
+ }
+
+ return 0;
+}
diff --git a/src/graphics/common/README.txt b/src/graphics/common/README.txt
deleted file mode 100644
index 495a453..0000000
--- a/src/graphics/common/README.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-src/graphics/common
-
-Universal structs and classes used in graphics engine
-
-Concrete implementation in OpenGL is in graphics/opengl directory.
diff --git a/src/graphics/common/color.cpp b/src/graphics/common/color.cpp
deleted file mode 100644
index dd502f9..0000000
--- a/src/graphics/common/color.cpp
+++ /dev/null
@@ -1,150 +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/.
-
-// color.cpp
-
-#include "graphics/common/color.h"
-
-#include "math/func.h"
-
-
-// Returns the color corresponding long.
-
-long Gfx::RetColor(float intensity)
-{
- long color;
-
- if ( intensity <= 0.0f ) return 0x00000000;
- if ( intensity >= 1.0f ) return 0xffffffff;
-
- color = (int)(intensity*255.0f)<<24;
- color |= (int)(intensity*255.0f)<<16;
- color |= (int)(intensity*255.0f)<<8;
- color |= (int)(intensity*255.0f);
-
- return color;
-}
-
-// Returns the color corresponding long.
-
-long Gfx::RetColor(Gfx::Color intensity)
-{
- long color;
-
- color = (int)(intensity.a*255.0f)<<24;
- color |= (int)(intensity.r*255.0f)<<16;
- color |= (int)(intensity.g*255.0f)<<8;
- color |= (int)(intensity.b*255.0f);
-
- return color;
-}
-
-// Returns the color corresponding Color.
-
-Gfx::Color Gfx::RetColor(long intensity)
-{
- Gfx::Color color;
-
- color.r = (float)((intensity>>16)&0xff)/256.0f;
- color.g = (float)((intensity>>8 )&0xff)/256.0f;
- color.b = (float)((intensity>>0 )&0xff)/256.0f;
- color.a = (float)((intensity>>24)&0xff)/256.0f;
-
- return color;
-}
-
-
-// RGB to HSV conversion.
-
-void Gfx::RGB2HSV(Gfx::Color src, Gfx::ColorHSV &dest)
-{
- float min, max, delta;
-
- min = Math::Min(src.r, src.g, src.b);
- max = Math::Max(src.r, src.g, src.b);
-
- dest.v = max; // intensity
-
- if ( max == 0.0f )
- {
- dest.s = 0.0f; // saturation
- dest.h = 0.0f; // undefined color!
- }
- else
- {
- delta = max-min;
- dest.s = delta/max; // saturation
-
- if ( src.r == max ) // between yellow & magenta
- {
- dest.h = (src.g-src.b)/delta;
- }
- else if ( src.g == max ) // between cyan & yellow
- {
- dest.h = 2.0f+(src.b-src.r)/delta;
- }
- else // between magenta & cyan
- {
- dest.h = 4.0f+(src.r-src.g)/delta;
- }
-
- dest.h *= 60.0f; // in degrees
- if ( dest.h < 0.0f ) dest.h += 360.0f;
- dest.h /= 360.0f; // 0..1
- }
-}
-
-// HSV to RGB conversion.
-
-void Gfx::HSV2RGB(Gfx::ColorHSV src, Gfx::Color &dest)
-{
- int i;
- float f,v,p,q,t;
-
- src.h = Math::Norm(src.h)*360.0f;
- src.s = Math::Norm(src.s);
- src.v = Math::Norm(src.v);
-
- if ( src.s == 0.0f ) // zero saturation?
- {
- dest.r = src.v;
- dest.g = src.v;
- dest.b = src.v; // gray
- }
- else
- {
- if ( src.h == 360.0f ) src.h = 0.0f;
- src.h /= 60.0f;
- i = (int)src.h; // integer part (0 .. 5)
- f = src.h-i; // fractional part
-
- v = src.v;
- p = src.v*(1.0f-src.s);
- q = src.v*(1.0f-(src.s*f));
- t = src.v*(1.0f-(src.s*(1.0f-f)));
-
- switch (i)
- {
- case 0: dest.r=v; dest.g=t; dest.b=p; break;
- case 1: dest.r=q; dest.g=v; dest.b=p; break;
- case 2: dest.r=p; dest.g=v; dest.b=t; break;
- case 3: dest.r=p; dest.g=q; dest.b=v; break;
- case 4: dest.r=t; dest.g=p; dest.b=v; break;
- case 5: dest.r=v; dest.g=p; dest.b=q; break;
- }
- }
-}
-
diff --git a/src/graphics/common/color.h b/src/graphics/common/color.h
deleted file mode 100644
index 12f008f..0000000
--- a/src/graphics/common/color.h
+++ /dev/null
@@ -1,50 +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/.
-
-// color.h
-
-#pragma once
-
-
-namespace Gfx {
-
-struct Color
-{
- float r, g, b, a;
-
- Color(float aR = 0.0f, float aG = 0.0f, float aB = 0.0f, float aA = 0.0f)
- : r(aR), g(aG), b(aB), a(aA) {}
-};
-
-
-struct ColorHSV
-{
- float h, s, v;
-
- ColorHSV(float aH = 0.0f, float aS = 0.0f, float aV = 0.0f)
- : h(aH), s(aS), v(aV) {}
-};
-
-
-long RetColor(float intensity);
-long RetColor(Color intensity);
-Color RetColor(long intensity);
-
-void RGB2HSV(Color src, ColorHSV &dest);
-void HSV2RGB(ColorHSV src, Color &dest);
-
-}; // namespace Gfx
-
diff --git a/src/graphics/common/device.cpp b/src/graphics/common/device.cpp
deleted file mode 100644
index 53274b3..0000000
--- a/src/graphics/common/device.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "graphics/common/device.h"
-
-//! Sets the default values
-Gfx::DeviceConfig::DeviceConfig()
-{
- width = 800;
- height = 600;
- bpp = 16;
- fullScreen = false;
- resizeable = false;
- hardwareAccel = true;
- doubleBuf = true;
- noFrame = false;
-} \ No newline at end of file
diff --git a/src/graphics/common/engine.cpp b/src/graphics/common/engine.cpp
deleted file mode 100644
index 3b9a89d..0000000
--- a/src/graphics/common/engine.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-// * 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/.
-
-// engine.cpp
-
-#include "graphics/common/engine.h"
-
-#include <GL/gl.h>
-#include <GL/glu.h>
-
-
-// TODO implementation
-
-Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
-{
- // TODO
-}
-
-Gfx::CEngine::~CEngine()
-{
- // TODO
-}
-
-int Gfx::CEngine::Render()
-{
- /* Just a hello world for now */
-
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glShadeModel(GL_SMOOTH);
- glDisable(GL_DEPTH_TEST);
- glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
-
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluOrtho2D(-10.0f, 10.0f, -10.0f, 10.0f);
-
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- //glTranslatef(0.0f, 0.0f, -6.0f);
-
- glBegin(GL_TRIANGLES);
- {
- glColor3f(1.0f, 0.0f, 0.0f);
- glVertex2f(-2.0f, -1.0f);
- glColor3f(0.0f, 1.0f, 0.0f);
- glVertex2f(2.0f, -1.0f);
- glColor3f(0.0f, 0.0f, 1.0f);
- glVertex2f(0.0f, 1.5f);
- }
- glEnd();
-
- glFlush();
-
- return 1;
-}
diff --git a/src/graphics/common/engine.h b/src/graphics/common/engine.h
deleted file mode 100644
index b36ccbc..0000000
--- a/src/graphics/common/engine.h
+++ /dev/null
@@ -1,715 +0,0 @@
-// * 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/.
-
-// engine.h
-
-#pragma once
-
-
-#include "graphics/common/color.h"
-#include "graphics/common/material.h"
-#include "graphics/common/vertex.h"
-#include "math/intpoint.h"
-#include "math/matrix.h"
-#include "math/point.h"
-#include "math/vector.h"
-
-
-class CApplication;
-class CInstanceManager;
-class CObject;
-class CSound;
-
-
-namespace Gfx {
-
-class CDevice;
-class CLight;
-class CText;
-class CParticle;
-class CWater;
-class CCloud;
-class CLightning;
-class CPlanet;
-class CTerrain;
-
-
-//const int MAXOBJECT = 1200;
-//const int MAXSHADOW = 500;
-//const int MAXGROUNDSPOT = 100;
-
-
-enum ObjectType
-{
- //! Object doesn't exist
- OBJTYPE_NULL = 0,
- //! Terrain
- OBJTYPE_TERRAIN = 1,
- //! Fixed object
- OBJTYPE_FIX = 2,
- //! Moving object
- OBJTYPE_VEHICULE = 3,
- //! Part of a moving object
- OBJTYPE_DESCENDANT = 4,
- //! Fixed object type quartz
- OBJTYPE_QUARTZ = 5,
- //! Fixed object type metal
- OBJTYPE_METAL = 6
-};
-
-enum TriangleType
-{
- //! triangles
- TRIANGLE_TYPE_6T = 1,
- //! surfaces
- TRIANGLE_TYPE_6S = 2
-};
-
-enum Mapping
-{
- MAPPING_X = 1,
- MAPPING_Y = 2,
- MAPPING_Z = 3,
- MAPPING_1X = 4,
- MAPPING_1Y = 5,
- MAPPING_1Z = 6
-};
-
-enum MouseType
-{
- MOUSE_HIDE = 0, // no mouse
- MOUSE_NORM = 1,
- MOUSE_WAIT = 2,
- MOUSE_EDIT = 3,
- MOUSE_HAND = 4,
- MOUSE_CROSS = 5,
- MOUSE_SHOW = 6,
- MOUSE_NO = 7,
- MOUSE_MOVE = 8, // +
- MOUSE_MOVEH = 9, // -
- MOUSE_MOVEV = 10, // |
- MOUSE_MOVED = 11, // /
- MOUSE_MOVEI = 12, // \ //
- MOUSE_SCROLLL = 13, // <<
- MOUSE_SCROLLR = 14, // >>
- MOUSE_SCROLLU = 15, // ^
- MOUSE_SCROLLD = 16, // v
- MOUSE_TARGET = 17
-};
-
-enum ShadowType
-{
- SHADOW_NORM = 0,
- SHADOW_WORM = 1
-};
-
-enum RenderState
-{
- //! Normal opaque materials
- RSTATE_NORMAL = 0,
- //! The transparent texture (black = no)
- RSTATE_TTEXTURE_BLACK = (1<<0),
- //! The transparent texture (white = no)
- RSTATE_TTEXTURE_WHITE = (1<<1),
- //! The transparent diffuse color
- RSTATE_TDIFFUSE = (1<<2),
- //! Texture wrap
- RSTATE_WRAP = (1<<3),
- //! Texture borders with solid color
- RSTATE_CLAMP = (1<<4),
- //! Light texture (ambient max)
- RSTATE_LIGHT = (1<<5),
- //! Double black texturing
- RSTATE_DUAL_BLACK = (1<<6),
- //! Double white texturing
- RSTATE_DUAL_WHITE = (1<<7),
- //! Part 1 (no change in. MOD!)
- RSTATE_PART1 = (1<<8),
- //! Part 2
- RSTATE_PART2 = (1<<9),
- //! Part 3
- RSTATE_PART3 = (1<<10),
- //! Part 4
- RSTATE_PART4 = (1<<11),
- //! Double-sided face
- RSTATE_2FACE = (1<<12),
- //! Image using alpha channel
- RSTATE_ALPHA = (1<<13),
- //! Always use 2nd floor texturing
- RSTATE_SECOND = (1<<14),
- //! Causes the fog
- RSTATE_FOG = (1<<15),
- //! The transparent color (black = no)
- RSTATE_TCOLOR_BLACK = (1<<16),
- //! The transparent color (white = no)
- RSTATE_TCOLOR_WHITE = (1<<17)
-};
-
-
-struct Triangle
-{
- Gfx::VertexTex2 triangle[3];
- Gfx::Material material;
- int state;
- char texName1[20];
- char texName2[20];
-};
-
-
-struct ObjLevel6
-{
- int totalPossible;
- int totalUsed;
- Gfx::Material material;
- int state;
- Gfx::TriangleType type;
- Gfx::VertexTex2 vertex[1];
-};
-
-struct ObjLevel5
-{
- int totalPossible;
- int totalUsed;
- int reserve;
- Gfx::ObjLevel6* table[1];
-};
-
-struct ObjLevel4
-{
- int totalPossible;
- int totalUsed;
- float min, max;
- Gfx::ObjLevel5* table[1];
-};
-
-struct ObjLevel3
-{
- int totalPossible;
- int totalUsed;
- int objRank;
- Gfx::ObjLevel4* table[1];
-};
-
-struct ObjLevel2
-{
- int totalPossible;
- int totalUsed;
- char texName1[20];
- char texName2[20];
- Gfx::ObjLevel3* table[1];
-};
-
-struct ObjLevel1
-{
- int totalPossible;
- int totalUsed;
- Gfx::ObjLevel2* table[1];
-};
-
-
-struct Object
-{
- bool used; // true -> object exists
- bool visible; // true -> visible object
- bool drawWorld; // true -> shape behind the interface
- bool drawFront; // true -> shape before the interface
- int totalTriangle; // number of triangles used
- Gfx::ObjectType type; // type of the object (TYPE*)
- Math::Matrix transform; // transformation matrix
- float distance; // distance point of view - original
- Math::Vector bboxMin; // bounding box of the object
- Math::Vector bboxMax; // (the origin 0, 0, 0 is always included)
- float radius; // radius of the sphere at the origin
- int shadowRank; // rank of the associated shadow
- float transparency; // transparency of the object (0 .. 1)
-};
-
-struct Shadow
-{
- bool used; // true -> object exists
- bool hide; // true -> invisible shadow (object carried by ex.)
- int objRank; // rank of the object
- Gfx::ShadowType type; // type of shadow
- Math::Vector pos; // position for the shadow
- Math::Vector normal; // normal terrain
- float angle; // angle of the shadow
- float radius; // radius of the shadow
- float intensity; // intensity of the shadow
- float height; // height from the ground
-};
-
-struct GroundSpot
-{
- bool used; // true -> object exists
- Gfx::Color color; // color of the shadow
- float min, max; // altitudes min / max
- float smooth; // transition area
- Math::Vector pos; // position for the shadow
- float radius; // radius of the shadow
- Math::Vector drawPos; // drawn to position the shade
- float drawRadius; // radius of the shadow drawn
-};
-
-struct GroundMark
-{
- bool used; // true -> object exists
- bool draw; // true -> drawn mark
- int phase; // 1 = increase, 2 = fixed, 3 = decrease
- float delay[3]; // time for 3 phases
- float fix; // fixed time
- Math::Vector pos; // position for marks
- float radius; // radius of marks
- float intensity; // color intensity
- Math::Vector drawPos; // drawn in position marks
- float drawRadius; // radius marks drawn
- float drawIntensity; // current drawn
- int dx, dy; // dimensions table
- char* table; // pointer to the table
-};
-
-
-
-class CEngine
-{
-public:
- CEngine(CInstanceManager *iMan, CApplication *app);
- ~CEngine();
-
- void SetDevice(Gfx::CDevice *device);
- Gfx::CDevice* RetDevice();
-
- void SetTerrain(Gfx::CTerrain* terrain);
-
- bool WriteProfile();
-
- void SetPause(bool pause);
- bool RetPause();
-
- void SetMovieLock(bool lock);
- bool RetMovieLock();
-
- void SetShowStat(bool show);
- bool RetShowStat();
-
- void SetRenderEnable(bool enable);
-
- int OneTimeSceneInit();
- int InitDeviceObjects();
- int DeleteDeviceObjects();
- int RestoreSurfaces();
- int Render();
- int FrameMove(float rTime);
- void StepSimul(float rTime);
- int FinalCleanup();
- void AddStatisticTriangle(int nb);
- int RetStatisticTriangle();
- 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 * RetInfoText(int line);
- //LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
- void FirstExecuteAdapt(bool first);
- //int GetVidMemTotal();
- //bool IsVideo8MB();
- //bool IsVideo32MB();
-
- bool EnumDevices(char *bufDevices, int lenDevices, char *bufModes, int lenModes, int &totalDevices, int &selectDevices, int &totalModes, int &selectModes);
- bool RetFullScreen();
- bool ChangeDevice(char *device, char *mode, bool full);
-
- Math::Matrix* RetMatView();
- Math::Matrix* RetMatLeftView();
- Math::Matrix* RetMatRightView();
-
- void TimeInit();
- void TimeEnterGel();
- void TimeExitGel();
- float TimeGet();
-
- int RetRestCreate();
- int CreateObject();
- void FlushObject();
- bool DeleteObject(int objRank);
- bool SetDrawWorld(int objRank, bool draw);
- bool SetDrawFront(int objRank, bool draw);
- bool AddTriangle(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material &mat, int state, char* texName1, char* texName2, float min, float max, bool globalUpdate);
- bool AddSurface(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material &mat, int state, char* texName1, char* texName2, float min, float max, bool globalUpdate);
- bool AddQuick(int objRank, Gfx::ObjLevel6* buffer, char* texName1, char* texName2, float min, float max, bool globalUpdate);
- Gfx::ObjLevel6* SearchTriangle(int objRank, const Gfx::Material &mat, int state, char* texName1, char* texName2, float min, float max);
- void ChangeLOD();
- bool ChangeSecondTexture(int objRank, char* texName2);
- int RetTotalTriangles(int objRank);
- int GetTriangles(int objRank, float min, float max, Gfx::Triangle* 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, char* texName1, char* texName2, float min, float max, Gfx::Mapping mode, float au, float bu, float av, float bv);
- bool TrackTextureMapping(int objRank, const Gfx::Material &mat, int state, char* texName1, char* texName2, float min, float max, Gfx::Mapping 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::ObjectType type);
- Gfx::ObjectType RetObjectType(int objRank);
- bool SetObjectTransparency(int objRank, float value);
-
- bool ShadowCreate(int objRank);
- void ShadowDelete(int objRank);
- bool SetObjectShadowHide(int objRank, bool hide);
- bool SetObjectShadowType(int objRank, Gfx::ShadowType type);
- bool SetObjectShadowPos(int objRank, const Math::Vector &pos);
- bool SetObjectShadowNormal(int objRank, const Math::Vector &n);
- bool SetObjectShadowAngle(int objRank, float angle);
- bool SetObjectShadowRadius(int objRank, float radius);
- bool SetObjectShadowIntensity(int objRank, float intensity);
- bool SetObjectShadowHeight(int objRank, float h);
- float RetObjectShadowRadius(int objRank);
-
- void GroundSpotFlush();
- int GroundSpotCreate();
- void GroundSpotDelete(int rank);
- bool SetObjectGroundSpotPos(int rank, const Math::Vector &pos);
- bool SetObjectGroundSpotRadius(int rank, float radius);
- 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, float delay1, float delay2, float delay3, int dx, int dy, char* table);
- bool GroundMarkDelete(int rank);
-
- void Update();
-
- void SetViewParams(const Math::Vector &vEyePt, const Math::Vector &vLookatPt, const Math::Vector &vUpVec, float fEyeDistance);
-
- bool FreeTexture(char* name);
- bool LoadTexture(char* name, int stage=0);
- bool LoadAllTexture();
-
- void SetLimitLOD(int rank, float limit);
- float RetLimitLOD(int rank, bool last=false);
-
- void SetTerrainVision(float vision);
-
- void SetGroundSpot(bool mode);
- bool RetGroundSpot();
- void SetShadow(bool mode);
- bool RetShadow();
- void SetDirty(bool mode);
- bool RetDirty();
- void SetFog(bool mode);
- bool RetFog();
- bool RetStateColor();
-
- void SetSecondTexture(int texNum);
- int RetSecondTexture();
-
- void SetRankView(int rank);
- int RetRankView();
-
- void SetDrawWorld(bool draw);
- void SetDrawFront(bool draw);
-
- void SetAmbiantColor(const Gfx::Color &color, int rank=0);
- Gfx::Color RetAmbiantColor(int rank=0);
-
- void SetWaterAddColor(const Gfx::Color &color);
- Gfx::Color RetWaterAddColor();
-
- void SetFogColor(const Gfx::Color &color, int rank=0);
- Gfx::Color RetFogColor(int rank=0);
-
- void SetDeepView(float length, int rank=0, bool ref=false);
- float RetDeepView(int rank=0);
-
- void SetFogStart(float start, int rank=0);
- float RetFogStart(int rank=0);
-
- void SetBackground(char *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 RetBackground(char *name, Gfx::Color &up, Gfx::Color &down, Gfx::Color &cloudUp, Gfx::Color &cloudDown, bool &full, bool &quarter);
- void SetFrontsizeName(char *name);
- void SetOverFront(bool front);
- void SetOverColor(const Gfx::Color &color=Gfx::Color(), int mode=RSTATE_TCOLOR_BLACK);
-
- void SetParticuleDensity(float value);
- float RetParticuleDensity();
- float ParticuleAdapt(float factor);
-
- void SetClippingDistance(float value);
- float RetClippingDistance();
-
- void SetObjectDetail(float value);
- float RetObjectDetail();
-
- void SetGadgetQuantity(float value);
- float RetGadgetQuantity();
-
- void SetTextureQuality(int value);
- int RetTextureQuality();
-
- void SetTotoMode(bool present);
- bool RetTotoMode();
-
- void SetLensMode(bool present);
- bool RetLensMode();
-
- void SetWaterMode(bool present);
- bool RetWaterMode();
-
- void SetBlitzMode(bool present);
- bool RetBlitzMode();
-
- void SetSkyMode(bool present);
- bool RetSkyMode();
-
- void SetBackForce(bool present);
- bool RetBackForce();
-
- void SetPlanetMode(bool present);
- bool RetPlanetMode();
-
- void SetLightMode(bool present);
- bool RetLightMode();
-
- void SetEditIndentMode(bool indentAuto);
- bool RetEditIndentMode();
-
- void SetEditIndentValue(int value);
- int RetEditIndentValue();
-
- void SetSpeed(float speed);
- float RetSpeed();
-
- void SetTracePrecision(float factor);
- float RetTracePrecision();
-
- void SetFocus(float focus);
- float RetFocus();
- Math::Vector RetEyePt();
- Math::Vector RetLookatPt();
- float RetEyeDirH();
- float RetEyeDirV();
- Math::Point RetDim();
- void UpdateMatProj();
-
- void ApplyChange();
-
- void FlushPressKey();
- void ResetKey();
- void SetKey(int keyRank, int option, int key);
- int RetKey(int keyRank, int option);
-
- void SetJoystick(bool enable);
- bool RetJoystick();
-
- void SetDebugMode(bool mode);
- bool RetDebugMode();
- bool RetSetupMode();
-
- 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(char *name, int stage=0);
- void SetMaterial(const Gfx::Material &mat);
-
- void MoveMousePos(Math::Point pos);
- void SetMousePos(Math::Point pos);
- Math::Point RetMousePos();
- void SetMouseType(Gfx::MouseType type);
- Gfx::MouseType RetMouseType();
- void SetMouseHide(bool hide);
- bool RetMouseHide();
- void SetNiceMouse(bool nice);
- bool RetNiceMouse();
- bool RetNiceMouseCap();
-
- CText* RetText();
-
- 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);
-
-protected:
- void MemSpace1(Gfx::ObjLevel1 *&p, int nb);
- void MemSpace2(Gfx::ObjLevel2 *&p, int nb);
- void MemSpace3(Gfx::ObjLevel3 *&p, int nb);
- void MemSpace4(Gfx::ObjLevel4 *&p, int nb);
- void MemSpace5(Gfx::ObjLevel5 *&p, int nb);
- void MemSpace6(Gfx::ObjLevel6 *&p, int nb);
-
- 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);
-
- bool IsVisible(int objRank);
- bool DetectBBox(int objRank, Math::Point mouse);
- bool DetectTriangle(Math::Point mouse, Gfx::VertexTex2 *triangle, int objRank, float &dist);
- bool TransformPoint(Math::Vector &p2D, int objRank, Math::Vector p3D);
- void ComputeDistance();
- void UpdateGeometry();
- void RenderGroundSpot();
- void DrawShadow();
- void DrawBackground();
- void DrawBackgroundGradient(Gfx::Color up, Gfx::Color down);
- void DrawBackgroundImageQuarter(Math::Point p1, Math::Point p2, char *name);
- void DrawBackgroundImage();
- void DrawPlanet();
- void DrawFrontsize();
- void DrawOverColor();
- bool GetBBox2D(int objRank, Math::Point &min, Math::Point &max);
- void DrawHilite();
- void DrawMouse();
- void DrawSprite(Math::Point pos, Math::Point dim, int icon);
-
-protected:
- CInstanceManager* m_iMan;
- CApplication* m_app;
- Gfx::CDevice* m_device;
- Gfx::CText* m_text;
- Gfx::CLight* m_light;
- Gfx::CParticle* m_particule;
- Gfx::CWater* m_water;
- Gfx::CCloud* m_cloud;
- Gfx::CLightning* m_blitz;
- Gfx::CPlanet* m_planet;
- Gfx::CTerrain* m_terrain;
- CSound* m_sound;
-
- 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];
-
- Math::Matrix m_matProj;
- Math::Matrix m_matLeftView;
- Math::Matrix m_matRightView;
- Math::Matrix m_matView;
- float m_focus;
-
- Math::Matrix m_matWorldInterface;
- Math::Matrix m_matProjInterface;
- 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;
-
- Math::IntPoint m_dim;
- Math::IntPoint m_lastDim;
- Gfx::ObjLevel1* m_objectPointer;
- int m_objectParamTotal;
- Gfx::Object* m_objectParam;
- int m_shadowTotal;
- Gfx::Shadow* m_shadow;
- Gfx::GroundSpot* m_groundSpot;
- Gfx::GroundMark m_groundMark;
- Math::Vector m_eyePt;
- Math::Vector m_lookatPt;
- float m_eyeDirH;
- float m_eyeDirV;
- int m_rankView;
- Gfx::Color m_ambiantColor[2];
- Gfx::Color m_backColor[2];
- Gfx::Color m_fogColor[2];
- float m_deepView[2];
- float m_fogStart[2];
- Gfx::Color m_waterAddColor;
- int m_statisticTriangle;
- bool m_updateGeometry;
- char m_infoText[10][200];
- int m_alphaMode;
- bool m_stateColor;
- bool m_forceStateColor;
- bool m_groundSpotVisible;
- bool m_shadowVisible;
- bool m_dirty;
- bool m_fog;
- bool m_firstGroundSpot;
- int m_secondTexNum;
- char m_backgroundName[50];
- 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;
- char m_frontsizeName[50];
- bool m_drawWorld;
- bool m_drawFront;
- float m_limitLOD[2];
- float m_particuleDensity;
- float m_clippingDistance;
- float m_lastClippingDistance;
- float m_objectDetail;
- float m_lastObjectDetail;
- float m_terrainVision;
- float m_gadgetQuantity;
- int m_textureQuality;
- bool m_totoMode;
- bool m_lensMode;
- bool m_waterMode;
- bool m_skyMode;
- bool m_backForce;
- bool m_planetMode;
- bool m_lightMode;
- bool m_editIndentMode;
- 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;
-
- Math::Point m_mousePos;
- Gfx::MouseType m_mouseType;
- bool m_mouseHide;
- bool m_niceMouse;
-
- //LPDIRECTDRAWSURFACE7 m_imageSurface;
- //DDSURFACEDESC2 m_imageDDSD;
- //WORD* m_imageCopy;
- //int m_imageDX;
- //int m_imageDY;
-};
-
-}; // namespace Gfx
diff --git a/src/graphics/common/light.cpp b/src/graphics/common/light.cpp
deleted file mode 100644
index d938256..0000000
--- a/src/graphics/common/light.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// * 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/.
-
-// light.cpp
-
-#include "graphics/common/light.h"
-
-// TODO implementation \ No newline at end of file
diff --git a/src/graphics/common/light.h b/src/graphics/common/light.h
deleted file mode 100644
index dec9912..0000000
--- a/src/graphics/common/light.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// * 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/.
-
-// light.h
-
-#pragma once
-
-
-#include "graphics/common/color.h"
-#include "math/vector.h"
-
-
-namespace Gfx {
-
-/** \enum LightType
- * \brief Type of light */
-enum LightType
-{
- LT_Point,
- LT_Spot,
- LT_Directional
-};
-
-/**
- * \struct Light
- * \brief Light
- *
- * This structure was created as analog to DirectX's D3DLIGHT.
- *
- * It contains analogous fields as the D3DLIGHT struct.
- */
-struct Light
-{
- //! Type of light source
- Gfx::LightType type;
- //! Color of light
- Gfx::Color color;
- //! Position in world space
- Math::Vector position;
- //! Direction in world space
- Math::Vector direction;
- //! Cutoff range
- float range;
- //! Falloff
- float falloff;
- //! Constant attenuation
- float attenuation0;
- //! Linear attenuation
- float attenuation1;
- //! Quadratic attenuation
- float attenuation2;
- //! Inner angle of spotlight cone
- float theta;
- //! Outer angle of spotlight cone
- float phi;
-
- Light() : type(LT_Point), range(0.0f), falloff(0.0f),
- attenuation0(0.0f), attenuation1(0.0f), attenuation2(0.0f),
- theta(0.0f), phi(0.0f) {}
-};
-
-struct LightProg
-{
- float starting;
- float ending;
- float current;
- float progress;
- float speed;
-};
-
-/**
- * \struct SceneLight
- * \brief Dynamic light in 3D scene
- *
- * TODO documentation
- */
-struct SceneLight
-{
- //! true -> light exists
- bool used;
- //! true -> light turned on
- bool enable;
-
- //! Type of all objects included
- //D3DTypeObj incluType;
- //! Type of all objects excluded
- //D3DTypeObj excluType;
-
- //! Configuration of the light
- Gfx::Light light;
-
- //! intensity (0 .. 1)
- Gfx::LightProg intensity;
- Gfx::LightProg colorRed;
- Gfx::LightProg colorGreen;
- Gfx::LightProg colorBlue;
-};
-
-// TODO CLight
-
-}; // namespace Gfx
diff --git a/src/graphics/common/model.cpp b/src/graphics/common/model.cpp
deleted file mode 100644
index c415fb8..0000000
--- a/src/graphics/common/model.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// * 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/.
-
-// model.cpp
-
-#include "graphics/common/model.h"
-
-
-// TODO implementation
diff --git a/src/graphics/common/model.h b/src/graphics/common/model.h
deleted file mode 100644
index e8a5f19..0000000
--- a/src/graphics/common/model.h
+++ /dev/null
@@ -1,141 +0,0 @@
-// * 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/.
-
-// model.h
-
-#pragma once
-
-#include "engine.h"
-#include "common/event.h"
-#include "modfile.h"
-#include "vertex.h"
-#include "math/point.h"
-
-
-class CInstanceManager;
-class CModFile;
-class CInterface;
-
-
-namespace Gfx {
-
-class CEngine;
-
-
-class CModel {
- public:
- CModel(CInstanceManager* iMan);
- ~CModel();
-
- void StartUserAction();
- void StopUserAction();
-
- bool EventProcess(const Event &event);
-
- void InitView();
- void InitViewFromSelect();
- void UpdateView();
- void ViewMove(const Event &event, float speed);
-
- protected:
- bool EventFrame(const Event &event);
- bool GetVertex(int rank, Gfx::VertexTex2 &vertex);
- bool SetVertex(int rank, Gfx::VertexTex2 &vertex);
- Math::Vector RetSelectCDG();
- Math::Vector RetSelectNormal();
- void SmoothSelect();
- void PlaneSelect();
- void ColorSelect();
- void StateSelect();
- void MoveSelect(Math::Vector move);
- void OperSelect(Math::Vector move, char oper);
- void ReadScript(char *filename);
- void BBoxCompute(Math::Vector &min, Math::Vector &max);
- bool IsMappingSelectPlausible(Gfx::Mapping D3Dmode);
- void MappingSelect(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName);
- void MappingSelectSpherical(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName);
- Math::Vector RetMappingCenter(Math::Vector pos, Math::Vector min);
- void MappingSelectCylindrical(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName);
- void MappingSelectFace(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName);
- void MappingSelect2(int texNum2, int subdiv, int offsetU, int offsetV, bool bMirrorX, bool bMirrorY);
- void MappingSelectPlane2(int mode, bool bMirrorX, bool bMirrorY);
- void MappingSelectSpherical2(bool bMirrorX, bool bMirrorY);
- void MappingSelectMagic2(bool bMirrorX, bool bMirrorY);
- int SearchNext(int rank, int step);
- int SearchSamePlane(int first, int step);
- void CurrentSearchNext(int step, bool bControl);
- void CurrentInit();
- void CurrentSelect(bool bSelect);
- void DeselectAll();
- void SelectAll();
- void SelectZone(int first, int last);
- void SelectTerm();
- void DefaultSelect();
- void SelectDelete();
- void Compress();
- void MinMaxSelect();
- void MinMaxChange();
- void UpdateInfoText();
- int* RetTextureTable();
- void TexturePartUpdate();
- void TextureRankChange(int step);
- void TexturePartChange(int step);
- void PutTextureValues();
- void GetTextureValues();
- void GetModelName(char *buffer);
- void GetDXFName(char *buffer);
- void GetScriptName(char *buffer);
- bool IsEditFocus();
-
- protected:
- CInstanceManager* m_iMan;
- Gfx::CEngine* m_engine;
- CModFile* m_modFile;
- CInterface* m_interface;
-
- float m_time;
- ModelTriangle* m_triangleTable;
- int m_triangleSel1;
- int m_triangleSel2;
- int m_mode;
- int m_textureMode;
- int m_textureRotate;
- bool m_bTextureMirrorX;
- bool m_bTextureMirrorY;
- Math::Point m_textureInf;
- Math::Point m_textureSup;
- int m_texturePart;
- int m_textureRank;
- char m_textureName[20];
- bool m_bDisplayTransparent;
- bool m_bDisplayOnlySelection;
- float m_viewHeight;
- float m_viewDist;
- float m_viewAngleH;
- float m_viewAngleV;
- int m_color;
- int m_state;
- int m_secondTexNum;
- int m_secondSubdiv;
- int m_secondOffsetU;
- int m_secondOffsetV;
- char m_oper;
- float m_min;
- float m_max;
-};
-
-}; // namespace Gfx
diff --git a/src/graphics/common/modfile.cpp b/src/graphics/common/modfile.cpp
deleted file mode 100644
index 6f80be7..0000000
--- a/src/graphics/common/modfile.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// * 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/.
-
-// modfile.cpp
-
-#include "graphics/common/modfile.h"
-
-
-// TODO implementation \ No newline at end of file
diff --git a/src/graphics/common/modfile.h b/src/graphics/common/modfile.h
deleted file mode 100644
index c81739b..0000000
--- a/src/graphics/common/modfile.h
+++ /dev/null
@@ -1,114 +0,0 @@
-// * 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/.
-
-// modfile.h
-
-#include "engine.h"
-#include "vertex.h"
-#include "material.h"
-#include "math/vector.h"
-
-
-class CInstanceManager;
-
-
-namespace Gfx {
-
-struct OldModelTriangle1
-{
- char bUsed; // TRUE -> using
- char bSelect; // TRUE -> selected
- Vertex p1;
- Vertex p2;
- Vertex p3;
- Material material;
- char texName[20];
- float min;
- float max;
-}; // length = 196 bytes
-
-struct OldModelTriangle2
-{
- char bUsed; // TRUE -> used
- char bSelect; // TRUE -> selected
- Vertex p1;
- Vertex p2;
- Vertex p3;
- Material material;
- char texName[20];
- float min;
- float max;
- long state;
- short reserve1;
- short reserve2;
- short reserve3;
- short reserve4;
-};
-
-struct ModelTriangle
-{
- char bUsed; // TRUE -> used
- char bSelect; // TRUE -> selected
- VertexTex2 p1;
- VertexTex2 p2;
- VertexTex2 p3;
- Material material;
- char texName[20];
- float min;
- float max;
- long state;
- short texNum2;
- short reserve2;
- short reserve3;
- short reserve4;
-}; // length = 208 bytes
-
-
-
-
-class CModFile {
-public:
- CModFile(CInstanceManager* iMan);
- ~CModFile();
-
- bool ReadDXF(char *filename, float min, float max);
- bool AddModel(char *filename, int first, bool bEdit=false, bool bMeta=true);
- bool ReadModel(char *filename, bool bEdit=false, bool bMeta=true);
- bool WriteModel(char *filename);
-
- bool CreateEngineObject(int objRank, int addState=0);
- void Mirror();
-
- void SetTriangleUsed(int total);
- int RetTriangleUsed();
- int RetTriangleMax();
- ModelTriangle* RetTriangleList();
-
- float RetHeight(Math::Vector pos);
-
-protected:
- bool CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max);
-
-protected:
- CInstanceManager* m_iMan;
- CEngine* m_engine;
-
- ModelTriangle* m_triangleTable;
- int m_triangleUsed;
-};
-
-};
diff --git a/src/graphics/common/vertex.h b/src/graphics/common/vertex.h
deleted file mode 100644
index 0cc6402..0000000
--- a/src/graphics/common/vertex.h
+++ /dev/null
@@ -1,68 +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/.
-
-// vertex.h
-
-#pragma once
-
-
-#include "math/vector.h"
-#include "math/point.h"
-
-namespace Gfx {
-
-/**
- * \struct Vertex
- * \brief Vertex of a primitive
- *
- * This structure was created as analog to DirectX's D3DVERTEX.
- *
- * It contains:
- * - vertex coordinates (x,y,z) as Math::Vector,
- * - normal coordinates (nx,ny,nz) as Math::Vector
- * - texture coordinates (u,v) as Math::Point.
- */
-struct Vertex
-{
- Math::Vector coord;
- Math::Vector normal;
- Math::Point texCoord;
-
- Vertex(Math::Vector aCoord = Math::Vector(),
- Math::Vector aNormal = Math::Vector(),
- Math::Point aTexCoord = Math::Point())
- : coord(aCoord), normal(aNormal), texCoord(aTexCoord) {}
-};
-
-/**
- * \struct VertexTex2
- * \brief Vertex with secondary texture coordinates
- *
- * In addition to fields from Gfx::Vector, it contains
- * secondary texture coordinates (u2, v2) as Math::Point
- */
-struct VertexTex2 : public Gfx::Vertex
-{
- Math::Point texCoord2;
-
- VertexTex2(Math::Vector aCoord = Math::Vector(),
- Math::Vector aNormal = Math::Vector(),
- Math::Point aTexCoord = Math::Point(),
- Math::Point aTexCoord2 = Math::Point())
- : Vertex(aCoord, aNormal, aTexCoord), texCoord2(aTexCoord2) {}
-};
-
-}; // namespace Gfx
diff --git a/src/graphics/core/README.txt b/src/graphics/core/README.txt
new file mode 100644
index 0000000..12beef9
--- /dev/null
+++ b/src/graphics/core/README.txt
@@ -0,0 +1,6 @@
+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
diff --git a/src/graphics/core/color.cpp b/src/graphics/core/color.cpp
new file mode 100644
index 0000000..8dec0e4
--- /dev/null
+++ b/src/graphics/core/color.cpp
@@ -0,0 +1,103 @@
+// * 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/.
+
+// color.cpp
+
+#include "graphics/core/color.h"
+
+#include "math/func.h"
+
+
+Gfx::ColorHSV Gfx::RGB2HSV(Gfx::Color color)
+{
+ Gfx::ColorHSV result;
+
+ float min = Math::Min(color.r, color.g, color.b);
+ float max = Math::Max(color.r, color.g, color.b);
+
+ result.v = max; // intensity
+
+ if ( max == 0.0f )
+ {
+ result.s = 0.0f; // saturation
+ result.h = 0.0f; // undefined color!
+ }
+ else
+ {
+ float delta = max-min;
+ result.s = delta/max; // saturation
+
+ if ( color.r == max ) // between yellow & magenta
+ {
+ result.h = (color.g-color.b)/delta;
+ }
+ else if ( color.g == max ) // between cyan & yellow
+ {
+ result.h = 2.0f+(color.b-color.r)/delta;
+ }
+ else // between magenta & cyan
+ {
+ result.h = 4.0f+(color.r-color.g)/delta;
+ }
+
+ result.h *= 60.0f; // in degrees
+ if ( result.h < 0.0f ) result.h += 360.0f;
+ result.h /= 360.0f; // 0..1
+ }
+
+ return result;
+}
+
+Gfx::Color Gfx::HSV2RGB(Gfx::ColorHSV color)
+{
+ Gfx::Color result;
+
+ color.h = Math::Norm(color.h)*360.0f;
+ color.s = Math::Norm(color.s);
+ color.v = Math::Norm(color.v);
+
+ if ( color.s == 0.0f ) // zero saturation?
+ {
+ result.r = color.v;
+ result.g = color.v;
+ result.b = color.v; // gray
+ }
+ else
+ {
+ if ( color.h == 360.0f ) color.h = 0.0f;
+ color.h /= 60.0f;
+ int i = (int)color.h; // integer part (0 .. 5)
+ float f = color.h-i; // fractional part
+
+ float v = color.v;
+ float p = color.v*(1.0f-color.s);
+ float q = color.v*(1.0f-(color.s*f));
+ float t = color.v*(1.0f-(color.s*(1.0f-f)));
+
+ switch (i)
+ {
+ case 0: result.r=v; result.g=t; result.b=p; break;
+ case 1: result.r=q; result.g=v; result.b=p; break;
+ case 2: result.r=p; result.g=v; result.b=t; break;
+ case 3: result.r=p; result.g=q; result.b=v; break;
+ case 4: result.r=t; result.g=p; result.b=v; break;
+ case 5: result.r=v; result.g=p; result.b=q; break;
+ }
+ }
+
+ return result;
+}
+
diff --git a/src/graphics/core/color.h b/src/graphics/core/color.h
new file mode 100644
index 0000000..907a3b9
--- /dev/null
+++ b/src/graphics/core/color.h
@@ -0,0 +1,98 @@
+// * 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/.
+
+// color.h
+
+#pragma once
+
+
+#include <sstream>
+
+
+namespace Gfx {
+
+/**
+ \struct Color
+ \brief RGBA color */
+struct Color
+{
+ //! Red, green, blue and alpha components
+ float r, g, b, a;
+
+ //! Constructor; default values are (0,0,0,0) = black
+ Color(float aR = 0.0f, float aG = 0.0f, float aB = 0.0f, float aA = 0.0f)
+ : r(aR), g(aG), b(aB), a(aA) {}
+
+ inline Gfx::Color Inverse() const
+ {
+ return Gfx::Color(1.0f - r, 1.0f - g, 1.0f - b, 1.0f - a);
+ }
+
+ //! Returns the struct cast to \c float* array; use with care!
+ inline float* Array()
+ {
+ return (float*)this;
+ }
+
+ //! Returns the struct cast to <tt>const float*</tt> array; use with care!
+ inline const float* Array() const
+ {
+ return (const float*)this;
+ }
+
+ //! Returns a string (r, g, b, a)
+ inline std::string ToString() const
+ {
+ std::stringstream s;
+ s.precision(3);
+ s << "(" << r << ", " << g << ", " << b << ", " << a << ")";
+ return s.str();
+ }
+
+ inline bool operator==(const Gfx::Color &other) const
+ {
+ return r == other.r && g == other.g && b == other.b && a == other.a;
+ }
+};
+
+/**
+ \struct ColorHSV
+ \brief HSV color */
+struct ColorHSV
+{
+ float h, s, v;
+
+ ColorHSV(float aH = 0.0f, float aS = 0.0f, float aV = 0.0f)
+ : h(aH), s(aS), v(aV) {}
+
+ //! Returns a string "(h, s, v)"
+ inline std::string ToString() const
+ {
+ std::stringstream s;
+ s.precision(3);
+ s << "(" << h << ", " << s << ", " << v << ")";
+ return s.str();
+ }
+};
+
+//! Converts a RGB color to HSV color
+Gfx::ColorHSV RGB2HSV(Gfx::Color color);
+
+//! Converts a HSV color to RGB color
+Gfx::Color HSV2RGB(Gfx::ColorHSV color);
+
+}; // namespace Gfx
+
diff --git a/src/graphics/core/device.h b/src/graphics/core/device.h
new file mode 100644
index 0000000..ae612b7
--- /dev/null
+++ b/src/graphics/core/device.h
@@ -0,0 +1,414 @@
+// * 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/.
+
+// device.h
+
+#pragma once
+
+
+#include "graphics/core/color.h"
+#include "graphics/core/light.h"
+#include "graphics/core/material.h"
+#include "graphics/core/texture.h"
+#include "graphics/core/vertex.h"
+#include "math/matrix.h"
+
+#include <string>
+
+
+class CImage;
+
+
+namespace Gfx {
+
+/**
+ \struct DeviceConfig
+ \brief General config for graphics device
+
+ These settings are common window options set by SDL.
+*/
+struct DeviceConfig
+{
+ //! Screen width
+ int width;
+ //! Screen height
+ int height;
+ //! Bits per pixel
+ int bpp;
+ //! Full screen
+ bool fullScreen;
+ //! Resizeable window
+ bool resizeable;
+ //! Double buffering
+ bool doubleBuf;
+ //! No window frame (also set with full screen)
+ bool noFrame;
+
+ //! Constructor calls LoadDefault()
+ DeviceConfig() { LoadDefault(); }
+
+ //! Loads the default values
+ inline void LoadDefault()
+ {
+ width = 800;
+ height = 600;
+ bpp = 32;
+ fullScreen = false;
+ resizeable = false;
+ doubleBuf = true;
+ noFrame = false;
+ }
+};
+
+
+/**
+ \enum TransformType
+ \brief Type of transformation in rendering pipeline
+
+ These correspond to DirectX's three transformation matrices. */
+enum TransformType
+{
+ TRANSFORM_WORLD,
+ TRANSFORM_VIEW,
+ TRANSFORM_PROJECTION
+};
+
+/**
+ \enum RenderState
+ \brief Render states that can be enabled/disabled */
+enum RenderState
+{
+ RENDER_STATE_LIGHTING,
+ RENDER_STATE_TEXTURING,
+ RENDER_STATE_BLENDING,
+ RENDER_STATE_FOG,
+ RENDER_STATE_DEPTH_TEST,
+ RENDER_STATE_DEPTH_WRITE,
+ RENDER_STATE_ALPHA_TEST,
+ RENDER_STATE_CULLING,
+ RENDER_STATE_DITHERING
+};
+
+/**
+ \enum CompFunc
+ \brief Type of function used to compare values */
+enum CompFunc
+{
+ COMP_FUNC_NEVER,
+ COMP_FUNC_LESS,
+ COMP_FUNC_EQUAL,
+ COMP_FUNC_NOTEQUAL,
+ COMP_FUNC_LEQUAL,
+ COMP_FUNC_GREATER,
+ COMP_FUNC_GEQUAL,
+ COMP_FUNC_ALWAYS
+};
+
+/**
+ \enum BlendFunc
+ \brief Type of blending function */
+enum BlendFunc
+{
+ BLEND_ZERO,
+ BLEND_ONE,
+ BLEND_SRC_COLOR,
+ BLEND_INV_SRC_COLOR,
+ BLEND_DST_COLOR,
+ BLEND_INV_DST_COLOR,
+ BLEND_SRC_ALPHA,
+ BLEND_INV_SRC_ALPHA,
+ BLEND_DST_ALPHA,
+ BLEND_INV_DST_ALPHA,
+ BLEND_SRC_ALPHA_SATURATE
+};
+
+/**
+ \enum FogMode
+ \brief Type of fog calculation function */
+enum FogMode
+{
+ FOG_LINEAR,
+ FOG_EXP,
+ FOG_EXP2
+};
+
+/**
+ \enum CullMode
+ \brief Culling mode for polygons */
+enum CullMode
+{
+ //! Cull clockwise side
+ CULL_CW,
+ //! Cull counter-clockwise side
+ CULL_CCW
+};
+
+/**
+ \enum ShadeModel
+ \brief Shade model used in rendering */
+enum ShadeModel
+{
+ SHADE_FLAT,
+ SHADE_SMOOTH
+};
+
+/**
+ \enum FillMode
+ \brief Polygon fill mode */
+enum FillMode
+{
+ //! Draw only points
+ FILL_POINT,
+ //! Draw only lines
+ FILL_LINES,
+ //! Draw full polygons
+ FILL_FILL
+};
+
+/**
+ \enum PrimitiveType
+ \brief Type of primitive to render
+
+ Only these two types are used. */
+enum PrimitiveType
+{
+ PRIMITIVE_LINES,
+ PRIMITIVE_TRIANGLES,
+ PRIMITIVE_TRIANGLE_STRIP
+};
+
+/**
+ \enum IntersectPlane
+ \brief Intersection plane of projection volume
+
+ These flags can be OR'd together. */
+enum IntersectPlane
+{
+ INTERSECT_PLANE_LEFT = 0x01,
+ INTERSECT_PLANE_RIGHT = 0x02,
+ INTERSECT_PLANE_TOP = 0x04,
+ INTERSECT_PLANE_BOTTOM = 0x08,
+ INTERSECT_PLANE_FRONT = 0x10,
+ INTERSECT_PLANE_BACK = 0x20,
+ INTERSECT_PLANE_ALL = INTERSECT_PLANE_LEFT | INTERSECT_PLANE_RIGHT |
+ INTERSECT_PLANE_TOP | INTERSECT_PLANE_BOTTOM |
+ INTERSECT_PLANE_FRONT | INTERSECT_PLANE_BACK
+};
+
+/*
+
+Notes for rewriting DirectX code:
+
+>> SetRenderState() translates to many functions depending on param
+
+D3DRENDERSTATE_ALPHABLENDENABLE -> SetRenderState() with RENDER_STATE_BLENDING
+D3DRENDERSTATE_ALPHAFUNC -> SetAlphaTestFunc() func
+D3DRENDERSTATE_ALPHAREF -> SetAlphaTestFunc() ref
+D3DRENDERSTATE_ALPHATESTENABLE -> SetRenderState() with RENDER_STATE_ALPHA_TEST
+D3DRENDERSTATE_AMBIENT -> SetGlobalAmbient()
+D3DRENDERSTATE_CULLMODE -> SetCullMode()
+D3DRENDERSTATE_DESTBLEND -> SetBlendFunc() dest blending func
+D3DRENDERSTATE_DITHERENABLE -> SetRenderState() with RENDER_STATE_DITHERING
+D3DRENDERSTATE_FILLMODE -> SetFillMode()
+D3DRENDERSTATE_FOGCOLOR -> SetFogParams()
+D3DRENDERSTATE_FOGENABLE -> SetRenderState() with RENDER_STATE_FOG
+D3DRENDERSTATE_FOGEND -> SetFogParams()
+D3DRENDERSTATE_FOGSTART -> SetFogParams()
+D3DRENDERSTATE_FOGVERTEXMODE -> SetFogParams() fog model
+D3DRENDERSTATE_LIGHTING -> SetRenderState() with RENDER_STATE_LIGHTING
+D3DRENDERSTATE_SHADEMODE -> SetShadeModel()
+D3DRENDERSTATE_SPECULARENABLE -> doesn't matter (always enabled)
+D3DRENDERSTATE_SRCBLEND -> SetBlendFunc() src blending func
+D3DRENDERSTATE_TEXTUREFACTOR -> SetTextureFactor()
+D3DRENDERSTATE_ZBIAS -> SetDepthBias()
+D3DRENDERSTATE_ZENABLE -> SetRenderState() with RENDER_STATE_DEPTH_TEST
+D3DRENDERSTATE_ZFUNC -> SetDepthTestFunc()
+D3DRENDERSTATE_ZWRITEENABLE -> SetRenderState() with RENDER_STATE_DEPTH_WRITE
+
+
+>> SetTextureStageState() translates to SetTextureParams() or CreateTexture() for some params
+
+Params from enum in struct TextureCreateParams or TextureParams
+ D3DTSS_ADDRESS -> Gfx::TexWrapMode wrapS, wrapT
+ D3DTSS_ALPHAARG1 -> Gfx::TexMixArgument alphaArg1
+ D3DTSS_ALPHAARG2 -> Gfx::TexMixArgument alphaArg2
+ D3DTSS_ALPHAOP -> Gfx::TexMixOperation alphaOperation
+ D3DTSS_COLORARG1 -> Gfx::TexMixArgument colorArg1
+ D3DTSS_COLORARG2 -> Gfx::TexMixArgument colorArg2
+ D3DTSS_COLOROP -> Gfx::TexMixOperation colorOperation
+ D3DTSS_MAGFILTER -> Gfx::TexMagFilter magFilter
+ D3DTSS_MINFILTER -> Gfx::TexMinFilter minFilter
+ D3DTSS_TEXCOORDINDEX -> doesn't matter (texture coords are set explicitly by glMultiTexCoordARB*)
+
+Note that D3DTSS_ALPHAOP or D3DTSS_COLOROP set to D3DTOP_DISABLE must translate to disabling the whole texture stage.
+In DirectX, you shouldn't mix enabling one and disabling the other.
+Also, if previous stage is disabled in DirectX, the later ones are disabled, too. In OpenGL, that is not the case.
+
+*/
+
+/**
+ \class CDevice
+ \brief Abstract interface of graphics device
+
+ It is based on DIRECT3DDEVICE class from DirectX to make it easier to port existing code.
+ It encapsulates the general graphics device state and provides a common interface
+ to graphics-specific functions which will be used throughout the program,
+ both in CEngine class and in UI classes. Note that it doesn't contain all functions from DirectX,
+ only those that were used in old code.
+
+ */
+class CDevice
+{
+public:
+ virtual ~CDevice() {}
+
+ //! 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;
+
+ //! Begins drawing the 3D scene
+ virtual void BeginScene() = 0;
+ //! Ends drawing the 3D scene
+ virtual void EndScene() = 0;
+
+ //! Clears the screen to blank
+ virtual void Clear() = 0;
+
+ //! Sets the transform matrix of given type
+ virtual void SetTransform(TransformType type, const Math::Matrix &matrix) = 0;
+ //! Returns the current transform matrix of given type
+ virtual const Math::Matrix& GetTransform(TransformType type) = 0;
+ //! Multiplies the current transform matrix of given type by given matrix
+ virtual void MultiplyTransform(TransformType type, const Math::Matrix &matrix) = 0;
+
+ //! Sets the current material
+ virtual void SetMaterial(const Gfx::Material &material) = 0;
+ //! Returns the current material
+ virtual const Gfx::Material& GetMaterial() = 0;
+
+ //! Returns the maximum number of lights available
+ virtual int GetMaxLightCount() = 0;
+ //! Sets the light at given index
+ virtual void SetLight(int index, const Gfx::Light &light) = 0;
+ //! Returns the current light at given index
+ virtual const Gfx::Light& GetLight(int index) = 0;
+ //! Enables/disables the light at given index
+ virtual void SetLightEnabled(int index, bool enabled) = 0;
+ //! Returns the current enable state of light at given index
+ virtual bool GetLightEnabled(int index) = 0;
+
+ //! Creates a texture from image; the image can be safely removed after that
+ virtual Gfx::Texture CreateTexture(CImage *image, 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
+ virtual void DestroyAllTextures() = 0;
+
+ //! Returns the maximum number of multitexture stages
+ virtual int GetMaxTextureCount() = 0;
+ //! Sets the (multi)texture at given index
+ virtual void SetTexture(int index, const Gfx::Texture &texture) = 0;
+ //! Returns the (multi)texture at given index
+ virtual Gfx::Texture GetTexture(int index) = 0;
+ //! Enables/disables the given texture stage
+ virtual void SetTextureEnabled(int index, bool enabled) = 0;
+ //! Returns the current enable state of given texture stage
+ virtual bool GetTextureEnabled(int index) = 0;
+
+ //! Sets the params for texture stage with given index
+ virtual void SetTextureStageParams(int index, const Gfx::TextureStageParams &params) = 0;
+ //! Returns the current params of texture stage with given index
+ virtual Gfx::TextureStageParams GetTextureStageParams(int index) = 0;
+
+ //! Sets the texture factor to the given color value
+ virtual void SetTextureFactor(const Gfx::Color &color) = 0;
+ //! Returns the current texture factor
+ virtual Gfx::Color GetTextureFactor() = 0;
+
+ //! Renders primitive composed of vertices with single texture
+ virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::Vertex *vertices , int vertexCount) = 0;
+ //! Renders primitive composed of vertices with color information and single texture
+ virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexCol *vertices , int vertexCount) = 0;
+ //! Renders primitive composed of vertices with multitexturing (2 textures)
+ virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexTex2 *vertices, int vertexCount) = 0;
+
+ //! Tests whether a sphere intersects the 6 clipping planes of projection volume
+ virtual int ComputeSphereVisibility(const Math::Vector &center, float radius) = 0;
+
+ //! Enables/disables the given render state
+ virtual void SetRenderState(Gfx::RenderState state, bool enabled) = 0;
+ //! Returns the current setting of given render state
+ virtual bool GetRenderState(Gfx::RenderState state) = 0;
+
+ //! Sets the function of depth test
+ virtual void SetDepthTestFunc(Gfx::CompFunc func) = 0;
+ //! Returns the current function of depth test
+ virtual Gfx::CompFunc GetDepthTestFunc() = 0;
+
+ //! Sets the depth bias (constant value added to Z-coords)
+ virtual void SetDepthBias(float factor) = 0;
+ //! Returns the current depth bias
+ virtual float GetDepthBias() = 0;
+
+ //! Sets the alpha test function and reference value
+ virtual void SetAlphaTestFunc(Gfx::CompFunc func, float refValue) = 0;
+ //! Returns the current alpha test function and reference value
+ virtual void GetAlphaTestFunc(Gfx::CompFunc &func, float &refValue) = 0;
+
+ //! Sets the blending functions for source and destination operations
+ virtual void SetBlendFunc(Gfx::BlendFunc srcBlend, Gfx::BlendFunc dstBlend) = 0;
+ //! Returns the current blending functions for source and destination operations
+ virtual void GetBlendFunc(Gfx::BlendFunc &srcBlend, Gfx::BlendFunc &dstBlend) = 0;
+
+ //! Sets the clear color
+ virtual void SetClearColor(const Gfx::Color &color) = 0;
+ //! Returns the current clear color
+ virtual Gfx::Color GetClearColor() = 0;
+
+ //! Sets the global ambient color
+ virtual void SetGlobalAmbient(const Gfx::Color &color) = 0;
+ //! Returns the global ambient color
+ virtual Gfx::Color GetGlobalAmbient() = 0;
+
+ //! Sets the fog parameters: mode, color, start distance, end distance and density (for exp models)
+ virtual void SetFogParams(Gfx::FogMode mode, const Gfx::Color &color, float start, float end, float density) = 0;
+ //! Returns the current fog parameters: mode, color, start distance, end distance and density (for exp models)
+ virtual void GetFogParams(Gfx::FogMode &mode, Gfx::Color &color, float &start, float &end, float &density) = 0;
+
+ //! Sets the current cull mode
+ virtual void SetCullMode(Gfx::CullMode mode) = 0;
+ //! Returns the current cull mode
+ virtual Gfx::CullMode GetCullMode() = 0;
+
+ //! Sets the shade model
+ virtual void SetShadeModel(Gfx::ShadeModel model) = 0;
+ //! Returns the current shade model
+ virtual Gfx::ShadeModel GetShadeModel() = 0;
+
+ //! Sets the current fill mode
+ virtual void SetFillMode(Gfx::FillMode mode) = 0;
+ //! Returns the current fill mode
+ virtual Gfx::FillMode GetFillMode() = 0;
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/core/light.h b/src/graphics/core/light.h
new file mode 100644
index 0000000..b787cb2
--- /dev/null
+++ b/src/graphics/core/light.h
@@ -0,0 +1,91 @@
+// * 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/.
+
+// light.h
+
+#pragma once
+
+
+#include "graphics/core/color.h"
+#include "math/vector.h"
+
+
+namespace Gfx {
+
+/**
+ \enum LightType
+ \brief Type of light in 3D scene */
+enum LightType
+{
+ LIGHT_POINT,
+ LIGHT_SPOT,
+ LIGHT_DIRECTIONAL
+};
+
+/**
+ \struct Light
+ \brief Properties of light in 3D scene
+
+ This structure was created as analog to DirectX's D3DLIGHT. */
+struct Light
+{
+ //! Type of light source
+ Gfx::LightType type;
+ //! Color of ambient light
+ Gfx::Color ambient;
+ //! Color of diffuse light
+ Gfx::Color diffuse;
+ //! Color of specular light
+ Gfx::Color specular;
+ //! Position in world space (for point & spot lights)
+ Math::Vector position;
+ //! Direction in world space (for directional & spot lights)
+ Math::Vector direction;
+ //! Constant attenuation factor
+ float attenuation0;
+ //! Linear attenuation factor
+ float attenuation1;
+ //! Quadratic attenuation factor
+ float attenuation2;
+ //! Angle of spotlight cone (0-90 degrees)
+ float spotAngle;
+ //! Intensity of spotlight (0 = uniform; 128 = most intense)
+ float spotIntensity;
+
+ //! Constructor; calls LoadDefault()
+ Light()
+ {
+ LoadDefault();
+ }
+
+ //! Loads default values
+ void LoadDefault()
+ {
+ type = LIGHT_POINT;
+ ambient = Gfx::Color(0.4f, 0.4f, 0.4f);
+ diffuse = Gfx::Color(0.8f, 0.8f, 0.8f);
+ specular = Gfx::Color(1.0f, 1.0f, 1.0f);
+ position = Math::Vector(0.0f, 0.0f, 0.0f);
+ direction = Math::Vector(0.0f, 0.0f, 1.0f);
+ attenuation0 = 1.0f;
+ attenuation1 = attenuation2 = 0.0f;
+ spotAngle = 90.0f;
+ spotIntensity = 0.0f;
+ }
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/common/material.h b/src/graphics/core/material.h
index f71923f..31b42f3 100644
--- a/src/graphics/common/material.h
+++ b/src/graphics/core/material.h
@@ -19,6 +19,9 @@
#pragma once
+#include "graphics/core/color.h"
+
+
namespace Gfx {
/**
diff --git a/src/graphics/core/texture.h b/src/graphics/core/texture.h
new file mode 100644
index 0000000..787c2bf
--- /dev/null
+++ b/src/graphics/core/texture.h
@@ -0,0 +1,237 @@
+// * 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/.
+
+// texture.h
+
+#pragma once
+
+namespace Gfx {
+
+/**
+ \enum TexImgFormat
+ \brief Format of image data */
+enum TexImgFormat
+{
+ //! Try to determine automatically (may not work)
+ TEX_IMG_AUTO,
+ //! RGB triplet, 3 bytes
+ TEX_IMG_RGB,
+ //! BGR triplet, 3 bytes
+ TEX_IMG_BGR,
+ //! RGBA triplet, 4 bytes
+ TEX_IMG_RGBA,
+ //! BGRA triplet, 4 bytes
+ TEX_IMG_BGRA
+};
+
+/**
+ \enum TexMinFilter
+ \brief Texture minification filter
+
+ Corresponds to OpenGL modes but should translate to DirectX too. */
+enum TexMinFilter
+{
+ TEX_MIN_FILTER_NEAREST,
+ TEX_MIN_FILTER_LINEAR,
+ TEX_MIN_FILTER_NEAREST_MIPMAP_NEAREST,
+ TEX_MIN_FILTER_LINEAR_MIPMAP_NEAREST,
+ TEX_MIN_FILTER_NEAREST_MIPMAP_LINEAR,
+ TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR
+};
+
+/**
+ \enum TexMagFilter
+ \brief Texture magnification filter */
+enum TexMagFilter
+{
+ TEX_MAG_FILTER_NEAREST,
+ TEX_MAG_FILTER_LINEAR
+};
+
+/**
+ \enum TexWrapMode
+ \brief Wrapping mode for texture coords */
+enum TexWrapMode
+{
+ TEX_WRAP_CLAMP,
+ TEX_WRAP_REPEAT
+};
+
+/**
+ \enum TexMixOperation
+ \brief Multitexture mixing operation */
+enum TexMixOperation
+{
+ //! Default operation on default params (modulate on computed & texture)
+ TEX_MIX_OPER_DEFAULT,
+ //! = Arg1
+ TEX_MIX_OPER_REPLACE,
+ //! = Arg1 * Arg2
+ TEX_MIX_OPER_MODULATE,
+ //! = Arg1 + Arg2
+ TEX_MIX_OPER_ADD,
+ //! = Arg1 - Arg2
+ TEX_MIX_OPER_SUBTRACT
+};
+
+/**
+ \enum TexMixArgument
+ \brief Multitexture mixing argument */
+enum TexMixArgument
+{
+ //! Color from current texture
+ TEX_MIX_ARG_TEXTURE,
+ //! Color computed by previous texture unit (current in DirectX; previous in OpenGL)
+ TEX_MIX_ARG_COMPUTED_COLOR,
+ //! (Source) color of textured fragment (diffuse in DirectX; primary color in OpenGL)
+ TEX_MIX_ARG_SRC_COLOR,
+ //! Constant color (texture factor in DirectX; texture env color in OpenGL)
+ TEX_MIX_ARG_FACTOR
+};
+
+/**
+ \struct TextureCreateParams
+ \brief Parameters for texture creation
+
+ These params define how particular texture is created and later displayed.
+ They must be specified at texture creation time and cannot be changed later. */
+struct TextureCreateParams
+{
+ //! Whether to generate mipmaps
+ bool mipmap;
+ //! Format of source image data
+ Gfx::TexImgFormat format;
+ //! Minification filter
+ Gfx::TexMinFilter minFilter;
+ //! Magnification filter
+ Gfx::TexMagFilter magFilter;
+
+ //! Constructor; calls LoadDefault()
+ TextureCreateParams()
+ { LoadDefault(); }
+
+ //! Loads the default values
+ inline void LoadDefault()
+ {
+ format = Gfx::TEX_IMG_RGB;
+ mipmap = false;
+
+ minFilter = Gfx::TEX_MIN_FILTER_NEAREST;
+ magFilter = Gfx::TEX_MAG_FILTER_NEAREST;
+ }
+};
+
+/**
+ \struct TextureStageParams
+ \brief Parameters for a texture unit
+
+ These params define the behavior of texturing units (stages).
+ They can be changed freely and are feature of graphics engine, not any particular texture. */
+struct TextureStageParams
+{
+ //! Mixing operation done on color values
+ Gfx::TexMixOperation colorOperation;
+ //! 1st argument of color operations
+ Gfx::TexMixArgument colorArg1;
+ //! 2nd argument of color operations
+ Gfx::TexMixArgument colorArg2;
+ //! Mixing operation done on alpha values
+ Gfx::TexMixOperation alphaOperation;
+ //! 1st argument of alpha operations
+ Gfx::TexMixArgument alphaArg1;
+ //! 2nd argument of alpha operations
+ Gfx::TexMixArgument alphaArg2;
+ //! Wrap mode for 1st tex coord
+ Gfx::TexWrapMode wrapS;
+ //! Wrap mode for 2nd tex coord
+ Gfx::TexWrapMode wrapT;
+
+ //! Constructor; calls LoadDefault()
+ TextureStageParams()
+ { LoadDefault(); }
+
+ //! Loads the default values
+ inline void LoadDefault()
+ {
+ colorOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ colorArg1 = Gfx::TEX_MIX_ARG_COMPUTED_COLOR;
+ colorArg2 = Gfx::TEX_MIX_ARG_TEXTURE;
+
+ alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ alphaArg1 = Gfx::TEX_MIX_ARG_COMPUTED_COLOR;
+ alphaArg2 = Gfx::TEX_MIX_ARG_TEXTURE;
+
+ wrapS = wrapT = Gfx::TEX_WRAP_REPEAT;
+ }
+};
+
+/**
+ \struct Texture
+ \brief Info about a texture
+
+ Identifies (through id) a texture created in graphics engine.
+ Also contains some additional data. */
+struct Texture
+{
+ //! Whether the texture (ID) is valid
+ bool valid;
+ //! ID of the texture in graphics engine
+ unsigned int id;
+ //! Width of texture
+ int width;
+ //! Height of texture
+ int height;
+ //! Whether the texture has alpha channel
+ bool alpha;
+
+ Texture()
+ {
+ valid = false;
+ id = 0;
+ width = height = 0;
+ alpha = false;
+ }
+
+ //! 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) )
+ return false;
+
+ if (!valid)
+ return true;
+
+ if (!other.valid)
+ return false;
+
+ return id < other.id;
+ }
+
+ //! Comparator
+ inline bool operator==(const Gfx::Texture &other) const
+ {
+ if (valid != other.valid)
+ return false;
+ if ( (!valid) && (!other.valid) )
+ return true;
+
+ return id == other.id;
+ }
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/core/vertex.h b/src/graphics/core/vertex.h
new file mode 100644
index 0000000..b7fab1c
--- /dev/null
+++ b/src/graphics/core/vertex.h
@@ -0,0 +1,141 @@
+// * 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/.
+
+// vertex.h
+
+#pragma once
+
+
+#include "graphics/core/color.h"
+#include "math/vector.h"
+#include "math/point.h"
+
+#include <sstream>
+
+namespace Gfx {
+
+/**
+ * \struct Vertex
+ * \brief Vertex of a primitive
+ *
+ * This structure was created as analog to DirectX's D3DVERTEX.
+ *
+ * It contains:
+ * - vertex coordinates (x,y,z) as Math::Vector,
+ * - normal coordinates (nx,ny,nz) as Math::Vector
+ * - texture coordinates (u,v) as Math::Point.
+ */
+struct Vertex
+{
+ Math::Vector coord;
+ Math::Vector normal;
+ Math::Point texCoord;
+
+ Vertex(Math::Vector aCoord = Math::Vector(),
+ Math::Vector aNormal = Math::Vector(),
+ Math::Point aTexCoord = Math::Point())
+ : coord(aCoord), normal(aNormal), texCoord(aTexCoord) {}
+
+
+ //! Returns a string "(c: [...], n: [...], tc: [...])"
+ inline std::string ToString() const
+ {
+ std::stringstream s;
+ s.precision(3);
+ s << "(c: " << coord.ToString() << ", n: " << normal.ToString()
+ << ", tc: " << texCoord.ToString() << ")";
+ return s.str();
+ }
+};
+
+/**
+ * \struct VertexCol
+ * \brief Vertex with color information
+ *
+ * This structure was created as analog to DirectX's D3DLVERTEX.
+ *
+ * It contains:
+ * - vertex coordinates (x,y,z) as Math::Vector,
+ * - RGBA color as Gfx::Color,
+ * - RGBA specular color as Gfx::Color,
+ * - texture coordinates (u,v) as Math::Point.
+ */
+struct VertexCol
+{
+ Math::Vector coord;
+ Gfx::Color color;
+ Gfx::Color specular;
+ Math::Point texCoord;
+
+ VertexCol(Math::Vector aCoord = Math::Vector(),
+ Gfx::Color aColor = Gfx::Color(),
+ Gfx::Color aSpecular = Gfx::Color(),
+ Math::Point aTexCoord = Math::Point())
+ : coord(aCoord), color(aColor), specular(aSpecular), texCoord(aTexCoord) {}
+
+ //! Returns a string "(c: [...], col: [...], sp: [...], tc: [...])"
+ inline std::string ToString() const
+ {
+ std::stringstream s;
+ s.precision(3);
+ s << "(c: " << coord.ToString() << ", col: " << color.ToString() << ", sp: "
+ << specular.ToString() << ", tc: " << texCoord.ToString() << ")";
+ return s.str();
+ }
+};
+
+
+/**
+ * \struct VertexTex2
+ * \brief Vertex with secondary texture coordinates
+ *
+ * In addition to fields from Gfx::Vector, it contains
+ * secondary texture coordinates (u2, v2) as Math::Point
+ */
+struct VertexTex2
+{
+ Math::Vector coord;
+ Math::Vector normal;
+ Math::Point texCoord;
+ Math::Point texCoord2;
+
+ VertexTex2(Math::Vector aCoord = Math::Vector(),
+ Math::Vector aNormal = Math::Vector(),
+ Math::Point aTexCoord = Math::Point(),
+ Math::Point aTexCoord2 = Math::Point())
+ : coord(aCoord), normal(aNormal), texCoord(aTexCoord), texCoord2(aTexCoord2) {}
+
+ //! Sets the fields from Gfx::Vertex with texCoord2 = (0,0)
+ void FromVertex(const Gfx::Vertex &v)
+ {
+ coord = v.coord;
+ normal = v.normal;
+ texCoord = v.texCoord;
+ texCoord2 = Math::Point();
+ }
+
+ //! Returns a string "(c: [...], n: [...], tc: [...], tc2: [...])"
+ inline std::string ToString() const
+ {
+ std::stringstream s;
+ s.precision(3);
+ s << "(c: " << coord.ToString() << ", n: " << normal.ToString()
+ << ", tc: " << texCoord.ToString() << ", tc2: " << texCoord2.ToString() << ")";
+ return s.str();
+ }
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/engine/README.txt b/src/graphics/engine/README.txt
new file mode 100644
index 0000000..308b601
--- /dev/null
+++ b/src/graphics/engine/README.txt
@@ -0,0 +1,8 @@
+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
diff --git a/src/graphics/common/camera.cpp b/src/graphics/engine/camera.cpp
index 9990d01..04bf868 100644
--- a/src/graphics/common/camera.cpp
+++ b/src/graphics/engine/camera.cpp
@@ -17,7 +17,7 @@
// camera.cpp
-#include "graphics/common/camera.h"
+#include "graphics/engine/camera.h"
// TODO implementation
diff --git a/src/graphics/common/camera.h b/src/graphics/engine/camera.h
index f17ecef..76077bf 100644
--- a/src/graphics/common/camera.h
+++ b/src/graphics/engine/camera.h
@@ -24,9 +24,6 @@
class CInstanceManager;
-class Gfx::CEngine;
-class Gfx::CTerrain;
-class Gfx::CWater;
class CObject;
namespace Gfx {
@@ -144,7 +141,7 @@ class CCamera {
void SetCameraInvertY(bool bInvert);
float RetMotorTurn();
- Gfx::MouseType RetMouseDef(Math::Point pos);
+ Gfx::EngineMouseType RetMouseDef(Math::Point pos);
protected:
bool EventMouseMove(const Event &event);
diff --git a/src/graphics/common/cloud.cpp b/src/graphics/engine/cloud.cpp
index 707f641..d0e5ed8 100644
--- a/src/graphics/common/cloud.cpp
+++ b/src/graphics/engine/cloud.cpp
@@ -17,7 +17,7 @@
// cloud.cpp
-#include "graphics/common/cloud.h"
+#include "graphics/engine/cloud.h"
// TODO implementation
diff --git a/src/graphics/common/cloud.h b/src/graphics/engine/cloud.h
index 19b689f..d2d29d7 100644
--- a/src/graphics/common/cloud.h
+++ b/src/graphics/engine/cloud.h
@@ -20,7 +20,7 @@
#pragma once
#include "common/event.h"
-#include "graphics/common/color.h"
+#include "graphics/core/color.h"
#include "math/point.h"
#include "math/vector.h"
diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp
new file mode 100644
index 0000000..0914f9e
--- /dev/null
+++ b/src/graphics/engine/engine.cpp
@@ -0,0 +1,729 @@
+// * 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/.
+
+// engine.cpp
+
+#include "graphics/engine/engine.h"
+
+#include "app/app.h"
+#include "common/iman.h"
+#include "common/image.h"
+#include "common/key.h"
+#include "common/logger.h"
+#include "graphics/core/device.h"
+#include "math/geometry.h"
+
+// Initial size of various vectors
+const int OBJECT_PREALLOCATE_COUNT = 1200;
+const int SHADOW_PREALLOCATE_COUNT = 500;
+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;
+
+
+Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
+{
+ m_iMan = iMan;
+ m_app = app;
+ m_device = NULL;
+
+ m_wasInit = false;
+
+ 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_dim.x = 640;
+ m_dim.y = 480;
+ m_lastDim = m_dim;
+ 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);
+ m_ambientColor[1] = Gfx::Color(0.5f, 0.5f, 0.5f, 0.5f);
+ m_fogColor[0] = Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f);
+ m_fogColor[1] = Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f);
+ m_deepView[0] = 1000.0f;
+ m_deepView[1] = 1000.0f;
+ m_fogStart[0] = 0.75f;
+ m_fogStart[1] = 0.75f;
+ m_waterAddColor = Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f);
+
+ m_pause = false;
+ m_render = true;
+ m_movieLock = false;
+ m_shadowVisible = true;
+ m_groundSpotVisible = true;
+ m_dirty = true;
+ m_fog = true;
+ m_speed = 1.0f;
+ m_secondTexNum = 0;
+ m_eyeDirH = 0.0f;
+ m_eyeDirV = 0.0f;
+ m_backgroundName = ""; // no background image
+ m_backgroundColorUp = 0;
+ m_backgroundColorDown = 0;
+ m_backgroundCloudUp = 0;
+ m_backgroundCloudDown = 0;
+ m_backgroundFull = false;
+ m_backgroundQuarter = false;
+ m_overFront = true;
+ m_overColor = 0;
+ m_overMode = ENG_RSTATE_TCOLOR_BLACK;
+ m_frontsizeName = ""; // no front image
+ m_hiliteRank[0] = -1; // empty list
+ 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_clippingDistance = 1.0f;
+ m_lastClippingDistance = m_clippingDistance;
+ m_objectDetail = 1.0f;
+ m_lastObjectDetail = m_objectDetail;
+ m_terrainVision = 1000.0f;
+ m_gadgetQuantity = 1.0f;
+ m_textureQuality = 1;
+ m_totoMode = true;
+ m_lensMode = true;
+ m_waterMode = true;
+ m_skyMode = true;
+ m_backForce = true;
+ m_planetMode = true;
+ m_lightMode = true;
+ m_editIndentMode = true;
+ m_editIndentValue = 4;
+ m_tracePrecision = 1.0f;
+
+ m_alphaMode = 1;
+
+ 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_mouseSize = Math::Point(0.04f, 0.04f * (800.0f / 600.0f));
+ m_mousePos = Math::Point(0.5f, 0.5f);
+ m_mouseType = Gfx::ENG_MOUSE_NORM;
+ m_mouseVisible = false;
+
+ m_texPath = "textures/";
+ m_defaultTexParams.format = Gfx::TEX_IMG_RGBA;
+ 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);
+}
+
+Gfx::CEngine::~CEngine()
+{
+ m_iMan = NULL;
+ m_app = NULL;
+ m_device = NULL;
+
+ m_sound = NULL;
+ m_terrain = NULL;
+}
+
+bool Gfx::CEngine::GetWasInit()
+{
+ return m_wasInit;
+}
+
+std::string Gfx::CEngine::GetError()
+{
+ return m_error;
+}
+
+bool Gfx::CEngine::Create()
+{
+ m_wasInit = true;
+
+ /*m_lightMan = new Gfx::CLight(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_matWorldInterface.LoadIdentity();
+ m_matViewInterface.LoadIdentity();
+ Math::LoadOrthoProjectionMatrix(m_matProjInterface, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
+
+ return true;
+}
+
+void Gfx::CEngine::Destroy()
+{
+ // TODO
+
+ /*delete m_lightMan;
+ m_lightMan = NULL;
+
+ delete m_text;
+ m_text = NULL;
+
+ delete m_particle;
+ m_particle = NULL;
+
+ delete m_water;
+ m_water = NULL;
+
+ delete m_cloud;
+ m_cloud = NULL;
+
+ delete m_lightning;
+ m_lightning = NULL;
+
+ delete m_planet;
+ m_planet = NULL;*/
+
+ m_wasInit = false;
+}
+
+void Gfx::CEngine::SetDevice(Gfx::CDevice *device)
+{
+ m_device = device;
+}
+
+Gfx::CDevice* Gfx::CEngine::GetDevice()
+{
+ return m_device;
+}
+
+bool Gfx::CEngine::AfterDeviceSetInit()
+{
+ m_device->SetClearColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f));
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, false);
+
+ Gfx::TextureCreateParams params;
+ params.format = Gfx::TEX_IMG_RGB;
+ params.minFilter = Gfx::TEX_MIN_FILTER_NEAREST;
+ params.magFilter = Gfx::TEX_MAG_FILTER_NEAREST;
+ params.mipmap = false;
+ m_miceTexture = CreateTexture("mouse.png", params);
+
+ return true;
+}
+
+Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName, const Gfx::TextureCreateParams &params)
+{
+ CImage img;
+ if (! img.Load(m_app->GetDataFilePath(m_texPath, texName)))
+ {
+ std::stringstream str;
+ str << "Couldn't load texture '" << texName << "': " << img.GetError();
+ m_error = str.str();
+ return Gfx::Texture(); // invalid texture
+ }
+
+ Gfx::Texture result = m_device->CreateTexture(&img, params);
+
+ if (! result.valid)
+ {
+ std::stringstream str;
+ str << "Couldn't load texture '" << texName << "': " << m_device->GetError();
+ m_error = str.str();
+ return result;
+ }
+
+ m_texNameMap[texName] = result;
+ m_revTexNameMap[result] = texName;
+
+ return result;
+}
+
+Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName)
+{
+ return CreateTexture(texName, m_defaultTexParams);
+}
+
+void Gfx::CEngine::DestroyTexture(const std::string &texName)
+{
+ std::map<std::string, Gfx::Texture>::iterator it = m_texNameMap.find(texName);
+ if (it == m_texNameMap.end())
+ return;
+
+ std::map<Gfx::Texture, std::string>::iterator revIt = m_revTexNameMap.find((*it).second);
+
+ m_device->DestroyTexture((*it).second);
+
+ m_revTexNameMap.erase(revIt);
+ m_texNameMap.erase(it);
+}
+
+void Gfx::CEngine::SetTexture(const std::string &name, int stage)
+{
+ std::map<std::string, Gfx::Texture>::iterator it = m_texNameMap.find(name);
+ if (it != m_texNameMap.end())
+ m_device->SetTexture(stage, (*it).second);
+
+ // TODO if not present...
+}
+
+void Gfx::CEngine::SetMaterial(const Gfx::Material &mat)
+{
+ m_device->SetMaterial(mat);
+}
+
+void Gfx::CEngine::SetState(int state, 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) )
+ {
+ state &= ~Gfx::ENG_RSTATE_ALPHA;
+
+ if (m_alphaMode == 2)
+ state |= Gfx::ENG_RSTATE_TTEXTURE_BLACK;
+ }
+
+ // TODO other modes & thorough testing
+
+ if (state & Gfx::ENG_RSTATE_TTEXTURE_BLACK) // The 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->SetBlendFunc(Gfx::BLEND_ONE, Gfx::BLEND_INV_SRC_COLOR);
+ m_device->SetTextureEnabled(0, 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;
+ m_device->SetTextureStageParams(0, params);
+ }
+ else if (state & Gfx::ENG_RSTATE_TTEXTURE_WHITE) // The 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->SetBlendFunc(Gfx::BLEND_DST_COLOR, Gfx::BLEND_ZERO);
+ m_device->SetTextureEnabled(0, 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;
+ m_device->SetTextureStageParams(0, params);
+ }
+ else if (state & Gfx::ENG_RSTATE_TCOLOR_BLACK) // The transparent black color?
+ {
+ 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->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?
+ {
+ 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->SetBlendFunc(Gfx::BLEND_DST_COLOR, Gfx::BLEND_ZERO);
+
+ m_device->SetTextureFactor(color.Inverse());
+ m_device->SetTextureEnabled(0, true);
+ m_device->SetTextureStageParams(0, Gfx::TextureStageParams());
+ }
+ else if (state & Gfx::ENG_RSTATE_TDIFFUSE) // diffuse color as transparent?
+ {
+ /*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->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ m_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);*/
+ }
+ else if (state & Gfx::ENG_RSTATE_ALPHA) // image with alpha channel?
+ {
+ /*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);*/
+ }
+ else // normal ?
+ {
+ 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_TEXTURING, true);
+
+ m_device->SetTextureEnabled(0, true);
+ m_device->SetTextureStageParams(0, Gfx::TextureStageParams());
+
+ /*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);*/
+ }
+
+ if (state & Gfx::ENG_RSTATE_FOG)
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, true);
+
+
+ bool second = m_groundSpotVisible || m_dirty;
+
+ 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 )
+ {
+ /*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);*/
+ }
+ 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);*/
+ }
+ else
+ {
+ m_device->SetTextureEnabled(1, false);
+ }
+
+ 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);*/
+ }
+ else
+ {
+ /*m_device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
+ m_device->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);*/
+ }
+
+ if (state & Gfx::ENG_RSTATE_2FACE)
+ {
+ m_device->SetRenderState(Gfx::RENDER_STATE_CULLING, false);
+ }
+ else
+ {
+ m_device->SetRenderState(Gfx::RENDER_STATE_CULLING, true);
+ m_device->SetCullMode(Gfx::CULL_CCW);
+ }
+
+ if (state & Gfx::ENG_RSTATE_LIGHT)
+ m_device->SetGlobalAmbient(Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f));
+ else
+ m_device->SetGlobalAmbient(m_ambientColor[m_rankView]);
+}
+
+bool Gfx::CEngine::ProcessEvent(const Event &event)
+{
+ if (event.type == EVENT_MOUSE_MOVE)
+ {
+ m_mousePos = event.mouseMove.pos;
+ }
+ else 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 );
+ }
+ }
+
+ // By default, pass on all events
+ return true;
+}
+
+bool Gfx::CEngine::Render()
+{
+ m_statisticTriangle = 0;
+
+ m_lastState = -1;
+ SetState(Gfx::ENG_RSTATE_NORMAL);
+
+ m_device->BeginScene();
+
+ SetUp3DView();
+
+ if (! Draw3DScene() )
+ return false;
+
+ SetUpInterfaceView();
+
+ if (! DrawInterface() )
+ return false;
+
+ m_device->EndScene();
+
+ return true;
+}
+
+void Gfx::CEngine::SetUp3DView()
+{
+ // TODO
+}
+
+bool Gfx::CEngine::Draw3DScene()
+{
+ // TODO
+ return true;
+}
+
+void Gfx::CEngine::SetUpInterfaceView()
+{
+ m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_matWorldInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matViewInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_PROJECTION, m_matProjInterface);
+}
+
+bool Gfx::CEngine::DrawInterface()
+{
+ Gfx::VertexCol vertices[3] =
+ {
+ 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))
+ };
+
+ m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, vertices, 3);
+
+ DrawMouse();
+
+ return true;
+}
+
+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);
+}
+
+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(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_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertex, 4);
+ AddStatisticTriangle(2);
+}
+
+bool Gfx::CEngine::GetPause()
+{
+ return m_pause;
+}
+
+Math::Vector Gfx::CEngine::GetLookatPt()
+{
+ return m_lookatPt;
+}
+
+Math::Vector Gfx::CEngine::GetEyePt()
+{
+ return m_eyePt;
+}
+
+void Gfx::CEngine::SetMouseVisible(bool visible)
+{
+ m_mouseVisible = visible;
+}
+
+bool Gfx::CEngine::GetMouseVisible()
+{
+ return m_mouseVisible;
+}
+
+void Gfx::CEngine::SetMousePos(Math::Point pos)
+{
+ m_mousePos = pos;
+}
+
+Math::Point Gfx::CEngine::GetMousePos()
+{
+ return m_mousePos;
+}
+
+void Gfx::CEngine::SetMouseType(Gfx::EngineMouseType type)
+{
+ m_mouseType = type;
+}
+
+Gfx::EngineMouseType Gfx::CEngine::GetMouseType()
+{
+ return m_mouseType;
+}
+
+void Gfx::CEngine::AddStatisticTriangle(int count)
+{
+ m_statisticTriangle += count;
+}
diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h
new file mode 100644
index 0000000..1348cdd
--- /dev/null
+++ b/src/graphics/engine/engine.h
@@ -0,0 +1,985 @@
+// * 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/.
+
+// engine.h
+
+#pragma once
+
+
+#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/matrix.h"
+#include "math/point.h"
+#include "math/vector.h"
+
+
+#include <string>
+#include <vector>
+#include <map>
+
+
+class CApplication;
+class CInstanceManager;
+class CObject;
+class CSound;
+
+
+namespace Gfx {
+
+class CDevice;
+class CLightManager;
+class CText;
+class CParticle;
+class CWater;
+class CCloud;
+class CLightning;
+class CPlanet;
+class CTerrain;
+
+
+/**
+ \enum EngineTriangleType
+ \brief Type of triangles drawn for engine objects */
+enum EngineTriangleType
+{
+ //! Triangles
+ ENG_TRIANGLE_TYPE_6T = 1,
+ //! Surfaces
+ ENG_TRIANGLE_TYPE_6S = 2
+};
+
+/**
+ \struct EngineTriangle
+ \brief A triangle drawn by the graphics engine */
+struct EngineTriangle
+{
+ //! Triangle vertices
+ Gfx::VertexTex2 triangle[3];
+ //! Material
+ Gfx::Material material;
+ //! Render state (TODO: ?)
+ int state;
+ //! 1st texture
+ Gfx::Texture tex1;
+ //! 2nd texture
+ Gfx::Texture tex2;
+
+ EngineTriangle()
+ {
+ state = 0;
+ }
+};
+
+/**
+ \enum EngineObjectType
+ \brief Class of graphics engine object */
+enum EngineObjectType
+{
+ //! Object doesn't exist
+ ENG_OBJTYPE_NULL = 0,
+ //! Terrain
+ ENG_OBJTYPE_TERRAIN = 1,
+ //! Fixed object
+ ENG_OBJTYPE_FIX = 2,
+ //! Moving object
+ ENG_OBJTYPE_VEHICULE = 3,
+ //! Part of a moving object
+ ENG_OBJTYPE_DESCENDANT = 4,
+ //! Fixed object type quartz
+ ENG_OBJTYPE_QUARTZ = 5,
+ //! Fixed object type metal
+ ENG_OBJTYPE_METAL = 6
+};
+
+/**
+ \struct EngineObject
+ \brief Object drawn by the graphics engine */
+struct EngineObject
+{
+ //! If true, the object is drawn
+ bool visible;
+ //! If true, object is behind the 2D interface
+ bool drawWorld;
+ //! If true, the shape is before the 2D interface
+ bool drawFront;
+ //! Number of triangles
+ int totalTriangles;
+ //! Type of object
+ Gfx::EngineObjectType type;
+ //! Transformation matrix
+ Math::Matrix transform;
+ //! Distance view - origin (TODO: ?)
+ float distance;
+ //! Bounding box min (origin 0,0,0 always included)
+ Math::Vector bboxMin;
+ //! bounding box max (origin 0,0,0 always included)
+ Math::Vector bboxMax;
+ //! Radius of the sphere at the origin
+ float radius;
+ //! Rank of the associated shadow
+ int shadowRank;
+ //! Transparency of the object [0, 1]
+ float transparency;
+
+ EngineObject()
+ {
+ visible = false;
+ drawWorld = false;
+ drawFront = false;
+ totalTriangles = 0;
+ distance = 0.0f;
+ radius = 0.0f;
+ shadowRank = 0;
+ transparency = 0.0f;
+ }
+};
+
+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;
+
+ EngineObjLevel4();
+};
+
+/**
+ \struct EngineObjLevel3
+ \brief Tier 3 of object tree */
+struct EngineObjLevel3
+{
+ float min;
+ float max;
+ std::vector<Gfx::EngineObjLevel4> up;
+ Gfx::EngineObjLevel2* down;
+
+ EngineObjLevel3();
+};
+
+/**
+ \struct EngineObjLevel2
+ \brief Tier 2 of object tree */
+struct EngineObjLevel2
+{
+ int objRank;
+ std::vector<Gfx::EngineObjLevel3> up;
+ Gfx::EngineObjLevel1* down;
+
+ EngineObjLevel2();
+};
+
+/**
+ \struct EngineObjLevel1
+ \brief Tier 1 of object tree */
+struct EngineObjLevel1
+{
+ Gfx::Texture tex1;
+ Gfx::Texture tex2;
+ std::vector<Gfx::EngineObjLevel2> up;
+
+ EngineObjLevel1();
+};
+
+/**
+ \struct EngineShadowType
+ \brief Type of shadow drawn by the graphics engine */
+enum EngineShadowType
+{
+ //! Normal shadow
+ ENG_SHADOW_NORM = 0,
+ //! TODO: ?
+ ENG_SHADOW_WORM = 1
+};
+
+/**
+ \struct EngineShadow
+ \brief Shadow drawn by the graphics engine */
+struct EngineShadow
+{
+ //! If true, shadow is invisible (object being carried for example)
+ bool hide;
+ //! Rank of the associated object
+ int objRank;
+ //! Type of shadow
+ Gfx::EngineShadowType type;
+ //! Position of the shadow
+ Math::Vector pos;
+ //! Normal to the terrain
+ Math::Vector normal;
+ //! Angle of the shadow
+ float angle;
+ //! Radius of the shadow
+ float radius;
+ //! Intensity of the shadow
+ float intensity;
+ //! Height from the ground
+ float height;
+
+ EngineShadow()
+ {
+ hide = false;
+ objRank = 0;
+ angle = radius = intensity = height = 0.0f;
+ }
+};
+
+/**
+ \struct EngineGroundSpot
+ \brief A spot (large shadow) drawn on the ground by the graphics engine */
+struct EngineGroundSpot
+{
+ //! Color of the shadow
+ Gfx::Color color;
+ //! Min altitude
+ float min;
+ //! Max altitude
+ float max;
+ //! Transition area
+ float smooth;
+ //! Position for the shadow
+ Math::Vector pos;
+ //! Radius of the shadow
+ float radius;
+ //! Position of the shadow drawn
+ Math::Vector drawPos;
+ //! Radius of the shadow drawn
+ float drawRadius;
+
+ EngineGroundSpot()
+ {
+ min = max = smooth = radius = drawRadius = 0.0f;
+ }
+};
+
+/**
+ \enum EngineGroundMarkPhase
+ \brief Phase of life of an EngineGroundMark */
+enum EngineGroundMarkPhase
+{
+ //! Increase
+ ENG_GR_MARK_PHASE_INC = 1,
+ //! Fixed
+ ENG_GR_MARK_PHASE_FIX = 2,
+ //! Decrease
+ ENG_GR_MARK_PHASE_DEC = 2
+};
+
+/**
+ \struct EngineGroundMark
+ \brief A mark on ground drawn by the graphics engine */
+struct EngineGroundMark
+{
+ //! If true, draw mark
+ bool draw;
+ //! Phase of life
+ Gfx::EngineGroundMarkPhase phase;
+ //! Times for 3 life phases
+ float delay[3];
+ //! Fixed time
+ float fix;
+ //! Position for marks
+ Math::Vector pos;
+ //! Radius of marks
+ float radius;
+ //! Color intensity
+ float intensity;
+ //! Draw position for marks
+ Math::Vector drawPos;
+ //! Radius for marks
+ float drawRadius;
+ //! Draw intensity for marks
+ float drawIntensity;
+ //! X dimension of table
+ int dx;
+ //! Y dimension of table
+ int dy;
+ //! Pointer to the table
+ char* table;
+
+ EngineGroundMark()
+ {
+ draw = false;
+ delay[0] = delay[1] = delay[2] = 0.0f;
+ fix = radius = intensity = drawRadius = drawIntensity = 0.0f;
+ dx = dy = 0;
+ table = NULL;
+ }
+};
+
+/**
+ \enum EngineTextureMapping
+ \brief Type of texture mapping
+ */
+enum EngineTextureMapping
+{
+ ENG_TEX_MAPPING_X = 1,
+ ENG_TEX_MAPPING_Y = 2,
+ ENG_TEX_MAPPING_Z = 3,
+ ENG_TEX_MAPPING_1X = 4,
+ ENG_TEX_MAPPING_1Y = 5,
+ ENG_TEX_MAPPING_1Z = 6
+};
+
+
+/**
+ \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
+{
+ //! Normal cursor (arrow)
+ ENG_MOUSE_NORM = 0,
+ //! Busy
+ ENG_MOUSE_WAIT = 1,
+ //! Edit (I-beam)
+ ENG_MOUSE_EDIT = 2,
+ //! Hand
+ ENG_MOUSE_HAND = 3,
+ //! Small cross
+ ENG_MOUSE_CROSS = 4,
+ //! TODO: ?
+ ENG_MOUSE_SHOW = 5,
+ //! Crossed out sign
+ ENG_MOUSE_NO = 6,
+ //! Resize
+ ENG_MOUSE_MOVE = 7,
+ //! Resize horizontally
+ ENG_MOUSE_MOVEH = 8,
+ //! Resize vertically
+ ENG_MOUSE_MOVEV = 9,
+ //! Resize diagonally bottom-left to top-right
+ ENG_MOUSE_MOVED = 10,
+ //! Resize diagonally top-left to bottom-right
+ ENG_MOUSE_MOVEI = 11,
+ //! Scroll to the left
+ ENG_MOUSE_SCROLLL = 12,
+ //! Scroll to the right
+ ENG_MOUSE_SCROLLR = 13,
+ //! Scroll up
+ ENG_MOUSE_SCROLLU = 14,
+ //! Scroll down
+ ENG_MOUSE_SCROLLD = 15,
+ //! Larger crosshair
+ ENG_MOUSE_TARGET = 16,
+
+ //! Number of items in enum
+ ENG_MOUSE_COUNT
+};
+
+/**
+ \struct EngineMouse
+ \brief Information about mouse cursor */
+struct EngineMouse
+{
+ //! Index of texture element for 1st image
+ int icon1;
+ //! Index of texture element for 2nd image
+ int icon2;
+ //! Shadow texture part
+ int iconShadow;
+ //! Mode to render 1st image in
+ Gfx::EngineRenderState mode1;
+ //! Mode to render 2nd image in
+ Gfx::EngineRenderState mode2;
+ //! Hot point
+ Math::Point hotPoint;
+
+ EngineMouse(int icon1 = -1, int icon2 = -1, int iconShadow = -1,
+ Gfx::EngineRenderState mode1 = Gfx::ENG_RSTATE_NORMAL,
+ Gfx::EngineRenderState mode2 = Gfx::ENG_RSTATE_NORMAL,
+ Math::Point hotPoint = Math::Point())
+ {
+ this->icon1 = icon1;
+ this->icon2 = icon2;
+ this->iconShadow = iconShadow;
+ this->mode1 = mode1;
+ this->mode2 = mode2;
+ this->hotPoint = hotPoint;
+ }
+};
+
+
+/**
+ \class CEngine
+ \brief The graphics engine
+
+ This is the main class for graphics engine. It is responsible for drawing the 3D scene,
+ setting various render states, and facilitating the drawing of 2D interface.
+
+ It uses a lower-level CDevice object which is implementation-independent core engine.
+
+ \section Objecs Engine objects
+
+ 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).
+ 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.
+
+ ...
+ */
+class CEngine
+{
+public:
+ CEngine(CInstanceManager *iMan, CApplication *app);
+ ~CEngine();
+
+ bool GetWasInit();
+ std::string GetError();
+
+ bool Create();
+ void Destroy();
+
+ void SetDevice(Gfx::CDevice *device);
+ Gfx::CDevice* GetDevice();
+
+ bool AfterDeviceSetInit();
+
+ void SetTerrain(Gfx::CTerrain* terrain);
+
+ bool ProcessEvent(const Event &event);
+
+ bool Render();
+
+
+ bool WriteProfile();
+
+ void SetPause(bool pause);
+ bool GetPause();
+
+ void SetMovieLock(bool lock);
+ bool GetMovieLock();
+
+ void SetShowStat(bool show);
+ bool GetShowStat();
+
+ void SetRenderEnable(bool enable);
+
+ int OneTimeSceneInit();
+ int InitDeviceObjects();
+ int DeleteDeviceObjects();
+ int RestoreSurfaces();
+ int FrameMove(float rTime);
+ void StepSimulation(float rTime);
+ int FinalCleanup();
+ void AddStatisticTriangle(int nb);
+ 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();
+
+ void TimeInit();
+ void TimeEnterGel();
+ void TimeExitGel();
+ float TimeGet();
+
+ int GetRestCreate();
+ int CreateObject();
+ void FlushObject();
+ bool DeleteObject(int objRank);
+ bool SetDrawWorld(int objRank, bool draw);
+ bool SetDrawFront(int objRank, bool draw);
+
+ bool AddTriangle(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material &mat,
+ 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,
+ float min, float max, bool globalUpdate);
+ bool AddQuick(int objRank, Gfx::EngineObjLevel5* buffer,
+ std::string texName1, std::string texName2,
+ 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);
+
+ 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,
+ 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,
+ 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);
+ 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 SetObjectShadowAngle(int objRank, float angle);
+ bool SetObjectShadowRadius(int objRank, float radius);
+ bool SetObjectShadowIntensity(int objRank, float intensity);
+ bool SetObjectShadowHeight(int objRank, float h);
+ float GetObjectShadowRadius(int objRank);
+
+ void GroundSpotFlush();
+ int GroundSpotCreate();
+ void GroundSpotDelete(int rank);
+ bool SetObjectGroundSpotPos(int rank, const Math::Vector &pos);
+ bool SetObjectGroundSpotRadius(int rank, float radius);
+ 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,
+ float delay1, float delay2, float delay3,
+ int dx, int dy, char* table);
+ bool GroundMarkDelete(int rank);
+
+ 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);
+
+ bool LoadTexture(const std::string &name, int stage = 0);
+ bool LoadAllTextures();
+
+ void SetLimitLOD(int rank, float limit);
+ float GetLimitLOD(int rank, bool last=false);
+
+ void SetTerrainVision(float vision);
+
+ void SetGroundSpot(bool mode);
+ bool GetGroundSpot();
+ void SetShadow(bool mode);
+ bool GetShadow();
+ void SetDirty(bool mode);
+ bool GetDirty();
+ void SetFog(bool mode);
+ bool GetFog();
+ bool GetStateColor();
+
+ void SetSecondTexture(int texNum);
+ int GetSecondTexture();
+
+ void SetRankView(int rank);
+ int GetRankView();
+
+ void SetDrawWorld(bool draw);
+ void SetDrawFront(bool draw);
+
+ void SetAmbientColor(const Gfx::Color &color, int rank = 0);
+ Gfx::Color GetAmbientColor(int rank = 0);
+
+ void SetWaterAddColor(const Gfx::Color &color);
+ Gfx::Color GetWaterAddColor();
+
+ void SetFogColor(const Gfx::Color &color, int rank = 0);
+ Gfx::Color GetFogColor(int rank = 0);
+
+ void SetDeepView(float length, int rank = 0, bool ref=false);
+ float GetDeepView(int rank = 0);
+
+ 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(),
+ 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 SetOverFront(bool front);
+ void SetOverColor(const Gfx::Color &color = Gfx::Color(), int mode = ENG_RSTATE_TCOLOR_BLACK);
+
+ void SetParticleDensity(float value);
+ float GetParticleDensity();
+ float ParticleAdapt(float factor);
+
+ void SetClippingDistance(float value);
+ float GetClippingDistance();
+
+ void SetObjectDetail(float value);
+ float GetObjectDetail();
+
+ void SetGadgetQuantity(float value);
+ float GetGadgetQuantity();
+
+ void SetTextureQuality(int value);
+ int GetTextureQuality();
+
+ void SetTotoMode(bool present);
+ bool GetTotoMode();
+
+ void SetLensMode(bool present);
+ bool GetLensMode();
+
+ void SetWaterMode(bool present);
+ bool GetWaterMode();
+
+ void SetLightingMode(bool present);
+ bool GetLightingMode();
+
+ void SetSkyMode(bool present);
+ bool GetSkyMode();
+
+ void SetBackForce(bool present);
+ bool GetBackForce();
+
+ void SetPlanetMode(bool present);
+ bool GetPlanetMode();
+
+ void SetLightMode(bool present);
+ bool GetLightMode();
+
+ void SetEditIndentMode(bool autoIndent);
+ bool GetEditIndentMode();
+
+ void SetEditIndentValue(int value);
+ int GetEditIndentValue();
+
+ void SetSpeed(float speed);
+ float GetSpeed();
+
+ 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);
+
+ void SetMouseVisible(bool show);
+ bool GetMouseVisible();
+ void SetMousePos(Math::Point pos);
+ Math::Point GetMousePos();
+ void SetMouseType(Gfx::EngineMouseType type);
+ Gfx::EngineMouseType GetMouseType();
+
+ CText* GetText();
+
+ 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);
+
+protected:
+
+ void SetUp3DView();
+ bool Draw3DScene();
+
+ void SetUpInterfaceView();
+ bool DrawInterface();
+
+ void DrawGroundSpot();
+ void DrawShadow();
+ void DrawBackground();
+ void DrawBackgroundGradient(Gfx::Color up, Gfx::Color down);
+ void DrawBackgroundImageQuarter(Math::Point p1, Math::Point p2, char *name);
+ void DrawBackgroundImage();
+ void DrawPlanet();
+ void DrawFrontsize();
+ void DrawOverColor();
+ void DrawHilite();
+ void DrawMouse();
+ 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);*/
+
+ bool IsVisible(int objRank);
+ 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);
+ void ComputeDistance();
+ void UpdateGeometry();
+
+protected:
+ CInstanceManager* m_iMan;
+ CApplication* m_app;
+ CSound* m_sound;
+ Gfx::CDevice* m_device;
+ Gfx::CText* m_text;
+ Gfx::CLightManager* m_lightMan;
+ Gfx::CParticle* m_particle;
+ Gfx::CWater* m_water;
+ Gfx::CCloud* m_cloud;
+ Gfx::CLightning* m_lightning;
+ Gfx::CPlanet* m_planet;
+ Gfx::CTerrain* m_terrain;
+
+ bool m_wasInit;
+ std::string m_error;
+
+ 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];
+
+ Math::Matrix m_matProj;
+ Math::Matrix m_matLeftView;
+ Math::Matrix m_matRightView;
+ Math::Matrix m_matView;
+ float m_focus;
+
+ Math::Matrix m_matWorldInterface;
+ Math::Matrix m_matProjInterface;
+ 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;
+
+ Math::IntPoint m_dim;
+ Math::IntPoint m_lastDim;
+
+ std::vector<Gfx::EngineObjLevel1> m_objectTree;
+ std::vector<Gfx::EngineObject> m_objects;
+ std::vector<Gfx::EngineShadow> m_shadow;
+ std::vector<Gfx::EngineGroundSpot> m_groundSpot;
+ Gfx::EngineGroundMark m_groundMark;
+
+ Math::Vector m_eyePt;
+ Math::Vector m_lookatPt;
+ float m_eyeDirH;
+ float m_eyeDirV;
+ int m_rankView;
+ Gfx::Color m_ambientColor[2];
+ Gfx::Color m_backColor[2];
+ Gfx::Color m_fogColor[2];
+ float m_deepView[2];
+ float m_fogStart[2];
+ Gfx::Color m_waterAddColor;
+ int m_statisticTriangle;
+ bool m_updateGeometry;
+ //char m_infoText[10][200];
+ int m_alphaMode;
+ bool m_stateColor;
+ bool m_forceStateColor;
+ bool m_groundSpotVisible;
+ bool m_shadowVisible;
+ bool m_dirty;
+ bool m_fog;
+ bool m_firstGroundSpot;
+ int m_secondTexNum;
+ std::string m_backgroundName;
+ 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;
+ bool m_drawWorld;
+ bool m_drawFront;
+ float m_limitLOD[2];
+ float m_particuleDensity;
+ float m_clippingDistance;
+ float m_lastClippingDistance;
+ float m_objectDetail;
+ float m_lastObjectDetail;
+ float m_terrainVision;
+ float m_gadgetQuantity;
+ int m_textureQuality;
+ bool m_totoMode;
+ bool m_lensMode;
+ bool m_waterMode;
+ bool m_skyMode;
+ bool m_backForce;
+ bool m_planetMode;
+ bool m_lightMode;
+ bool m_editIndentMode;
+ 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;
+
+ std::string m_texPath;
+ Gfx::TextureCreateParams m_defaultTexParams;
+
+ std::map<std::string, Gfx::Texture> m_texNameMap;
+ std::map<Gfx::Texture, std::string> m_revTexNameMap;
+
+ Gfx::EngineMouse m_mice[Gfx::ENG_MOUSE_COUNT];
+ Gfx::Texture m_miceTexture;
+ Math::Point m_mouseSize;
+ Gfx::EngineMouseType m_mouseType;
+ Math::Point m_mousePos;
+ bool m_mouseVisible;
+
+ //LPDIRECTDRAWSURFACE7 m_imageSurface;
+ //DDSURFACEDESC2 m_imageDDSD;
+ //WORD* m_imageCopy;
+ //int m_imageDX;
+ //int m_imageDY;
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/engine/lightman.cpp b/src/graphics/engine/lightman.cpp
new file mode 100644
index 0000000..9e15b5a
--- /dev/null
+++ b/src/graphics/engine/lightman.cpp
@@ -0,0 +1,416 @@
+// * 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/.
+
+// light.cpp
+
+#include "graphics/engine/lightman.h"
+
+#include "common/iman.h"
+#include "graphics/core/device.h"
+#include "math/geometry.h"
+
+#include <cmath>
+
+
+void Gfx::LightProgression::Init(float value)
+{
+ starting = value;
+ ending = value;
+ current = value;
+ progress = 0.0f;
+ speed = 100.0f;
+}
+
+void Gfx::LightProgression::Update(float rTime)
+{
+ if (speed < 100.0f)
+ {
+ if (progress < 1.0f)
+ {
+ progress += speed * rTime;
+ if (progress > 1.0f)
+ progress = 1.0f;
+ }
+
+ current = starting + progress * (ending - starting);
+ }
+ else
+ {
+ current = ending;
+ }
+}
+
+void Gfx::LightProgression::SetTarget(float value)
+{
+ starting = current;
+ ending = value;
+ progress = 0.0f;
+}
+
+
+Gfx::DynamicLight::DynamicLight()
+{
+ used = enabled = false;
+}
+
+
+
+Gfx::CLightManager::CLightManager(CInstanceManager* iMan, Gfx::CEngine* engine)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_LIGHT, this);
+
+ m_device = NULL;
+ m_engine = engine;
+
+ m_time = 0.0f;
+}
+
+Gfx::CLightManager::~CLightManager()
+{
+ m_iMan->DeleteInstance(CLASS_LIGHT, this);
+
+ m_iMan = NULL;
+ m_device = NULL;
+ m_engine = NULL;
+}
+
+void Gfx::CLightManager::SetDevice(Gfx::CDevice* device)
+{
+ m_device = device;
+
+ m_dynLights = std::vector<Gfx::DynamicLight>(m_device->GetMaxLightCount(), Gfx::DynamicLight());
+}
+
+void Gfx::CLightManager::FlushLights()
+{
+ for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
+ {
+ m_dynLights[i].used = false;
+ m_device->SetLightEnabled(i, false);
+ }
+}
+
+/** Returns the index of light created or -1 if all lights are used. */
+int Gfx::CLightManager::CreateLight()
+{
+ for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
+ {
+ if (m_dynLights[i].used) continue;
+
+ m_dynLights[i] = Gfx::DynamicLight();
+
+ m_dynLights[i].used = true;
+ m_dynLights[i].enabled = true;
+
+ m_dynLights[i].includeType = Gfx::ENG_OBJTYPE_NULL;
+ m_dynLights[i].excludeType = Gfx::ENG_OBJTYPE_NULL;
+
+ m_dynLights[i].light.type = Gfx::LIGHT_DIRECTIONAL;
+ m_dynLights[i].light.diffuse = Gfx::Color(0.5f, 0.5f, 0.5f);
+ m_dynLights[i].light.position = Math::Vector(-100.0f, 100.0f, -100.0f);
+ m_dynLights[i].light.direction = Math::Vector( 1.0f, -1.0f, 1.0f);
+
+ m_dynLights[i].intensity.Init(1.0f); // maximum
+ m_dynLights[i].colorRed.Init(0.5f);
+ m_dynLights[i].colorGreen.Init(0.5f);
+ m_dynLights[i].colorBlue.Init(0.5f); // gray
+
+ return i;
+ }
+
+ return -1;
+}
+
+bool Gfx::CLightManager::DeleteLight(int lightRank)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].used = false;
+ m_device->SetLightEnabled(lightRank, false);
+
+ return true;
+}
+
+// Specifies a light.
+
+bool Gfx::CLightManager::SetLight(int lightRank, const Gfx::Light &light)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].light = light;
+
+ m_dynLights[lightRank].colorRed.Init(m_dynLights[lightRank].light.diffuse.r);
+ m_dynLights[lightRank].colorGreen.Init(m_dynLights[lightRank].light.diffuse.g);
+ m_dynLights[lightRank].colorBlue.Init(m_dynLights[lightRank].light.diffuse.b);
+
+ return true;
+}
+
+bool Gfx::CLightManager::GetLight(int lightRank, Gfx::Light &light)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ light = m_dynLights[lightRank].light;
+ return true;
+}
+
+bool Gfx::CLightManager::SetLightEnabled(int lightRank, bool enabled)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].enabled = enabled;
+ return true;
+}
+
+bool Gfx::CLightManager::SetLightIncludeType(int lightRank, Gfx::EngineObjectType type)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].includeType = type;
+ return true;
+}
+
+bool Gfx::CLightManager::SetLightExcludeType(int lightRank, Gfx::EngineObjectType type)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].excludeType = type;
+ return true;
+}
+
+bool Gfx::CLightManager::SetLightPos(int lightRank, const Math::Vector &pos)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].light.position = pos;
+ return true;
+}
+
+Math::Vector Gfx::CLightManager::GetLightPos(int lightRank)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return Math::Vector(0.0f, 0.0f, 0.0f);
+
+ return m_dynLights[lightRank].light.position;
+}
+
+bool Gfx::CLightManager::SetLightDir(int lightRank, const Math::Vector &dir)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].light.direction = dir;
+ return true;
+}
+
+Math::Vector Gfx::CLightManager::GetLightDir(int lightRank)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return Math::Vector(0.0f, 0.0f, 0.0f);
+
+ return m_dynLights[lightRank].light.direction;
+}
+
+bool Gfx::CLightManager::SetLightIntensitySpeed(int lightRank, float speed)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].intensity.speed = speed;
+ return true;
+}
+
+bool Gfx::CLightManager::SetLightIntensity(int lightRank, float value)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].intensity.SetTarget(value);
+ return true;
+}
+
+float Gfx::CLightManager::GetLightIntensity(int lightRank)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return 0.0f;
+
+ return m_dynLights[lightRank].intensity.current;
+}
+
+
+bool Gfx::CLightManager::SetLightColorSpeed(int lightRank, float speed)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].colorRed.speed = speed;
+ m_dynLights[lightRank].colorGreen.speed = speed;
+ m_dynLights[lightRank].colorBlue.speed = speed;
+ return true;
+}
+
+bool Gfx::CLightManager::SetLightColor(int lightRank, const Gfx::Color &color)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].colorRed.SetTarget(color.r);
+ m_dynLights[lightRank].colorGreen.SetTarget(color.g);
+ m_dynLights[lightRank].colorBlue.SetTarget(color.b);
+ return true;
+}
+
+Gfx::Color Gfx::CLightManager::GetLightColor(int lightRank)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return Gfx::Color(0.5f, 0.5f, 0.5f, 0.5f);
+
+ Gfx::Color color;
+ color.r = m_dynLights[lightRank].colorRed.current;
+ color.g = m_dynLights[lightRank].colorGreen.current;
+ color.b = m_dynLights[lightRank].colorBlue.current;
+ return color;
+}
+
+void Gfx::CLightManager::AdaptLightColor(const Gfx::Color &color, float factor)
+{
+ for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
+ {
+ if (! m_dynLights[i].used)
+ continue;
+
+ Gfx::Color value;
+ value.r = m_dynLights[i].colorRed.current;
+ value.g = m_dynLights[i].colorGreen.current;
+ value.b = m_dynLights[i].colorBlue.current;
+
+ value.r += color.r * factor;
+ value.g += color.g * factor;
+ value.b += color.b * factor;
+
+ m_dynLights[i].colorRed.Init(value.r);
+ m_dynLights[i].colorGreen.Init(value.g);
+ m_dynLights[i].colorBlue.Init(value.b);
+ }
+
+ UpdateLights();
+}
+
+void Gfx::CLightManager::UpdateProgression(float rTime)
+{
+ if (m_engine->GetPause())
+ return;
+
+ m_time += rTime;
+
+ for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
+ {
+ if (! m_dynLights[i].used)
+ continue;
+
+ m_dynLights[i].intensity.Update(rTime);
+ m_dynLights[i].colorRed.Update(rTime);
+ m_dynLights[i].colorGreen.Update(rTime);
+ m_dynLights[i].colorBlue.Update(rTime);
+
+ if (m_dynLights[i].includeType == Gfx::ENG_OBJTYPE_QUARTZ)
+ {
+ m_dynLights[i].light.direction.x = sinf(1.0f * (m_time + i*Math::PI*0.5f));
+ m_dynLights[i].light.direction.z = cosf(1.1f * (m_time + i*Math::PI*0.5f));
+ m_dynLights[i].light.direction.y = -1.0f + 0.5f * cosf((m_time + i*Math::PI*0.5f)*2.7f);
+ }
+
+ if (m_dynLights[i].includeType == Gfx::ENG_OBJTYPE_METAL)
+ {
+ Math::Vector dir = m_engine->GetEyePt() - m_engine->GetLookatPt();
+ float angle = Math::RotateAngle(dir.x, dir.z);
+ angle += Math::PI * 0.5f * i;
+ m_dynLights[i].light.direction.x = sinf(2.0f * angle);
+ m_dynLights[i].light.direction.z = cosf(2.0f * angle);
+ }
+ }
+}
+
+
+void Gfx::CLightManager::UpdateLights()
+{
+ for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
+ {
+ if (! m_dynLights[i].used)
+ continue;
+
+ bool enabled = m_dynLights[i].enabled;
+ if (m_dynLights[i].intensity.current == 0.0f)
+ enabled = false;
+
+ if (enabled)
+ {
+ float value = m_dynLights[i].colorRed.current * m_dynLights[i].intensity.current;
+ m_dynLights[i].light.diffuse.r = value;
+
+ value = m_dynLights[i].colorGreen.current * m_dynLights[i].intensity.current;
+ m_dynLights[i].light.diffuse.g = value;
+
+ value = m_dynLights[i].colorBlue.current * m_dynLights[i].intensity.current;
+ m_dynLights[i].light.diffuse.b = value;
+
+ m_device->SetLight(i, m_dynLights[i].light);
+ m_device->SetLightEnabled(i, enabled);
+ }
+ else
+ {
+ m_dynLights[i].light.diffuse.r = 0.0f;
+ m_dynLights[i].light.diffuse.g = 0.0f;
+ m_dynLights[i].light.diffuse.b = 0.0f;
+
+ m_device->SetLightEnabled(i, enabled);
+ }
+ }
+}
+
+void Gfx::CLightManager::UpdateLightsEnableState(Gfx::EngineObjectType type)
+{
+ for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
+ {
+ if (! m_dynLights[i].used)
+ continue;
+ if (! m_dynLights[i].enabled)
+ continue;
+ if (m_dynLights[i].intensity.current == 0.0f)
+ continue;
+
+ if (m_dynLights[i].includeType != Gfx::ENG_OBJTYPE_NULL)
+ {
+ bool enabled = (m_dynLights[i].includeType == type);
+ m_device->SetLightEnabled(i, enabled);
+ }
+
+ if (m_dynLights[i].excludeType != Gfx::ENG_OBJTYPE_NULL)
+ {
+ bool enabled = (m_dynLights[i].excludeType != type);
+ m_device->SetLightEnabled(i, enabled);
+ }
+ }
+}
diff --git a/src/graphics/engine/lightman.h b/src/graphics/engine/lightman.h
new file mode 100644
index 0000000..8272125
--- /dev/null
+++ b/src/graphics/engine/lightman.h
@@ -0,0 +1,181 @@
+// * 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/.
+
+// lightman.h
+
+#pragma once
+
+
+#include "graphics/core/color.h"
+#include "graphics/core/light.h"
+#include "graphics/engine/engine.h"
+#include "math/vector.h"
+
+
+namespace Gfx {
+
+/**
+ \struct LightProgression
+ \brief Describes the progression of light parameters change */
+struct LightProgression
+{
+ //! Starting value
+ float starting;
+ //! Ending (destination) value
+ float ending;
+ //! Current value
+ float current;
+ //! Progress from start to end
+ float progress;
+ //! Speed of progression
+ float speed;
+
+ LightProgression()
+ {
+ starting = ending = current = progress = speed = 0.0f;
+ }
+
+ //! Initializes the progression
+ void Init(float value);
+
+ //! Updates the progression
+ void Update(float rTime);
+
+ //! Sets the new end value (starting is set to current)
+ void SetTarget(float value);
+};
+
+/**
+ \struct DynamicLight
+ \brief Dynamic light in 3D scene
+
+ It is an extension over standard light properties. Added are dynamic progressions for light
+ colors and intensity and types of objects included/excluded in lighting. */
+struct DynamicLight
+{
+ //! Whether the light is used
+ bool used;
+ //! Whether the light is turned on
+ bool enabled;
+
+ //! Configuration of the light
+ Gfx::Light light;
+
+ //! Progression of intensity [0, 1]
+ Gfx::LightProgression intensity;
+ //! Progression of red diffuse color
+ Gfx::LightProgression colorRed;
+ //! Progression of green diffuse color
+ Gfx::LightProgression colorGreen;
+ //! Progression of blue diffuse color
+ Gfx::LightProgression colorBlue;
+
+ //! Type of objects included in lighting with this light; if Gfx::ENG_OBJTYPE_NULL is used, it is ignored
+ Gfx::EngineObjectType includeType;
+ //! Type of objects excluded from lighting with this light; if Gfx::ENG_OBJTYPE_NULL is used, it is ignored
+ Gfx::EngineObjectType excludeType;
+
+ DynamicLight();
+};
+
+/**
+ \class CLightManager
+ \brief Manager for dynamic lights in 3D scene
+
+ (Old CLight class)
+
+ The class is responsible for managing dynamic lights (struct Gfx::DynamicLight) used in 3D scene.
+ The dynamic lights are created, updated and deleted through the class' interface.
+
+ Number of available lights depends on graphics device used. Class allocates vector
+ for the total number of lights, but only some are used.
+ */
+class CLightManager
+{
+public:
+ //! Constructor
+ CLightManager(CInstanceManager *iMan, Gfx::CEngine* engine);
+ //! Destructor
+ virtual ~CLightManager();
+
+ //! Sets the device to be used
+ void SetDevice(Gfx::CDevice* device);
+
+ //! Clears and disables all lights
+ void FlushLights();
+ //! Creates a new dynamic light and returns its index (lightRank)
+ int CreateLight();
+ //! Deletes and disables the given dynamic light
+ bool DeleteLight(int lightRank);
+ //! Sets the light parameters for dynamic light
+ bool SetLight(int lightRank, const Gfx::Light &light);
+ //! Returns the light parameters for given dynamic light
+ bool GetLight(int lightRank, Gfx::Light &light);
+ //! Enables/disables the given dynamic light
+ bool SetLightEnabled(int lightRank, bool enable);
+
+ //! Sets what objects are included in given dynamic light
+ bool SetLightIncludeType(int lightRank, Gfx::EngineObjectType type);
+ //! Sets what objects are excluded from given dynamic light
+ bool SetLightExcludeType(int lightRank, Gfx::EngineObjectType type);
+
+ //! Sets the position of dynamic light
+ bool SetLightPos(int lightRank, const Math::Vector &pos);
+ //! Returns the position of dynamic light
+ Math::Vector GetLightPos(int lightRank);
+
+ //! Sets the direction of dynamic light
+ bool SetLightDir(int lightRank, const Math::Vector &dir);
+ //! Returns the direction of dynamic light
+ Math::Vector GetLightDir(int lightRank);
+
+ //! Sets the destination intensity for dynamic light's intensity progression
+ bool SetLightIntensity(int lightRank, float value);
+ //! Returns the current light intensity
+ float GetLightIntensity(int lightRank);
+ //! Sets the rate of change for dynamic light intensity
+ bool SetLightIntensitySpeed(int lightRank, float speed);
+
+ //! Adjusts the color of all dynamic lights
+ void AdaptLightColor(const Gfx::Color &color, float factor);
+
+ //! Sets the destination color for dynamic light's color progression
+ bool SetLightColor(int lightRank, const Gfx::Color &color);
+ //! Returns current light color
+ Gfx::Color GetLightColor(int lightRank);
+ //! Sets the rate of change for dynamic light colors (RGB)
+ bool SetLightColorSpeed(int lightRank, float speed);
+
+ //! Updates progression of dynamic lights
+ void UpdateProgression(float rTime);
+ //! Updates (recalculates) all dynamic lights
+ void UpdateLights();
+ //! Enables or disables dynamic lights affecting the given object type
+ void UpdateLightsEnableState(Gfx::EngineObjectType type);
+
+protected:
+ CInstanceManager* m_iMan;
+ CEngine* m_engine;
+ CDevice* m_device;
+
+ //! Current time
+ float m_time;
+ //! List of dynamic lights
+ std::vector<Gfx::DynamicLight> m_dynLights;
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/common/lightning.cpp b/src/graphics/engine/lightning.cpp
index 076fcb4..4db5511 100644
--- a/src/graphics/common/lightning.cpp
+++ b/src/graphics/engine/lightning.cpp
@@ -17,7 +17,7 @@
// lightning.cpp (aka blitz.cpp)
-#include "graphics/common/lightning.h"
+#include "graphics/engine/lightning.h"
// TODO implementation
diff --git a/src/graphics/common/lightning.h b/src/graphics/engine/lightning.h
index 957344c..957344c 100644
--- a/src/graphics/common/lightning.h
+++ b/src/graphics/engine/lightning.h
diff --git a/src/graphics/engine/modelfile.cpp b/src/graphics/engine/modelfile.cpp
new file mode 100644
index 0000000..537add4
--- /dev/null
+++ b/src/graphics/engine/modelfile.cpp
@@ -0,0 +1,841 @@
+// * 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/.
+
+// modelfile.cpp (aka modfile.cpp)
+
+#include "graphics/engine/modelfile.h"
+
+#include "common/iman.h"
+#include "common/ioutils.h"
+#include "common/logger.h"
+#include "common/stringutils.h"
+#include "math/geometry.h"
+
+#include <string.h>
+
+#include <fstream>
+
+
+//! How big the triangle vector is by default
+const int TRIANGLE_PREALLOCATE_COUNT = 2000;
+
+/**
+ \struct ModelHeader
+ \brief Header info for model file
+ */
+struct ModelHeader
+{
+ //! Revision number
+ int revision;
+ //! Version number
+ int version;
+ //! Total number of vertices
+ int totalVertices;
+ //! Reserved area
+ int reserved[10];
+
+ ModelHeader()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+
+struct OldModelTriangle1
+{
+ char used;
+ char selected;
+ Gfx::Vertex p1;
+ Gfx::Vertex p2;
+ Gfx::Vertex p3;
+ Gfx::Material material;
+ char texName[20];
+ float min;
+ float max;
+
+ OldModelTriangle1()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+struct OldModelTriangle2
+{
+ char used;
+ char selected;
+ Gfx::Vertex p1;
+ Gfx::Vertex p2;
+ Gfx::Vertex p3;
+ Gfx::Material material;
+ char texName[20];
+ float min;
+ float max;
+ long state;
+ short reserved1;
+ short reserved2;
+ short reserved3;
+ short reserved4;
+ OldModelTriangle2()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+
+struct NewModelTriangle
+{
+ char used;
+ char selected;
+ Gfx::VertexTex2 p1;
+ Gfx::VertexTex2 p2;
+ Gfx::VertexTex2 p3;
+ Gfx::Material material;
+ char texName[20];
+ float min;
+ float max;
+ long state;
+ short texNum2;
+ short reserved2;
+ short reserved3;
+ short reserved4;
+
+ NewModelTriangle()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+
+Gfx::Vertex ReadBinaryVertex(std::istream &stream)
+{
+ Gfx::Vertex result;
+
+ result.coord.x = IOUtils::ReadBinaryFloat(stream);
+ result.coord.y = IOUtils::ReadBinaryFloat(stream);
+ result.coord.z = IOUtils::ReadBinaryFloat(stream);
+ result.normal.x = IOUtils::ReadBinaryFloat(stream);
+ result.normal.y = IOUtils::ReadBinaryFloat(stream);
+ result.normal.z = IOUtils::ReadBinaryFloat(stream);
+ result.texCoord.x = IOUtils::ReadBinaryFloat(stream);
+ result.texCoord.y = IOUtils::ReadBinaryFloat(stream);
+
+ return result;
+}
+
+void WriteBinaryVertex(Gfx::Vertex vertex, std::ostream &stream)
+{
+ IOUtils::WriteBinaryFloat(vertex.coord.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.coord.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.coord.z, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.z, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord.y, stream);
+}
+
+Gfx::VertexTex2 ReadBinaryVertexTex2(std::istream &stream)
+{
+ Gfx::VertexTex2 result;
+
+ result.coord.x = IOUtils::ReadBinaryFloat(stream);
+ result.coord.y = IOUtils::ReadBinaryFloat(stream);
+ result.coord.z = IOUtils::ReadBinaryFloat(stream);
+ result.normal.x = IOUtils::ReadBinaryFloat(stream);
+ result.normal.y = IOUtils::ReadBinaryFloat(stream);
+ result.normal.z = IOUtils::ReadBinaryFloat(stream);
+ result.texCoord.x = IOUtils::ReadBinaryFloat(stream);
+ result.texCoord.y = IOUtils::ReadBinaryFloat(stream);
+ result.texCoord2.x = IOUtils::ReadBinaryFloat(stream);
+ result.texCoord2.y = IOUtils::ReadBinaryFloat(stream);
+
+ return result;
+}
+
+void WriteBinaryVertexTex2(Gfx::VertexTex2 vertex, std::ostream &stream)
+{
+ IOUtils::WriteBinaryFloat(vertex.coord.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.coord.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.coord.z, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.z, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord2.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord2.y, stream);
+}
+
+Gfx::Material ReadBinaryMaterial(std::istream &stream)
+{
+ Gfx::Material result;
+
+ result.diffuse.r = IOUtils::ReadBinaryFloat(stream);
+ result.diffuse.g = IOUtils::ReadBinaryFloat(stream);
+ result.diffuse.b = IOUtils::ReadBinaryFloat(stream);
+ result.diffuse.a = IOUtils::ReadBinaryFloat(stream);
+
+ result.ambient.r = IOUtils::ReadBinaryFloat(stream);
+ result.ambient.g = IOUtils::ReadBinaryFloat(stream);
+ result.ambient.b = IOUtils::ReadBinaryFloat(stream);
+ result.ambient.a = IOUtils::ReadBinaryFloat(stream);
+
+ result.specular.r = IOUtils::ReadBinaryFloat(stream);
+ result.specular.g = IOUtils::ReadBinaryFloat(stream);
+ result.specular.b = IOUtils::ReadBinaryFloat(stream);
+ result.specular.a = IOUtils::ReadBinaryFloat(stream);
+
+ /* emissive.r = */ IOUtils::ReadBinaryFloat(stream);
+ /* emissive.g = */ IOUtils::ReadBinaryFloat(stream);
+ /* emissive.b = */ IOUtils::ReadBinaryFloat(stream);
+ /* emissive.a = */ IOUtils::ReadBinaryFloat(stream);
+
+ /* power = */ IOUtils::ReadBinaryFloat(stream);
+
+ return result;
+}
+
+void WriteBinaryMaterial(Gfx::Material material, std::ostream &stream)
+{
+ IOUtils::WriteBinaryFloat(material.diffuse.r, stream);
+ IOUtils::WriteBinaryFloat(material.diffuse.g, stream);
+ IOUtils::WriteBinaryFloat(material.diffuse.b, stream);
+ IOUtils::WriteBinaryFloat(material.diffuse.a, stream);
+
+ IOUtils::WriteBinaryFloat(material.ambient.r, stream);
+ IOUtils::WriteBinaryFloat(material.ambient.g, stream);
+ IOUtils::WriteBinaryFloat(material.ambient.b, stream);
+ IOUtils::WriteBinaryFloat(material.ambient.a, stream);
+
+ IOUtils::WriteBinaryFloat(material.specular.r, stream);
+ IOUtils::WriteBinaryFloat(material.specular.g, stream);
+ IOUtils::WriteBinaryFloat(material.specular.b, stream);
+ IOUtils::WriteBinaryFloat(material.specular.a, stream);
+
+ /* emissive.r */ IOUtils::WriteBinaryFloat(0.0f, stream);
+ /* emissive.g */ IOUtils::WriteBinaryFloat(0.0f, stream);
+ /* emissive.b */ IOUtils::WriteBinaryFloat(0.0f, stream);
+ /* emissive.a */ IOUtils::WriteBinaryFloat(0.0f, stream);
+
+ /* power */ IOUtils::WriteBinaryFloat(0.0f, stream);
+}
+
+Gfx::ModelTriangle::ModelTriangle()
+{
+ min = 0.0f;
+ max = 0.0f;
+ state = 0L;
+}
+
+
+Gfx::CModelFile::CModelFile(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+
+ m_engine = (CEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+
+ m_triangles.reserve(TRIANGLE_PREALLOCATE_COUNT);
+}
+
+Gfx::CModelFile::~CModelFile()
+{
+}
+
+std::string Gfx::CModelFile::GetError()
+{
+ return m_error;
+}
+
+
+bool Gfx::CModelFile::ReadModel(const std::string &filename, bool edit, bool meta)
+{
+ m_triangles.clear();
+ m_error = "";
+
+ std::ifstream stream;
+ stream.open(filename.c_str(), std::ios_base::in | std::ios_base::binary);
+ if (! stream.good())
+ {
+ m_error = std::string("Could not open file '") + filename + std::string("'");
+ return false;
+ }
+
+ return ReadModel(stream, edit, meta);
+}
+
+bool Gfx::CModelFile::ReadModel(std::istream &stream, bool edit, bool meta)
+{
+ m_triangles.clear();
+ m_error = "";
+
+ // FIXME: for now, reading models only from files, not metafile
+
+ ModelHeader header;
+
+ header.revision = IOUtils::ReadBinary<4, int>(stream);
+ header.version = IOUtils::ReadBinary<4, int>(stream);
+ header.totalVertices = IOUtils::ReadBinary<4, int>(stream);
+ for (int i = 0; i < 10; ++i)
+ header.reserved[i] = IOUtils::ReadBinary<4, int>(stream);
+
+
+ if (! stream.good())
+ {
+ m_error = "Error reading model file header";
+ return false;
+ }
+
+ // Old model version #1
+ if ( (header.revision == 1) && (header.version == 0) )
+ {
+ for (int i = 0; i < header.totalVertices; ++i)
+ {
+ OldModelTriangle1 t;
+ t.used = IOUtils::ReadBinary<1, char>(stream);
+ t.selected = IOUtils::ReadBinary<1, char>(stream);
+
+ t.p1 = ReadBinaryVertex(stream);
+ t.p2 = ReadBinaryVertex(stream);
+ t.p3 = ReadBinaryVertex(stream);
+
+ t.material = ReadBinaryMaterial(stream);
+ stream.read(t.texName, 20);
+ t.min = IOUtils::ReadBinaryFloat(stream);
+ t.max = IOUtils::ReadBinaryFloat(stream);
+
+ if (! stream.good())
+ {
+ m_error = "Error reading model data";
+ return false;
+ }
+
+ Gfx::ModelTriangle triangle;
+ triangle.p1.FromVertex(t.p1);
+ triangle.p2.FromVertex(t.p2);
+ triangle.p3.FromVertex(t.p3);
+
+ triangle.material = t.material;
+ triangle.tex1Name = std::string(t.texName);
+ triangle.min = t.min;
+ triangle.max = t.max;
+
+ m_triangles.push_back(triangle);
+ }
+ }
+ else if ( header.revision == 1 && header.version == 1 )
+ {
+ for (int i = 0; i < header.totalVertices; ++i)
+ {
+ OldModelTriangle2 t;
+ t.used = IOUtils::ReadBinary<1, char>(stream);
+ t.selected = IOUtils::ReadBinary<1, char>(stream);
+
+ t.p1 = ReadBinaryVertex(stream);
+ t.p2 = ReadBinaryVertex(stream);
+ t.p3 = ReadBinaryVertex(stream);
+
+ t.material = ReadBinaryMaterial(stream);
+ stream.read(t.texName, 20);
+ t.min = IOUtils::ReadBinaryFloat(stream);
+ t.max = IOUtils::ReadBinaryFloat(stream);
+ t.state = IOUtils::ReadBinary<4, long>(stream);
+
+ t.reserved1 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved2 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved3 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved4 = IOUtils::ReadBinary<2, short>(stream);
+
+ if (! stream.good())
+ {
+ m_error = "Error reading model data";
+ return false;
+ }
+
+ Gfx::ModelTriangle triangle;
+ triangle.p1.FromVertex(t.p1);
+ triangle.p2.FromVertex(t.p2);
+ triangle.p3.FromVertex(t.p3);
+
+ triangle.material = t.material;
+ triangle.tex1Name = std::string(t.texName);
+ triangle.min = t.min;
+ triangle.max = t.max;
+ triangle.state = t.state;
+
+ m_triangles.push_back(triangle);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < header.totalVertices; ++i)
+ {
+ NewModelTriangle t;
+ t.used = IOUtils::ReadBinary<1, char>(stream);
+ t.selected = IOUtils::ReadBinary<1, char>(stream);
+
+ /* padding */ IOUtils::ReadBinary<2, unsigned int>(stream);
+
+ t.p1 = ReadBinaryVertexTex2(stream);
+ t.p2 = ReadBinaryVertexTex2(stream);
+ t.p3 = ReadBinaryVertexTex2(stream);
+
+ t.material = ReadBinaryMaterial(stream);
+ stream.read(t.texName, 20);
+ t.min = IOUtils::ReadBinaryFloat(stream);
+ t.max = IOUtils::ReadBinaryFloat(stream);
+ t.state = IOUtils::ReadBinary<4, long>(stream);
+ t.texNum2 = IOUtils::ReadBinary<2, short>(stream);
+
+ t.reserved2 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved3 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved4 = IOUtils::ReadBinary<2, short>(stream);
+
+ if (! stream.good())
+ {
+ m_error = "Error reading model data";
+ return false;
+ }
+
+ Gfx::ModelTriangle triangle;
+ triangle.p1 = t.p1;
+ triangle.p2 = t.p2;
+ triangle.p3 = t.p3;
+
+ triangle.material = t.material;
+ triangle.tex1Name = std::string(t.texName);
+ char tex2Name[20] = { 0 };
+ triangle.min = t.min;
+ triangle.max = t.max;
+ triangle.state = t.state;
+
+ if (t.texNum2 != 0)
+ sprintf(tex2Name, "dirty%.2d.tga", t.texNum2); // hardcoded as in the original code
+
+ triangle.tex2Name = std::string(tex2Name);
+
+ m_triangles.push_back(triangle);
+ }
+ }
+
+ for (int i = 0; i < (int) m_triangles.size(); ++i)
+ {
+ m_triangles[i].tex1Name = StrUtils::Replace(m_triangles[i].tex1Name, "bmp", "tga");
+
+ GetLogger()->Info("ModelTriangle %d\n", i+1);
+ std::string s1 = m_triangles[i].p1.ToString();
+ GetLogger()->Info(" p1: %s\n", s1.c_str());
+ std::string s2 = m_triangles[i].p2.ToString();
+ GetLogger()->Info(" p2: %s\n", s2.c_str());
+ std::string s3 = m_triangles[i].p3.ToString();
+ GetLogger()->Info(" p3: %s\n", s3.c_str());
+
+ std::string d = m_triangles[i].material.diffuse.ToString();
+ std::string a = m_triangles[i].material.ambient.ToString();
+ std::string s = m_triangles[i].material.specular.ToString();
+ GetLogger()->Info(" mat: d: %s a: %s s: %s\n", d.c_str(), a.c_str(), s.c_str());
+
+ GetLogger()->Info(" tex1: %s tex2: %s\n", m_triangles[i].tex1Name.c_str(), m_triangles[i].tex2Name.c_str());
+ GetLogger()->Info(" min: %.2f max: %.2f\n", m_triangles[i].min, m_triangles[i].max);
+ GetLogger()->Info(" state: %ld\n", m_triangles[i].state);
+ }
+
+ /*
+ if (! edit)
+ {
+ float limit[2];
+ limit[0] = m_engine->RetLimitLOD(0); // frontier AB as config
+ limit[1] = m_engine->RetLimitLOD(1); // frontier BC as config
+
+ // Standard frontiers -> config.
+ for (int i = 0; i < m_triangles.size(); ++i)
+ {
+ if ( m_triangles[i].min == 0.0f &&
+ m_triangles[i].max == 100.0f ) // resolution A ?
+ {
+ m_triangles[i].max = limit[0];
+ }
+ else if ( m_triangles[i].min == 100.0f &&
+ m_triangles[i].max == 200.0f ) // resolution B ?
+ {
+ m_triangles[i].min = limit[0];
+ m_triangles[i].max = limit[1];
+ }
+ else if ( m_triangles[i].min == 200.0f &&
+ m_triangles[i].max == 1000000.0f ) // resolution C ?
+ {
+ m_triangles[i].min = limit[1];
+ }
+ }
+ }*/
+
+ return true;
+}
+
+bool Gfx::CModelFile::WriteModel(const std::string &filename)
+{
+ m_error = "";
+
+ std::ofstream stream;
+ stream.open(filename.c_str(), std::ios_base::out | std::ios_base::binary);
+ if (! stream.good())
+ {
+ m_error = std::string("Could not open file '") + filename + std::string("'");
+ return false;
+ }
+
+ return WriteModel(stream);
+}
+
+bool Gfx::CModelFile::WriteModel(std::ostream &stream)
+{
+ m_error = "";
+
+ if (m_triangles.size() == 0)
+ {
+ m_error = "Empty model";
+ return false;
+ }
+
+ ModelHeader header;
+ header.revision = 1;
+ header.version = 2;
+ header.totalVertices = m_triangles.size();
+
+ IOUtils::WriteBinary<4, int>(header.revision, stream);
+ IOUtils::WriteBinary<4, int>(header.version, stream);
+ IOUtils::WriteBinary<4, int>(header.totalVertices, stream);
+ for (int i = 0; i < 10; ++i)
+ IOUtils::WriteBinary<4, int>(header.reserved[i], stream);
+
+ for (int i = 0; i < (int)m_triangles.size(); ++i)
+ {
+ NewModelTriangle t;
+
+ t.used = true;
+
+ t.p1 = m_triangles[i].p1;
+ t.p2 = m_triangles[i].p2;
+ t.p3 = m_triangles[i].p3;
+
+ t.material = m_triangles[i].material;
+ strncpy(t.texName, m_triangles[i].tex1Name.c_str(), 20);
+ t.min = m_triangles[i].min;
+ t.max = m_triangles[i].max;
+ t.state = m_triangles[i].state;
+ int no = 0;
+ sscanf(m_triangles[i].tex2Name.c_str(), "dirty%d.tga", &no); // hardcoded as in the original code
+ t.texNum2 = no;
+
+
+ IOUtils::WriteBinary<1, char>(t.used, stream);
+ IOUtils::WriteBinary<1, char>(t.selected, stream);
+
+ WriteBinaryVertexTex2(t.p1, stream);
+ WriteBinaryVertexTex2(t.p2, stream);
+ WriteBinaryVertexTex2(t.p3, stream);
+
+ WriteBinaryMaterial(t.material, stream);
+ stream.write(t.texName, 20);
+ IOUtils::WriteBinaryFloat(t.min, stream);
+ IOUtils::WriteBinaryFloat(t.max, stream);
+ IOUtils::WriteBinary<4, long>(t.state, stream);
+ IOUtils::WriteBinary<2, short>(t.texNum2, stream);
+
+ IOUtils::WriteBinary<2, short>(t.reserved2, stream);
+ IOUtils::WriteBinary<2, short>(t.reserved3, stream);
+ IOUtils::WriteBinary<2, short>(t.reserved4, stream);
+ }
+
+ return true;
+}
+
+bool Gfx::CModelFile::ReadDXF(const std::string &filename, float min, float max)
+{
+ m_triangles.clear();
+ m_error = "";
+
+ std::ifstream stream;
+ stream.open(filename.c_str(), std::ios_base::in);
+ if (! stream.good())
+ {
+ m_error = std::string("Couldn't open file '") + filename + std::string("'");
+ return false;
+ }
+
+ return ReadDXF(stream, min, max);
+}
+
+bool Gfx::CModelFile::ReadDXF(std::istream &stream, float min, float max)
+{
+ m_triangles.clear();
+ m_error = "";
+
+ if (! stream.good())
+ {
+ m_error = "Invalid stream";
+ return false;
+ }
+
+ // Input state
+ bool waitNumVertex = false;
+ bool waitNumFace = false;
+ bool waitVertexX = false;
+ bool waitVertexY = false;
+ bool waitVertexZ = false;
+ bool waitFaceX = false;
+ bool waitFaceY = false;
+ bool waitFaceZ = false;
+
+ // Vertex array
+ std::vector<Math::Vector> vertices;
+ vertices.reserve(TRIANGLE_PREALLOCATE_COUNT);
+
+ // Number of vertices & faces of the primitive to be read
+ int vertexNum = 0, faceNum = 0;
+ // Vertex coords
+ Math::Vector coords;
+ // Indexes of face (triangle) points
+ int p1 = 0, p2 = 0, p3 = 0;
+
+ // Input line
+ std::string line;
+ while (! stream.eof() )
+ {
+ // Read line with command
+ std::getline(stream, line);
+ int command = StrUtils::FromString<int>(line);
+
+ // Read line with param
+ std::getline(stream, line);
+
+ bool ok = true;
+
+
+ if (command == 66)
+ {
+ waitNumVertex = true;
+ }
+
+ if ( command == 71 && waitNumVertex )
+ {
+ waitNumVertex = false;
+ vertexNum = StrUtils::FromString<int>(line, &ok);
+ waitNumFace = true;
+ }
+
+ if ( command == 72 && waitNumFace )
+ {
+ waitNumFace = false;
+ faceNum = StrUtils::FromString<int>(line, &ok);
+ waitVertexX = true;
+ }
+
+ if ( command == 10 && waitVertexX )
+ {
+ waitVertexX = false;
+ coords.x = StrUtils::FromString<float>(line, &ok);
+ waitVertexY = true;
+ }
+
+ if ( command == 20 && waitVertexY )
+ {
+ waitVertexY = false;
+ coords.y = StrUtils::FromString<float>(line, &ok);
+ waitVertexZ = true;
+ }
+
+ if ( command == 30 && waitVertexZ )
+ {
+ waitVertexZ = false;
+ coords.z = StrUtils::FromString<float>(line, &ok);
+
+ vertexNum --;
+ if ( vertexNum >= 0 )
+ {
+ Math::Vector p(coords.x, coords.z, coords.y); // permutation of Y and Z!
+ vertices.push_back(p);
+ waitVertexX = true;
+ }
+ else
+ {
+ waitFaceX = true;
+ }
+ }
+
+ if ( command == 71 && waitFaceX )
+ {
+ waitFaceX = false;
+ p1 = StrUtils::FromString<int>(line, &ok);
+ if ( p1 < 0 ) p1 = -p1;
+ waitFaceY = true;
+ }
+
+ if ( command == 72 && waitFaceY )
+ {
+ waitFaceY = false;
+ p2 = StrUtils::FromString<int>(line, &ok);
+ if ( p2 < 0 ) p2 = -p2;
+ waitFaceZ = true;
+ }
+
+ if ( command == 73 && waitFaceZ )
+ {
+ waitFaceZ = false;
+ p3 = StrUtils::FromString<int>(line, &ok);
+ if ( p3 < 0 ) p3 = -p3;
+
+ faceNum --;
+ if ( faceNum >= 0 )
+ {
+ assert( (p1-1 >= 0) && (p1-1 < (int)vertices.size() ) );
+ assert( (p2-1 >= 0) && (p2-1 < (int)vertices.size() ) );
+ assert( (p3-1 >= 0) && (p3-1 < (int)vertices.size() ) );
+
+ CreateTriangle(vertices[p3-1], vertices[p2-1], vertices[p1-1], min, max);
+ waitFaceX = true;
+ }
+ }
+
+ if (! ok)
+ {
+ m_error = "Error reading data";
+ return false;
+ }
+
+ }
+
+ return true;
+}
+
+bool Gfx::CModelFile::CreateEngineObject(int objRank, int addState)
+{
+ /*char texName1[20];
+ char texName2[20];
+ int texNum, i, state;
+
+ for (int i = 0; i < m_trianglesUsed; i++)
+ {
+ if (! m_triangles[i].used) continue;
+
+ state = m_triangles[i].state;
+ strcpy(texName1, m_triangles[i].texName);
+ texName2[0] = 0;
+
+ if ( strcmp(texName1, "plant.tga") == 0 ) // ???
+ {
+ state |= D3DSTATEALPHA;
+ }
+
+ if ( m_triangles[i].texNum2 != 0 )
+ {
+ if ( m_triangles[i].texNum2 == 1 )
+ {
+ texNum = m_engine->RetSecondTexture();
+ }
+ else
+ {
+ texNum = m_triangles[i].texNum2;
+ }
+
+ if ( texNum >= 1 && texNum <= 10 )
+ {
+ state |= D3DSTATEDUALb;
+ }
+ if ( texNum >= 11 && texNum <= 20 )
+ {
+ state |= D3DSTATEDUALw;
+ }
+ sprintf(texName2, "dirty%.2d.tga", texNum); // ???
+ }
+
+ m_engine->AddTriangle(objRank, &m_triangles[i].p1, 3,
+ m_triangles[i].material,
+ state + addState,
+ texName1, texName2,
+ m_triangles[i].min,
+ m_triangles[i].max, false);
+ }*/
+ return true;
+}
+
+void Gfx::CModelFile::Mirror()
+{
+ for (int i = 0; i < (int)m_triangles.size(); i++)
+ {
+ Gfx::VertexTex2 t = m_triangles[i].p1;
+ m_triangles[i].p1 = m_triangles[i].p2;
+ m_triangles[i].p2 = t;
+
+ m_triangles[i].p1.coord.z = -m_triangles[i].p1.coord.z;
+ m_triangles[i].p2.coord.z = -m_triangles[i].p2.coord.z;
+ m_triangles[i].p3.coord.z = -m_triangles[i].p3.coord.z;
+
+ m_triangles[i].p1.normal.z = -m_triangles[i].p1.normal.z;
+ m_triangles[i].p2.normal.z = -m_triangles[i].p2.normal.z;
+ m_triangles[i].p3.normal.z = -m_triangles[i].p3.normal.z;
+ }
+}
+
+std::vector<Gfx::ModelTriangle>& Gfx::CModelFile::GetTriangles()
+{
+ return m_triangles;
+}
+
+int Gfx::CModelFile::GetTriangleCount()
+{
+ return m_triangles.size();
+}
+
+float Gfx::CModelFile::GetHeight(Math::Vector pos)
+{
+ float limit = 5.0f;
+
+ for (int i = 0; i < (int)m_triangles.size(); i++)
+ {
+ if ( fabs(pos.x - m_triangles[i].p1.coord.x) < limit &&
+ fabs(pos.z - m_triangles[i].p1.coord.z) < limit )
+ return m_triangles[i].p1.coord.y;
+
+ if ( fabs(pos.x - m_triangles[i].p2.coord.x) < limit &&
+ fabs(pos.z - m_triangles[i].p2.coord.z) < limit )
+ return m_triangles[i].p2.coord.y;
+
+ if ( fabs(pos.x - m_triangles[i].p3.coord.x) < limit &&
+ fabs(pos.z - m_triangles[i].p3.coord.z) < limit )
+ return m_triangles[i].p3.coord.y;
+ }
+
+ return 0.0f;
+}
+
+void Gfx::CModelFile::CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max)
+{
+ Gfx::ModelTriangle triangle;
+
+ Math::Vector n = Math::NormalToPlane(p3, p2, p1);
+ triangle.p1 = Gfx::VertexTex2(p1, n);
+ triangle.p2 = Gfx::VertexTex2(p2, n);
+ triangle.p3 = Gfx::VertexTex2(p3, n);
+
+ triangle.material.diffuse = Gfx::Color(1.0f, 1.0f, 1.0f, 0.0f);
+ triangle.material.ambient = Gfx::Color(0.5f, 0.5f, 0.5f, 0.0f);
+
+ triangle.min = min;
+ triangle.max = max;
+
+ m_triangles.push_back(triangle);
+}
diff --git a/src/graphics/engine/modelfile.h b/src/graphics/engine/modelfile.h
new file mode 100644
index 0000000..6a30487
--- /dev/null
+++ b/src/graphics/engine/modelfile.h
@@ -0,0 +1,120 @@
+// * 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/.
+
+// modelfile.h (aka modfile.h)
+
+#include "graphics/engine/engine.h"
+#include "graphics/core/vertex.h"
+#include "graphics/core/material.h"
+#include "math/vector.h"
+
+#include <string>
+#include <vector>
+#include <iostream>
+
+
+class CInstanceManager;
+
+
+namespace Gfx {
+
+/**
+ \struct ModelTriangle
+ \brief Triangle of a 3D model
+ */
+struct ModelTriangle
+{
+ //! 1st vertex
+ Gfx::VertexTex2 p1;
+ //! 2nd vertex
+ Gfx::VertexTex2 p2;
+ //! 3rd vertex
+ Gfx::VertexTex2 p3;
+ //! Material
+ Gfx::Material material;
+ //! Name of 1st texture
+ std::string tex1Name;
+ //! Name of 2nd texture
+ std::string tex2Name;
+ //! Min LOD threshold
+ float min;
+ //! Max LOD threshold
+ float max;
+ //! Rendering state to be set
+ long state;
+
+ ModelTriangle();
+};
+
+
+/**
+ \class CModelFile
+ \brief Model file reader/writer
+
+ Allows reading and writing model objects. Models are collections of ModelTriangle structs. */
+class CModelFile
+{
+public:
+ CModelFile(CInstanceManager* iMan);
+ ~CModelFile();
+
+ //! Returns the last error encountered
+ std::string GetError();
+
+ //! Reads a binary Colobot model from file
+ bool ReadModel(const std::string &filename, bool edit = false, bool meta = true);
+ //! Reads a binary Colobot model from stream
+ bool ReadModel(std::istream &stream, bool edit = false, bool meta = true);
+ //! Writes the model to Colobot binary model file
+ bool WriteModel(const std::string &filename);
+ //! Writes the model to Colobot binary model file
+ bool WriteModel(std::ostream &stream);
+
+ //! Reads a DXF model from file
+ bool ReadDXF(const std::string &filename, float min, float max);
+ //! Reads a DXF model from stream
+ bool ReadDXF(std::istream &stream, float min, float max);
+
+ //! Returns the number of triangles in model
+ int GetTriangleCount();
+ //! Returns the triangle vector
+ std::vector<Gfx::ModelTriangle>& GetTriangles();
+ //! Returns the height of model -- closest point to X and Z coords of \a pos
+ float GetHeight(Math::Vector pos);
+
+ //! Mirrors the model along the Z axis
+ void Mirror();
+
+ //! Creates an object in the graphics engine from the model
+ bool CreateEngineObject(int objRank, int addState = 0);
+
+protected:
+ //! Adds a triangle to the list
+ void CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max);
+
+protected:
+ CInstanceManager* m_iMan;
+ Gfx::CEngine* m_engine;
+
+ //! Last error
+ std::string m_error;
+
+ //! Model triangles
+ std::vector<Gfx::ModelTriangle> m_triangles;
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/common/particle.cpp b/src/graphics/engine/particle.cpp
index 322c2d0..84e2f9d 100644
--- a/src/graphics/common/particle.cpp
+++ b/src/graphics/engine/particle.cpp
@@ -17,7 +17,7 @@
// particle.cpp (aka particule.cpp)
-#include "graphics/common/particle.h"
+#include "graphics/engine/particle.h"
// TODO implementation
diff --git a/src/graphics/common/particle.h b/src/graphics/engine/particle.h
index b72075f..bd9741f 100644
--- a/src/graphics/common/particle.h
+++ b/src/graphics/engine/particle.h
@@ -25,9 +25,8 @@
class CInstanceManager;
class CRobotMain;
-class Gfx::CTerrain;
-class Gfx::CWater;
class CObject;
+class CSound;
@@ -52,7 +51,7 @@ const short SH_MAX = 3;
// type == 4 -> text (white background)
-enum ParticuleType
+enum ParticleType
{
PARTIEXPLOT = 1, // technology explosion
PARTIEXPLOO = 2, // organic explosion
@@ -195,20 +194,20 @@ enum ParticuleType
PARTITRACE19 = 159, // trace
};
-enum ParticulePhase
+enum ParticlePhase
{
PARPHSTART = 0,
PARPHEND = 1,
};
-struct Particule
+struct Particle
{
char bUsed; // TRUE -> particle used
char bRay; // TRUE -> ray with goal
unsigned short uniqueStamp; // unique mark
short sheet; // sheet (0..n)
- ParticuleType type; // type PARTI*
- ParticulePhase 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
@@ -235,7 +234,7 @@ struct Particule
struct Track
{
char bUsed; // TRUE -> drag used
- char bDrawParticule;
+ char bDrawParticle;
float step; // duration of not
float last; // increase last not memorized
float intensity; // intensity at starting (0..1)
@@ -248,7 +247,7 @@ struct Track
struct WheelTrace
{
- ParticuleType type; // type PARTI*
+ ParticleType type; // type PARTI*
Math::Vector pos[4]; // rectangle positions
float startTime; // beginning of life
};
@@ -263,16 +262,16 @@ public:
void SetGLDevice(CDevice device);
- void FlushParticule();
- void FlushParticule(int sheet);
- int CreateParticule(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticuleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0);
- int CreateFrag(Math::Vector pos, Math::Vector speed, Triangle *triangle, ParticuleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0);
- int CreatePart(Math::Vector pos, Math::Vector speed, ParticuleType 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, ParticuleType type, Math::Point dim, float duration=1.0f, int sheet=0);
- int CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticuleType 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, ParticuleType type);
- void DeleteParticule(ParticuleType type);
- void DeleteParticule(int channel);
+ 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);
+ void DeleteParticle(int channel);
void SetObjectLink(int channel, CObject *object);
void SetObjectFather(int channel, CObject *object);
void SetPosition(int channel, Math::Vector pos);
@@ -281,57 +280,57 @@ 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, ParticulePhase phase, float duration);
+ void SetPhase(int channel, ParticlePhase phase, float duration);
bool GetPosition(int channel, Math::Vector &pos);
Gfx::Color RetFogColor(Math::Vector pos);
void SetFrameUpdate(int sheet, bool bUpdate);
- void FrameParticule(float rTime);
- void DrawParticule(int sheet);
+ void FrameParticle(float rTime);
+ void DrawParticle(int sheet);
bool WriteWheelTrace(char *filename, int width, int height, Math::Vector dl, Math::Vector ur);
protected:
void DeleteRank(int rank);
bool CheckChannel(int &channel);
- void DrawParticuleTriangle(int i);
- void DrawParticuleNorm(int i);
- void DrawParticuleFlat(int i);
- void DrawParticuleFog(int i);
- void DrawParticuleRay(int i);
- void DrawParticuleSphere(int i);
- void DrawParticuleCylinder(int i);
- void DrawParticuleWheel(int i);
- CObject* SearchObjectGun(Math::Vector old, Math::Vector pos, ParticuleType type, CObject *father);
- CObject* SearchObjectRay(Math::Vector pos, Math::Vector goal, ParticuleType type, CObject *father);
+ void DrawParticleTriangle(int i);
+ void DrawParticleNorm(int i);
+ void DrawParticleFlat(int i);
+ void DrawParticleFog(int i);
+ void DrawParticleRay(int i);
+ 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);
void Play(Sound sound, Math::Vector pos, float amplitude);
bool TrackMove(int i, Math::Vector pos, float progress);
- void TrackDraw(int i, ParticuleType type);
+ void TrackDraw(int i, ParticleType type);
protected:
- CInstanceManager* m_iMan;
- CEngine* m_engine;
- CDevice* m_pDevice;
- CRobotMain* m_main;
- CTerrain* m_terrain;
- CWater* m_water;
- CSound* m_sound;
+ CInstanceManager* m_iMan;
+ CEngine* m_engine;
+ CDevice* m_pDevice;
+ CRobotMain* m_main;
+ CTerrain* m_terrain;
+ CWater* m_water;
+ CSound* m_sound;
- Particule m_particule[MAXPARTICULE*MAXPARTITYPE];
- Gfx::Triangle m_triangle[MAXPARTICULE]; // triangle if PartiType == 0
- Track m_track[MAXTRACK];
- int m_wheelTraceTotal;
- int m_wheelTraceIndex;
- WheelTrace m_wheelTrace[MAXWHEELTRACE];
- int m_totalInterface[MAXPARTITYPE][SH_MAX];
- bool m_bFrameUpdate[SH_MAX];
- int m_fogTotal;
- int m_fog[MAXPARTIFOG];
- int m_uniqueStamp;
- int m_exploGunCounter;
- float m_lastTimeGunDel;
- float m_absTime;
+ Gfx::Particle m_particule[MAXPARTICULE*MAXPARTITYPE];
+ Gfx::EngineTriangle m_triangle[MAXPARTICULE]; // triangle if PartiType == 0
+ Track m_track[MAXTRACK];
+ int m_wheelTraceTotal;
+ int m_wheelTraceIndex;
+ WheelTrace m_wheelTrace[MAXWHEELTRACE];
+ int m_totalInterface[MAXPARTITYPE][SH_MAX];
+ bool m_bFrameUpdate[SH_MAX];
+ int m_fogTotal;
+ int m_fog[MAXPARTIFOG];
+ int m_uniqueStamp;
+ int m_exploGunCounter;
+ float m_lastTimeGunDel;
+ float m_absTime;
};
diff --git a/src/graphics/common/planet.cpp b/src/graphics/engine/planet.cpp
index 4fa17a1..4f1f614 100644
--- a/src/graphics/common/planet.cpp
+++ b/src/graphics/engine/planet.cpp
@@ -17,7 +17,7 @@
// planet.cpp
-#include "graphics/common/planet.h"
+#include "graphics/engine/planet.h"
// TODO implementation
diff --git a/src/graphics/common/planet.h b/src/graphics/engine/planet.h
index 264d05c..264d05c 100644
--- a/src/graphics/common/planet.h
+++ b/src/graphics/engine/planet.h
diff --git a/src/graphics/common/pyro.cpp b/src/graphics/engine/pyro.cpp
index 6b5b1af..e699db2 100644
--- a/src/graphics/common/pyro.cpp
+++ b/src/graphics/engine/pyro.cpp
@@ -17,7 +17,7 @@
// pyro.cpp
-#include "graphics/common/pyro.h"
+#include "graphics/engine/pyro.h"
// TODO implementation
diff --git a/src/graphics/common/pyro.h b/src/graphics/engine/pyro.h
index fda74b3..d663ca5 100644
--- a/src/graphics/common/pyro.h
+++ b/src/graphics/engine/pyro.h
@@ -20,7 +20,7 @@
#pragma once
#include "common/misc.h"
-#include "graphics/common/engine.h"
+#include "graphics/engine/engine.h"
//#include "object/object.h"
// TEMPORARILY!
enum ObjectType {};
diff --git a/src/graphics/common/terrain.cpp b/src/graphics/engine/terrain.cpp
index 9b61dfc..c489321 100644
--- a/src/graphics/common/terrain.cpp
+++ b/src/graphics/engine/terrain.cpp
@@ -17,7 +17,7 @@
// terrain.cpp
-#include "graphics/common/terrain.h"
+#include "graphics/engine/terrain.h"
// TODO implementation
diff --git a/src/graphics/common/terrain.h b/src/graphics/engine/terrain.h
index fd9a1a6..8d8b165 100644
--- a/src/graphics/common/terrain.h
+++ b/src/graphics/engine/terrain.h
@@ -19,7 +19,7 @@
#pragma once
-#include "graphics/common/engine.h"
+#include "graphics/engine/engine.h"
class CInstanceManager;
diff --git a/src/graphics/engine/test/CMakeLists.txt b/src/graphics/engine/test/CMakeLists.txt
new file mode 100644
index 0000000..bd83773
--- /dev/null
+++ b/src/graphics/engine/test/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(CMAKE_BUILD_TYPE debug)
+set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0")
+
+include_directories(. ../../..)
+add_executable(modelfile_test modelfile_test.cpp ../modelfile.cpp ../../../common/logger.cpp ../../../common/stringutils.cpp ../../../common/iman.cpp)
diff --git a/src/graphics/engine/test/modelfile_test.cpp b/src/graphics/engine/test/modelfile_test.cpp
new file mode 100644
index 0000000..f7ed87f
--- /dev/null
+++ b/src/graphics/engine/test/modelfile_test.cpp
@@ -0,0 +1,48 @@
+#include "graphics/engine/modelfile.h"
+#include "common/iman.h"
+
+#include <iostream>
+
+
+int main(int argc, char *argv[])
+{
+ if (argc != 4)
+ {
+ std::cerr << "Usage: " << argv[0] << " {mod|dxf} in_file out_file" << std::endl;
+ return 1;
+ }
+
+ CInstanceManager iMan;
+ Gfx::CModelFile modfile(&iMan);
+
+ std::string mode(argv[1]);
+ if (mode == "mod")
+ {
+ if (! modfile.ReadModel(argv[2], false, false) )
+ {
+ std::cerr << "Read error: " << modfile.GetError() << std::endl;
+ return 2;
+ }
+ }
+ else if (mode == "dxf")
+ {
+ if (! modfile.ReadDXF(argv[2], false, false) )
+ {
+ std::cerr << "Read error: " << modfile.GetError() << std::endl;
+ return 2;
+ }
+ }
+ else
+ {
+ std::cerr << "Usage: " << argv[0] << " {mod|dxf} in_file out_file" << std::endl;
+ return 1;
+ }
+
+ if (! modfile.WriteModel(argv[3]) )
+ {
+ std::cerr << "Write error: " << modfile.GetError() << std::endl;
+ return 3;
+ }
+
+ return 0;
+}
diff --git a/src/graphics/common/text.cpp b/src/graphics/engine/text.cpp
index 0c5eb66..2a9543c 100644
--- a/src/graphics/common/text.cpp
+++ b/src/graphics/engine/text.cpp
@@ -17,7 +17,7 @@
// text.cpp
-#include "graphics/common/text.h"
+#include "graphics/engine/text.h"
// TODO implementation
diff --git a/src/graphics/common/text.h b/src/graphics/engine/text.h
index 00b73f2..c2de220 100644
--- a/src/graphics/common/text.h
+++ b/src/graphics/engine/text.h
@@ -19,8 +19,8 @@
#pragma once
-#include "graphics/common/engine.h"
-#include "graphics/common/device.h"
+#include "graphics/engine/engine.h"
+#include "graphics/core/device.h"
#include "math/point.h"
@@ -73,7 +73,7 @@ public:
CText(CInstanceManager *iMan, Gfx::CEngine* engine);
~CText();
- void SetGLDevice(Gfx::CDevice device);
+ 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);
@@ -106,7 +106,7 @@ protected:
protected:
CInstanceManager* m_iMan;
Gfx::CEngine* m_engine;
- Gfx::CDevice m_pDevice;
+ Gfx::CDevice* m_device;
};
diff --git a/src/graphics/common/water.cpp b/src/graphics/engine/water.cpp
index 5172b9f..a157e82 100644
--- a/src/graphics/common/water.cpp
+++ b/src/graphics/engine/water.cpp
@@ -17,7 +17,7 @@
// water.cpp
-#include "graphics/common/water.h"
+#include "graphics/engine/water.h"
// TODO implementation
diff --git a/src/graphics/common/water.h b/src/graphics/engine/water.h
index 5999eac..67be9dc 100644
--- a/src/graphics/common/water.h
+++ b/src/graphics/engine/water.h
@@ -19,8 +19,8 @@
#pragma once
-#include "graphics/common/engine.h"
-#include "graphics/common/particle.h"
+#include "graphics/engine/engine.h"
+#include "graphics/engine/particle.h"
#include "common/event.h"
@@ -48,7 +48,7 @@ const short MAXWATVAPOR = 10;
struct WaterVapor
{
bool bUsed;
- ParticuleType type;
+ ParticleType type;
Math::Vector pos;
float delay;
float time;
@@ -96,7 +96,7 @@ protected:
bool CreateLine(int x, int y, int len);
void VaporFlush();
- bool VaporCreate(ParticuleType type, Math::Vector pos, float delay);
+ bool VaporCreate(ParticleType type, Math::Vector pos, float delay);
void VaporFrame(int i, float rTime);
protected:
diff --git a/src/graphics/opengl/README.txt b/src/graphics/opengl/README.txt
index 11aba8d..0aba0ed 100644
--- a/src/graphics/opengl/README.txt
+++ b/src/graphics/opengl/README.txt
@@ -2,5 +2,5 @@ src/graphics/opengl
OpenGL engine implementation
-Contains the concreate implementation using OpenGL of functions
-of grahpics engine in graphics/common.
+Contains the concrete implementation using OpenGL of abstract CDevice class
+from src/graphics/core
diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp
index 7938e62..d31d007 100644
--- a/src/graphics/opengl/gldevice.cpp
+++ b/src/graphics/opengl/gldevice.cpp
@@ -16,6 +16,1150 @@
// gldevice.cpp
+#include "common/image.h"
#include "graphics/opengl/gldevice.h"
+#include "math/geometry.h"
-// TODO
+// Should define prototypes of used extensions as OpenGL functions
+#define GL_GLEXT_PROTOTYPES
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glext.h>
+
+#include <SDL/SDL.h>
+
+#include <assert.h>
+
+
+
+void Gfx::GLDeviceConfig::LoadDefault()
+{
+ Gfx::DeviceConfig::LoadDefault();
+
+ hardwareAccel = true;
+
+ redSize = 8;
+ blueSize = 8;
+ greenSize = 8;
+ alphaSize = 8;
+ depthSize = 24;
+}
+
+
+
+
+Gfx::CGLDevice::CGLDevice()
+{
+ m_wasInit = false;
+ m_lighting = false;
+ m_texturing = false;
+}
+
+
+Gfx::CGLDevice::~CGLDevice()
+{
+}
+
+bool Gfx::CGLDevice::GetWasInit()
+{
+ return m_wasInit;
+}
+
+std::string Gfx::CGLDevice::GetError()
+{
+ return m_error;
+}
+
+bool Gfx::CGLDevice::Create()
+{
+ /* NOTE: extension testing is not done here as the assumed version of OpenGL to be used (1.4+)
+ must already have the required extensions. The used extensions are listed here for reference:
+ GL_ARB_multitexture, GL_EXT_texture_env_combine, GL_EXT_secondary_color */
+
+ 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
+ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+
+ // To use separate specular color in drawing primitives
+ glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
+
+ // To avoid problems with scaling & lighting
+ glEnable(GL_RESCALE_NORMAL);
+
+ // Set just to be sure
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+
+ m_lights = std::vector<Gfx::Light>(GL_MAX_LIGHTS, Gfx::Light());
+ m_lightsEnabled = std::vector<bool> (GL_MAX_LIGHTS, false);
+
+ int maxTextures = 0;
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextures);
+
+ m_currentTextures = std::vector<Gfx::Texture> (maxTextures, Gfx::Texture());
+ m_texturesEnabled = std::vector<bool> (maxTextures, false);
+ m_textureStageParams = std::vector<Gfx::TextureStageParams>(maxTextures, Gfx::TextureStageParams());
+
+ return true;
+}
+
+void Gfx::CGLDevice::Destroy()
+{
+ // Delete the remaining textures
+ // Should not be strictly necessary, but just in case
+ DestroyAllTextures();
+
+ m_lights.clear();
+ m_lightsEnabled.clear();
+
+ m_currentTextures.clear();
+ m_texturesEnabled.clear();
+ m_textureStageParams.clear();
+
+ m_wasInit = false;
+}
+
+void Gfx::CGLDevice::BeginScene()
+{
+ Clear();
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(m_projectionMat.Array());
+
+ UpdateModelviewMatrix();
+}
+
+void Gfx::CGLDevice::EndScene()
+{
+ glFlush();
+}
+
+void Gfx::CGLDevice::Clear()
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void Gfx::CGLDevice::SetTransform(Gfx::TransformType type, const Math::Matrix &matrix)
+{
+ if (type == Gfx::TRANSFORM_WORLD)
+ {
+ m_worldMat = matrix;
+ UpdateModelviewMatrix();
+ }
+ else if (type == Gfx::TRANSFORM_VIEW)
+ {
+ m_viewMat = matrix;
+ UpdateModelviewMatrix();
+ }
+ else if (type == Gfx::TRANSFORM_PROJECTION)
+ {
+ m_projectionMat = matrix;
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(m_projectionMat.Array());
+ }
+ else
+ {
+ assert(false);
+ }
+}
+
+const Math::Matrix& Gfx::CGLDevice::GetTransform(Gfx::TransformType type)
+{
+ if (type == Gfx::TRANSFORM_WORLD)
+ return m_worldMat;
+ else if (type == Gfx::TRANSFORM_VIEW)
+ return m_viewMat;
+ else if (type == Gfx::TRANSFORM_PROJECTION)
+ return m_projectionMat;
+ else
+ assert(false);
+
+ return m_worldMat; // to avoid warning
+}
+
+void Gfx::CGLDevice::MultiplyTransform(Gfx::TransformType type, const Math::Matrix &matrix)
+{
+ if (type == Gfx::TRANSFORM_WORLD)
+ {
+ m_worldMat = Math::MultiplyMatrices(m_worldMat, matrix);
+ UpdateModelviewMatrix();
+ }
+ else if (type == Gfx::TRANSFORM_VIEW)
+ {
+ m_viewMat = Math::MultiplyMatrices(m_viewMat, matrix);
+ UpdateModelviewMatrix();
+ }
+ else if (type == Gfx::TRANSFORM_PROJECTION)
+ {
+ m_projectionMat = Math::MultiplyMatrices(m_projectionMat, matrix);
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(m_projectionMat.Array());
+ }
+ else
+ {
+ assert(false);
+ }
+}
+
+void Gfx::CGLDevice::UpdateModelviewMatrix()
+{
+ m_modelviewMat = Math::MultiplyMatrices(m_viewMat, m_worldMat);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glScalef(1.0f, 1.0f, -1.0f);
+ glMultMatrixf(m_modelviewMat.Array());
+
+ if (m_lighting)
+ {
+ for (int index = 0; index < (int)m_lights.size(); ++index)
+ UpdateLightPosition(index);
+ }
+}
+
+void Gfx::CGLDevice::SetMaterial(const Gfx::Material &material)
+{
+ m_material = material;
+
+ glMaterialfv(GL_FRONT, GL_AMBIENT, m_material.ambient.Array());
+ glMaterialfv(GL_FRONT, GL_DIFFUSE, m_material.diffuse.Array());
+ glMaterialfv(GL_FRONT, GL_SPECULAR, m_material.specular.Array());
+}
+
+const Gfx::Material& Gfx::CGLDevice::GetMaterial()
+{
+ return m_material;
+}
+
+int Gfx::CGLDevice::GetMaxLightCount()
+{
+ return m_lights.size();
+}
+
+void Gfx::CGLDevice::SetLight(int index, const Gfx::Light &light)
+{
+ assert(index >= 0);
+ assert(index < (int)m_lights.size());
+
+ m_lights[index] = light;
+
+ // Indexing from GL_LIGHT0 should always work
+ glLightfv(GL_LIGHT0 + index, GL_AMBIENT, const_cast<GLfloat*>(light.ambient.Array()));
+ glLightfv(GL_LIGHT0 + index, GL_DIFFUSE, const_cast<GLfloat*>(light.diffuse.Array()));
+ glLightfv(GL_LIGHT0 + index, GL_SPECULAR, const_cast<GLfloat*>(light.specular.Array()));
+
+ glLightf(GL_LIGHT0 + index, GL_CONSTANT_ATTENUATION, light.attenuation0);
+ glLightf(GL_LIGHT0 + index, GL_LINEAR_ATTENUATION, light.attenuation1);
+ glLightf(GL_LIGHT0 + index, GL_QUADRATIC_ATTENUATION, light.attenuation2);
+
+ if (light.type == Gfx::LIGHT_SPOT)
+ {
+ glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, light.spotAngle);
+ glLightf(GL_LIGHT0 + index, GL_SPOT_EXPONENT, light.spotIntensity);
+ }
+ else
+ {
+ glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, 180.0f);
+ }
+
+ UpdateLightPosition(index);
+}
+
+void Gfx::CGLDevice::UpdateLightPosition(int index)
+{
+ assert(index >= 0);
+ assert(index < (int)m_lights.size());
+
+ if ((! m_lighting) || (! m_lightsEnabled[index]))
+ return;
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+
+ glLoadIdentity();
+ glScalef(1.0f, 1.0f, -1.0f);
+ glMultMatrixf(m_viewMat.Array());
+
+ if (m_lights[index].type == LIGHT_DIRECTIONAL)
+ {
+ GLfloat position[4] = { m_lights[index].direction.x, m_lights[index].direction.y, m_lights[index].direction.z, 0.0f };
+ glLightfv(GL_LIGHT0 + index, GL_POSITION, position);
+ }
+ else
+ {
+ GLfloat position[4] = { m_lights[index].position.x, m_lights[index].position.y, m_lights[index].position.z, 1.0f };
+ glLightfv(GL_LIGHT0 + index, GL_POSITION, position);
+ }
+
+ if (m_lights[index].type == Gfx::LIGHT_SPOT)
+ {
+ GLfloat direction[4] = { m_lights[index].direction.x, m_lights[index].direction.y, m_lights[index].direction.z, 0.0f };
+ glLightfv(GL_LIGHT0 + index, GL_SPOT_DIRECTION, direction);
+ }
+
+ glPopMatrix();
+}
+
+const Gfx::Light& Gfx::CGLDevice::GetLight(int index)
+{
+ assert(index >= 0);
+ assert(index < (int)m_lights.size());
+
+ return m_lights[index];
+}
+
+void Gfx::CGLDevice::SetLightEnabled(int index, bool enabled)
+{
+ assert(index >= 0);
+ assert(index < (int)m_lights.size());
+
+ m_lightsEnabled[index] = enabled;
+
+ glEnable(GL_LIGHT0 + index);
+}
+
+bool Gfx::CGLDevice::GetLightEnabled(int index)
+{
+ assert(index >= 0);
+ assert(index < (int)m_lights.size());
+
+ return m_lightsEnabled[index];
+}
+
+/** If image is invalid, returns invalid texture.
+ Otherwise, returns pointer to new Gfx::Texture struct.
+ 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
+ }
+
+ result.valid = true;
+ result.width = data->surface->w;
+ result.height = data->surface->h;
+
+ // Use & enable 1st texture stage
+ glActiveTexture(GL_TEXTURE0);
+ glEnable(GL_TEXTURE_2D);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glGenTextures(1, &result.id);
+ glBindTexture(GL_TEXTURE_2D, result.id);
+
+ // Set params
+
+ GLint minF = 0;
+ if (params.minFilter == Gfx::TEX_MIN_FILTER_NEAREST) minF = GL_NEAREST;
+ else if (params.minFilter == Gfx::TEX_MIN_FILTER_LINEAR) minF = GL_LINEAR;
+ else if (params.minFilter == Gfx::TEX_MIN_FILTER_NEAREST_MIPMAP_NEAREST) minF = GL_NEAREST_MIPMAP_NEAREST;
+ else if (params.minFilter == Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_NEAREST) minF = GL_LINEAR_MIPMAP_NEAREST;
+ else if (params.minFilter == Gfx::TEX_MIN_FILTER_NEAREST_MIPMAP_LINEAR) minF = GL_NEAREST_MIPMAP_LINEAR;
+ else if (params.minFilter == Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR) minF = GL_LINEAR_MIPMAP_LINEAR;
+ else assert(false);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minF);
+
+ GLint magF = 0;
+ if (params.magFilter == Gfx::TEX_MAG_FILTER_NEAREST) magF = GL_NEAREST;
+ else if (params.magFilter == Gfx::TEX_MAG_FILTER_LINEAR) magF = GL_LINEAR;
+ else assert(false);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magF);
+
+ if (params.mipmap)
+ glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
+ else
+ glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
+
+ GLenum sourceFormat = 0;
+ if (params.format == Gfx::TEX_IMG_RGB)
+ {
+ sourceFormat = GL_RGB;
+ result.alpha = false;
+ }
+ else if (params.format == Gfx::TEX_IMG_BGR)
+ {
+ sourceFormat = GL_BGR;
+ result.alpha = false;
+ }
+ else if (params.format == Gfx::TEX_IMG_RGBA)
+ {
+ sourceFormat = GL_RGBA;
+ result.alpha = true;
+ }
+ else if (params.format == Gfx::TEX_IMG_BGRA)
+ {
+ sourceFormat = GL_BGRA;
+ result.alpha = true;
+ }
+ else
+ assert(false);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data->surface->w, data->surface->h,
+ 0, sourceFormat, GL_UNSIGNED_BYTE, data->surface->pixels);
+
+
+ // Restore the previous state of 1st stage
+ if (m_currentTextures[0].valid)
+ glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
+ else
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ if ( (! m_texturing) || (! m_texturesEnabled[0]) )
+ glDisable(GL_TEXTURE_2D);
+
+ return result;
+}
+
+void Gfx::CGLDevice::DestroyTexture(const Gfx::Texture &texture)
+{
+ std::set<Gfx::Texture>::iterator it = m_allTextures.find(texture);
+ if (it != m_allTextures.end())
+ m_allTextures.erase(it);
+
+ // Unbind the texture if in use anywhere
+ for (int index = 0; index < (int)m_currentTextures.size(); ++index)
+ {
+ if (m_currentTextures[index] == texture)
+ SetTexture(index, Gfx::Texture()); // set to invalid texture
+ }
+
+ glDeleteTextures(1, &texture.id);
+}
+
+void Gfx::CGLDevice::DestroyAllTextures()
+{
+ std::set<Gfx::Texture> allCopy = m_allTextures;
+ std::set<Gfx::Texture>::iterator it;
+ for (it = allCopy.begin(); it != allCopy.end(); ++it)
+ DestroyTexture(*it);
+}
+
+int Gfx::CGLDevice::GetMaxTextureCount()
+{
+ return m_currentTextures.size();
+}
+
+/**
+ If \a texture is invalid, unbinds the given texture.
+ If valid, binds the texture and enables the given texture stage.
+ The setting is remembered, even if texturing is disabled at the moment. */
+void Gfx::CGLDevice::SetTexture(int index, const Gfx::Texture &texture)
+{
+ assert(index >= 0);
+ assert(index < (int)m_currentTextures.size());
+
+ // Enable the given texture stage
+ glActiveTexture(GL_TEXTURE0 + index);
+ glEnable(GL_TEXTURE_2D);
+
+ m_currentTextures[index] = texture; // remember the change
+
+ if (! texture.valid)
+ {
+ glBindTexture(GL_TEXTURE_2D, 0); // unbind texture
+ }
+ else
+ {
+ glBindTexture(GL_TEXTURE_2D, texture.id); // bind the texture
+ SetTextureStageParams(index, m_textureStageParams[index]); // texture stage params need to be re-set for the new texture
+ }
+
+ // 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)
+{
+ assert(index >= 0);
+ assert(index < (int)m_currentTextures.size());
+
+ return m_currentTextures[index];
+}
+
+void Gfx::CGLDevice::SetTextureEnabled(int index, bool enabled)
+{
+ assert(index >= 0);
+ assert(index < (int)m_currentTextures.size());
+
+ m_texturesEnabled[index] = enabled;
+
+ glActiveTexture(GL_TEXTURE0 + index);
+ if (enabled)
+ glEnable(GL_TEXTURE_2D);
+ else
+ glDisable(GL_TEXTURE_2D);
+}
+
+bool Gfx::CGLDevice::GetTextureEnabled(int index)
+{
+ assert(index >= 0);
+ assert(index < (int)m_currentTextures.size());
+
+ return m_texturesEnabled[index];
+}
+
+/**
+ Sets the texture parameters for the given texture stage.
+ If the given texture was not set (bound) yet, nothing happens.
+ The settings are remembered, even if texturing is disabled at the moment. */
+void Gfx::CGLDevice::SetTextureStageParams(int index, const Gfx::TextureStageParams &params)
+{
+ assert(index >= 0);
+ assert(index < (int)m_currentTextures.size());
+
+ // Remember the settings
+ m_textureStageParams[index] = params;
+
+ // Don't actually do anything if texture not set
+ if (! m_currentTextures[index].valid)
+ return;
+
+ // Enable the given stage
+ glActiveTexture(GL_TEXTURE0 + index);
+ glEnable(GL_TEXTURE_2D);
+
+ glBindTexture(GL_TEXTURE_2D, m_currentTextures[index].id);
+
+ // To save some trouble
+ if ( (params.colorOperation == Gfx::TEX_MIX_OPER_DEFAULT) &&
+ (params.alphaOperation == Gfx::TEX_MIX_OPER_DEFAULT) )
+ {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ goto after_tex_operations;
+ }
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ // Only these modes of getting color & alpha are used
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+
+ // Color operation
+
+ if (params.colorOperation == Gfx::TEX_MIX_OPER_DEFAULT)
+ {
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
+ goto after_tex_color;
+ }
+ else if (params.colorOperation == Gfx::TEX_MIX_OPER_REPLACE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
+ else if (params.colorOperation == Gfx::TEX_MIX_OPER_MODULATE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ else if (params.colorOperation == Gfx::TEX_MIX_OPER_ADD)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
+ else if (params.colorOperation == Gfx::TEX_MIX_OPER_SUBTRACT)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT);
+ else assert(false);
+
+ // Color arg1
+ if (params.colorArg1 == Gfx::TEX_MIX_ARG_TEXTURE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
+ else if (params.colorArg1 == Gfx::TEX_MIX_ARG_COMPUTED_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
+ else if (params.colorArg1 == Gfx::TEX_MIX_ARG_SRC_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
+ else if (params.colorArg1 == Gfx::TEX_MIX_ARG_FACTOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT);
+ else assert(false);
+
+ // Color arg2
+ if (params.colorArg2 == Gfx::TEX_MIX_ARG_TEXTURE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
+ else if (params.colorArg2 == Gfx::TEX_MIX_ARG_COMPUTED_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
+ else if (params.colorArg2 == Gfx::TEX_MIX_ARG_SRC_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
+ else if (params.colorArg2 == Gfx::TEX_MIX_ARG_FACTOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
+ else assert(false);
+
+
+after_tex_color:
+
+ // Alpha operation
+ if (params.alphaOperation == Gfx::TEX_MIX_OPER_DEFAULT)
+ {
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
+ goto after_tex_operations;
+ }
+ else if (params.colorOperation == Gfx::TEX_MIX_OPER_REPLACE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+ else if (params.alphaOperation == Gfx::TEX_MIX_OPER_MODULATE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ else if (params.alphaOperation == Gfx::TEX_MIX_OPER_ADD)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
+ else if (params.alphaOperation == Gfx::TEX_MIX_OPER_SUBTRACT)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_SUBTRACT);
+ else assert(false);
+
+ // Alpha arg1
+ if (params.alphaArg1 == Gfx::TEX_MIX_ARG_TEXTURE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
+ else if (params.alphaArg1 == Gfx::TEX_MIX_ARG_COMPUTED_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
+ else if (params.alphaArg1 == Gfx::TEX_MIX_ARG_SRC_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
+ else if (params.alphaArg1 == Gfx::TEX_MIX_ARG_FACTOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT);
+ else assert(false);
+
+ // Alpha arg2
+ if (params.alphaArg2 == Gfx::TEX_MIX_ARG_TEXTURE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
+ else if (params.alphaArg2 == Gfx::TEX_MIX_ARG_COMPUTED_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);
+ else if (params.alphaArg2 == Gfx::TEX_MIX_ARG_SRC_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
+ else if (params.alphaArg2 == Gfx::TEX_MIX_ARG_FACTOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT);
+ else assert(false);
+
+
+after_tex_operations:
+
+ if (params.wrapS == Gfx::TEX_WRAP_CLAMP)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ else if (params.wrapS == Gfx::TEX_WRAP_REPEAT)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ else assert(false);
+
+ if (params.wrapT == Gfx::TEX_WRAP_CLAMP)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ else if (params.wrapT == Gfx::TEX_WRAP_REPEAT)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ else assert(false);
+
+ // Disable the stage if it is set so
+ if ( (! m_texturing) || (! m_texturesEnabled[index]) )
+ glDisable(GL_TEXTURE_2D);
+}
+
+Gfx::TextureStageParams Gfx::CGLDevice::GetTextureStageParams(int index)
+{
+ assert(index >= 0);
+ assert(index < (int)m_currentTextures.size());
+
+ return m_textureStageParams[index];
+}
+
+void Gfx::CGLDevice::SetTextureFactor(const Gfx::Color &color)
+{
+ // Needs to be set for all texture stages
+ for (int index = 0; index < (int)m_currentTextures.size(); ++index)
+ {
+ // Activate stage
+ glActiveTexture(GL_TEXTURE0 + index);
+ glEnable(GL_TEXTURE_2D);
+
+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color.Array());
+
+ // Disable the stage if it is set so
+ if ( (! m_texturing) || (! m_texturesEnabled[index]) )
+ glDisable(GL_TEXTURE_2D);
+ }
+}
+
+Gfx::Color Gfx::CGLDevice::GetTextureFactor()
+{
+ // Get from 1st stage (should be the same for all stages)
+ glActiveTexture(GL_TEXTURE0);
+ glEnable(GL_TEXTURE_2D);
+
+ GLfloat color[4] = { 0.0f };
+ glGetTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
+
+ // Disable the 1st stage if it is set so
+ if ( (! m_texturing) || (! m_texturesEnabled[0]) )
+ glDisable(GL_TEXTURE_2D);
+
+ return Gfx::Color(color[0], color[1], color[2], color[3]);
+}
+
+void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, const Vertex *vertices, int vertexCount)
+{
+ if (type == Gfx::PRIMITIVE_LINES)
+ glBegin(GL_LINES);
+ else if (type == Gfx::PRIMITIVE_TRIANGLES)
+ glBegin(GL_TRIANGLES);
+ else if (type == Gfx::PRIMITIVE_TRIANGLE_STRIP)
+ glBegin(GL_TRIANGLE_STRIP);
+
+ glColor3f(1.0f, 1.0f, 1.0f);
+
+ for (int i = 0; i < vertexCount; ++i)
+ {
+ glNormal3fv(const_cast<GLfloat*>(vertices[i].normal.Array()));
+ glMultiTexCoord2fv(GL_TEXTURE0, const_cast<GLfloat*>(vertices[i].texCoord.Array()));
+ glVertex3fv(const_cast<GLfloat*>(vertices[i].coord.Array()));
+ }
+
+ glEnd();
+}
+
+void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexCol *vertices, int vertexCount)
+{
+ if (type == Gfx::PRIMITIVE_LINES)
+ glBegin(GL_LINES);
+ else if (type == Gfx::PRIMITIVE_TRIANGLES)
+ glBegin(GL_TRIANGLES);
+ else if (type == Gfx::PRIMITIVE_TRIANGLE_STRIP)
+ glBegin(GL_TRIANGLE_STRIP);
+
+ for (int i = 0; i < vertexCount; ++i)
+ {
+ glColor4fv(const_cast<GLfloat*>(vertices[i].color.Array()));
+ glSecondaryColor3fv(const_cast<GLfloat*>(vertices[i].specular.Array()));
+ glMultiTexCoord2fv(GL_TEXTURE0, const_cast<GLfloat*>(vertices[i].texCoord.Array()));
+ glVertex3fv(const_cast<GLfloat*>(vertices[i].coord.Array()));
+ }
+
+ glEnd();
+}
+
+void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, const VertexTex2 *vertices, int vertexCount)
+{
+ if (type == Gfx::PRIMITIVE_LINES)
+ glBegin(GL_LINES);
+ else if (type == Gfx::PRIMITIVE_TRIANGLES)
+ glBegin(GL_TRIANGLES);
+ else if (type == Gfx::PRIMITIVE_TRIANGLE_STRIP)
+ glBegin(GL_TRIANGLE_STRIP);
+
+ glColor3f(1.0f, 1.0f, 1.0f);
+
+ for (int i = 0; i < vertexCount; ++i)
+ {
+ glNormal3fv(const_cast<GLfloat*>(vertices[i].normal.Array()));
+ glMultiTexCoord2fv(GL_TEXTURE0, const_cast<GLfloat*>(vertices[i].texCoord.Array()));
+ glMultiTexCoord2fv(GL_TEXTURE1, const_cast<GLfloat*>(vertices[i].texCoord.Array()));
+ glVertex3fv(const_cast<GLfloat*>(vertices[i].coord.Array()));
+ }
+
+ glEnd();
+}
+
+bool InPlane(Math::Vector normal, float originPlane, Math::Vector center, float radius)
+{
+ float distance = (originPlane + Math::DotProduct(normal, center)) / normal.Length();
+
+ if (distance < -radius)
+ return true;
+
+ return false;
+}
+
+/*
+ The implementation of ComputeSphereVisibility is taken from libwine's device.c
+ Copyright of the WINE team, licensed under GNU LGPL v 2.1
+ */
+
+// TODO: testing
+int Gfx::CGLDevice::ComputeSphereVisibility(const Math::Vector &center, float radius)
+{
+ Math::Matrix m;
+ m.LoadIdentity();
+ m = Math::MultiplyMatrices(m, m_worldMat);
+ m = Math::MultiplyMatrices(m, m_viewMat);
+ m = Math::MultiplyMatrices(m, m_projectionMat);
+
+ Math::Vector vec[6];
+ float originPlane[6];
+
+ // Left plane
+ vec[0].x = m.Get(4, 1) + m.Get(1, 1);
+ vec[0].y = m.Get(4, 2) + m.Get(1, 2);
+ vec[0].z = m.Get(4, 3) + m.Get(1, 3);
+ originPlane[0] = m.Get(4, 4) + m.Get(1, 4);
+
+ // Right plane
+ vec[1].x = m.Get(4, 1) - m.Get(1, 1);
+ vec[1].y = m.Get(4, 2) - m.Get(1, 2);
+ vec[1].z = m.Get(4, 3) - m.Get(1, 3);
+ originPlane[1] = m.Get(4, 4) - m.Get(1, 4);
+
+ // Top plane
+ vec[2].x = m.Get(4, 1) - m.Get(2, 1);
+ vec[2].y = m.Get(4, 2) - m.Get(2, 2);
+ vec[2].z = m.Get(4, 3) - m.Get(2, 3);
+ originPlane[2] = m.Get(4, 4) - m.Get(2, 4);
+
+ // Bottom plane
+ vec[3].x = m.Get(4, 1) + m.Get(2, 1);
+ vec[3].y = m.Get(4, 2) + m.Get(2, 2);
+ vec[3].z = m.Get(4, 3) + m.Get(2, 3);
+ originPlane[3] = m.Get(4, 4) + m.Get(2, 4);
+
+ // Front plane
+ vec[4].x = m.Get(3, 1);
+ vec[4].y = m.Get(3, 2);
+ vec[4].z = m.Get(3, 3);
+ originPlane[4] = m.Get(3, 4);
+
+ // Back plane
+ vec[5].x = m.Get(4, 1) - m.Get(3, 1);
+ vec[5].y = m.Get(4, 2) - m.Get(3, 2);
+ vec[5].z = m.Get(4, 3) - m.Get(3, 3);
+ originPlane[5] = m.Get(4, 4) - m.Get(3, 4);
+
+ int result = 0;
+
+ if (InPlane(vec[0], originPlane[0], center, radius))
+ result |= Gfx::INTERSECT_PLANE_LEFT;
+ if (InPlane(vec[1], originPlane[1], center, radius))
+ result |= Gfx::INTERSECT_PLANE_RIGHT;
+ if (InPlane(vec[2], originPlane[2], center, radius))
+ result |= Gfx::INTERSECT_PLANE_TOP;
+ if (InPlane(vec[3], originPlane[3], center, radius))
+ result |= Gfx::INTERSECT_PLANE_BOTTOM;
+ if (InPlane(vec[4], originPlane[4], center, radius))
+ result |= Gfx::INTERSECT_PLANE_FRONT;
+ if (InPlane(vec[5], originPlane[5], center, radius))
+ result |= Gfx::INTERSECT_PLANE_BACK;
+
+ return result;
+}
+
+void Gfx::CGLDevice::SetRenderState(Gfx::RenderState state, bool enabled)
+{
+ if (state == Gfx::RENDER_STATE_DEPTH_WRITE)
+ {
+ glDepthMask(enabled ? GL_TRUE : GL_FALSE);
+ return;
+ }
+ else if (state == Gfx::RENDER_STATE_LIGHTING)
+ {
+ m_lighting = enabled;
+
+ if (enabled)
+ glEnable(GL_LIGHTING);
+ else
+ glDisable(GL_LIGHTING);
+
+ if (enabled)
+ {
+ for (int index = 0; index < (int)m_lights.size(); ++index)
+ UpdateLightPosition(index);
+ }
+
+ return;
+ }
+ else if (state == Gfx::RENDER_STATE_TEXTURING)
+ {
+ m_texturing = enabled;
+
+ // Enable/disable stages with new setting
+ for (int index = 0; index < (int)m_currentTextures.size(); ++index)
+ {
+ glActiveTexture(GL_TEXTURE0 + index);
+ if (m_texturing && m_texturesEnabled[index])
+ glEnable(GL_TEXTURE_2D);
+ else
+ glDisable(GL_TEXTURE_2D);
+ }
+
+ return;
+ }
+
+ GLenum flag = 0;
+
+ switch (state)
+ {
+ case Gfx::RENDER_STATE_BLENDING: flag = GL_BLEND; break;
+ case Gfx::RENDER_STATE_FOG: flag = GL_FOG; break;
+ case Gfx::RENDER_STATE_DEPTH_TEST: flag = GL_DEPTH_TEST; break;
+ case Gfx::RENDER_STATE_ALPHA_TEST: flag = GL_ALPHA_TEST; break;
+ case Gfx::RENDER_STATE_CULLING: flag = GL_CULL_FACE; break;
+ case Gfx::RENDER_STATE_DITHERING: flag = GL_DITHER; break;
+ default: assert(false); break;
+ }
+
+ if (enabled)
+ glEnable(flag);
+ else
+ glDisable(flag);
+}
+
+bool Gfx::CGLDevice::GetRenderState(Gfx::RenderState state)
+{
+ if (state == Gfx::RENDER_STATE_LIGHTING)
+ return m_lighting;
+
+ if (state == Gfx::RENDER_STATE_TEXTURING)
+ return m_texturing;
+
+ GLenum flag = 0;
+
+ switch (state)
+ {
+ case Gfx::RENDER_STATE_DEPTH_WRITE: flag = GL_DEPTH_WRITEMASK; break;
+ case Gfx::RENDER_STATE_BLENDING: flag = GL_BLEND; break;
+ case Gfx::RENDER_STATE_FOG: flag = GL_FOG; break;
+ case Gfx::RENDER_STATE_DEPTH_TEST: flag = GL_DEPTH_TEST; break;
+ case Gfx::RENDER_STATE_ALPHA_TEST: flag = GL_ALPHA_TEST; break;
+ case Gfx::RENDER_STATE_CULLING: flag = GL_CULL_FACE; break;
+ case Gfx::RENDER_STATE_DITHERING: flag = GL_DITHER; break;
+ default: assert(false); break;
+ }
+
+ GLboolean result = GL_FALSE;
+ glGetBooleanv(flag, &result);
+
+ return result == GL_TRUE;
+}
+
+Gfx::CompFunc TranslateGLCompFunc(GLenum flag)
+{
+ switch (flag)
+ {
+ case GL_NEVER: return Gfx::COMP_FUNC_NEVER;
+ case GL_LESS: return Gfx::COMP_FUNC_LESS;
+ case GL_EQUAL: return Gfx::COMP_FUNC_EQUAL;
+ case GL_NOTEQUAL: return Gfx::COMP_FUNC_NOTEQUAL;
+ case GL_LEQUAL: return Gfx::COMP_FUNC_LEQUAL;
+ case GL_GREATER: return Gfx::COMP_FUNC_GREATER;
+ case GL_GEQUAL: return Gfx::COMP_FUNC_GEQUAL;
+ case GL_ALWAYS: return Gfx::COMP_FUNC_ALWAYS;
+ default: assert(false); break;
+ }
+ return Gfx::COMP_FUNC_NEVER;
+}
+
+GLenum TranslateGfxCompFunc(Gfx::CompFunc func)
+{
+ switch (func)
+ {
+ case Gfx::COMP_FUNC_NEVER: return GL_NEVER;
+ case Gfx::COMP_FUNC_LESS: return GL_LESS;
+ case Gfx::COMP_FUNC_EQUAL: return GL_EQUAL;
+ case Gfx::COMP_FUNC_NOTEQUAL: return GL_NOTEQUAL;
+ case Gfx::COMP_FUNC_LEQUAL: return GL_LEQUAL;
+ case Gfx::COMP_FUNC_GREATER: return GL_GREATER;
+ case Gfx::COMP_FUNC_GEQUAL: return GL_GEQUAL;
+ case Gfx::COMP_FUNC_ALWAYS: return GL_ALWAYS;
+ default: assert(false); break;
+ }
+ return 0;
+}
+
+void Gfx::CGLDevice::SetDepthTestFunc(Gfx::CompFunc func)
+{
+ glDepthFunc(TranslateGfxCompFunc(func));
+}
+
+Gfx::CompFunc Gfx::CGLDevice::GetDepthTestFunc()
+{
+ GLenum flag = 0;
+ glGetIntegerv(GL_DEPTH_FUNC, (GLint*)&flag);
+ return TranslateGLCompFunc(flag);
+}
+
+void Gfx::CGLDevice::SetDepthBias(float factor)
+{
+ glPolygonOffset(factor, 0.0f);
+}
+
+float Gfx::CGLDevice::GetDepthBias()
+{
+ GLfloat result = 0.0f;
+ glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &result);
+ return result;
+}
+
+void Gfx::CGLDevice::SetAlphaTestFunc(Gfx::CompFunc func, float refValue)
+{
+ glAlphaFunc(TranslateGfxCompFunc(func), refValue);
+}
+
+void Gfx::CGLDevice::GetAlphaTestFunc(Gfx::CompFunc &func, float &refValue)
+{
+ GLenum flag = 0;
+ glGetIntegerv(GL_ALPHA_TEST_FUNC, (GLint*)&flag);
+ func = TranslateGLCompFunc(flag);
+
+ glGetFloatv(GL_ALPHA_TEST_REF, (GLfloat*) &refValue);
+}
+
+Gfx::BlendFunc TranslateGLBlendFunc(GLenum flag)
+{
+ switch (flag)
+ {
+ case GL_ZERO: return Gfx::BLEND_ZERO;
+ case GL_ONE: return Gfx::BLEND_ONE;
+ case GL_SRC_COLOR: return Gfx::BLEND_SRC_COLOR;
+ case GL_ONE_MINUS_SRC_COLOR: return Gfx::BLEND_INV_SRC_COLOR;
+ case GL_DST_COLOR: return Gfx::BLEND_DST_COLOR;
+ case GL_ONE_MINUS_DST_COLOR: return Gfx::BLEND_INV_DST_COLOR;
+ case GL_SRC_ALPHA: return Gfx::BLEND_SRC_ALPHA;
+ case GL_ONE_MINUS_SRC_ALPHA: return Gfx::BLEND_INV_SRC_ALPHA;
+ case GL_DST_ALPHA: return Gfx::BLEND_DST_ALPHA;
+ case GL_ONE_MINUS_DST_ALPHA: return Gfx::BLEND_INV_DST_ALPHA;
+ case GL_SRC_ALPHA_SATURATE: return Gfx::BLEND_SRC_ALPHA_SATURATE;
+ default: assert(false); break;
+ }
+
+ return Gfx::BLEND_ZERO;
+}
+
+GLenum TranslateGfxBlendFunc(Gfx::BlendFunc func)
+{
+ switch (func)
+ {
+ case Gfx::BLEND_ZERO: return GL_ZERO;
+ case Gfx::BLEND_ONE: return GL_ONE;
+ case Gfx::BLEND_SRC_COLOR: return GL_SRC_COLOR;
+ case Gfx::BLEND_INV_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR;
+ case Gfx::BLEND_DST_COLOR: return GL_DST_COLOR;
+ case Gfx::BLEND_INV_DST_COLOR: return GL_ONE_MINUS_DST_COLOR;
+ case Gfx::BLEND_SRC_ALPHA: return GL_SRC_ALPHA;
+ case Gfx::BLEND_INV_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA;
+ case Gfx::BLEND_DST_ALPHA: return GL_DST_ALPHA;
+ case Gfx::BLEND_INV_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA;
+ case Gfx::BLEND_SRC_ALPHA_SATURATE: return GL_SRC_ALPHA_SATURATE;
+ default: assert(false); break;
+ }
+ return 0;
+}
+
+void Gfx::CGLDevice::SetBlendFunc(Gfx::BlendFunc srcBlend, Gfx::BlendFunc dstBlend)
+{
+ glBlendFunc(TranslateGfxBlendFunc(srcBlend), TranslateGfxBlendFunc(dstBlend));
+}
+
+void Gfx::CGLDevice::GetBlendFunc(Gfx::BlendFunc &srcBlend, Gfx::BlendFunc &dstBlend)
+{
+ GLenum srcFlag = 0;
+ glGetIntegerv(GL_ALPHA_TEST_FUNC, (GLint*)&srcFlag);
+ srcBlend = TranslateGLBlendFunc(srcFlag);
+
+ GLenum dstFlag = 0;
+ glGetIntegerv(GL_ALPHA_TEST_FUNC, (GLint*)&dstFlag);
+ dstBlend = TranslateGLBlendFunc(dstFlag);
+}
+
+void Gfx::CGLDevice::SetClearColor(const Gfx::Color &color)
+{
+ glClearColor(color.r, color.g, color.b, color.a);
+}
+
+Gfx::Color Gfx::CGLDevice::GetClearColor()
+{
+ GLfloat color[4] = { 0.0f };
+ glGetFloatv(GL_COLOR_CLEAR_VALUE, color);
+ return Gfx::Color(color[0], color[1], color[2], color[3]);
+}
+
+void Gfx::CGLDevice::SetGlobalAmbient(const Gfx::Color &color)
+{
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.Array());
+}
+
+Gfx::Color Gfx::CGLDevice::GetGlobalAmbient()
+{
+ GLfloat color[4] = { 0.0f };
+ glGetFloatv(GL_LIGHT_MODEL_AMBIENT, color);
+ return Gfx::Color(color[0], color[1], color[2], color[3]);
+}
+
+void Gfx::CGLDevice::SetFogParams(Gfx::FogMode mode, const Gfx::Color &color, float start, float end, float density)
+{
+ if (mode == Gfx::FOG_LINEAR) glFogi(GL_FOG_MODE, GL_LINEAR);
+ else if (mode == Gfx::FOG_EXP) glFogi(GL_FOG_MODE, GL_EXP);
+ else if (mode == Gfx::FOG_EXP2) glFogi(GL_FOG_MODE, GL_EXP2);
+ else assert(false);
+
+ glFogf(GL_FOG_START, start);
+ glFogf(GL_FOG_END, end);
+ glFogf(GL_FOG_DENSITY, density);
+}
+
+void Gfx::CGLDevice::GetFogParams(Gfx::FogMode &mode, Gfx::Color &color, float &start, float &end, float &density)
+{
+ GLenum flag = 0;
+ glGetIntegerv(GL_FOG_MODE, (GLint*)&flag);
+ if (flag == GL_LINEAR) mode = Gfx::FOG_LINEAR;
+ else if (flag == GL_EXP) mode = Gfx::FOG_EXP;
+ else if (flag == GL_EXP2) mode = Gfx::FOG_EXP2;
+ else assert(false);
+
+ glGetFloatv(GL_FOG_START, (GLfloat*)&start);
+ glGetFloatv(GL_FOG_END, (GLfloat*)&end);
+ glGetFloatv(GL_FOG_DENSITY, (GLfloat*)&density);
+}
+
+void Gfx::CGLDevice::SetCullMode(Gfx::CullMode mode)
+{
+ if (mode == Gfx::CULL_CW) glCullFace(GL_CW);
+ else if (mode == Gfx::CULL_CCW) glCullFace(GL_CCW);
+ else assert(false);
+}
+
+Gfx::CullMode Gfx::CGLDevice::GetCullMode()
+{
+ GLenum flag = 0;
+ glGetIntegerv(GL_CULL_FACE, (GLint*)&flag);
+ if (flag == GL_CW) return Gfx::CULL_CW;
+ else if (flag == GL_CCW) return Gfx::CULL_CCW;
+ else assert(false);
+ return Gfx::CULL_CW;
+}
+
+void Gfx::CGLDevice::SetShadeModel(Gfx::ShadeModel model)
+{
+ if (model == Gfx::SHADE_FLAT) glShadeModel(GL_FLAT);
+ else if (model == Gfx::SHADE_SMOOTH) glShadeModel(GL_SMOOTH);
+ else assert(false);
+}
+
+Gfx::ShadeModel Gfx::CGLDevice::GetShadeModel()
+{
+ GLenum flag = 0;
+ glGetIntegerv(GL_SHADE_MODEL, (GLint*)&flag);
+ if (flag == GL_FLAT) return Gfx::SHADE_FLAT;
+ else if (flag == GL_SMOOTH) return Gfx::SHADE_SMOOTH;
+ else assert(false);
+ return Gfx::SHADE_FLAT;
+}
+
+void Gfx::CGLDevice::SetFillMode(Gfx::FillMode mode)
+{
+ if (mode == Gfx::FILL_POINT) glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
+ else if (mode == Gfx::FILL_LINES) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ else if (mode == Gfx::FILL_FILL) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ else assert(false);
+}
+
+Gfx::FillMode Gfx::CGLDevice::GetFillMode()
+{
+ GLenum flag = 0;
+ glGetIntegerv(GL_POLYGON_MODE, (GLint*)&flag);
+ if (flag == GL_POINT) return Gfx::FILL_POINT;
+ else if (flag == GL_LINE) return Gfx::FILL_LINES;
+ else if (flag == GL_FILL) return Gfx::FILL_FILL;
+ else assert(false);
+ return Gfx::FILL_POINT;
+}
diff --git a/src/graphics/opengl/gldevice.h b/src/graphics/opengl/gldevice.h
index a2fb4a0..313ea02 100644
--- a/src/graphics/opengl/gldevice.h
+++ b/src/graphics/opengl/gldevice.h
@@ -19,13 +19,181 @@
#pragma once
-#include "graphics/common/device.h"
+#include "graphics/core/device.h"
+
+#include <string>
+#include <vector>
+#include <set>
+
namespace Gfx {
+/**
+ \struct GLDeviceConfig
+ \brief Additional config with OpenGL-specific settings */
+struct GLDeviceConfig : public DeviceConfig
+{
+ //! Size of red channel in bits
+ int redSize;
+ //! Size of green channel in bits
+ int greenSize;
+ //! Size of blue channel in bits
+ int blueSize;
+ //! Size of alpha channel in bits
+ int alphaSize;
+ //! Color depth in bits
+ int depthSize;
+
+ //! Force hardware acceleration (video mode set will fail on lack of hw accel)
+ bool hardwareAccel;
+
+ //! Constructor calls LoadDefaults()
+ GLDeviceConfig() { LoadDefault(); }
+
+ //! Loads the default values
+ void LoadDefault();
+};
+
+struct GLDevicePrivate;
+
+/**
+ \class CGLDevice
+ \brief Implementation of CDevice interface in OpenGL
+
+ Provides the concrete implementation of 3D device in OpenGL.
+
+ This class should be initialized (by calling Initialize() ) only after
+ setting the video mode by CApplication, once the OpenGL context is defined.
+ Because of that, CGLDeviceConfig is outside the CDevice class and must be set
+ in CApplication.
+*/
class CGLDevice : public Gfx::CDevice
{
- // TODO
+public:
+ CGLDevice();
+ virtual ~CGLDevice();
+
+ virtual bool GetWasInit();
+ virtual std::string GetError();
+
+ virtual bool Create();
+ virtual void Destroy();
+
+ virtual void BeginScene();
+ virtual void EndScene();
+
+ virtual void Clear();
+
+ virtual void SetTransform(Gfx::TransformType type, const Math::Matrix &matrix);
+ virtual const Math::Matrix& GetTransform(Gfx::TransformType type);
+ virtual void MultiplyTransform(Gfx::TransformType type, const Math::Matrix &matrix);
+
+ virtual void SetMaterial(const Gfx::Material &material);
+ virtual const Gfx::Material& GetMaterial();
+
+ virtual int GetMaxLightCount();
+ virtual void SetLight(int index, const Gfx::Light &light);
+ virtual const Gfx::Light& GetLight(int index);
+ virtual void SetLightEnabled(int index, bool enabled);
+ virtual bool GetLightEnabled(int index);
+
+ virtual Gfx::Texture CreateTexture(CImage *image, 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 Gfx::Texture GetTexture(int index);
+ virtual void SetTextureEnabled(int index, bool enabled);
+ virtual bool GetTextureEnabled(int index);
+
+ virtual void SetTextureStageParams(int index, const Gfx::TextureStageParams &params);
+ virtual Gfx::TextureStageParams GetTextureStageParams(int index);
+
+ virtual void SetTextureFactor(const Gfx::Color &color);
+ virtual Gfx::Color GetTextureFactor();
+
+ virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::Vertex *vertices, int vertexCount);
+ virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexCol *vertices, int vertexCount);
+ virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexTex2 *vertices, int vertexCount);
+
+ virtual int ComputeSphereVisibility(const Math::Vector &center, float radius);
+
+ virtual void SetRenderState(Gfx::RenderState state, bool enabled);
+ virtual bool GetRenderState(Gfx::RenderState state);
+
+ virtual void SetDepthTestFunc(Gfx::CompFunc func);
+ virtual Gfx::CompFunc GetDepthTestFunc();
+
+ virtual void SetDepthBias(float factor);
+ virtual float GetDepthBias();
+
+ virtual void SetAlphaTestFunc(Gfx::CompFunc func, float refValue);
+ virtual void GetAlphaTestFunc(Gfx::CompFunc &func, float &refValue);
+
+ virtual void SetBlendFunc(Gfx::BlendFunc srcBlend, Gfx::BlendFunc dstBlend);
+ virtual void GetBlendFunc(Gfx::BlendFunc &srcBlend, Gfx::BlendFunc &dstBlend);
+
+ virtual void SetClearColor(const Gfx::Color &color);
+ virtual Gfx::Color GetClearColor();
+
+ virtual void SetGlobalAmbient(const Gfx::Color &color);
+ virtual Gfx::Color GetGlobalAmbient();
+
+ virtual void SetFogParams(Gfx::FogMode mode, const Gfx::Color &color, float start, float end, float density);
+ virtual void GetFogParams(Gfx::FogMode &mode, Gfx::Color &color, float &start, float &end, float &density);
+
+ virtual void SetCullMode(Gfx::CullMode mode);
+ virtual Gfx::CullMode GetCullMode();
+
+ virtual void SetShadeModel(Gfx::ShadeModel model);
+ virtual Gfx::ShadeModel GetShadeModel();
+
+ virtual void SetFillMode(Gfx::FillMode mode) ;
+ virtual Gfx::FillMode GetFillMode();
+
+private:
+ //! Updates internal modelview matrix
+ void UpdateModelviewMatrix();
+ //! Updates position for given light based on transformation matrices
+ void UpdateLightPosition(int index);
+
+private:
+ //! Was initialized?
+ bool m_wasInit;
+ //! Last encountered error
+ std::string m_error;
+
+ //! Current world matrix
+ Math::Matrix m_worldMat;
+ //! Current view matrix
+ Math::Matrix m_viewMat;
+ //! OpenGL modelview matrix = world matrix * view matrix
+ Math::Matrix m_modelviewMat;
+ //! Current projection matrix
+ Math::Matrix m_projectionMat;
+
+ //! The current material
+ Gfx::Material m_material;
+
+ //! Whether lighting is enabled
+ bool m_lighting;
+ //! Current lights
+ std::vector<Gfx::Light> m_lights;
+ //! Current lights enable status
+ std::vector<bool> m_lightsEnabled;
+
+ //! Whether texturing is enabled in general
+ bool m_texturing;
+ //! Current textures; \c NULL value means unassigned
+ std::vector<Gfx::Texture> m_currentTextures;
+ //! Current texture stages enable status
+ std::vector<bool> m_texturesEnabled;
+ //! Current texture params
+ std::vector<Gfx::TextureStageParams> m_textureStageParams;
+
+ //! Set of all created textures
+ std::set<Gfx::Texture> m_allTextures;
};
}; // namespace Gfx
diff --git a/src/graphics/opengl/glengine.cpp b/src/graphics/opengl/glengine.cpp
deleted file mode 100644
index 9aab348..0000000
--- a/src/graphics/opengl/glengine.cpp
+++ /dev/null
@@ -1,21 +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/.
-
-// glengine.h
-
-#include "graphics/opengl/glengine.h"
-
-// TODO \ No newline at end of file
diff --git a/src/graphics/opengl/glengine.h b/src/graphics/opengl/glengine.h
deleted file mode 100644
index fa67bfe..0000000
--- a/src/graphics/opengl/glengine.h
+++ /dev/null
@@ -1,32 +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/.
-
-// glengine.h
-
-#pragma once
-
-
-#include "graphics/common/engine.h"
-
-namespace Gfx
-{
-
-class CGLEngine : public Gfx::CEngine
-{
- // TODO
-};
-
-};
diff --git a/src/graphics/opengl/test/CMakeLists.txt b/src/graphics/opengl/test/CMakeLists.txt
new file mode 100644
index 0000000..8ed7364
--- /dev/null
+++ b/src/graphics/opengl/test/CMakeLists.txt
@@ -0,0 +1,87 @@
+cmake_minimum_required(VERSION 2.8)
+
+find_package(OpenGL REQUIRED)
+find_package(SDL REQUIRED)
+find_package(SDL_image REQUIRED)
+find_package(PNG REQUIRED)
+
+set(CMAKE_BUILD_TYPE debug)
+set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0")
+
+set(ADD_LIBS "")
+
+if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+ set(PLATFORM_WINDOWS 1)
+ set(PLATFORM_LINUX 0)
+ set(PLATFORM_OTHER 0)
+elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+ set(PLATFORM_WINDOWS 0)
+ set(PLATFORM_LINUX 1)
+ set(PLATFORM_OTHER 0)
+ set(ADD_LIBS "-lrt")
+else()
+ set(PLATFORM_WINDOWS 0)
+ set(PLATFORM_LINUX 0)
+ set(PLATFORM_OTHER 1)
+endif()
+
+configure_file(../../../common/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/common/config.h)
+
+
+set(TEXTURE_SOURCES
+../gldevice.cpp
+../../../common/logger.cpp
+../../../common/image.cpp
+texture_test.cpp
+)
+
+set(MODEL_SOURCES
+../gldevice.cpp
+../../engine/modelfile.cpp
+../../../common/logger.cpp
+../../../common/image.cpp
+../../../common/iman.cpp
+../../../common/stringutils.cpp
+../../../app/system.cpp
+model_test.cpp
+)
+
+set(TRANSFORM_SOURCES
+../gldevice.cpp
+../../../common/logger.cpp
+../../../common/image.cpp
+../../../common/iman.cpp
+../../../app/system.cpp
+transform_test.cpp
+)
+
+set(LIGHT_SOURCES
+../gldevice.cpp
+../../../common/logger.cpp
+../../../common/image.cpp
+../../../common/iman.cpp
+../../../app/system.cpp
+light_test.cpp
+)
+
+include_directories(../../../ ${CMAKE_CURRENT_BINARY_DIR})
+
+set(LIBS
+${SDL_LIBRARY}
+${SDLIMAGE_LIBRARY}
+${OPENGL_LIBRARY}
+${PNG_LIBRARIES}
+${ADD_LIBS}
+)
+
+add_executable(texture_test ${TEXTURE_SOURCES})
+target_link_libraries(texture_test ${LIBS})
+
+add_executable(model_test ${MODEL_SOURCES})
+target_link_libraries(model_test ${LIBS})
+
+add_executable(transform_test ${TRANSFORM_SOURCES})
+target_link_libraries(transform_test ${LIBS})
+
+add_executable(light_test ${LIGHT_SOURCES})
+target_link_libraries(light_test ${LIBS})
diff --git a/src/graphics/opengl/test/README.txt b/src/graphics/opengl/test/README.txt
new file mode 100644
index 0000000..c618415
--- /dev/null
+++ b/src/graphics/opengl/test/README.txt
@@ -0,0 +1,9 @@
+Test programs for OpenGL engine:
+ - texture_test -> multitexturing test with 2 textures (included as files: ./tex1.png, ./tex2.png)
+ - model_test -> simple model viewer to test model loading
+ usage: ./model_test {dxf|mod} model_file
+ second argument is the loaded format (DXF or Colobot .mod files)
+ requires ./tex folder (or symlink) with Colobot textures
+ viewer is controlled from keyboard - the bindings can be found in code
+ - transform_test -> simple "walk around" test for world & view transformations
+ - light test -> test for lighting
diff --git a/src/graphics/opengl/test/light_test.cpp b/src/graphics/opengl/test/light_test.cpp
new file mode 100644
index 0000000..80fa911
--- /dev/null
+++ b/src/graphics/opengl/test/light_test.cpp
@@ -0,0 +1,437 @@
+#include "app/system.h"
+#include "common/logger.h"
+#include "common/image.h"
+#include "common/iman.h"
+#include "graphics/opengl/gldevice.h"
+#include "math/geometry.h"
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <map>
+
+enum KeySlots
+{
+ K_Forward,
+ K_Back,
+ K_Left,
+ K_Right,
+ K_Up,
+ K_Down,
+ K_Count
+};
+bool KEYMAP[K_Count] = { false };
+
+Math::Point MOUSE_POS_BASE;
+
+Math::Vector TRANSLATION(0.0f, 2.0f, 0.0f);
+Math::Vector ROTATION, ROTATION_BASE;
+
+float CUBE_ORBIT = 0.0f;
+
+const int FRAME_DELAY = 5000;
+
+SystemTimeStamp *PREV_TIME = NULL, *CURR_TIME = NULL;
+
+void Init(Gfx::CGLDevice *device)
+{
+ device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, true);
+ device->SetShadeModel(Gfx::SHADE_SMOOTH);
+}
+
+void Render(Gfx::CGLDevice *device)
+{
+ device->BeginScene();
+
+ /* Unlit part of scene */
+
+ device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, false);
+ device->SetRenderState(Gfx::RENDER_STATE_CULLING, false); // Double-sided drawing
+
+ Math::Matrix persp;
+ Math::LoadProjectionMatrix(persp, Math::PI / 4.0f, (800.0f) / (600.0f), 0.1f, 100.0f);
+ device->SetTransform(Gfx::TRANSFORM_PROJECTION, persp);
+
+
+ Math::Matrix viewMat;
+ Math::Matrix mat;
+
+ viewMat.LoadIdentity();
+
+ Math::LoadRotationXMatrix(mat, -ROTATION.x);
+ viewMat = Math::MultiplyMatrices(viewMat, mat);
+
+ Math::LoadRotationYMatrix(mat, -ROTATION.y);
+ viewMat = Math::MultiplyMatrices(viewMat, mat);
+
+ Math::LoadTranslationMatrix(mat, -TRANSLATION);
+ viewMat = Math::MultiplyMatrices(viewMat, mat);
+
+ device->SetTransform(Gfx::TRANSFORM_VIEW, viewMat);
+
+ Math::Matrix worldMat;
+ worldMat.LoadIdentity();
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ Gfx::VertexCol line[2] = { Gfx::VertexCol() };
+
+ for (int x = -40; x <= 40; ++x)
+ {
+ line[0].color = Gfx::Color(0.7f + x / 120.0f, 0.0f, 0.0f);
+ line[0].coord.z = -40;
+ line[0].coord.x = x;
+ line[1].color = Gfx::Color(0.7f + x / 120.0f, 0.0f, 0.0f);
+ line[1].coord.z = 40;
+ line[1].coord.x = x;
+ device->DrawPrimitive(Gfx::PRIMITIVE_LINES, line, 2);
+ }
+
+ for (int z = -40; z <= 40; ++z)
+ {
+ line[0].color = Gfx::Color(0.0f, 0.7f + z / 120.0f, 0.0f);
+ line[0].coord.z = z;
+ line[0].coord.x = -40;
+ line[1].color = Gfx::Color(0.0f, 0.7f + z / 120.0f, 0.0f);
+ line[1].coord.z = z;
+ line[1].coord.x = 40;
+ device->DrawPrimitive(Gfx::PRIMITIVE_LINES, line, 2);
+ }
+
+
+ Gfx::VertexCol quad[6] = { Gfx::VertexCol() };
+
+ quad[0].coord = Math::Vector(-1.0f, -1.0f, 0.0f);
+ quad[1].coord = Math::Vector( 1.0f, -1.0f, 0.0f);
+ quad[2].coord = Math::Vector(-1.0f, 1.0f, 0.0f);
+ quad[3].coord = Math::Vector( 1.0f, 1.0f, 0.0f);
+
+ for (int i = 0; i < 6; ++i)
+ quad[i].color = Gfx::Color(1.0f, 1.0f, 0.0f);
+
+ Math::LoadTranslationMatrix(worldMat, Math::Vector(40.0f, 2.0f, 40.0f));
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4);
+
+ for (int i = 0; i < 6; ++i)
+ quad[i].color = Gfx::Color(0.0f, 1.0f, 1.0f);
+
+ Math::LoadTranslationMatrix(worldMat, Math::Vector(-40.0f, 2.0f, -40.0f));
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4);
+
+ for (int i = 0; i < 6; ++i)
+ quad[i].color = Gfx::Color(1.0f, 0.0f, 1.0f);
+
+ Math::LoadTranslationMatrix(worldMat, Math::Vector(10.0f, 4.5f, 5.0f));
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4);
+
+ /* Moving lit cube */
+ device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, true);
+ device->SetRenderState(Gfx::RENDER_STATE_CULLING, true); // Culling (CCW faces)
+
+ device->SetGlobalAmbient(Gfx::Color(0.4f, 0.4f, 0.4f));
+
+ Gfx::Light light1;
+ light1.type = Gfx::LIGHT_POINT;
+ light1.position = Math::Vector(10.0f, 4.5f, 5.0f);
+ light1.ambient = Gfx::Color(0.2f, 0.2f, 0.2f);
+ light1.diffuse = Gfx::Color(1.0f, 0.1f, 0.1f);
+ light1.specular = Gfx::Color(0.0f, 0.0f, 0.0f);
+ device->SetLight(0, light1);
+ device->SetLightEnabled(0, true);
+
+ /*Gfx::Light light2;
+ device->SetLight(1, light2);
+ device->SetLightEnabled(1, true);*/
+
+ Gfx::Material material;
+ material.ambient = Gfx::Color(0.3f, 0.3f, 0.3f);
+ material.diffuse = Gfx::Color(0.8f, 0.7f, 0.6f);
+ material.specular = Gfx::Color(0.0f, 0.0f, 0.0f);
+ device->SetMaterial(material);
+
+ const Gfx::Vertex cube[6][4] =
+ {
+ {
+ // Front
+ Gfx::Vertex(Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector( 0.0f, 0.0f, -1.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, -1.0f, -1.0f), Math::Vector( 0.0f, 0.0f, -1.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, 1.0f, -1.0f), Math::Vector( 0.0f, 0.0f, -1.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, 1.0f, -1.0f), Math::Vector( 0.0f, 0.0f, -1.0f))
+ },
+
+ {
+ // Back
+ Gfx::Vertex(Math::Vector( 1.0f, -1.0f, 1.0f), Math::Vector( 0.0f, 0.0f, 1.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, -1.0f, 1.0f), Math::Vector( 0.0f, 0.0f, 1.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, 1.0f, 1.0f), Math::Vector( 0.0f, 0.0f, 1.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, 1.0f, 1.0f), Math::Vector( 0.0f, 0.0f, 1.0f))
+ },
+
+ {
+ // Top
+ Gfx::Vertex(Math::Vector(-1.0f, 1.0f, -1.0f), Math::Vector( 0.0f, 1.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, 1.0f, -1.0f), Math::Vector( 0.0f, 1.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, 1.0f, 1.0f), Math::Vector( 0.0f, 1.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, 1.0f, 1.0f), Math::Vector( 0.0f, 1.0f, 0.0f))
+ },
+
+ {
+ // Bottom
+ Gfx::Vertex(Math::Vector(-1.0f, -1.0f, 1.0f), Math::Vector( 0.0f, -1.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, -1.0f, 1.0f), Math::Vector( 0.0f, -1.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector( 0.0f, -1.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, -1.0f, -1.0f), Math::Vector( 0.0f, -1.0f, 0.0f))
+ },
+
+ {
+ // Left
+ Gfx::Vertex(Math::Vector(-1.0f, -1.0f, 1.0f), Math::Vector(-1.0f, 0.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector(-1.0f, 0.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, 1.0f, 1.0f), Math::Vector(-1.0f, 0.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, 1.0f, -1.0f), Math::Vector(-1.0f, 0.0f, 0.0f))
+ },
+
+ {
+ // Right
+ Gfx::Vertex(Math::Vector( 1.0f, -1.0f, -1.0f), Math::Vector( 1.0f, 0.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, -1.0f, 1.0f), Math::Vector( 1.0f, 0.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, 1.0f, -1.0f), Math::Vector( 1.0f, 0.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, 1.0f, 1.0f), Math::Vector( 1.0f, 0.0f, 0.0f))
+ }
+ };
+
+ Math::Matrix cubeTrans;
+ Math::LoadTranslationMatrix(cubeTrans, Math::Vector(10.0f, 2.0f, 5.0f));
+ Math::Matrix cubeRot;
+ Math::LoadRotationMatrix(cubeRot, Math::Vector(0.0f, 1.0f, 0.0f), CUBE_ORBIT);
+ Math::Matrix cubeRotInv;
+ Math::LoadRotationMatrix(cubeRotInv, Math::Vector(0.0f, 1.0f, 0.0f), -CUBE_ORBIT);
+ Math::Matrix cubeTransRad;
+ Math::LoadTranslationMatrix(cubeTransRad, Math::Vector(0.0f, 0.0f, 6.0f));
+ worldMat = Math::MultiplyMatrices(cubeTransRad, cubeRotInv);
+ worldMat = Math::MultiplyMatrices(cubeRot, worldMat);
+ worldMat = Math::MultiplyMatrices(cubeTrans, worldMat);
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ for (int i = 0; i < 6; ++i)
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, cube[i], 4);
+
+ device->EndScene();
+}
+
+void Update()
+{
+ const float TRANS_SPEED = 6.0f; // units / sec
+
+ GetCurrentTimeStamp(CURR_TIME);
+ float timeDiff = TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC);
+ CopyTimeStamp(PREV_TIME, CURR_TIME);
+
+ CUBE_ORBIT += timeDiff * (Math::PI / 4.0f);
+
+ Math::Vector incTrans;
+
+ if (KEYMAP[K_Forward])
+ incTrans.z = +TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Back])
+ incTrans.z = -TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Right])
+ incTrans.x = +TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Left])
+ incTrans.x = -TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Up])
+ incTrans.y = +TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Down])
+ incTrans.y = -TRANS_SPEED * timeDiff;
+
+ Math::Point rotTrans = Math::RotatePoint(-ROTATION.y, Math::Point(incTrans.x, incTrans.z));
+ incTrans.x = rotTrans.x;
+ incTrans.z = rotTrans.y;
+ TRANSLATION += incTrans;
+}
+
+void KeyboardDown(SDLKey key)
+{
+ switch (key)
+ {
+ case SDLK_w:
+ KEYMAP[K_Forward] = true;
+ break;
+ case SDLK_s:
+ KEYMAP[K_Back] = true;
+ break;
+ case SDLK_d:
+ KEYMAP[K_Right] = true;
+ break;
+ case SDLK_a:
+ KEYMAP[K_Left] = true;
+ break;
+ case SDLK_z:
+ KEYMAP[K_Down] = true;
+ break;
+ case SDLK_x:
+ KEYMAP[K_Up] = true;
+ break;
+ default:
+ break;
+ }
+}
+
+void KeyboardUp(SDLKey key)
+{
+ switch (key)
+ {
+ case SDLK_w:
+ KEYMAP[K_Forward] = false;
+ break;
+ case SDLK_s:
+ KEYMAP[K_Back] = false;
+ break;
+ case SDLK_d:
+ KEYMAP[K_Right] = false;
+ break;
+ case SDLK_a:
+ KEYMAP[K_Left] = false;
+ break;
+ case SDLK_z:
+ KEYMAP[K_Down] = false;
+ break;
+ case SDLK_x:
+ KEYMAP[K_Up] = false;
+ break;
+ default:
+ break;
+ }
+}
+
+void MouseMove(int x, int y)
+{
+ Math::Point currentPos((float)x, (float)y);
+
+ static bool first = true;
+ if (first || (x < 10) || (y < 10) || (x > 790) || (y > 590))
+ {
+ SDL_WarpMouse(400, 300);
+ MOUSE_POS_BASE.x = 400;
+ MOUSE_POS_BASE.y = 300;
+ ROTATION_BASE = ROTATION;
+ first = false;
+ return;
+ }
+
+ ROTATION.y = ROTATION_BASE.y + ((float) (x - MOUSE_POS_BASE.x) / 800.0f) * Math::PI;
+ ROTATION.x = ROTATION_BASE.x + ((float) (y - MOUSE_POS_BASE.y) / 600.0f) * Math::PI;
+}
+
+int main(int argc, char *argv[])
+{
+ CLogger logger;
+
+ PREV_TIME = CreateTimeStamp();
+ CURR_TIME = CreateTimeStamp();
+
+ GetCurrentTimeStamp(PREV_TIME);
+ GetCurrentTimeStamp(CURR_TIME);
+
+ CInstanceManager iMan;
+
+ // Without any error checking, for simplicity
+
+ SDL_Init(SDL_INIT_VIDEO);
+
+ IMG_Init(IMG_INIT_PNG);
+
+ const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
+
+ Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
+
+ if (videoInfo->hw_available)
+ videoFlags |= SDL_HWSURFACE;
+ else
+ videoFlags |= SDL_SWSURFACE;
+
+ if (videoInfo->blit_hw)
+ videoFlags |= SDL_HWACCEL;
+
+
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ SDL_Surface *surface = SDL_SetVideoMode(800, 600, 32, videoFlags);
+
+
+ SDL_WM_SetCaption("Light Test", "Light Test");
+
+ //SDL_WM_GrabInput(SDL_GRAB_ON);
+ SDL_ShowCursor(SDL_DISABLE);
+
+ Gfx::CGLDevice *device = new Gfx::CGLDevice();
+ device->Create();
+
+ Init(device);
+
+ bool done = false;
+ while (! done)
+ {
+ Render(device);
+ Update();
+
+ SDL_GL_SwapBuffers();
+
+ SDL_Event event;
+ while (SDL_PollEvent(&event))
+ {
+ if (event.type == SDL_QUIT)
+ {
+ break;
+ done = true;
+ }
+ else if (event.type == SDL_KEYDOWN)
+ {
+ if (event.key.keysym.sym == SDLK_q)
+ {
+ done = true;
+ break;
+ }
+ else
+ KeyboardDown(event.key.keysym.sym);
+ }
+ else if (event.type == SDL_KEYUP)
+ KeyboardUp(event.key.keysym.sym);
+ else if (event.type == SDL_MOUSEMOTION)
+ MouseMove(event.motion.x, event.motion.y);
+ }
+
+ usleep(FRAME_DELAY);
+ }
+
+ //SDL_WM_GrabInput(SDL_GRAB_OFF);
+ SDL_ShowCursor(SDL_ENABLE);
+
+ device->Destroy();
+ delete device;
+
+ SDL_FreeSurface(surface);
+
+ IMG_Quit();
+
+ SDL_Quit();
+
+ DestroyTimeStamp(PREV_TIME);
+ DestroyTimeStamp(CURR_TIME);
+
+ return 0;
+}
diff --git a/src/graphics/opengl/test/model_test.cpp b/src/graphics/opengl/test/model_test.cpp
new file mode 100644
index 0000000..3e8efe6
--- /dev/null
+++ b/src/graphics/opengl/test/model_test.cpp
@@ -0,0 +1,377 @@
+#include "app/system.h"
+#include "common/logger.h"
+#include "common/image.h"
+#include "common/iman.h"
+#include "graphics/engine/modelfile.h"
+#include "graphics/opengl/gldevice.h"
+#include "math/geometry.h"
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <map>
+
+enum KeySlots
+{
+ K_RotXUp,
+ K_RotXDown,
+ K_RotYLeft,
+ K_RotYRight,
+ K_Forward,
+ K_Back,
+ K_Left,
+ K_Right,
+ K_Up,
+ K_Down,
+ K_Count
+};
+bool KEYMAP[K_Count] = { false };
+
+Math::Vector TRANSLATION(0.0f, 0.0f, 30.0f);
+Math::Vector ROTATION;
+
+const int FRAME_DELAY = 5000;
+
+std::map<std::string, Gfx::Texture> TEXS;
+
+SystemTimeStamp *PREV_TIME = NULL, *CURR_TIME = NULL;
+
+Gfx::Texture GetTexture(const std::string &name)
+{
+ std::map<std::string, Gfx::Texture>::iterator it = TEXS.find(name);
+ if (it == TEXS.end())
+ return Gfx::Texture();
+
+ return (*it).second;
+}
+
+void LoadTexture(Gfx::CGLDevice *device, const std::string &name)
+{
+ if (name.empty())
+ return;
+
+ Gfx::Texture tex = GetTexture(name);
+
+ if (tex.valid)
+ return;
+
+ CImage img;
+ if (! img.Load(std::string("tex/") + name))
+ {
+ std::string err = img.GetError();
+ GetLogger()->Error("Texture not loaded, error: %s!\n", err.c_str());
+ }
+ else
+ {
+ Gfx::TextureCreateParams texCreateParams;
+ texCreateParams.mipmap = true;
+ if (img.GetData()->surface->format->Amask == 0)
+ texCreateParams.format = Gfx::TEX_IMG_BGR;
+ else
+ texCreateParams.format = Gfx::TEX_IMG_BGRA;
+ texCreateParams.minFilter = Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR;
+ texCreateParams.magFilter = Gfx::TEX_MAG_FILTER_LINEAR;
+
+ tex = device->CreateTexture(&img, texCreateParams);
+ }
+
+ TEXS[name] = tex;
+}
+
+void Init(Gfx::CGLDevice *device, Gfx::CModelFile *model)
+{
+ std::vector<Gfx::ModelTriangle> &triangles = model->GetTriangles();
+
+ for (int i = 0; i < (int) triangles.size(); ++i)
+ {
+ LoadTexture(device, triangles[i].tex1Name);
+ LoadTexture(device, triangles[i].tex2Name);
+ }
+
+ device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+ device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, true);
+ device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, true);
+ device->SetShadeModel(Gfx::SHADE_SMOOTH);
+
+ Gfx::Light light;
+ light.type = Gfx::LIGHT_DIRECTIONAL;
+ light.ambient = Gfx::Color(0.4f, 0.4f, 0.4f, 0.0f);
+ light.diffuse = Gfx::Color(0.8f, 0.8f, 0.8f, 0.0f);
+ light.specular = Gfx::Color(0.2f, 0.2f, 0.2f, 0.0f);
+ light.position = Math::Vector(0.0f, 0.0f, -1.0f);
+ light.direction = Math::Vector(0.0f, 0.0f, 1.0f);
+
+ device->SetGlobalAmbient(Gfx::Color(0.5f, 0.5f, 0.5f, 0.0f));
+ device->SetLight(0, light);
+ device->SetLightEnabled(0, true);
+}
+
+void Render(Gfx::CGLDevice *device, Gfx::CModelFile *modelFile)
+{
+ device->BeginScene();
+
+ Math::Matrix persp;
+ Math::LoadProjectionMatrix(persp, Math::PI / 4.0f, (800.0f) / (600.0f), 0.1f, 100.0f);
+ device->SetTransform(Gfx::TRANSFORM_PROJECTION, persp);
+
+ Math::Matrix id;
+ id.LoadIdentity();
+ device->SetTransform(Gfx::TRANSFORM_WORLD, id);
+
+ Math::Matrix viewMat;
+ Math::LoadTranslationMatrix(viewMat, TRANSLATION);
+ Math::Matrix rot;
+ Math::LoadRotationXZYMatrix(rot, ROTATION);
+ viewMat = Math::MultiplyMatrices(viewMat, rot);
+ device->SetTransform(Gfx::TRANSFORM_VIEW, viewMat);
+
+ std::vector<Gfx::ModelTriangle> &triangles = modelFile->GetTriangles();
+
+ Gfx::VertexTex2 tri[3];
+
+ for (int i = 0; i < (int) triangles.size(); ++i)
+ {
+ device->SetTexture(0, GetTexture(triangles[i].tex1Name));
+ device->SetTexture(1, GetTexture(triangles[i].tex2Name));
+ device->SetTextureEnabled(0, true);
+ device->SetTextureEnabled(1, true);
+
+ device->SetMaterial(triangles[i].material);
+
+ tri[0] = triangles[i].p1;
+ tri[1] = triangles[i].p2;
+ tri[2] = triangles[i].p3;
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, tri, 3);
+ }
+
+ device->EndScene();
+}
+
+void Update()
+{
+ const float ROT_SPEED = 80.0f * Math::DEG_TO_RAD; // rad / sec
+ const float TRANS_SPEED = 3.0f; // units / sec
+
+ GetCurrentTimeStamp(CURR_TIME);
+ float timeDiff = TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC);
+ CopyTimeStamp(PREV_TIME, CURR_TIME);
+
+ if (KEYMAP[K_RotYLeft])
+ ROTATION.y -= ROT_SPEED * timeDiff;
+ if (KEYMAP[K_RotYRight])
+ ROTATION.y += ROT_SPEED * timeDiff;
+ if (KEYMAP[K_RotXDown])
+ ROTATION.x -= ROT_SPEED * timeDiff;
+ if (KEYMAP[K_RotXUp])
+ ROTATION.x += ROT_SPEED * timeDiff;
+
+ if (KEYMAP[K_Forward])
+ TRANSLATION.z -= TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Back])
+ TRANSLATION.z += TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Left])
+ TRANSLATION.x += TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Right])
+ TRANSLATION.x -= TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Up])
+ TRANSLATION.y += TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Down])
+ TRANSLATION.y -= TRANS_SPEED * timeDiff;
+}
+
+void KeyboardDown(SDLKey key)
+{
+ switch (key)
+ {
+ case SDLK_LEFT:
+ KEYMAP[K_RotYLeft] = true;
+ break;
+ case SDLK_RIGHT:
+ KEYMAP[K_RotYRight] = true;
+ break;
+ case SDLK_UP:
+ KEYMAP[K_RotXUp] = true;
+ break;
+ case SDLK_DOWN:
+ KEYMAP[K_RotXDown] = true;
+ break;
+ case SDLK_w:
+ KEYMAP[K_Forward] = true;
+ break;
+ case SDLK_s:
+ KEYMAP[K_Back] = true;
+ break;
+ case SDLK_a:
+ KEYMAP[K_Left] = true;
+ break;
+ case SDLK_d:
+ KEYMAP[K_Right] = true;
+ break;
+ case SDLK_z:
+ KEYMAP[K_Down] = true;
+ break;
+ case SDLK_x:
+ KEYMAP[K_Up] = true;
+ break;
+ default:
+ break;
+ }
+}
+
+void KeyboardUp(SDLKey key)
+{
+ switch (key)
+ {
+ case SDLK_LEFT:
+ KEYMAP[K_RotYLeft] = false;
+ break;
+ case SDLK_RIGHT:
+ KEYMAP[K_RotYRight] = false;
+ break;
+ case SDLK_UP:
+ KEYMAP[K_RotXUp] = false;
+ break;
+ case SDLK_DOWN:
+ KEYMAP[K_RotXDown] = false;
+ break;
+ case SDLK_w:
+ KEYMAP[K_Forward] = false;
+ break;
+ case SDLK_s:
+ KEYMAP[K_Back] = false;
+ break;
+ case SDLK_a:
+ KEYMAP[K_Left] = false;
+ break;
+ case SDLK_d:
+ KEYMAP[K_Right] = false;
+ break;
+ case SDLK_z:
+ KEYMAP[K_Down] = false;
+ break;
+ case SDLK_x:
+ KEYMAP[K_Up] = false;
+ break;
+ default:
+ break;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ CLogger logger;
+
+ PREV_TIME = CreateTimeStamp();
+ CURR_TIME = CreateTimeStamp();
+
+ GetCurrentTimeStamp(PREV_TIME);
+ GetCurrentTimeStamp(CURR_TIME);
+
+ if (argc != 3)
+ {
+ std::cerr << "Usage: " << argv[0] << "{mod|dxf} model_file" << std::endl;
+ return 1;
+ }
+
+ CInstanceManager iMan;
+
+ Gfx::CModelFile *modelFile = new Gfx::CModelFile(&iMan);
+ if (std::string(argv[1]) == "mod")
+ {
+ if (! modelFile->ReadModel(argv[2], false, false))
+ {
+ std::cerr << "Error reading MOD: " << modelFile->GetError() << std::endl;
+ return 1;
+ }
+ }
+ else if (std::string(argv[1]) == "dxf")
+ {
+ if (! modelFile->ReadDXF(argv[2], 0.0f, 0.0f))
+ {
+ std::cerr << "Error reading DXF: " << modelFile->GetError() << std::endl;
+ return 1;
+ }
+ }
+ else
+ {
+ std::cerr << "Usage: " << argv[0] << "{mod|dxf} model_file" << std::endl;
+ return 1;
+ }
+
+ // Without any error checking, for simplicity
+
+ SDL_Init(SDL_INIT_VIDEO);
+
+ IMG_Init(IMG_INIT_PNG);
+
+ const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
+
+ Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
+
+ if (videoInfo->hw_available)
+ videoFlags |= SDL_HWSURFACE;
+ else
+ videoFlags |= SDL_SWSURFACE;
+
+ if (videoInfo->blit_hw)
+ videoFlags |= SDL_HWACCEL;
+
+
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ SDL_Surface *surface = SDL_SetVideoMode(800, 600, 32, videoFlags);
+
+
+ SDL_WM_SetCaption("Model Test", "Model Test");
+
+ Gfx::CGLDevice *device = new Gfx::CGLDevice();
+ device->Create();
+
+ Init(device, modelFile);
+
+ bool done = false;
+ while (! done)
+ {
+ Render(device, modelFile);
+ Update();
+
+ SDL_GL_SwapBuffers();
+
+ SDL_Event event;
+ SDL_PollEvent(&event);
+ if (event.type == SDL_QUIT)
+ done = true;
+ else if (event.type == SDL_KEYDOWN)
+ KeyboardDown(event.key.keysym.sym);
+ else if (event.type == SDL_KEYUP)
+ KeyboardUp(event.key.keysym.sym);
+
+ usleep(FRAME_DELAY);
+ }
+
+ delete modelFile;
+
+ device->Destroy();
+ delete device;
+
+ SDL_FreeSurface(surface);
+
+ IMG_Quit();
+
+ SDL_Quit();
+
+ DestroyTimeStamp(PREV_TIME);
+ DestroyTimeStamp(CURR_TIME);
+
+ return 0;
+}
diff --git a/src/graphics/opengl/test/tex1.png b/src/graphics/opengl/test/tex1.png
new file mode 100644
index 0000000..46c68a0
--- /dev/null
+++ b/src/graphics/opengl/test/tex1.png
Binary files differ
diff --git a/src/graphics/opengl/test/tex2.png b/src/graphics/opengl/test/tex2.png
new file mode 100644
index 0000000..ebdae0d
--- /dev/null
+++ b/src/graphics/opengl/test/tex2.png
Binary files differ
diff --git a/src/graphics/opengl/test/texture_test.cpp b/src/graphics/opengl/test/texture_test.cpp
new file mode 100644
index 0000000..c3c568b
--- /dev/null
+++ b/src/graphics/opengl/test/texture_test.cpp
@@ -0,0 +1,193 @@
+#include "common/logger.h"
+#include "common/image.h"
+#include "graphics/opengl/gldevice.h"
+#include "math/geometry.h"
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+#include <unistd.h>
+
+
+void Init(Gfx::CGLDevice *device)
+{
+ device->SetShadeModel(Gfx::SHADE_SMOOTH);
+
+ device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, false);
+ device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+
+ device->SetTextureEnabled(0, true);
+ device->SetTextureEnabled(1, true);
+
+ CImage img1;
+ if (! img1.Load("tex1.png"))
+ {
+ std::string err = img1.GetError();
+ GetLogger()->Error("texture 1 not loaded, error: %d!\n", err.c_str());
+ }
+ CImage img2;
+ if (! img2.Load("tex2.png"))
+ {
+ std::string err = img2.GetError();
+ GetLogger()->Error("texture 2 not loaded, error: %d!\n", err.c_str());
+ }
+
+ Gfx::TextureCreateParams tex1CreateParams;
+ tex1CreateParams.mipmap = true;
+ tex1CreateParams.format = Gfx::TEX_IMG_RGBA;
+ tex1CreateParams.minFilter = Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR;
+ tex1CreateParams.magFilter = Gfx::TEX_MAG_FILTER_LINEAR;
+
+ Gfx::TextureCreateParams tex2CreateParams;
+ tex2CreateParams.mipmap = true;
+ tex2CreateParams.format = Gfx::TEX_IMG_RGBA;
+ tex2CreateParams.minFilter = Gfx::TEX_MIN_FILTER_NEAREST_MIPMAP_NEAREST;
+ tex2CreateParams.magFilter = Gfx::TEX_MAG_FILTER_NEAREST;
+
+ Gfx::Texture tex1 = device->CreateTexture(&img1, tex1CreateParams);
+ Gfx::Texture tex2 = device->CreateTexture(&img2, tex2CreateParams);
+
+ device->SetTexture(0, tex1);
+ device->SetTexture(1, tex2);
+}
+
+void Render(Gfx::CGLDevice *device)
+{
+ device->BeginScene();
+
+ Math::Matrix ortho;
+ Math::LoadOrthoProjectionMatrix(ortho, -10, 10, -10, 10);
+ device->SetTransform(Gfx::TRANSFORM_PROJECTION, ortho);
+
+ Math::Matrix id;
+ id.LoadIdentity();
+
+ device->SetTransform(Gfx::TRANSFORM_WORLD, id);
+ device->SetTransform(Gfx::TRANSFORM_VIEW, id);
+
+ static Gfx::VertexTex2 quad[] =
+ {
+ Gfx::VertexTex2(Math::Vector(-2.0f, 2.0f, 0.0f), Math::Vector(), Math::Point(0.0f, 0.0f), Math::Point(0.0f, 0.0f)),
+ Gfx::VertexTex2(Math::Vector( 2.0f, 2.0f, 0.0f), Math::Vector(), Math::Point(1.0f, 0.0f), Math::Point(1.0f, 0.0f)),
+ Gfx::VertexTex2(Math::Vector( 2.0f, -2.0f, 0.0f), Math::Vector(), Math::Point(1.0f, 1.0f), Math::Point(1.0f, 1.0f)),
+
+ Gfx::VertexTex2(Math::Vector( 2.0f, -2.0f, 0.0f), Math::Vector(), Math::Point(1.0f, 1.0f), Math::Point(1.0f, 1.0f)),
+ Gfx::VertexTex2(Math::Vector(-2.0f, -2.0f, 0.0f), Math::Vector(), Math::Point(0.0f, 1.0f), Math::Point(0.0f, 1.0f)),
+ Gfx::VertexTex2(Math::Vector(-2.0f, 2.0f, 0.0f), Math::Vector(), Math::Point(0.0f, 0.0f), Math::Point(0.0f, 0.0f)),
+ };
+
+ Gfx::TextureStageParams tex1StageParams;
+ tex1StageParams.colorOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ tex1StageParams.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ device->SetTextureStageParams(0, tex1StageParams);
+
+ Gfx::TextureStageParams tex2StageParams;
+ tex2StageParams.colorOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ tex2StageParams.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ device->SetTextureStageParams(1, tex2StageParams);
+
+ Math::Matrix t;
+ Math::LoadTranslationMatrix(t, Math::Vector(-4.0f, 4.0f, 0.0f));
+ device->SetTransform(Gfx::TRANSFORM_VIEW, t);
+
+ device->SetTextureEnabled(0, true);
+ device->SetTextureEnabled(1, false);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6);
+
+ Math::LoadTranslationMatrix(t, Math::Vector( 4.0f, 4.0f, 0.0f));
+ device->SetTransform(Gfx::TRANSFORM_VIEW, t);
+
+ device->SetTextureEnabled(0, false);
+ device->SetTextureEnabled(1, true);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6);
+
+ Math::LoadTranslationMatrix(t, Math::Vector( 0.0f, -4.0f, 0.0f));
+ device->SetTransform(Gfx::TRANSFORM_VIEW, t);
+
+ device->SetTextureEnabled(0, true);
+ device->SetTextureEnabled(1, true);
+
+ tex1StageParams.colorOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ tex1StageParams.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ device->SetTextureStageParams(0, tex1StageParams);
+
+ tex2StageParams.colorOperation = Gfx::TEX_MIX_OPER_ADD;
+ tex2StageParams.colorArg1 = Gfx::TEX_MIX_ARG_COMPUTED_COLOR;
+ tex2StageParams.colorArg2 = Gfx::TEX_MIX_ARG_TEXTURE;
+ tex2StageParams.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ device->SetTextureStageParams(1, tex2StageParams);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6);
+
+ device->EndScene();
+}
+
+int main()
+{
+ CLogger();
+
+ // Without any error checking, for simplicity
+
+ SDL_Init(SDL_INIT_VIDEO);
+
+ IMG_Init(IMG_INIT_PNG);
+
+ const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
+
+ Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
+
+ if (videoInfo->hw_available)
+ videoFlags |= SDL_HWSURFACE;
+ else
+ videoFlags |= SDL_SWSURFACE;
+
+ if (videoInfo->blit_hw)
+ videoFlags |= SDL_HWACCEL;
+
+
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ SDL_Surface *surface = SDL_SetVideoMode(800, 600, 32, videoFlags);
+
+
+ SDL_WM_SetCaption("Texture Test", "Texture Test");
+
+ Gfx::CGLDevice *device = new Gfx::CGLDevice();
+ device->Create();
+
+ Init(device);
+
+ bool done = false;
+ while (! done)
+ {
+ Render(device);
+
+ SDL_GL_SwapBuffers();
+
+ SDL_Event event;
+ SDL_PollEvent(&event);
+ if (event.type == SDL_QUIT)
+ done = true;
+
+ usleep(10000);
+ }
+
+ device->Destroy();
+ delete device;
+
+ SDL_FreeSurface(surface);
+
+ IMG_Quit();
+
+ SDL_Quit();
+
+ return 0;
+}
diff --git a/src/graphics/opengl/test/transform_test.cpp b/src/graphics/opengl/test/transform_test.cpp
new file mode 100644
index 0000000..83819b8
--- /dev/null
+++ b/src/graphics/opengl/test/transform_test.cpp
@@ -0,0 +1,339 @@
+#include "app/system.h"
+#include "common/logger.h"
+#include "common/image.h"
+#include "common/iman.h"
+#include "graphics/opengl/gldevice.h"
+#include "math/geometry.h"
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <map>
+
+enum KeySlots
+{
+ K_Forward,
+ K_Back,
+ K_Left,
+ K_Right,
+ K_Up,
+ K_Down,
+ K_Count
+};
+bool KEYMAP[K_Count] = { false };
+
+Math::Point MOUSE_POS_BASE;
+
+Math::Vector TRANSLATION(0.0f, 2.0f, 0.0f);
+Math::Vector ROTATION, ROTATION_BASE;
+
+const int FRAME_DELAY = 5000;
+
+SystemTimeStamp *PREV_TIME = NULL, *CURR_TIME = NULL;
+
+void Init(Gfx::CGLDevice *device)
+{
+ device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, true);
+ device->SetShadeModel(Gfx::SHADE_SMOOTH);
+}
+
+void Render(Gfx::CGLDevice *device)
+{
+ device->BeginScene();
+
+ Math::Matrix persp;
+ Math::LoadProjectionMatrix(persp, Math::PI / 4.0f, (800.0f) / (600.0f), 0.1f, 100.0f);
+ device->SetTransform(Gfx::TRANSFORM_PROJECTION, persp);
+
+
+ Math::Matrix viewMat;
+ Math::Matrix mat;
+
+ viewMat.LoadIdentity();
+
+ Math::LoadRotationXMatrix(mat, -ROTATION.x);
+ viewMat = Math::MultiplyMatrices(viewMat, mat);
+
+ Math::LoadRotationYMatrix(mat, -ROTATION.y);
+ viewMat = Math::MultiplyMatrices(viewMat, mat);
+
+ Math::LoadTranslationMatrix(mat, -TRANSLATION);
+ viewMat = Math::MultiplyMatrices(viewMat, mat);
+
+ device->SetTransform(Gfx::TRANSFORM_VIEW, viewMat);
+
+
+ Math::Matrix worldMat;
+ worldMat.LoadIdentity();
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ Gfx::VertexCol line[2] = { Gfx::VertexCol() };
+
+ for (int x = -40; x <= 40; ++x)
+ {
+ line[0].color = Gfx::Color(0.7f + x / 120.0f, 0.0f, 0.0f);
+ line[0].coord.z = -40;
+ line[0].coord.x = x;
+ line[1].color = Gfx::Color(0.7f + x / 120.0f, 0.0f, 0.0f);
+ line[1].coord.z = 40;
+ line[1].coord.x = x;
+ device->DrawPrimitive(Gfx::PRIMITIVE_LINES, line, 2);
+ }
+
+ for (int z = -40; z <= 40; ++z)
+ {
+ line[0].color = Gfx::Color(0.0f, 0.7f + z / 120.0f, 0.0f);
+ line[0].coord.z = z;
+ line[0].coord.x = -40;
+ line[1].color = Gfx::Color(0.0f, 0.7f + z / 120.0f, 0.0f);
+ line[1].coord.z = z;
+ line[1].coord.x = 40;
+ device->DrawPrimitive(Gfx::PRIMITIVE_LINES, line, 2);
+ }
+
+
+ Gfx::VertexCol quad[6] = { Gfx::VertexCol() };
+
+ for (int i = 0; i < 6; ++i)
+ quad[i].color = Gfx::Color(1.0f, 1.0f, 0.0f);
+
+ quad[0].coord = Math::Vector(-1.0f, -1.0f, 0.0f);
+ quad[1].coord = Math::Vector( 1.0f, -1.0f, 0.0f);
+ quad[2].coord = Math::Vector( 1.0f, 1.0f, 0.0f);
+ quad[3].coord = Math::Vector( 1.0f, 1.0f, 0.0f);
+ quad[4].coord = Math::Vector(-1.0f, 1.0f, 0.0f);
+ quad[5].coord = Math::Vector(-1.0f, -1.0f, 0.0f);
+
+ Math::LoadTranslationMatrix(worldMat, Math::Vector(40.0f, 2.0f, 40.0f));
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6);
+
+ for (int i = 0; i < 6; ++i)
+ quad[i].color = Gfx::Color(0.0f, 1.0f, 1.0f);
+
+ Math::LoadTranslationMatrix(worldMat, Math::Vector(-40.0f, 2.0f, -40.0f));
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6);
+
+ for (int i = 0; i < 6; ++i)
+ quad[i].color = Gfx::Color(1.0f, 0.0f, 1.0f);
+
+ Math::LoadTranslationMatrix(worldMat, Math::Vector(0.0f, 10.0f, 0.0f));
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6);
+
+ device->EndScene();
+}
+
+void Update()
+{
+ const float TRANS_SPEED = 6.0f; // units / sec
+
+ GetCurrentTimeStamp(CURR_TIME);
+ float timeDiff = TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC);
+ CopyTimeStamp(PREV_TIME, CURR_TIME);
+
+ Math::Vector incTrans;
+
+ if (KEYMAP[K_Forward])
+ incTrans.z = +TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Back])
+ incTrans.z = -TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Right])
+ incTrans.x = +TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Left])
+ incTrans.x = -TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Up])
+ incTrans.y = +TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Down])
+ incTrans.y = -TRANS_SPEED * timeDiff;
+
+ Math::Point rotTrans = Math::RotatePoint(-ROTATION.y, Math::Point(incTrans.x, incTrans.z));
+ incTrans.x = rotTrans.x;
+ incTrans.z = rotTrans.y;
+ TRANSLATION += incTrans;
+}
+
+void KeyboardDown(SDLKey key)
+{
+ switch (key)
+ {
+ case SDLK_w:
+ KEYMAP[K_Forward] = true;
+ break;
+ case SDLK_s:
+ KEYMAP[K_Back] = true;
+ break;
+ case SDLK_d:
+ KEYMAP[K_Right] = true;
+ break;
+ case SDLK_a:
+ KEYMAP[K_Left] = true;
+ break;
+ case SDLK_z:
+ KEYMAP[K_Down] = true;
+ break;
+ case SDLK_x:
+ KEYMAP[K_Up] = true;
+ break;
+ default:
+ break;
+ }
+}
+
+void KeyboardUp(SDLKey key)
+{
+ switch (key)
+ {
+ case SDLK_w:
+ KEYMAP[K_Forward] = false;
+ break;
+ case SDLK_s:
+ KEYMAP[K_Back] = false;
+ break;
+ case SDLK_d:
+ KEYMAP[K_Right] = false;
+ break;
+ case SDLK_a:
+ KEYMAP[K_Left] = false;
+ break;
+ case SDLK_z:
+ KEYMAP[K_Down] = false;
+ break;
+ case SDLK_x:
+ KEYMAP[K_Up] = false;
+ break;
+ default:
+ break;
+ }
+}
+
+void MouseMove(int x, int y)
+{
+ Math::Point currentPos((float)x, (float)y);
+
+ static bool first = true;
+ if (first || (x < 10) || (y < 10) || (x > 790) || (y > 590))
+ {
+ SDL_WarpMouse(400, 300);
+ MOUSE_POS_BASE.x = 400;
+ MOUSE_POS_BASE.y = 300;
+ ROTATION_BASE = ROTATION;
+ first = false;
+ return;
+ }
+
+ ROTATION.y = ROTATION_BASE.y + ((float) (x - MOUSE_POS_BASE.x) / 800.0f) * Math::PI;
+ ROTATION.x = ROTATION_BASE.x + ((float) (y - MOUSE_POS_BASE.y) / 600.0f) * Math::PI;
+}
+
+int main(int argc, char *argv[])
+{
+ CLogger logger;
+
+ PREV_TIME = CreateTimeStamp();
+ CURR_TIME = CreateTimeStamp();
+
+ GetCurrentTimeStamp(PREV_TIME);
+ GetCurrentTimeStamp(CURR_TIME);
+
+ CInstanceManager iMan;
+
+ // Without any error checking, for simplicity
+
+ SDL_Init(SDL_INIT_VIDEO);
+
+ IMG_Init(IMG_INIT_PNG);
+
+ const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
+
+ Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
+
+ if (videoInfo->hw_available)
+ videoFlags |= SDL_HWSURFACE;
+ else
+ videoFlags |= SDL_SWSURFACE;
+
+ if (videoInfo->blit_hw)
+ videoFlags |= SDL_HWACCEL;
+
+
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ SDL_Surface *surface = SDL_SetVideoMode(800, 600, 32, videoFlags);
+
+
+ SDL_WM_SetCaption("Transform Test", "Transform Test");
+
+ //SDL_WM_GrabInput(SDL_GRAB_ON);
+ SDL_ShowCursor(SDL_DISABLE);
+
+ Gfx::CGLDevice *device = new Gfx::CGLDevice();
+ device->Create();
+
+ Init(device);
+
+ bool done = false;
+ while (! done)
+ {
+ Render(device);
+ Update();
+
+ SDL_GL_SwapBuffers();
+
+ SDL_Event event;
+ while (SDL_PollEvent(&event))
+ {
+ if (event.type == SDL_QUIT)
+ {
+ break;
+ done = true;
+ }
+ else if (event.type == SDL_KEYDOWN)
+ {
+ if (event.key.keysym.sym == SDLK_q)
+ {
+ done = true;
+ break;
+ }
+ else
+ KeyboardDown(event.key.keysym.sym);
+ }
+ else if (event.type == SDL_KEYUP)
+ KeyboardUp(event.key.keysym.sym);
+ else if (event.type == SDL_MOUSEMOTION)
+ MouseMove(event.motion.x, event.motion.y);
+ }
+
+ usleep(FRAME_DELAY);
+ }
+
+ //SDL_WM_GrabInput(SDL_GRAB_OFF);
+ SDL_ShowCursor(SDL_ENABLE);
+
+ device->Destroy();
+ delete device;
+
+ SDL_FreeSurface(surface);
+
+ IMG_Quit();
+
+ SDL_Quit();
+
+ DestroyTimeStamp(PREV_TIME);
+ DestroyTimeStamp(CURR_TIME);
+
+ return 0;
+}
diff --git a/src/math/func.h b/src/math/func.h
index 8f0e4ab..9a417dc 100644
--- a/src/math/func.h
+++ b/src/math/func.h
@@ -34,15 +34,15 @@ namespace Math
/* @{ */ // start of group
//! Compares \a a and \a b within \a tolerance
-inline bool IsEqual(float a, float b, float tolerance = TOLERANCE)
+inline bool IsEqual(float a, float b, float tolerance = Math::TOLERANCE)
{
return fabs(a - b) < tolerance;
}
//! Compares \a a to zero within \a tolerance
-inline bool IsZero(float a, float tolerance = TOLERANCE)
+inline bool IsZero(float a, float tolerance = Math::TOLERANCE)
{
- return IsEqual(a, 0.0f, tolerance);
+ return Math::IsEqual(a, 0.0f, tolerance);
}
//! Minimum
@@ -59,12 +59,12 @@ inline float Min(float a, float b, float c)
inline float Min(float a, float b, float c, float d)
{
- return Min( Min(a, b), Min(c, d) );
+ return Math::Min( Math::Min(a, b), Math::Min(c, d) );
}
inline float Min(float a, float b, float c, float d, float e)
{
- return Min( Min(a, b), Min(c, d), e );
+ return Math::Min( Math::Min(a, b), Math::Min(c, d), e );
}
//! Maximum
@@ -76,17 +76,17 @@ inline float Max(float a, float b)
inline float Max(float a, float b, float c)
{
- return Max( Max(a, b), c );
+ return Math::Max( Math::Max(a, b), c );
}
inline float Max(float a, float b, float c, float d)
{
- return Max( Max(a, b), Max(c, d) );
+ return Math::Max( Math::Max(a, b), Math::Max(c, d) );
}
inline float Max(float a, float b, float c, float d, float e)
{
- return Max( Max(a, b), Max(c, d), e );
+ return Math::Max( Math::Max(a, b), Math::Max(c, d), e );
}
//! Returns the normalized value (0 .. 1)
@@ -130,7 +130,7 @@ inline float Rand()
//! Returns a normalized angle, that is in other words between 0 and 2 * PI
inline float NormAngle(float angle)
{
- angle = Mod(angle, PI*2.0f);
+ angle = Math::Mod(angle, PI*2.0f);
if ( angle < 0.0f )
return PI*2.0f + angle;
@@ -140,9 +140,9 @@ inline float NormAngle(float angle)
//! Test if a angle is between two terminals
inline bool TestAngle(float angle, float min, float max)
{
- angle = NormAngle(angle);
- min = NormAngle(min);
- max = NormAngle(max);
+ angle = Math::NormAngle(angle);
+ min = Math::NormAngle(min);
+ max = Math::NormAngle(max);
if ( min > max )
return ( angle <= max || angle >= min );
@@ -163,8 +163,8 @@ inline float PropAngle(int a, int b, float p)
/** A positive angle is counterclockwise (CCW). */
inline float Direction(float a, float g)
{
- a = NormAngle(a);
- g = NormAngle(g);
+ a = Math::NormAngle(a);
+ g = Math::NormAngle(g);
if ( a < g )
{
diff --git a/src/math/geometry.h b/src/math/geometry.h
index 2f937e5..61d1868 100644
--- a/src/math/geometry.h
+++ b/src/math/geometry.h
@@ -40,7 +40,7 @@ namespace Math
//! Returns py up on the line \a a - \a b
-inline float MidPoint(const Point &a, const Point &b, float px)
+inline float MidPoint(const Math::Point &a, const Math::Point &b, float px)
{
if (IsEqual(a.x, b.x))
{
@@ -53,7 +53,7 @@ inline float MidPoint(const Point &a, const Point &b, float px)
}
//! Tests whether the point \a p is inside the triangle (\a a,\a b,\a c)
-inline bool IsInsideTriangle(Point a, Point b, Point c, Point p)
+inline bool IsInsideTriangle(Math::Point a, Math::Point b, Math::Point c, Math::Point p)
{
float n, m;
@@ -82,13 +82,13 @@ inline bool IsInsideTriangle(Point a, Point b, Point c, Point p)
/** \a center center of rotation
\a angle angle is in radians (positive is counterclockwise (CCW) )
\a p the point */
-inline Point RotatePoint(const Point &center, float angle, const Point &p)
+inline Math::Point RotatePoint(const Math::Point &center, float angle, const Math::Point &p)
{
- Point a;
+ Math::Point a;
a.x = p.x-center.x;
a.y = p.y-center.y;
- Point b;
+ Math::Point b;
b.x = a.x*cosf(angle) - a.y*sinf(angle);
b.y = a.x*sinf(angle) + a.y*cosf(angle);
@@ -101,23 +101,23 @@ inline Point RotatePoint(const Point &center, float angle, const Point &p)
//! Rotates a point around the origin (0,0)
/** \a angle angle in radians (positive is counterclockwise (CCW) )
\a p the point */
-inline Point RotatePoint(float angle, const Point &p)
+inline Math::Point RotatePoint(float angle, const Math::Point &p)
{
float x = p.x*cosf(angle) - p.y*sinf(angle);
float y = p.x*sinf(angle) + p.y*cosf(angle);
- return Point(x, y);
+ return Math::Point(x, y);
}
//! Rotates a vector (dist, 0).
/** \a angle angle is in radians (positive is counterclockwise (CCW) )
\a dist distance to origin */
-inline Point RotatePoint(float angle, float dist)
+inline Math::Point RotatePoint(float angle, float dist)
{
float x = dist*cosf(angle);
float y = dist*sinf(angle);
- return Point(x, y);
+ return Math::Point(x, y);
}
//! TODO documentation
@@ -140,13 +140,13 @@ inline void RotatePoint(float cx, float cy, float angle, float &px, float &py)
\a angleH,angleV rotation angles in radians (positive is counterclockwise (CCW) ) )
\a p the point
\returns the rotated point */
-inline void RotatePoint(const Vector &center, float angleH, float angleV, Vector &p)
+inline void RotatePoint(const Math::Vector &center, float angleH, float angleV, Math::Vector &p)
{
p.x -= center.x;
p.y -= center.y;
p.z -= center.z;
- Vector b;
+ Math::Vector b;
b.x = p.x*cosf(angleH) - p.z*sinf(angleH);
b.y = p.z*sinf(angleV) + p.y*cosf(angleV);
b.z = p.x*sinf(angleH) + p.z*cosf(angleH);
@@ -159,18 +159,18 @@ inline void RotatePoint(const Vector &center, float angleH, float angleV, Vector
\a angleH,angleV rotation angles in radians (positive is counterclockwise (CCW) ) )
\a p the point
\returns the rotated point */
-inline void RotatePoint2(const Vector center, float angleH, float angleV, Vector &p)
+inline void RotatePoint2(const Math::Vector center, float angleH, float angleV, Math::Vector &p)
{
p.x -= center.x;
p.y -= center.y;
p.z -= center.z;
- Vector a;
+ Math::Vector a;
a.x = p.x*cosf(angleH) - p.z*sinf(angleH);
a.y = p.y;
a.z = p.x*sinf(angleH) + p.z*cosf(angleH);
- Vector b;
+ Math::Vector b;
b.x = a.x;
b.y = a.z*sinf(angleV) + a.y*cosf(angleV);
b.z = a.z*cosf(angleV) - a.y*sinf(angleV);
@@ -196,7 +196,7 @@ inline float RotateAngle(float x, float y)
/** \a center the center point
\a p1,p2 the two points
\returns The angle in radians (positive is counterclockwise (CCW) ) */
-inline float RotateAngle(const Point &center, const Point &p1, const Point &p2)
+inline float RotateAngle(const Math::Point &center, const Math::Point &p1, const Math::Point &p2)
{
if (PointsEqual(p1, center))
return 0;
@@ -221,11 +221,12 @@ inline float RotateAngle(const Point &center, const Point &p1, const Point &p2)
/** \a from origin
\a at view direction
\a worldUp up vector */
-inline void LoadViewMatrix(Matrix &mat, const Vector &from, const Vector &at, const Vector &worldUp)
+inline void LoadViewMatrix(Math::Matrix &mat, const Math::Vector &from,
+ const Math::Vector &at, const Math::Vector &worldUp)
{
// Get the z basis vector, which points straight ahead. This is the
// difference from the eyepoint to the lookat point.
- Vector view = at - from;
+ Math::Vector view = at - from;
float length = view.Length();
assert(! IsZero(length) );
@@ -237,18 +238,18 @@ inline void LoadViewMatrix(Matrix &mat, const Vector &from, const Vector &at, co
// vector onto the up vector. The projection is the y basis vector.
float dotProduct = DotProduct(worldUp, view);
- Vector up = worldUp - dotProduct * view;
+ Math::Vector up = worldUp - dotProduct * view;
// If this vector has near-zero length because the input specified a
// bogus up vector, let's try a default up vector
if ( IsZero(length = up.Length()) )
{
- up = Vector(0.0f, 1.0f, 0.0f) - view.y * view;
+ up = Math::Vector(0.0f, 1.0f, 0.0f) - view.y * view;
// If we still have near-zero length, resort to a different axis.
if ( IsZero(length = up.Length()) )
{
- up = Vector(0.0f, 0.0f, 1.0f) - view.z * view;
+ up = Math::Vector(0.0f, 0.0f, 1.0f) - view.z * view;
assert(! IsZero(up.Length()) );
}
@@ -259,7 +260,7 @@ inline void LoadViewMatrix(Matrix &mat, const Vector &from, const Vector &at, co
// The x basis vector is found simply with the cross product of the y
// and z basis vectors
- Vector right = CrossProduct(up, view);
+ Math::Vector right = CrossProduct(up, view);
// Start building the matrix. The first three rows contains the basis
// vectors used to rotate the view to point at the lookat point
@@ -286,28 +287,44 @@ inline void LoadViewMatrix(Matrix &mat, const Vector &from, const Vector &at, co
\a aspect aspect ratio (width / height)
\a nearPlane distance to near cut plane
\a farPlane distance to far cut plane */
-inline void LoadProjectionMatrix(Matrix &mat, float fov = 1.570795f, float aspect = 1.0f,
+inline void LoadProjectionMatrix(Math::Matrix &mat, float fov = Math::PI / 2.0f, float aspect = 1.0f,
float nearPlane = 1.0f, float farPlane = 1000.0f)
{
assert(fabs(farPlane - nearPlane) >= 0.01f);
assert(fabs(sin(fov / 2)) >= 0.01f);
- float w = aspect * (cosf(fov / 2) / sinf(fov / 2));
- float h = 1.0f * (cosf(fov / 2) / sinf(fov / 2));
- float q = farPlane / (farPlane - nearPlane);
+ float f = cosf(fov / 2.0f) / sinf(fov / 2.0f);
mat.LoadZero();
- /* (1,1) */ mat.m[0 ] = w;
- /* (2,2) */ mat.m[5 ] = h;
- /* (3,3) */ mat.m[10] = q;
- /* (4,3) */ mat.m[11] = 1.0f;
- /* (3,4) */ mat.m[14] = -q * nearPlane;
+ /* (1,1) */ mat.m[0 ] = f / aspect;
+ /* (2,2) */ mat.m[5 ] = f;
+ /* (3,3) */ mat.m[10] = (nearPlane + farPlane) / (nearPlane - farPlane);
+ /* (4,3) */ mat.m[11] = -1.0f;
+ /* (3,4) */ mat.m[14] = (2.0f * farPlane * nearPlane) / (nearPlane - farPlane);
+}
+
+//! Loads an othogonal projection matrix
+/** \a left,right coordinates for left and right vertical clipping planes
+ \a bottom,top coordinates for bottom and top horizontal clipping planes
+ \a zNear,zFar distance to nearer and farther depth clipping planes */
+inline void LoadOrthoProjectionMatrix(Math::Matrix &mat, float left, float right, float bottom, float top,
+ float zNear = -1.0f, float zFar = 1.0f)
+{
+ mat.LoadIdentity();
+
+ /* (1,1) */ mat.m[0 ] = 2.0f / (right - left);
+ /* (2,2) */ mat.m[5 ] = 2.0f / (top - bottom);
+ /* (3,3) */ mat.m[10] = -2.0f / (zFar - zNear);
+
+ /* (1,4) */ mat.m[12] = - (right + left) / (right - left);
+ /* (2,4) */ mat.m[13] = - (top + bottom) / (top - bottom);
+ /* (3,4) */ mat.m[14] = - (zFar + zNear) / (zFar - zNear);
}
//! Loads a translation matrix from given vector
/** \a trans vector of translation*/
-inline void LoadTranslationMatrix(Matrix &mat, const Vector &trans)
+inline void LoadTranslationMatrix(Math::Matrix &mat, const Math::Vector &trans)
{
mat.LoadIdentity();
/* (1,4) */ mat.m[12] = trans.x;
@@ -317,7 +334,7 @@ inline void LoadTranslationMatrix(Matrix &mat, const Vector &trans)
//! Loads a scaling matrix fom given vector
/** \a scale vector with scaling factors for X, Y, Z */
-inline void LoadScaleMatrix(Matrix &mat, const Vector &scale)
+inline void LoadScaleMatrix(Math::Matrix &mat, const Math::Vector &scale)
{
mat.LoadIdentity();
/* (1,1) */ mat.m[0 ] = scale.x;
@@ -327,7 +344,7 @@ inline void LoadScaleMatrix(Matrix &mat, const Vector &scale)
//! Loads a rotation matrix along the X axis
/** \a angle angle in radians */
-inline void LoadRotationXMatrix(Matrix &mat, float angle)
+inline void LoadRotationXMatrix(Math::Matrix &mat, float angle)
{
mat.LoadIdentity();
/* (2,2) */ mat.m[5 ] = cosf(angle);
@@ -338,7 +355,7 @@ inline void LoadRotationXMatrix(Matrix &mat, float angle)
//! Loads a rotation matrix along the Y axis
/** \a angle angle in radians */
-inline void LoadRotationYMatrix(Matrix &mat, float angle)
+inline void LoadRotationYMatrix(Math::Matrix &mat, float angle)
{
mat.LoadIdentity();
/* (1,1) */ mat.m[0 ] = cosf(angle);
@@ -349,7 +366,7 @@ inline void LoadRotationYMatrix(Matrix &mat, float angle)
//! Loads a rotation matrix along the Z axis
/** \a angle angle in radians */
-inline void LoadRotationZMatrix(Matrix &mat, float angle)
+inline void LoadRotationZMatrix(Math::Matrix &mat, float angle)
{
mat.LoadIdentity();
/* (1,1) */ mat.m[0 ] = cosf(angle);
@@ -361,11 +378,11 @@ inline void LoadRotationZMatrix(Matrix &mat, float angle)
//! Loads a rotation matrix along the given axis
/** \a dir axis of rotation
\a angle angle in radians */
-inline void LoadRotationMatrix(Matrix &mat, const Vector &dir, float angle)
+inline void LoadRotationMatrix(Math::Matrix &mat, const Math::Vector &dir, float angle)
{
float cos = cosf(angle);
float sin = sinf(angle);
- Vector v = Normalize(dir);
+ Math::Vector v = Normalize(dir);
mat.LoadIdentity();
@@ -383,9 +400,9 @@ inline void LoadRotationMatrix(Matrix &mat, const Vector &dir, float angle)
}
//! Calculates the matrix to make three rotations in the order X, Z and Y
-inline void LoadRotationXZYMatrix(Matrix &mat, const Vector &angle)
+inline void LoadRotationXZYMatrix(Math::Matrix &mat, const Math::Vector &angle)
{
- Matrix temp;
+ Math::Matrix temp;
LoadRotationXMatrix(temp, angle.x);
LoadRotationZMatrix(mat, angle.z);
@@ -396,9 +413,9 @@ inline void LoadRotationXZYMatrix(Matrix &mat, const Vector &angle)
}
//! Calculates the matrix to make three rotations in the order Z, X and Y
-inline void LoadRotationZXYMatrix(Matrix &mat, const Vector &angle)
+inline void LoadRotationZXYMatrix(Math::Matrix &mat, const Math::Vector &angle)
{
- Matrix temp;
+ Math::Matrix temp;
LoadRotationZMatrix(temp, angle.z);
LoadRotationXMatrix(mat, angle.x);
@@ -409,7 +426,7 @@ inline void LoadRotationZXYMatrix(Matrix &mat, const Vector &angle)
}
//! Returns the distance between projections on XZ plane of two vectors
-inline float DistanceProjected(const Vector &a, const Vector &b)
+inline float DistanceProjected(const Math::Vector &a, const Math::Vector &b)
{
return sqrtf( (a.x-b.x)*(a.x-b.x) +
(a.z-b.z)*(a.z-b.z) );
@@ -417,10 +434,10 @@ inline float DistanceProjected(const Vector &a, const Vector &b)
//! Returns the normal vector to a plane
/** \param p1,p2,p3 points defining the plane */
-inline Vector NormalToPlane(const Vector &p1, const Vector &p2, const Vector &p3)
+inline Math::Vector NormalToPlane(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3)
{
- Vector u = p3 - p1;
- Vector v = p2 - p1;
+ Math::Vector u = p3 - p1;
+ Math::Vector v = p2 - p1;
return Normalize(CrossProduct(u, v));
}
@@ -428,7 +445,7 @@ inline Vector NormalToPlane(const Vector &p1, const Vector &p2, const Vector &p3
//! Returns a point on the line \a p1 - \a p2, in \a dist distance from \a p1
/** \a p1,p2 line start and end
\a dist scaling factor from \a p1, relative to distance between \a p1 and \a p2 */
-inline Vector SegmentPoint(const Vector &p1, const Vector &p2, float dist)
+inline Math::Vector SegmentPoint(const Math::Vector &p1, const Math::Vector &p2, float dist)
{
return p1 + (p2 - p1) * dist;
}
@@ -436,9 +453,10 @@ inline Vector SegmentPoint(const Vector &p1, const Vector &p2, float dist)
//! Returns the distance between given point and a plane
/** \param p the point
\param a,b,c points defining the plane */
-inline float DistanceToPlane(const Vector &a, const Vector &b, const Vector &c, const Vector &p)
+inline float DistanceToPlane(const Math::Vector &a, const Math::Vector &b,
+ const Math::Vector &c, const Math::Vector &p)
{
- Vector n = NormalToPlane(a, b, c);
+ Math::Vector n = NormalToPlane(a, b, c);
float d = -(n.x*a.x + n.y*a.y + n.z*a.z);
return fabs(n.x*p.x + n.y*p.y + n.z*p.z + d);
@@ -447,10 +465,10 @@ inline float DistanceToPlane(const Vector &a, const Vector &b, const Vector &c,
//! Checks if two planes defined by three points are the same
/** \a plane1 array of three vectors defining the first plane
\a plane2 array of three vectors defining the second plane */
-inline bool IsSamePlane(const Vector (&plane1)[3], const Vector (&plane2)[3])
+inline bool IsSamePlane(const Math::Vector (&plane1)[3], const Math::Vector (&plane2)[3])
{
- Vector n1 = NormalToPlane(plane1[0], plane1[1], plane1[2]);
- Vector n2 = NormalToPlane(plane2[0], plane2[1], plane2[2]);
+ Math::Vector n1 = NormalToPlane(plane1[0], plane1[1], plane1[2]);
+ Math::Vector n2 = NormalToPlane(plane2[0], plane2[1], plane2[2]);
if ( fabs(n1.x-n2.x) > 0.1f ||
fabs(n1.y-n2.y) > 0.1f ||
@@ -465,7 +483,8 @@ inline bool IsSamePlane(const Vector (&plane1)[3], const Vector (&plane2)[3])
}
//! Calculates the intersection "i" right "of" the plane "abc".
-inline bool Intersect(const Vector &a, const Vector &b, const Vector &c, const Vector &d, const Vector &e, Vector &i)
+inline bool Intersect(const Math::Vector &a, const Math::Vector &b, const Math::Vector &c,
+ const Math::Vector &d, const Math::Vector &e, Math::Vector &i)
{
float d1 = (d.x-a.x)*((b.y-a.y)*(c.z-a.z)-(c.y-a.y)*(b.z-a.z)) -
(d.y-a.y)*((b.x-a.x)*(c.z-a.z)-(c.x-a.x)*(b.z-a.z)) +
@@ -487,7 +506,7 @@ inline bool Intersect(const Vector &a, const Vector &b, const Vector &c, const V
//! Calculates the intersection of the straight line passing through p (x, z)
/** Line is parallel to the y axis, with the plane abc. Returns p.y. */
-inline bool IntersectY(const Vector &a, const Vector &b, const Vector &c, Vector &p)
+inline bool IntersectY(const Math::Vector &a, const Math::Vector &b, const Math::Vector &c, Math::Vector &p)
{
float d = (b.x-a.x)*(c.z-a.z) - (c.x-a.x)*(b.z-a.z);
float d1 = (p.x-a.x)*(c.z-a.z) - (c.x-a.x)*(p.z-a.z);
@@ -502,9 +521,9 @@ inline bool IntersectY(const Vector &a, const Vector &b, const Vector &c, Vector
}
//! Calculates the end point
-inline Vector LookatPoint(const Vector &eye, float angleH, float angleV, float length)
+inline Math::Vector LookatPoint(const Math::Vector &eye, float angleH, float angleV, float length)
{
- Vector lookat = eye;
+ Math::Vector lookat = eye;
lookat.z += length;
RotatePoint(eye, angleH, angleV, lookat);
@@ -513,7 +532,7 @@ inline Vector LookatPoint(const Vector &eye, float angleH, float angleV, float l
}
//! TODO documentation
-inline Vector Transform(const Matrix &m, const Vector &p)
+inline Math::Vector Transform(const Math::Matrix &m, const Math::Vector &p)
{
return MatrixVectorMultiply(m, p);
}
@@ -521,7 +540,7 @@ inline Vector Transform(const Matrix &m, const Vector &p)
//! Calculates the projection of the point \a p on a straight line \a a to \a b.
/** \a p point to project
\a a,b two ends of the line */
-inline Vector Projection(const Vector &a, const Vector &b, const Vector &p)
+inline Math::Vector Projection(const Math::Vector &a, const Math::Vector &b, const Math::Vector &p)
{
float k = DotProduct(b - a, p - a);
k /= DotProduct(b - a, b - a);
@@ -530,15 +549,15 @@ inline Vector Projection(const Vector &a, const Vector &b, const Vector &p)
}
//! Calculates point of view to look at a center two angles and a distance
-inline Vector RotateView(Vector center, float angleH, float angleV, float dist)
+inline Math::Vector RotateView(Math::Vector center, float angleH, float angleV, float dist)
{
- Matrix mat1, mat2;
+ Math::Matrix mat1, mat2;
LoadRotationZMatrix(mat1, -angleV);
LoadRotationYMatrix(mat2, -angleH);
- Matrix mat = MultiplyMatrices(mat2, mat1);
+ Math::Matrix mat = MultiplyMatrices(mat2, mat1);
- Vector eye;
+ Math::Vector eye;
eye.x = 0.0f+dist;
eye.y = 0.0f;
eye.z = 0.0f;
diff --git a/src/math/matrix.h b/src/math/matrix.h
index 9b29f46..7ee40e8 100644
--- a/src/math/matrix.h
+++ b/src/math/matrix.h
@@ -118,6 +118,12 @@ struct Matrix
/* (4,4) */ m[15] = 1.0f;
}
+ //! Returns the struct cast to \c float* array; use with care!
+ inline float* Array()
+ {
+ return (float*)this;
+ }
+
//! Transposes the matrix
inline void Transpose()
{
@@ -382,9 +388,9 @@ inline bool MatricesEqual(const Matrix &m1, const Matrix &m2,
}
//! Convenience function for getting transposed matrix
-inline Matrix Transpose(const Matrix &m)
+inline Math::Matrix Transpose(const Math::Matrix &m)
{
- Matrix result = m;
+ Math::Matrix result = m;
result.Transpose();
return result;
}
@@ -393,7 +399,7 @@ inline Matrix Transpose(const Matrix &m)
/** \a left left-hand matrix
\a right right-hand matrix
\returns multiplied matrices */
-inline Matrix MultiplyMatrices(const Matrix &left, const Matrix &right)
+inline Math::Matrix MultiplyMatrices(const Math::Matrix &left, const Math::Matrix &right)
{
return left.Multiply(right);
}
@@ -407,25 +413,25 @@ inline Matrix MultiplyMatrices(const Matrix &left, const Matrix &right)
The result, a 4x1 vector is then converted to 3x1 by dividing
x,y,z coords by the fourth coord (w). */
-inline Vector MatrixVectorMultiply(const Matrix &m, const Vector &v, bool wDivide = false)
+inline Math::Vector MatrixVectorMultiply(const Math::Matrix &m, const Math::Vector &v, bool wDivide = false)
{
float x = v.x * m.m[0 ] + v.y * m.m[4 ] + v.z * m.m[8 ] + m.m[12];
float y = v.x * m.m[1 ] + v.y * m.m[5 ] + v.z * m.m[9 ] + m.m[13];
float z = v.x * m.m[2 ] + v.y * m.m[6 ] + v.z * m.m[10] + m.m[14];
if (!wDivide)
- return Vector(x, y, z);
+ return Math::Vector(x, y, z);
float w = v.x * m.m[3 ] + v.y * m.m[7 ] + v.z * m.m[11] + m.m[15];
if (IsZero(w))
- return Vector(x, y, z);
+ return Math::Vector(x, y, z);
x /= w;
y /= w;
z /= w;
- return Vector(x, y, z);
+ return Math::Vector(x, y, z);
}
/* @} */ // end of group
diff --git a/src/math/point.h b/src/math/point.h
index 84be190..740b275 100644
--- a/src/math/point.h
+++ b/src/math/point.h
@@ -24,6 +24,7 @@
#include "func.h"
#include <cmath>
+#include <sstream>
// Math module namespace
@@ -67,6 +68,18 @@ struct Point
x = y = 0.0f;
}
+ //! Returns the struct cast to \c float* array; use with care!
+ inline float* Array()
+ {
+ return (float*)this;
+ }
+
+ //! Returns the struct cast to <tt>const float*</tt> array; use with care!
+ inline const float* Array() const
+ {
+ return (const float*)this;
+ }
+
//! Returns the distance from (0,0) to the point (x,y)
inline float Length()
{
@@ -141,6 +154,15 @@ struct Point
return Point(left.x / right, left.y / right);
}
+
+ //! Returns a string "[x, y]"
+ inline std::string ToString() const
+ {
+ std::stringstream s;
+ s.precision(3);
+ s << "[" << x << ", " << y << "]";
+ return s.str();
+ }
}; // struct Point
diff --git a/src/math/vector.h b/src/math/vector.h
index 3c756f2..148d648 100644
--- a/src/math/vector.h
+++ b/src/math/vector.h
@@ -24,6 +24,7 @@
#include "func.h"
#include <cmath>
+#include <sstream>
// Math module namespace
@@ -72,6 +73,18 @@ struct Vector
x = y = z = 0.0f;
}
+ //! Returns the struct cast to \c float* array; use with care!
+ inline float* Array()
+ {
+ return (float*)this;
+ }
+
+ //! Returns the struct cast to <tt>const float*</tt> array; use with care!
+ inline const float* Array() const
+ {
+ return (const float*)this;
+ }
+
//! Returns the vector length
inline float Length() const
{
@@ -196,10 +209,20 @@ struct Vector
return Vector(left.x / right, left.y / right, left.z / right);
}
+
+ //! Returns a string "[x, y, z]"
+ inline std::string ToString() const
+ {
+ std::stringstream s;
+ s.precision(3);
+ s << "[" << x << ", " << y << ", " << z << "]";
+ return s.str();
+ }
+
}; // struct Point
//! Checks if two vectors are equal within given \a tolerance
-inline bool VectorsEqual(const Vector &a, const Vector &b, float tolerance = TOLERANCE)
+inline bool VectorsEqual(const Math::Vector &a, const Math::Vector &b, float tolerance = TOLERANCE)
{
return IsEqual(a.x, b.x, tolerance)
&& IsEqual(a.y, b.y, tolerance)
@@ -207,7 +230,7 @@ inline bool VectorsEqual(const Vector &a, const Vector &b, float tolerance = TOL
}
//! Convenience function for getting normalized vector
-inline Vector Normalize(const Vector &v)
+inline Vector Normalize(const Math::Vector &v)
{
Vector result = v;
result.Normalize();
@@ -215,25 +238,25 @@ inline Vector Normalize(const Vector &v)
}
//! Convenience function for calculating dot product
-inline float DotProduct(const Vector &left, const Vector &right)
+inline float DotProduct(const Math::Vector &left, const Math::Vector &right)
{
return left.DotMultiply(right);
}
//! Convenience function for calculating cross product
-inline Vector CrossProduct(const Vector &left, const Vector &right)
+inline Vector CrossProduct(const Math::Vector &left, const Math::Vector &right)
{
return left.CrossMultiply(right);
}
//! Convenience function for calculating angle (in radians) between two vectors
-inline float Angle(const Vector &a, const Vector &b)
+inline float Angle(const Math::Vector &a, const Math::Vector &b)
{
return a.Angle(b);
}
//! Returns the distance between the ends of two vectors
-inline float Distance(const Vector &a, const Vector &b)
+inline float Distance(const Math::Vector &a, const Math::Vector &b)
{
return sqrtf( (a.x-b.x)*(a.x-b.x) +
(a.y-b.y)*(a.y-b.y) +
diff --git a/src/sound/sound.h b/src/sound/sound.h
index 2eb92a0..d27721a 100644
--- a/src/sound/sound.h
+++ b/src/sound/sound.h
@@ -30,6 +30,7 @@
#include <string>
+
/*!
* Maximum possible audio volume
*/