summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPiotr Dziwinski <piotrdz@gmail.com>2012-07-15 19:17:49 +0200
committerPiotr Dziwinski <piotrdz@gmail.com>2012-07-15 19:17:49 +0200
commit54f4da87923465a5387e2e854b58616647deb7af (patch)
treefc52b1866b29393be7d61a2341f04d430c078fdd
parenteca6d26459200d2956d64ccf8a2713d96a82c989 (diff)
downloadcolobot-54f4da87923465a5387e2e854b58616647deb7af.tar.gz
colobot-54f4da87923465a5387e2e854b58616647deb7af.tar.bz2
colobot-54f4da87923465a5387e2e854b58616647deb7af.zip
Fix in model loading; simple model viewer
- fixed model loading code - added simple model viewer (model_test) in src/graphics/opengl/test - added system time stamp code - split the code in app/system modules to separate headers - added debug messages in model loading - minor fixes in OpenGL engine
-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/singleton.h2
-rw-r--r--src/graphics/common/color.h21
-rw-r--r--src/graphics/common/modelfile.cpp38
-rw-r--r--src/graphics/common/modelfile.h4
-rw-r--r--src/graphics/common/vertex.h34
-rw-r--r--src/graphics/opengl/gldevice.cpp76
-rw-r--r--src/graphics/opengl/test/CMakeLists.txt42
-rw-r--r--src/graphics/opengl/test/README.txt7
-rw-r--r--src/graphics/opengl/test/model_test.cpp385
-rw-r--r--src/graphics/opengl/test/texture_test.cpp1
-rw-r--r--src/math/point.h10
-rw-r--r--src/math/vector.h11
17 files changed, 1080 insertions, 236 deletions
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/singleton.h b/src/common/singleton.h
index dc09645..ee01b24 100644
--- a/src/common/singleton.h
+++ b/src/common/singleton.h
@@ -47,7 +47,7 @@ template<typename T> class CSingleton
mInstance = static_cast<T *>(this);
}
- ~CSingleton() {
+ virtual ~CSingleton() {
mInstance = NULL;
}
diff --git a/src/graphics/common/color.h b/src/graphics/common/color.h
index 3b19cf2..68421c7 100644
--- a/src/graphics/common/color.h
+++ b/src/graphics/common/color.h
@@ -19,6 +19,9 @@
#pragma once
+#include <sstream>
+
+
namespace Gfx {
/**
@@ -38,6 +41,15 @@ struct Color
{
return (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();
+ }
};
/**
@@ -49,6 +61,15 @@ struct ColorHSV
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
diff --git a/src/graphics/common/modelfile.cpp b/src/graphics/common/modelfile.cpp
index 8e509fe..22801e8 100644
--- a/src/graphics/common/modelfile.cpp
+++ b/src/graphics/common/modelfile.cpp
@@ -21,6 +21,7 @@
#include "common/iman.h"
#include "common/ioutils.h"
+#include "common/logger.h"
#include "common/stringutils.h"
#include "math/geometry.h"
@@ -205,8 +206,6 @@ Gfx::Material ReadBinaryMaterial(std::istream &stream)
/* power = */ IOUtils::ReadBinaryFloat(stream);
- /* padding? */ IOUtils::ReadBinary<2, unsigned int>(stream);
-
return result;
}
@@ -233,8 +232,6 @@ void WriteBinaryMaterial(Gfx::Material material, std::ostream &stream)
/* emissive.a */ IOUtils::WriteBinaryFloat(0.0f, stream);
/* power */ IOUtils::WriteBinaryFloat(0.0f, stream);
-
- /* padding? */ IOUtils::WriteBinary<2, unsigned int>(0, stream);
}
Gfx::ModelTriangle::ModelTriangle()
@@ -390,6 +387,8 @@ bool Gfx::CModelFile::ReadModel(std::istream &stream, bool edit, bool meta)
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);
@@ -422,16 +421,38 @@ bool Gfx::CModelFile::ReadModel(std::istream &stream, bool edit, bool meta)
triangle.min = t.min;
triangle.max = t.max;
triangle.state = t.state;
- sprintf(tex2Name, "dirty%.2d.tga", t.texNum2); // hardcoded as in the original code
+
+ 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)
{
@@ -769,6 +790,11 @@ void Gfx::CModelFile::Mirror()
}
}
+std::vector<Gfx::ModelTriangle>& Gfx::CModelFile::GetTriangles()
+{
+ return m_triangles;
+}
+
int Gfx::CModelFile::GetTriangleCount()
{
return m_triangles.size();
diff --git a/src/graphics/common/modelfile.h b/src/graphics/common/modelfile.h
index 625df50..f8cb022 100644
--- a/src/graphics/common/modelfile.h
+++ b/src/graphics/common/modelfile.h
@@ -91,6 +91,8 @@ public:
//! 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);
@@ -106,7 +108,7 @@ protected:
protected:
CInstanceManager* m_iMan;
- CEngine* m_engine;
+ Gfx::CEngine* m_engine;
//! Last error
std::string m_error;
diff --git a/src/graphics/common/vertex.h b/src/graphics/common/vertex.h
index c6375b9..0a74587 100644
--- a/src/graphics/common/vertex.h
+++ b/src/graphics/common/vertex.h
@@ -23,6 +23,8 @@
#include "math/vector.h"
#include "math/point.h"
+#include <sstream>
+
namespace Gfx {
/**
@@ -46,6 +48,17 @@ struct Vertex
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();
+ }
};
/**
@@ -72,6 +85,16 @@ struct VertexCol
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();
+ }
};
@@ -95,6 +118,7 @@ struct VertexTex2
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;
@@ -102,6 +126,16 @@ struct VertexTex2
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/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp
index f253568..eb4eb31 100644
--- a/src/graphics/opengl/gldevice.cpp
+++ b/src/graphics/opengl/gldevice.cpp
@@ -19,6 +19,8 @@
#include "common/image.h"
#include "graphics/opengl/gldevice.h"
+#define GL_GLEXT_PROTOTYPES
+
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glext.h>
@@ -121,6 +123,9 @@ bool Gfx::CGLDevice::Create()
// 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);
+
// Set just to be sure
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glMatrixMode(GL_PROJECTION);
@@ -174,7 +179,7 @@ void Gfx::CGLDevice::BeginScene()
void Gfx::CGLDevice::EndScene()
{
- glFlush();
+ glFinish();
}
void Gfx::CGLDevice::Clear()
@@ -256,9 +261,9 @@ void Gfx::CGLDevice::SetMaterial(Gfx::Material &material)
{
m_material = material;
- glMaterialfv(GL_AMBIENT, GL_FRONT_AND_BACK, m_material.ambient.Array());
- glMaterialfv(GL_DIFFUSE, GL_FRONT_AND_BACK, m_material.diffuse.Array());
- glMaterialfv(GL_SPECULAR, GL_FRONT_AND_BACK, m_material.specular.Array());
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, m_material.ambient.Array());
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, m_material.diffuse.Array());
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, m_material.specular.Array());
}
const Gfx::Material& Gfx::CGLDevice::GetMaterial()
@@ -517,78 +522,77 @@ void Gfx::CGLDevice::SetTextureParams(int index, const Gfx::TextureParams &param
// Don't actually do anything if texture not set
if (m_textures[index] == NULL)
- {
- printf("No texture set: %d\n", index);
return;
- }
// Enable the given stage
glActiveTextureARB(GL_TEXTURE0_ARB + index);
glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, m_textures[index]->id);
+
// Selection of operation and arguments
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
// Color operation
if (params.colorOperation == Gfx::TEX_MIX_OPER_MODULATE)
- glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_RGB, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_RGB_ARB, GL_MODULATE);
else if (params.colorOperation == Gfx::TEX_MIX_OPER_ADD)
- glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_RGB, GL_ADD);
+ glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_RGB_ARB, GL_ADD);
else assert(false);
// Color arg1
if (params.colorArg1 == Gfx::TEX_MIX_ARG_CURRENT)
{
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); // that's right - stupid D3D enum values
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS); // that's right - stupid D3D enum values
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
}
else if (params.colorArg1 == Gfx::TEX_MIX_ARG_TEXTURE)
{
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
}
else if (params.colorArg1 == Gfx::TEX_MIX_ARG_DIFFUSE)
{
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR); // here as well
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR); // here as well
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
}
else assert(false);
// Color arg2
if (params.colorArg2 == Gfx::TEX_MIX_ARG_CURRENT)
{
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
}
else if (params.colorArg2 == Gfx::TEX_MIX_ARG_TEXTURE)
{
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
}
else if (params.colorArg2 == Gfx::TEX_MIX_ARG_DIFFUSE)
{
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
}
else assert(false);
// Alpha operation
if (params.alphaOperation == Gfx::TEX_MIX_OPER_MODULATE)
- glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_ALPHA, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
else if (params.alphaOperation == Gfx::TEX_MIX_OPER_ADD)
- glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_ALPHA, GL_ADD);
+ glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_ALPHA_ARB, GL_ADD);
else assert(false);
// Alpha arg1
if (params.alphaArg1 == Gfx::TEX_MIX_ARG_CURRENT)
{
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
}
else if (params.alphaArg1 == Gfx::TEX_MIX_ARG_TEXTURE)
{
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
}
else if (params.alphaArg1 == Gfx::TEX_MIX_ARG_DIFFUSE)
{
@@ -600,18 +604,18 @@ void Gfx::CGLDevice::SetTextureParams(int index, const Gfx::TextureParams &param
// Alpha arg2
if (params.alphaArg2 == Gfx::TEX_MIX_ARG_CURRENT)
{
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
}
else if (params.alphaArg2 == Gfx::TEX_MIX_ARG_TEXTURE)
{
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
}
else if (params.alphaArg2 == Gfx::TEX_MIX_ARG_DIFFUSE)
{
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PRIMARY_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
}
else assert(false);
@@ -670,7 +674,7 @@ void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, Vertex *vertices, in
else if (type == Gfx::PRIMITIVE_TRIANGLE_STRIP)
glBegin(GL_TRIANGLE_STRIP);
- glColor3f(1.0f, 1.0f, 1.0f); // TODO: set global color?
+ glColor3f(1.0f, 1.0f, 1.0f);
for (int i = 0; i < vertexCount; ++i)
{
@@ -693,8 +697,8 @@ void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, Gfx::VertexCol *vert
for (int i = 0; i < vertexCount; ++i)
{
- // TODO: specular through EXT_separate_specular_color?
glColor4fv((GLfloat*)vertices[i].color.Array());
+ glSecondaryColor3fv((GLfloat*)vertices[i].specular.Array());
glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, (GLfloat*)vertices[i].texCoord.Array());
glVertex3fv((GLfloat*)vertices[i].coord.Array());
}
@@ -750,7 +754,7 @@ void Gfx::CGLDevice::SetRenderState(Gfx::RenderState state, bool enabled)
switch (state)
{
- case Gfx::RENDER_STATE_LIGHTING: flag = GL_DEPTH_WRITEMASK; break;
+ case Gfx::RENDER_STATE_LIGHTING: flag = GL_LIGHTING; 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;
diff --git a/src/graphics/opengl/test/CMakeLists.txt b/src/graphics/opengl/test/CMakeLists.txt
index ce2a83f..36bd738 100644
--- a/src/graphics/opengl/test/CMakeLists.txt
+++ b/src/graphics/opengl/test/CMakeLists.txt
@@ -8,16 +8,46 @@ find_package(PNG REQUIRED)
set(CMAKE_BUILD_TYPE debug)
set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0")
-
-set(SOURCES
+if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+ set(PLATFORM_WINDOWS 1)
+ set(PLATFORM_LINUX 0)
+ set(PLATFORM_OTHER 0)
+elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+ set(PLATFORM_WINDOWS 0)
+ set(PLATFORM_LINUX 1)
+ set(PLATFORM_OTHER 0)
+else()
+ set(PLATFORM_WINDOWS 0)
+ set(PLATFORM_LINUX 0)
+ set(PLATFORM_OTHER 1)
+endif()
+
+configure_file(../../../common/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/common/config.h)
+
+
+set(TEXTURE_SOURCES
../gldevice.cpp
../../common/device.cpp
+../../common/texture.cpp
../../../common/logger.cpp
../../../common/image.cpp
texture_test.cpp
)
-include_directories(../../../)
+set(MODEL_SOURCES
+../gldevice.cpp
+../../common/device.cpp
+../../common/modelfile.cpp
+../../common/texture.cpp
+../../../common/logger.cpp
+../../../common/image.cpp
+../../../common/iman.cpp
+../../../common/stringutils.cpp
+../../../app/system.cpp
+model_test.cpp
+)
+
+include_directories(../../../ ${CMAKE_CURRENT_BINARY_DIR})
set(LIBS
${SDL_LIBRARY}
@@ -26,6 +56,8 @@ ${OPENGL_LIBRARY}
${PNG_LIBRARIES}
)
-add_executable(texture_test ${SOURCES})
-
+add_executable(texture_test ${TEXTURE_SOURCES})
target_link_libraries(texture_test ${LIBS})
+
+add_executable(model_test ${MODEL_SOURCES})
+target_link_libraries(model_test ${LIBS})
diff --git a/src/graphics/opengl/test/README.txt b/src/graphics/opengl/test/README.txt
new file mode 100644
index 0000000..c309f23
--- /dev/null
+++ b/src/graphics/opengl/test/README.txt
@@ -0,0 +1,7 @@
+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
diff --git a/src/graphics/opengl/test/model_test.cpp b/src/graphics/opengl/test/model_test.cpp
new file mode 100644
index 0000000..b73dc71
--- /dev/null
+++ b/src/graphics/opengl/test/model_test.cpp
@@ -0,0 +1,385 @@
+#include "app/system.h"
+#include "common/logger.h"
+#include "common/image.h"
+#include "common/iman.h"
+#include "graphics/common/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 NULL;
+
+ return (*it).second;
+}
+
+void LoadTexture(Gfx::CGLDevice *device, const std::string &name)
+{
+ if (name.empty())
+ return;
+
+ if (GetTexture(name) != NULL)
+ return;
+
+ Gfx::Texture *tex = NULL;
+
+ 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.alpha = false;
+ texCreateParams.mipmap = true;
+ texCreateParams.minFilter = Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR;
+ texCreateParams.magFilter = Gfx::TEX_MAG_FILTER_LINEAR;
+ texCreateParams.wrapT = Gfx::TEX_WRAP_CLAMP;
+
+ 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, (600.0f) / (800.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);
+
+ Gfx::TextureParams tex1Params;
+ tex1Params.alphaOperation = Gfx::TEX_MIX_OPER_MODULATE;
+ tex1Params.colorOperation = Gfx::TEX_MIX_OPER_MODULATE;
+ device->SetTextureParams(0, tex1Params);
+
+ Gfx::TextureParams tex2Params;
+ tex2Params.alphaOperation = Gfx::TEX_MIX_OPER_MODULATE;
+ tex2Params.colorOperation = Gfx::TEX_MIX_OPER_MODULATE;
+ device->SetTextureParams(1, tex2Params);
+
+ 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/texture_test.cpp b/src/graphics/opengl/test/texture_test.cpp
index 764e127..79518f8 100644
--- a/src/graphics/opengl/test/texture_test.cpp
+++ b/src/graphics/opengl/test/texture_test.cpp
@@ -170,6 +170,7 @@ int main()
}
device->Destroy();
+ delete device;
SDL_FreeSurface(surface);
diff --git a/src/math/point.h b/src/math/point.h
index d6768c8..80f80f4 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
@@ -147,6 +148,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 41f11a8..65fc2f9 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
@@ -202,6 +203,16 @@ 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