From 54f4da87923465a5387e2e854b58616647deb7af Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Sun, 15 Jul 2012 19:17:49 +0200 Subject: 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 --- src/app/system.cpp | 270 +++++++-------------- src/app/system.h | 46 ++++ src/app/system_linux.h | 101 ++++++++ src/app/system_other.h | 146 +++++++++++ src/app/system_windows.h | 122 ++++++++++ src/common/singleton.h | 2 +- src/graphics/common/color.h | 21 ++ src/graphics/common/modelfile.cpp | 38 ++- src/graphics/common/modelfile.h | 4 +- src/graphics/common/vertex.h | 34 +++ src/graphics/opengl/gldevice.cpp | 76 +++--- src/graphics/opengl/test/CMakeLists.txt | 42 +++- src/graphics/opengl/test/README.txt | 7 + src/graphics/opengl/test/model_test.cpp | 385 ++++++++++++++++++++++++++++++ src/graphics/opengl/test/texture_test.cpp | 1 + src/math/point.h | 10 + src/math/vector.h | 11 + 17 files changed, 1080 insertions(+), 236 deletions(-) create mode 100644 src/app/system_linux.h create mode 100644 src/app/system_other.h create mode 100644 src/app/system_windows.h create mode 100644 src/graphics/opengl/test/README.txt create mode 100644 src/graphics/opengl/test/model_test.cpp 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 +#include "system_windows.h" + #elif defined(PLATFORM_LINUX) -#include +#include "system_linux.h" + #else -#include +#include "system_other.h" + #endif +#include -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 +/* 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 +#include +#include + + +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 + +#include + + +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 + + +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 class CSingleton mInstance = static_cast(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 + + 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::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& 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 + 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 #include #include @@ -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 ¶m // 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 ¶m // 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 +#include +#include + +#include +#include + +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 TEXS; + +SystemTimeStamp *PREV_TIME = NULL, *CURR_TIME = NULL; + +Gfx::Texture* GetTexture(const std::string &name) +{ + std::map::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 &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 &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 +#include // 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 +#include // 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 -- cgit v1.2.3-1-g7c22