diff options
Diffstat (limited to 'src/graphics')
42 files changed, 735 insertions, 432 deletions
diff --git a/src/graphics/README.txt b/src/graphics/README.txt index 1cb91ba..f9ec2ae 100644 --- a/src/graphics/README.txt +++ b/src/graphics/README.txt @@ -10,3 +10,4 @@ * This namespace was created to avoid clashing with old code, but now it still serves, * defining a border between pure graphics engine and other parts of application. */ + diff --git a/src/graphics/core/README.txt b/src/graphics/core/README.txt index ca3768c..056441d 100644 --- a/src/graphics/core/README.txt +++ b/src/graphics/core/README.txt @@ -4,4 +4,5 @@ * * Core types, enums, structs and CDevice abstract class that define * the abstract graphics device used in graphics engine - */
\ No newline at end of file + */ + diff --git a/src/graphics/core/color.cpp b/src/graphics/core/color.cpp index 1f9d7a5..f0b74f8 100644 --- a/src/graphics/core/color.cpp +++ b/src/graphics/core/color.cpp @@ -106,3 +106,4 @@ Color HSV2RGB(ColorHSV color) } // namespace Gfx + diff --git a/src/graphics/core/color.h b/src/graphics/core/color.h index 5d059e5..87a50f4 100644 --- a/src/graphics/core/color.h +++ b/src/graphics/core/color.h @@ -139,10 +139,10 @@ struct ColorHSV //! Returns a string "(h, s, v)" inline std::string ToString() const { - std::stringstream s; - s.precision(3); - s << "(" << h << ", " << s << ", " << v << ")"; - return s.str(); + std::stringstream str; + str.precision(3); + str << "(" << h << ", " << s << ", " << v << ")"; + return str.str(); } }; @@ -154,3 +154,4 @@ Color HSV2RGB(ColorHSV color); } // namespace Gfx + diff --git a/src/graphics/core/device.h b/src/graphics/core/device.h index 41d7796..4c1189c 100644 --- a/src/graphics/core/device.h +++ b/src/graphics/core/device.h @@ -72,7 +72,7 @@ struct DeviceConfig size = Math::IntPoint(800, 600); bpp = 32; fullScreen = false; - resizeable = false; + resizeable = true; doubleBuf = true; noFrame = false; } @@ -240,6 +240,9 @@ public: //! Provides a hook to debug graphics code (implementation-specific) virtual void DebugHook() = 0; + //! Displays light positions to aid in debuggings + virtual void DebugLights() = 0; + //! Initializes the device, setting the initial state virtual bool Create() = 0; //! Destroys the device, releasing every acquired resource @@ -401,3 +404,4 @@ public: } // namespace Gfx + diff --git a/src/graphics/core/light.h b/src/graphics/core/light.h index 28733c1..923d0e9 100644 --- a/src/graphics/core/light.h +++ b/src/graphics/core/light.h @@ -98,3 +98,4 @@ struct Light } // namespace Gfx + diff --git a/src/graphics/core/material.h b/src/graphics/core/material.h index 07782d5..e0bfaff 100644 --- a/src/graphics/core/material.h +++ b/src/graphics/core/material.h @@ -60,3 +60,4 @@ struct Material } // namespace Gfx + diff --git a/src/graphics/core/texture.h b/src/graphics/core/texture.h index 49b29f8..0702428 100644 --- a/src/graphics/core/texture.h +++ b/src/graphics/core/texture.h @@ -136,6 +136,8 @@ struct TextureCreateParams TexMinFilter minFilter; //! Magnification filter TexMagFilter magFilter; + //! Pad the image to nearest power of 2 dimensions + bool padToNearestPowerOfTwo; //! Constructor; calls LoadDefault() TextureCreateParams() @@ -146,6 +148,7 @@ struct TextureCreateParams { format = TEX_IMG_RGB; mipmap = false; + padToNearestPowerOfTwo = false; minFilter = TEX_MIN_FILTER_NEAREST; magFilter = TEX_MAG_FILTER_NEAREST; @@ -212,6 +215,8 @@ struct Texture unsigned int id; //! Size of texture Math::IntPoint size; + //! Original size of texture (as loaded from image) + Math::IntPoint originalSize; //! Whether the texture has alpha channel bool alpha; @@ -264,3 +269,4 @@ struct Texture } // namespace Gfx + diff --git a/src/graphics/core/vertex.h b/src/graphics/core/vertex.h index 66e1503..c3a657a 100644 --- a/src/graphics/core/vertex.h +++ b/src/graphics/core/vertex.h @@ -140,3 +140,4 @@ struct VertexTex2 } // namespace Gfx + diff --git a/src/graphics/d3d/README.txt b/src/graphics/d3d/README.txt index 0fe7db6..4f96f27 100644 --- a/src/graphics/d3d/README.txt +++ b/src/graphics/d3d/README.txt @@ -1 +1,2 @@ Possible future DirectX implementation of graphics engine + diff --git a/src/graphics/engine/README.txt b/src/graphics/engine/README.txt index 05d2d76..fbf45fd 100644 --- a/src/graphics/engine/README.txt +++ b/src/graphics/engine/README.txt @@ -7,3 +7,4 @@ * * Graphics operations are done on abstract interface from src/graphics/core */ + diff --git a/src/graphics/engine/camera.cpp b/src/graphics/engine/camera.cpp index f65a59a..f0c379c 100644 --- a/src/graphics/engine/camera.cpp +++ b/src/graphics/engine/camera.cpp @@ -1676,3 +1676,4 @@ Math::Vector CCamera::ExcludeObject(Math::Vector eye, Math::Vector lookat, } + diff --git a/src/graphics/engine/camera.h b/src/graphics/engine/camera.h index 0ffc2c2..6d94dad 100644 --- a/src/graphics/engine/camera.h +++ b/src/graphics/engine/camera.h @@ -128,8 +128,7 @@ enum CameraOverEffect ... */ class CCamera { - - public: +public: CCamera(); ~CCamera(); @@ -391,3 +390,4 @@ protected: } // namespace Gfx + diff --git a/src/graphics/engine/cloud.cpp b/src/graphics/engine/cloud.cpp index d9ebf5a..74083af 100644 --- a/src/graphics/engine/cloud.cpp +++ b/src/graphics/engine/cloud.cpp @@ -270,3 +270,4 @@ bool CCloud::GetEnabled() } // namespace Gfx + diff --git a/src/graphics/engine/cloud.h b/src/graphics/engine/cloud.h index 8f644f0..8e820c7 100644 --- a/src/graphics/engine/cloud.h +++ b/src/graphics/engine/cloud.h @@ -140,3 +140,4 @@ protected: } // namespace Gfx + diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index e2ef569..669ea42 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -42,6 +42,8 @@ #include "ui/interface.h" +#include <iomanip> + template<> Gfx::CEngine* CSingleton<Gfx::CEngine>::m_instance = nullptr; // Graphics module namespace @@ -94,7 +96,6 @@ CEngine::CEngine(CApplication *app) m_backgroundCloudUp = Color(); m_backgroundCloudDown = Color(); m_backgroundFull = false; - m_backgroundScale = Math::Point(1.0f, 1.0f); m_overFront = true; m_overColor = Color(); m_overMode = ENG_RSTATE_TCOLOR_BLACK; @@ -127,6 +128,9 @@ CEngine::CEngine(CApplication *app) m_interfaceMode = false; + m_debugLights = false; + m_debugDumpLights = false; + m_mice[ENG_MOUSE_NORM] = EngineMouse( 0, 1, 32, ENG_RSTATE_TTEXTURE_WHITE, ENG_RSTATE_TTEXTURE_BLACK, Math::Point( 1.0f, 1.0f)); m_mice[ENG_MOUSE_WAIT] = EngineMouse( 2, 3, 33, ENG_RSTATE_TTEXTURE_WHITE, ENG_RSTATE_TTEXTURE_BLACK, Math::Point( 8.0f, 12.0f)); m_mice[ENG_MOUSE_HAND] = EngineMouse( 4, 5, 34, ENG_RSTATE_TTEXTURE_WHITE, ENG_RSTATE_TTEXTURE_BLACK, Math::Point( 7.0f, 2.0f)); @@ -237,7 +241,6 @@ void CEngine::SetTerrain(CTerrain* terrain) m_terrain = terrain; } - bool CEngine::Create() { m_size = m_app->GetVideoConfig().size; @@ -317,7 +320,7 @@ void CEngine::ResetAfterDeviceChanged() m_text->FlushCache(); - // TODO reload textures, reset device state, etc. + FlushTextureCache(); } bool CEngine::ProcessEvent(const Event &event) @@ -325,7 +328,22 @@ bool CEngine::ProcessEvent(const Event &event) if (event.type == EVENT_KEY_DOWN) { if (event.key.key == KEY(F12)) + { m_showStats = !m_showStats; + return false; + } + + if (event.key.key == KEY(F11)) + { + m_debugLights = !m_debugLights; + return false; + } + + if (event.key.key == KEY(F10)) + { + m_debugDumpLights = true; + return false; + } } // By default, pass on all events @@ -591,6 +609,27 @@ void CEngine::CopyBaseObject(int sourceBaseObjRank, int destBaseObjRank) assert(destBaseObjRank >= 0 && destBaseObjRank < static_cast<int>( m_baseObjects.size() )); m_baseObjects[destBaseObjRank] = m_baseObjects[sourceBaseObjRank]; + + EngineBaseObject& p1 = m_baseObjects[destBaseObjRank]; + + if (! p1.used) + return; + + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + { + EngineBaseObjTexTier& p2 = p1.next[l2]; + + for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) + { + EngineBaseObjLODTier& p3 = p2.next[l3]; + + for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) + { + EngineBaseObjDataTier& p4 = p3.next[l4]; + p4.staticBufferId = 0; + } + } + } } void CEngine::AddBaseObjTriangles(int baseObjRank, const std::vector<VertexTex2>& vertices, @@ -677,6 +716,82 @@ void CEngine::AddBaseObjQuick(int baseObjRank, const EngineBaseObjDataTier& buff p1.totalTriangles += p4.vertices.size() - 2; } +void CEngine::DebugObject(int objRank) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + CLogger* l = GetLogger(); + + l->Debug("Debug object: %d\n", objRank); + if (! m_objects[objRank].used) + { + l->Debug(" not used\n"); + return; + } + + l->Debug(" baseObjRank = %d\n", m_objects[objRank].baseObjRank); + l->Debug(" visible = %s\n", m_objects[objRank].visible ? "true" : "false"); + l->Debug(" drawWorld = %s\n", m_objects[objRank].drawWorld ? "true" : "false"); + l->Debug(" drawFront = %s\n", m_objects[objRank].drawFront ? "true" : "false"); + l->Debug(" type = %d\n", m_objects[objRank].type); + l->Debug(" distance = %f\n", m_objects[objRank].distance); + l->Debug(" shadowRank = %d\n", m_objects[objRank].shadowRank); + l->Debug(" transparency = %f\n", m_objects[objRank].transparency); + + l->Debug(" baseObj:\n"); + int baseObjRank = m_objects[objRank].baseObjRank; + if (baseObjRank == -1) + { + l->Debug(" null\n"); + return; + } + + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); + + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + if (!p1.used) + { + l->Debug(" not used\n"); + return; + } + + std::string vecStr; + + vecStr = p1.bboxMin.ToString(); + l->Debug(" bboxMin: %s\n", vecStr.c_str()); + vecStr = p1.bboxMax.ToString(); + l->Debug(" bboxMax: %s\n", vecStr.c_str()); + l->Debug(" totalTriangles: %d\n", p1.totalTriangles); + l->Debug(" radius: %f\n", p1.radius); + + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + { + EngineBaseObjTexTier& p2 = p1.next[l2]; + l->Debug(" l2:\n"); + + l->Debug(" tex1: %s (id: %u)\n", p2.tex1Name.c_str(), p2.tex1.id); + l->Debug(" tex2: %s (id: %u)\n", p2.tex2Name.c_str(), p2.tex2.id); + + for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) + { + EngineBaseObjLODTier& p3 = p2.next[l3]; + + l->Debug(" l3:\n"); + l->Debug(" lodLevel: %d\n", p3.lodLevel); + + for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) + { + EngineBaseObjDataTier& p4 = p3.next[l4]; + + l->Debug(" l4:\n"); + l->Debug(" type: %d\n", p4.type); + l->Debug(" state: %d\n", p4.state); + l->Debug(" staticBufferId: %u\n", p4.staticBufferId); + l->Debug(" updateStaticBuffer: %s\n", p4.updateStaticBuffer ? "true" : "false"); + } + } + } +} int CEngine::CreateObject() { @@ -965,13 +1080,19 @@ void CEngine::ChangeSecondTexture(int objRank, const std::string& tex2Name) for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) { - EngineBaseObjTexTier& p2 = p1.next[l2]; - - if (p2.tex2Name == tex2Name) + if (p1.next[l2].tex2Name == tex2Name) continue; // already new - EngineBaseObjTexTier& newP2 = AddLevel2(p1, p2.tex1Name, tex2Name); - newP2.next.swap(p2.next); + std::string tex1Name = p1.next[l2].tex1Name; + EngineBaseObjTexTier& newP2 = AddLevel2(p1, tex1Name, tex2Name); + newP2.next.insert(newP2.next.end(), p1.next[l2].next.begin(), p1.next[l2].next.end()); + p1.next[l2].next.clear(); + + if (!newP2.tex1.Valid()) + newP2.tex1 = LoadTexture(newP2.tex1Name); + + if (!newP2.tex2.Valid()) + newP2.tex2 = LoadTexture(newP2.tex2Name); } } @@ -2098,25 +2219,44 @@ Texture CEngine::CreateTexture(const std::string& texName, const TextureCreatePa return Texture(); // invalid texture Texture tex; + CImage img; if (image == nullptr) { - CImage img; - if (! img.Load(m_app->GetDataFilePath(DIR_TEXTURE, texName))) + bool loadedFromTexPack = false; + + std::string texPackName = m_app->GetTexPackFilePath(texName); + if (! texPackName.empty()) { - std::string error = img.GetError(); - GetLogger()->Error("Couldn't load texture '%s': %s, blacklisting\n", texName.c_str(), error.c_str()); - m_texBlacklist.insert(texName); - return Texture(); // invalid texture + if (img.Load(texPackName)) + { + loadedFromTexPack = true; + } + else + { + std::string error = img.GetError(); + GetLogger()->Error("Couldn't load texture '%s' from texpack: %s, blacklisting the texpack path\n", + texName.c_str(), error.c_str()); + m_texBlacklist.insert(texPackName); + } } - tex = m_device->CreateTexture(&img, params); - } - else - { - tex = m_device->CreateTexture(image, params); + if (!loadedFromTexPack) + { + if (! img.Load(m_app->GetDataFilePath(DIR_TEXTURE, texName))) + { + std::string error = img.GetError(); + GetLogger()->Error("Couldn't load texture '%s': %s, blacklisting\n", texName.c_str(), error.c_str()); + m_texBlacklist.insert(texName); + return Texture(); // invalid texture + } + } + + image = &img; } + tex = m_device->CreateTexture(image, params); + if (! tex.Valid()) { GetLogger()->Error("Couldn't load texture '%s', blacklisting\n", texName.c_str()); @@ -2150,8 +2290,7 @@ Texture CEngine::LoadTexture(const std::string& name, const TextureCreateParams& if (it != m_texNameMap.end()) return (*it).second; - Texture tex = CreateTexture(name, params); - return tex; + return CreateTexture(name, params); } bool CEngine::LoadAllTextures() @@ -2167,7 +2306,11 @@ bool CEngine::LoadAllTextures() LoadTexture("map.png"); if (! m_backgroundName.empty()) - m_backgroundTex = LoadTexture(m_backgroundName); + { + TextureCreateParams params = m_defaultTexParams; + params.padToNearestPowerOfTwo = true; + m_backgroundTex = LoadTexture(m_backgroundName, params); + } else m_backgroundTex.SetInvalid(); @@ -2405,6 +2548,13 @@ void CEngine::DeleteTexture(const Texture& tex) m_texNameMap.erase(it); } +void CEngine::FlushTextureCache() +{ + m_texNameMap.clear(); + m_revTexNameMap.clear(); + m_texBlacklist.clear(); +} + bool CEngine::SetTexture(const std::string& name, int stage) { auto it = m_texNameMap.find(name); @@ -2588,8 +2738,7 @@ float CEngine::GetFogStart(int rank) } void CEngine::SetBackground(const std::string& name, Color up, Color down, - Color cloudUp, Color cloudDown, - bool full, Math::Point scale) + Color cloudUp, Color cloudDown, bool full) { if (m_backgroundTex.Valid()) { @@ -2603,15 +2752,17 @@ void CEngine::SetBackground(const std::string& name, Color up, Color down, m_backgroundCloudUp = cloudUp; m_backgroundCloudDown = cloudDown; m_backgroundFull = full; - m_backgroundScale = scale; if (! m_backgroundName.empty()) - m_backgroundTex = LoadTexture(m_backgroundName); + { + TextureCreateParams params = m_defaultTexParams; + params.padToNearestPowerOfTwo = true; + m_backgroundTex = LoadTexture(m_backgroundName, params); + } } void CEngine::GetBackground(std::string& name, Color& up, Color& down, - Color& cloudUp, Color& cloudDown, - bool &full, Math::Point& scale) + Color& cloudUp, Color& cloudDown, bool &full) { name = m_backgroundName; up = m_backgroundColorUp; @@ -2619,7 +2770,6 @@ void CEngine::GetBackground(std::string& name, Color& up, Color& down, cloudUp = m_backgroundCloudUp; cloudDown = m_backgroundCloudDown; full = m_backgroundFull; - scale = m_backgroundScale; } void CEngine::SetForegroundName(const std::string& name) @@ -3161,6 +3311,15 @@ void CEngine::Draw3DScene() m_lightMan->UpdateDeviceLights(ENG_OBJTYPE_TERRAIN); + if (m_debugLights) + m_device->DebugLights(); + + if (m_debugDumpLights) + { + m_debugDumpLights = false; + m_lightMan->DebugDumpLights(); + } + if (m_waterMode) { m_app->StartPerformanceCounter(PCNT_RENDER_WATER); @@ -3630,7 +3789,7 @@ void CEngine::DrawShadow() float lastIntensity = -1.0f; for (int i = 0; i < static_cast<int>( m_shadows.size() ); i++) { - if (m_shadows[i].hide) + if (m_shadows[i].hide || !m_shadows[i].used) continue; Math::Vector pos = m_shadows[i].pos; // pos = center of the shadow on the ground @@ -3879,8 +4038,12 @@ void CEngine::DrawBackgroundImage() v2 = v1+h; } - u2 *= m_backgroundScale.x; - v2 *= m_backgroundScale.y; + Math::Point backgroundScale; + backgroundScale.x = static_cast<float>(m_backgroundTex.originalSize.x) / static_cast<float>(m_backgroundTex.size.x); + backgroundScale.y = static_cast<float>(m_backgroundTex.originalSize.y) / static_cast<float>(m_backgroundTex.size.y); + + u2 *= backgroundScale.x; + v2 *= backgroundScale.y; SetTexture(m_backgroundTex); SetState(ENG_RSTATE_OPAQUE_TEXTURE | ENG_RSTATE_WRAP); @@ -4279,3 +4442,4 @@ void CEngine::DrawStats() } // namespace Gfx + diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index f9dfd45..5ecde8f 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -118,7 +118,7 @@ enum EngineRenderState //! Mode for rendering text ENG_RSTATE_TEXT = (1<<18), //! Only opaque texture, no blending, etc. - ENG_RSTATE_OPAQUE_TEXTURE = (1<<19), + ENG_RSTATE_OPAQUE_TEXTURE = (1<<19), //! Only opaque color, no texture, blending, etc. ENG_RSTATE_OPAQUE_COLOR = (1<<20) }; @@ -171,7 +171,7 @@ enum EngineObjectType //! Fixed object ENG_OBJTYPE_FIX = 2, //! Moving object - ENG_OBJTYPE_VEHICULE = 3, + ENG_OBJTYPE_VEHICLE = 3, //! Part of a moving object ENG_OBJTYPE_DESCENDANT = 4, //! Fixed object type quartz @@ -194,10 +194,15 @@ struct EngineBaseObjDataTier unsigned int staticBufferId; bool updateStaticBuffer; - inline EngineBaseObjDataTier(EngineTriangleType type = ENG_TRIANGLE_TYPE_TRIANGLES, - const Material& material = Material(), - int state = ENG_RSTATE_NORMAL) - : type(type), material(material), state(state), staticBufferId(0), updateStaticBuffer(false) {} + inline EngineBaseObjDataTier(EngineTriangleType _type = ENG_TRIANGLE_TYPE_TRIANGLES, + const Material& _material = Material(), + int _state = ENG_RSTATE_NORMAL) + : type(_type) + , material(_material) + , state(_state) + , staticBufferId(0) + , updateStaticBuffer(false) + {} }; /** @@ -209,8 +214,9 @@ struct EngineBaseObjLODTier LODLevel lodLevel; std::vector<EngineBaseObjDataTier> next; - inline EngineBaseObjLODTier(LODLevel lodLevel = LOD_Constant) - : lodLevel(lodLevel) {} + inline EngineBaseObjLODTier(LODLevel _lodLevel = LOD_Constant) + : lodLevel(_lodLevel) + {} }; /** @@ -225,8 +231,10 @@ struct EngineBaseObjTexTier Texture tex2; std::vector<EngineBaseObjLODTier> next; - inline EngineBaseObjTexTier(const std::string& tex1Name = "", const std::string& tex2Name = "") - : tex1Name(tex1Name), tex2Name(tex2Name) {} + inline EngineBaseObjTexTier(const std::string& _tex1Name = "", const std::string& _tex2Name = "") + : tex1Name(_tex1Name) + , tex2Name(_tex2Name) + {} }; /** @@ -556,18 +564,17 @@ struct EngineMouse //! Hot point Math::Point hotPoint; - inline EngineMouse(int icon1 = -1, int icon2 = -1, int iconShadow = -1, - EngineRenderState mode1 = ENG_RSTATE_NORMAL, - EngineRenderState mode2 = ENG_RSTATE_NORMAL, - Math::Point hotPoint = Math::Point()) - { - this->icon1 = icon1; - this->icon2 = icon2; - this->iconShadow = iconShadow; - this->mode1 = mode1; - this->mode2 = mode2; - this->hotPoint = hotPoint; - } + inline EngineMouse(int _icon1 = -1, int _icon2 = -1, int _iconShadow = -1, + EngineRenderState _mode1 = ENG_RSTATE_NORMAL, + EngineRenderState _mode2 = ENG_RSTATE_NORMAL, + Math::Point _hotPoint = Math::Point()) + : icon1(_icon1) + , icon2(_icon2) + , iconShadow(_iconShadow) + , mode1(_mode1) + , mode2(_mode2) + , hotPoint(_hotPoint) + {} }; @@ -726,6 +733,7 @@ public: //! Writes a screenshot containing the current frame bool WriteScreenShot(const std::string& fileName, int width, int height); + //@{ //! Management of game pause mode void SetPause(bool pause); @@ -799,6 +807,9 @@ public: // Objects + //! Print debug info about an object + void DebugObject(int rank); + //! Creates a new object and returns its rank int CreateObject(); //! Deletes all objects, shadows and ground spots @@ -957,6 +968,9 @@ public: //! Deletes the given texture, unloading it and removing from cache void DeleteTexture(const Texture& tex); + //! Empties the texture cache + void FlushTextureCache(); + //! Defines of the distance field of vision void SetTerrainVision(float vision); @@ -1050,10 +1064,10 @@ public: //! Management of the background image to use void SetBackground(const std::string& name, Color up = Color(), Color down = Color(), Color cloudUp = Color(), Color cloudDown = Color(), - bool full = false, Math::Point scale = Math::Point(1.0f, 1.0f)); + bool full = false); void GetBackground(std::string& name, Color& up, Color& down, Color& cloudUp, Color& cloudDown, - bool& full, Math::Point& scale); + bool& full); //@} //! Specifies the name of foreground texture @@ -1346,7 +1360,6 @@ protected: bool m_firstGroundSpot; int m_secondTexNum; bool m_backgroundFull; - Math::Point m_backgroundScale; std::string m_backgroundName; Texture m_backgroundTex; Color m_backgroundColorUp; @@ -1424,7 +1437,11 @@ protected: //! True when drawing 2D UI bool m_interfaceMode; + + bool m_debugLights; + bool m_debugDumpLights; }; } // namespace Gfx + diff --git a/src/graphics/engine/lightman.cpp b/src/graphics/engine/lightman.cpp index 16c84ea..8694c7a 100644 --- a/src/graphics/engine/lightman.cpp +++ b/src/graphics/engine/lightman.cpp @@ -71,6 +71,7 @@ void LightProgression::SetTarget(float value) DynamicLight::DynamicLight() { + rank = 0; used = enabled = false; priority = LIGHT_PRI_LOW; includeType = excludeType = ENG_OBJTYPE_NULL; @@ -98,6 +99,61 @@ void CLightManager::SetDevice(CDevice* device) m_lightMap = std::vector<int>(m_device->GetMaxLightCount(), -1); } +void CLightManager::DebugDumpLights() +{ + CLogger* l = GetLogger(); + + l->Debug("Dynamic lights:\n"); + + for (int i = 0; i < static_cast<int>( m_dynLights.size() ); ++i) + { + const DynamicLight& dynLight = m_dynLights[i]; + if (!dynLight.used) + continue; + + int deviceLight = -1; + for (int j = 0; j < static_cast<int>( m_lightMap.size() ); ++j) + { + if (m_lightMap[j] == i) + { + deviceLight = j; + break; + } + } + + l->Debug(" light %d\n", i); + l->Debug(" enabled = %s\n", dynLight.enabled ? "true" : "false"); + l->Debug(" priority = %d\n", dynLight.priority); + l->Debug(" device light = %d\n", deviceLight); + l->Debug(" light:\n"); + + const Light& light = dynLight.light; + std::string str; + + l->Debug(" type = %d\n", light.type); + str = light.ambient.ToString(); + l->Debug(" ambient = %s\n", str.c_str()); + str = light.diffuse.ToString(); + l->Debug(" diffuse = %s\n", str.c_str()); + str = light.specular.ToString(); + l->Debug(" specular = %s\n", str.c_str()); + str = light.position.ToString(); + l->Debug(" position = %s\n", str.c_str()); + str = light.direction.ToString(); + l->Debug(" direction = %s\n", str.c_str()); + l->Debug(" attenuation0 = %f\n", light.attenuation0); + l->Debug(" attenuation1 = %f\n", light.attenuation1); + l->Debug(" attenuation2 = %f\n", light.attenuation2); + l->Debug(" spotAngle = %f\n", light.spotAngle); + l->Debug(" spotIntensity = %f\n", light.spotIntensity); + + l->Debug(" intensity: %f\n", dynLight.intensity.current); + l->Debug(" color: %f %f %f\n", dynLight.colorRed.current, dynLight.colorGreen.current, dynLight.colorBlue.current); + l->Debug(" includeType: %d\n", dynLight.includeType); + l->Debug(" excludeType: %d\n", dynLight.excludeType); + } +} + void CLightManager::FlushLights() { m_dynLights.clear(); @@ -117,6 +173,7 @@ int CLightManager::CreateLight(LightPriority priority) m_dynLights.push_back(DynamicLight()); m_dynLights[index] = DynamicLight(); + m_dynLights[index].rank = index; m_dynLights[index].used = true; m_dynLights[index].enabled = true; m_dynLights[index].priority = priority; @@ -179,6 +236,15 @@ bool CLightManager::SetLightEnabled(int lightRank, bool enabled) return true; } +bool CLightManager::SetLightPriority(int lightRank, LightPriority priority) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return false; + + m_dynLights[lightRank].priority = priority; + return true; +} + bool CLightManager::SetLightIncludeType(int lightRank, EngineObjectType type) { if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) @@ -411,7 +477,7 @@ void CLightManager::UpdateDeviceLights(EngineObjectType type) if (enabled) { - m_lightMap[lightMapIndex] = i; + m_lightMap[lightMapIndex] = sortedLights[i].rank; ++lightMapIndex; } @@ -424,8 +490,9 @@ void CLightManager::UpdateDeviceLights(EngineObjectType type) int rank = m_lightMap[i]; if (rank != -1) { - sortedLights[rank].light.ambient = Gfx::Color(0.2f, 0.2f, 0.2f); - m_device->SetLight(i, sortedLights[rank].light); + Light light = m_dynLights[rank].light; + light.ambient = Gfx::Color(0.2f, 0.2f, 0.2f); + m_device->SetLight(i, light); m_device->SetLightEnabled(i, true); } else @@ -445,6 +512,9 @@ CLightManager::LightsComparator::LightsComparator(Math::Vector eyePos, EngineObj float CLightManager::LightsComparator::GetLightWeight(const DynamicLight& dynLight) { + if (dynLight.priority == LIGHT_PRI_HIGHEST) + return -1.0f; + bool enabled = true; if (!dynLight.used || !dynLight.enabled || dynLight.intensity.current == 0.0f) enabled = false; @@ -465,3 +535,4 @@ bool CLightManager::LightsComparator::operator()(const DynamicLight& left, const } } // namespace Gfx + diff --git a/src/graphics/engine/lightman.h b/src/graphics/engine/lightman.h index ab66524..a2f6044 100644 --- a/src/graphics/engine/lightman.h +++ b/src/graphics/engine/lightman.h @@ -71,8 +71,9 @@ struct LightProgression */ enum LightPriority { - LIGHT_PRI_HIGH = 1, - LIGHT_PRI_LOW = 2 + LIGHT_PRI_HIGHEST = 0, //!< always highest weight (always picked) + LIGHT_PRI_HIGH = 1, //!< high weight + LIGHT_PRI_LOW = 2 //!< low weight }; /** @@ -84,6 +85,9 @@ enum LightPriority */ struct DynamicLight { + //! Rank (index) + int rank; + //! Whether the light is used bool used; //! Whether the light is turned on @@ -136,6 +140,9 @@ public: //! Sets the device to be used void SetDevice(CDevice* device); + //! Prints debug info + void DebugDumpLights(); + //! Clears and disables all lights void FlushLights(); //! Creates a new dynamic light and returns its index (lightRank) @@ -148,6 +155,8 @@ public: bool GetLight(int lightRank, Light &light); //! Enables/disables the given dynamic light bool SetLightEnabled(int lightRank, bool enable); + //! Changes the light priority + bool SetLightPriority(int lightRank, LightPriority priority); //! Sets what objects are included in given dynamic light bool SetLightIncludeType(int lightRank, EngineObjectType type); @@ -216,3 +225,4 @@ protected: }; }; // namespace Gfx + diff --git a/src/graphics/engine/lightning.cpp b/src/graphics/engine/lightning.cpp index 5fdae51..4395eec 100644 --- a/src/graphics/engine/lightning.cpp +++ b/src/graphics/engine/lightning.cpp @@ -418,3 +418,4 @@ CObject* CLightning::SearchObject(Math::Vector pos) } // namespace Gfx + diff --git a/src/graphics/engine/lightning.h b/src/graphics/engine/lightning.h index 7809a6c..1b1d339 100644 --- a/src/graphics/engine/lightning.h +++ b/src/graphics/engine/lightning.h @@ -107,3 +107,4 @@ protected: } // namespace Gfx + diff --git a/src/graphics/engine/modelfile.cpp b/src/graphics/engine/modelfile.cpp index f6d7a7b..99496aa 100644 --- a/src/graphics/engine/modelfile.cpp +++ b/src/graphics/engine/modelfile.cpp @@ -310,6 +310,7 @@ bool ReadLineString(std::istream& stream, const std::string& prefix, std::string CModelFile::CModelFile() + : m_printDebugInfo(false) { } @@ -615,23 +616,26 @@ bool CModelFile::ReadModel(std::istream& stream) if (m_triangles[i].tex1Name == "plant.png") m_triangles[i].state |= ENG_RSTATE_ALPHA; - GetLogger()->Trace("ModelTriangle %d\n", i+1); - std::string s1 = m_triangles[i].p1.ToString(); - GetLogger()->Trace(" p1: %s\n", s1.c_str()); - std::string s2 = m_triangles[i].p2.ToString(); - GetLogger()->Trace(" p2: %s\n", s2.c_str()); - std::string s3 = m_triangles[i].p3.ToString(); - GetLogger()->Trace(" 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()->Trace(" mat: d: %s a: %s s: %s\n", d.c_str(), a.c_str(), s.c_str()); - - GetLogger()->Trace(" tex1: %s tex2: %s\n", m_triangles[i].tex1Name.c_str(), - m_triangles[i].variableTex2 ? "(variable)" : m_triangles[i].tex2Name.c_str()); - GetLogger()->Trace(" lod level: %d\n", m_triangles[i].lodLevel); - GetLogger()->Trace(" state: %ld\n", m_triangles[i].state); + if (m_printDebugInfo) + { + GetLogger()->Trace("ModelTriangle %d\n", i+1); + std::string s1 = m_triangles[i].p1.ToString(); + GetLogger()->Trace(" p1: %s\n", s1.c_str()); + std::string s2 = m_triangles[i].p2.ToString(); + GetLogger()->Trace(" p2: %s\n", s2.c_str()); + std::string s3 = m_triangles[i].p3.ToString(); + GetLogger()->Trace(" 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()->Trace(" mat: d: %s a: %s s: %s\n", d.c_str(), a.c_str(), s.c_str()); + + GetLogger()->Trace(" tex1: %s tex2: %s\n", m_triangles[i].tex1Name.c_str(), + m_triangles[i].variableTex2 ? "(variable)" : m_triangles[i].tex2Name.c_str()); + GetLogger()->Trace(" lod level: %d\n", m_triangles[i].lodLevel); + GetLogger()->Trace(" state: %ld\n", m_triangles[i].state); + } } return true; @@ -1093,24 +1097,27 @@ bool CModelFile::ReadBinaryModel(std::istream& stream) return false; } - for (int i = 0; i < static_cast<int>( m_triangles.size() ); ++i) + if (m_printDebugInfo) { - GetLogger()->Trace("ModelTriangle %d\n", i+1); - std::string s1 = m_triangles[i].p1.ToString(); - GetLogger()->Trace(" p1: %s\n", s1.c_str()); - std::string s2 = m_triangles[i].p2.ToString(); - GetLogger()->Trace(" p2: %s\n", s2.c_str()); - std::string s3 = m_triangles[i].p3.ToString(); - GetLogger()->Trace(" 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()->Trace(" mat: d: %s a: %s s: %s\n", d.c_str(), a.c_str(), s.c_str()); - - GetLogger()->Trace(" tex1: %s tex2: %s\n", m_triangles[i].tex1Name.c_str(), m_triangles[i].tex2Name.c_str()); - GetLogger()->Trace(" lod level: %d\n", m_triangles[i].lodLevel); - GetLogger()->Trace(" state: %ld\n", m_triangles[i].state); + for (int i = 0; i < static_cast<int>( m_triangles.size() ); ++i) + { + GetLogger()->Trace("ModelTriangle %d\n", i+1); + std::string s1 = m_triangles[i].p1.ToString(); + GetLogger()->Trace(" p1: %s\n", s1.c_str()); + std::string s2 = m_triangles[i].p2.ToString(); + GetLogger()->Trace(" p2: %s\n", s2.c_str()); + std::string s3 = m_triangles[i].p3.ToString(); + GetLogger()->Trace(" 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()->Trace(" mat: d: %s a: %s s: %s\n", d.c_str(), a.c_str(), s.c_str()); + + GetLogger()->Trace(" tex1: %s tex2: %s\n", m_triangles[i].tex1Name.c_str(), m_triangles[i].tex2Name.c_str()); + GetLogger()->Trace(" lod level: %d\n", m_triangles[i].lodLevel); + GetLogger()->Trace(" state: %ld\n", m_triangles[i].state); + } } return true; @@ -1197,5 +1204,10 @@ int CModelFile::GetTriangleCount() return m_triangles.size(); } +void CModelFile::SetPrintDebugInfo(bool printDebugInfo) +{ + m_printDebugInfo = printDebugInfo; +} } // namespace Gfx + diff --git a/src/graphics/engine/modelfile.h b/src/graphics/engine/modelfile.h index 3a702cb..3b4019b 100644 --- a/src/graphics/engine/modelfile.h +++ b/src/graphics/engine/modelfile.h @@ -137,6 +137,9 @@ public: //! Returns the triangle vector const std::vector<ModelTriangle>& GetTriangles(); + //! Controls printing of debug information + void SetPrintDebugInfo(bool printDebugInfo); + protected: //@{ //! @deprecated min, max conversions @@ -147,6 +150,8 @@ protected: protected: //! Model triangles std::vector<ModelTriangle> m_triangles; + bool m_printDebugInfo; }; }; // namespace Gfx + diff --git a/src/graphics/engine/modelmanager.cpp b/src/graphics/engine/modelmanager.cpp index c23b79d..abc8c6c 100644 --- a/src/graphics/engine/modelmanager.cpp +++ b/src/graphics/engine/modelmanager.cpp @@ -23,10 +23,13 @@ CModelManager::~CModelManager() bool CModelManager::LoadModel(const std::string& fileName, bool mirrored) { - GetLogger()->Info("Loading model '%s'\n", fileName.c_str()); + GetLogger()->Debug("Loading model '%s'\n", fileName.c_str()); CModelFile modelFile; + if (CApplication::GetInstance().IsDebugModeActive(DEBUG_MODELS)) + modelFile.SetPrintDebugInfo(true); + std::string filePath = CApplication::GetInstance().GetDataFilePath(DIR_MODEL, fileName); if (!modelFile.ReadModel(filePath)) @@ -111,6 +114,8 @@ bool CModelManager::AddModelCopy(const std::string& fileName, bool mirrored, int m_engine->CopyBaseObject((*it).second.baseObjRank, copyBaseObjRank); m_engine->SetObjectBaseRank(objRank, copyBaseObjRank); + m_copiesBaseRanks.push_back(copyBaseObjRank); + return true; } @@ -128,6 +133,16 @@ int CModelManager::GetModelBaseObjRank(const std::string& fileName, bool mirrore return (*it).second.baseObjRank; } +void CModelManager::DeleteAllModelCopies() +{ + for (int baseObjRank : m_copiesBaseRanks) + { + m_engine->DeleteBaseObject(baseObjRank); + } + + m_copiesBaseRanks.clear(); +} + void CModelManager::UnloadModel(const std::string& fileName, bool mirrored) { auto it = m_models.find(FileInfo(fileName, mirrored)); @@ -189,3 +204,4 @@ float CModelManager::GetHeight(std::vector<ModelTriangle>& triangles, Math::Vect } + diff --git a/src/graphics/engine/modelmanager.h b/src/graphics/engine/modelmanager.h index 601d636..9d50b97 100644 --- a/src/graphics/engine/modelmanager.h +++ b/src/graphics/engine/modelmanager.h @@ -53,6 +53,9 @@ public: //! Returns the rank of base engine object of given loaded model int GetModelBaseObjRank(const std::string& fileName, bool mirrored); + //! Deletes all copied objects + void DeleteAllModelCopies(); + //! Unloads the given model void UnloadModel(const std::string& fileName, bool mirrored); //! Unloads all models @@ -76,8 +79,10 @@ private: std::string fileName; bool mirrored; - inline FileInfo(const std::string& fileName, bool mirrored) - : fileName(fileName), mirrored(mirrored) {} + inline FileInfo(const std::string& _fileName, bool _mirrored) + : fileName(_fileName) + , mirrored(_mirrored) + {} inline bool operator<(const FileInfo& other) const { @@ -91,7 +96,9 @@ private: } }; std::map<FileInfo, ModelInfo> m_models; + std::vector<int> m_copiesBaseRanks; CEngine* m_engine; }; } // namespace Gfx + diff --git a/src/graphics/engine/particle.cpp b/src/graphics/engine/particle.cpp index d15ee3b..abee2e2 100644 --- a/src/graphics/engine/particle.cpp +++ b/src/graphics/engine/particle.cpp @@ -3553,9 +3553,9 @@ void CParticle::DrawParticle(int sheet) { m_engine->SetTexture("text.png"); m_engine->SetState(ENG_RSTATE_TTEXTURE_WHITE); - Math::Matrix mat; - mat.LoadIdentity(); - m_device->SetTransform(TRANSFORM_WORLD, mat); + Math::Matrix matrix; + matrix.LoadIdentity(); + m_device->SetTransform(TRANSFORM_WORLD, matrix); for (int i = 0; i < m_wheelTraceTotal; i++) DrawParticleWheel(i); @@ -3917,3 +3917,4 @@ bool CParticle::WriteWheelTrace(const char *filename, int width, int height, } } // namespace Gfx + diff --git a/src/graphics/engine/particle.h b/src/graphics/engine/particle.h index 708a04d..7fb24a1 100644 --- a/src/graphics/engine/particle.h +++ b/src/graphics/engine/particle.h @@ -395,3 +395,4 @@ protected: } // namespace Gfx + diff --git a/src/graphics/engine/planet.cpp b/src/graphics/engine/planet.cpp index 49bcb4c..0c96f63 100644 --- a/src/graphics/engine/planet.cpp +++ b/src/graphics/engine/planet.cpp @@ -185,3 +185,4 @@ int CPlanet::GetMode() } // namespace Gfx + diff --git a/src/graphics/engine/planet.h b/src/graphics/engine/planet.h index 3762e1d..58d3aeb 100644 --- a/src/graphics/engine/planet.h +++ b/src/graphics/engine/planet.h @@ -118,3 +118,4 @@ protected: } // namespace Gfx + diff --git a/src/graphics/engine/pyro.cpp b/src/graphics/engine/pyro.cpp index cab28b6..7c51829 100644 --- a/src/graphics/engine/pyro.cpp +++ b/src/graphics/engine/pyro.cpp @@ -89,13 +89,15 @@ bool CPyro::Create(PyroType type, CObject* obj, float force) DisplayError(type, obj); // displays eventual messages - int i = 0; - // Copies all spheres of the object. - for (; i < 50; i++) { - if ( !obj->GetCrashSphere(i, m_crashSpherePos[i], m_crashSphereRadius[i]) ) break; + int i = 0; + // Copies all spheres of the object. + for (; i < 50; i++) + { + if ( !obj->GetCrashSphere(i, m_crashSpherePos[i], m_crashSphereRadius[i]) ) break; + } + m_crashSphereUsed = i; } - m_crashSphereUsed = i; // Calculates the size of the effect. if ( oType == OBJECT_ANT || @@ -1554,8 +1556,15 @@ void CPyro::ExploStart() for (int i = 0; i < OBJECTMAXPART; i++) { int objRank = m_object->GetObjectRank(i); - if ( objRank == -1 ) continue; - m_engine->ChangeSecondTexture(objRank, "dirty04.tga"); + if (objRank == -1) continue; + + // TODO: refactor later to material change + int oldBaseObjRank = m_engine->GetObjectBaseRank(objRank); + int newBaseObjRank = m_engine->CreateBaseObject(); + m_engine->CopyBaseObject(oldBaseObjRank, newBaseObjRank); + m_engine->SetObjectBaseRank(objRank, newBaseObjRank); + + m_engine->ChangeSecondTexture(objRank, "dirty04.png"); Math::Vector pos = m_object->GetPosition(i); @@ -1616,6 +1625,13 @@ void CPyro::BurnStart() { int objRank = m_object->GetObjectRank(i); if (objRank == -1) continue; + + // TODO: refactor later to material change + int oldBaseObjRank = m_engine->GetObjectBaseRank(objRank); + int newBaseObjRank = m_engine->CreateBaseObject(); + m_engine->CopyBaseObject(oldBaseObjRank, newBaseObjRank); + m_engine->SetObjectBaseRank(objRank, newBaseObjRank); + m_engine->ChangeSecondTexture(objRank, "dirty04.png"); } m_engine->LoadTexture("dirty04.png"); @@ -2382,6 +2398,7 @@ void CPyro::LightOperFrame(float rTime) { if ( m_progress < m_lightOper[i].progress ) { + assert(i > 0); // TODO: if assert fails, fix the code float progress = (m_progress-m_lightOper[i-1].progress) / (m_lightOper[i].progress-m_lightOper[i-1].progress); float intensity = m_lightOper[i-1].intensity + (m_lightOper[i].intensity-m_lightOper[i-1].intensity)*progress; @@ -2399,3 +2416,4 @@ void CPyro::LightOperFrame(float rTime) } // namespace Gfx + diff --git a/src/graphics/engine/pyro.h b/src/graphics/engine/pyro.h index 9548a07..98b9a1b 100644 --- a/src/graphics/engine/pyro.h +++ b/src/graphics/engine/pyro.h @@ -219,3 +219,4 @@ protected: } // namespace Gfx + diff --git a/src/graphics/engine/terrain.cpp b/src/graphics/engine/terrain.cpp index c2a7855..4fe3057 100644 --- a/src/graphics/engine/terrain.cpp +++ b/src/graphics/engine/terrain.cpp @@ -1801,3 +1801,4 @@ float CTerrain::GetFlyingLimit(Math::Vector pos, bool noLimit) } // namespace Gfx + diff --git a/src/graphics/engine/terrain.h b/src/graphics/engine/terrain.h index 1fa8dec..e2317c4 100644 --- a/src/graphics/engine/terrain.h +++ b/src/graphics/engine/terrain.h @@ -418,3 +418,4 @@ protected: } // namespace Gfx + diff --git a/src/graphics/engine/test/CMakeLists.txt b/src/graphics/engine/test/CMakeLists.txt deleted file mode 100644 index afaa86a..0000000 --- a/src/graphics/engine/test/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE debug) -endif(NOT CMAKE_BUILD_TYPE) -set(CMAKE_CXX_FLAGS_DEBUG "-g -O0") - -set(MODELFILE_TEST_SOURCES -modelfile_test.cpp -../modelfile.cpp -../../../common/logger.cpp -../../../common/stringutils.cpp -) - -add_definitions(-DMODELFILE_NO_ENGINE) - -include_directories( -. -../../.. -${GTEST_INCLUDE_DIR} -) - -add_executable(modelfile_test ${MODELFILE_TEST_SOURCES}) - -target_link_libraries(modelfile_test gtest) - -add_test(modelfile_test modelfile_test) diff --git a/src/graphics/engine/test/modelfile_test.cpp b/src/graphics/engine/test/modelfile_test.cpp deleted file mode 100644 index e7078a9..0000000 --- a/src/graphics/engine/test/modelfile_test.cpp +++ /dev/null @@ -1,262 +0,0 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2012, Polish Portal of Colobot (PPC) -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - - -#include "common/logger.h" -#include "graphics/engine/modelfile.h" -#include "math/func.h" - -#include <gtest/gtest.h> - -#include <cassert> -#include <sstream> - -/* Test model file (new text format) */ -const char* const TEXT_MODEL = -"# Colobot text model\n" -"\n" -"### HEAD\n" -"version 1\n" -"total_triangles 2\n" -"\n" -"### TRIANGLES\n" -"p1 c -12.4099 10.0016 -2.54558 n 1 -0 1.87319e-07 t1 0.970703 0.751953 t2 0 0\n" -"p2 c -12.4099 10.0016 2.54558 n 1 -0 1.87319e-07 t1 0.998047 0.751953 t2 0 0\n" -"p3 c -12.4099 4.00165 -2.54558 n 1 -0 1.87319e-07 t1 0.970703 0.998047 t2 0 0\n" -"mat dif 1 1 1 0 amb 0.5 0.5 0.5 0 spc 0 0 0 0\n" -"tex1 lemt.png\n" -"tex2\n" -"var_tex2 N\n" -"lod_level 0\n" -"state 1024\n" -"\n" -"p1 c -19 -1 4 n -1 0 0 t1 0.248047 0.123047 t2 0.905224 0.52067\n" -"p2 c -19 4 4 n -1 0 0 t1 0.248047 0.00195312 t2 0.905224 0.614223\n" -"p3 c -19 4 -4 n -1 0 0 t1 0.00195312 0.00195312 t2 0.0947756 0.614223\n" -"mat dif 1 1 1 0 amb 0.5 0.5 0.5 0 spc 0 0 0 0\n" -"tex1 derrick.png\n" -"tex2\n" -"var_tex2 Y\n" -"lod_level 1\n" -"state 0\n" -""; - -// Triangles as defined in model file -Gfx::ModelTriangle TRIANGLE_1; -Gfx::ModelTriangle TRIANGLE_2; - -// Sets triangle data -void Init() -{ - - TRIANGLE_1.p1 = Gfx::VertexTex2(Math::Vector(-12.4099, 10.0016, -2.54558), - Math::Vector(1, 0, 1.87319e-07), - Math::Point(0.970703, 0.751953), - Math::Point(0, 0)); - TRIANGLE_1.p2 = Gfx::VertexTex2(Math::Vector(-12.4099, 10.0016, 2.54558), - Math::Vector(1, 0, 1.87319e-07), - Math::Point(0.998047, 0.751953), - Math::Point(0, 0)); - TRIANGLE_1.p3 = Gfx::VertexTex2(Math::Vector(-12.4099, 4.00165, -2.54558), - Math::Vector(1, 0, 1.87319e-07), - Math::Point(0.970703, 0.998047), - Math::Point(0, 0)); - TRIANGLE_1.material.diffuse = Gfx::Color(1, 1, 1, 0); - TRIANGLE_1.material.ambient = Gfx::Color(0.5, 0.5, 0.5, 0); - TRIANGLE_1.material.specular = Gfx::Color(0, 0, 0, 0); - TRIANGLE_1.tex1Name = "lemt.png"; - TRIANGLE_1.variableTex2 = false; - TRIANGLE_1.lodLevel = Gfx::LOD_Constant; - TRIANGLE_1.state = 1024; - - TRIANGLE_2.p1 = Gfx::VertexTex2(Math::Vector(-19, -1, 4), - Math::Vector(-1, 0, 0), - Math::Point(0.248047, 0.123047), - Math::Point(0.905224, 0.52067)); - TRIANGLE_2.p2 = Gfx::VertexTex2(Math::Vector(-19, 4, 4), - Math::Vector(-1, 0, 0), - Math::Point(0.248047, 0.00195312), - Math::Point(0.905224, 0.614223)); - TRIANGLE_2.p3 = Gfx::VertexTex2(Math::Vector(-19, 4, -4), - Math::Vector(-1, 0, 0), - Math::Point(0.00195312, 0.00195312), - Math::Point(0.0947756, 0.614223)); - TRIANGLE_2.material.diffuse = Gfx::Color(1, 1, 1, 0); - TRIANGLE_2.material.ambient = Gfx::Color(0.5, 0.5, 0.5, 0); - TRIANGLE_2.material.specular = Gfx::Color(0, 0, 0, 0); - TRIANGLE_2.tex1Name = "derrick.png"; - TRIANGLE_2.variableTex2 = true; - TRIANGLE_2.lodLevel = Gfx::LOD_Low; - TRIANGLE_2.state = 0; -} - - -// Compares vertices (within Math::TOLERANCE) -bool CompareVertices(const Gfx::VertexTex2& v1, const Gfx::VertexTex2& v2) -{ - if ( !( Math::IsEqual(v1.coord.x, v2.coord.x) && - Math::IsEqual(v1.coord.y, v2.coord.y) && - Math::IsEqual(v1.coord.z, v2.coord.z) ) ) - return false; - - if ( !( Math::IsEqual(v1.normal.x, v2.normal.x) && - Math::IsEqual(v1.normal.y, v2.normal.y) && - Math::IsEqual(v1.normal.z, v2.normal.z) ) ) - return false; - - if ( !( Math::IsEqual(v1.texCoord.x, v2.texCoord.x) && - Math::IsEqual(v1.texCoord.y, v2.texCoord.y) ) ) - return false; - - if ( !( Math::IsEqual(v1.texCoord2.x, v2.texCoord2.x) && - Math::IsEqual(v1.texCoord2.y, v2.texCoord2.y) ) ) - return false; - - return true; -} - -// Compares colors (within Math::TOLERANCE) -bool CompareColors(const Gfx::Color& c1, const Gfx::Color& c2) -{ - return Math::IsEqual(c1.r, c2.r) && - Math::IsEqual(c1.g, c2.g) && - Math::IsEqual(c1.b, c2.b) && - Math::IsEqual(c1.a, c2.a); -} - -// Compares model triangles (within Math::TOLERANCE) -bool CompareTriangles(const Gfx::ModelTriangle& t1, const Gfx::ModelTriangle& t2) -{ - if (! CompareVertices(t1.p1, t2.p1)) - return false; - - if (! CompareVertices(t1.p2, t2.p2)) - return false; - - if (! CompareVertices(t1.p3, t2.p3)) - return false; - - if (! CompareColors(t1.material.diffuse, t2.material.diffuse)) - return false; - - if (! CompareColors(t1.material.ambient, t2.material.ambient)) - return false; - - if (! CompareColors(t1.material.specular, t2.material.specular)) - return false; - - if (t1.tex1Name != t2.tex1Name) - return false; - - if (t1.tex2Name != t2.tex2Name) - return false; - - if (t1.variableTex2 != t2.variableTex2) - return false; - - if (t1.lodLevel != t2.lodLevel) - return false; - - if (t1.state != t2.state) - return false; - - return true; -} - -// Tests reading/writing new text model file -TEST(ModelFileTest, RWTxtModel) -{ - std::stringstream str; - str.str(TEXT_MODEL); - - Gfx::CModelFile modelFile; - - EXPECT_TRUE(modelFile.ReadTextModel(str)); - - EXPECT_EQ(modelFile.GetTriangleCount(), 2); - EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[0], TRIANGLE_1)); - EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[1], TRIANGLE_2)); - - str.str(""); - - EXPECT_TRUE(modelFile.WriteTextModel(str)); - str.seekg(0); - EXPECT_TRUE(modelFile.ReadTextModel(str)); - - EXPECT_EQ(modelFile.GetTriangleCount(), 2); - EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[0], TRIANGLE_1)); - EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[1], TRIANGLE_2)); -} - -// Tests reading/writing new binary model -TEST(ModelFileTest, RWBinModel) -{ - std::stringstream str; - str.str(TEXT_MODEL); - - Gfx::CModelFile modelFile; - - EXPECT_TRUE(modelFile.ReadTextModel(str)); - - EXPECT_EQ(modelFile.GetTriangleCount(), 2); - EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[0], TRIANGLE_1)); - EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[1], TRIANGLE_2)); - - str.str(""); - - EXPECT_TRUE(modelFile.WriteBinaryModel(str)); - str.seekg(0); - EXPECT_TRUE(modelFile.ReadBinaryModel(str)); - - EXPECT_EQ(modelFile.GetTriangleCount(), 2); - EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[0], TRIANGLE_1)); - EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[1], TRIANGLE_2)); -} - -// Tests reading/writing old model file -TEST(ModelFileTest, RWOldModel) -{ - std::stringstream str; - str.str(TEXT_MODEL); - - Gfx::CModelFile modelFile; - - EXPECT_TRUE(modelFile.ReadTextModel(str)); - - EXPECT_EQ(modelFile.GetTriangleCount(), 2); - EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[0], TRIANGLE_1)); - EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[1], TRIANGLE_2)); - - str.str(""); - - EXPECT_TRUE(modelFile.WriteModel(str)); - str.seekg(0); - EXPECT_TRUE(modelFile.ReadModel(str)); - - EXPECT_EQ(modelFile.GetTriangleCount(), 2); - EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[0], TRIANGLE_1)); - EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[1], TRIANGLE_2)); -} - -int main(int argc, char **argv) -{ - CLogger logger; - - Init(); - - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp index 308c813..610bfcf 100644 --- a/src/graphics/engine/text.cpp +++ b/src/graphics/engine/text.cpp @@ -56,6 +56,7 @@ CText::CText(CEngine* engine) m_engine = engine; m_defaultSize = 12.0f; + m_tabSize = 4; m_lastFontType = FONT_COLOBOT; m_lastFontSize = 0; @@ -148,6 +149,16 @@ void CText::FlushCache() m_lastCachedFont = nullptr; } +int CText::GetTabSize() +{ + return m_tabSize; +} + +void CText::SetTabSize(int tabSize) +{ + m_tabSize = tabSize; +} + void CText::DrawText(const std::string &text, std::vector<FontMetaChar>::iterator format, std::vector<FontMetaChar>::iterator end, float size, Math::Point pos, float width, TextAlign align, @@ -309,11 +320,16 @@ float CText::GetStringWidth(const std::string &text, return width; } -float CText::GetStringWidth(const std::string &text, FontType font, float size) +float CText::GetStringWidth(std::string text, FontType font, float size) { assert(font != FONT_BUTTON); - // TODO: special chars? + // Skip special chars + for (char& c : text) + { + if (c < 32) + c = ':'; + } CachedFont* cf = GetOrOpenFont(font, size); assert(cf != nullptr); @@ -328,8 +344,16 @@ float CText::GetCharWidth(UTF8Char ch, FontType font, float size, float offset) // TODO: if (font == FONT_BUTTON) if (font == FONT_BUTTON) return 0.0f; - // TODO: special chars? - // TODO: tab sizing + int width = 1; + if (ch.c1 < 32) + { + if (ch.c1 == '\t') + width = m_tabSize; + + // TODO: tab sizing at intervals? + + ch.c1 = ':'; + } CachedFont* cf = GetOrOpenFont(font, size); assert(cf != nullptr); @@ -341,7 +365,7 @@ float CText::GetCharWidth(UTF8Char ch, FontType font, float size, float offset) else tex = CreateCharTexture(ch, cf); - return tex.charSize.x; + return tex.charSize.x * width; } @@ -505,6 +529,63 @@ int CText::Detect(const std::string &text, FontType font, float size, float offs return index; } +UTF8Char CText::TranslateSpecialChar(int specialChar) +{ + UTF8Char ch; + + switch (specialChar) + { + case CHAR_TAB: + ch.c1 = ':'; + ch.c2 = 0; + ch.c3 = 0; + break; + + case CHAR_NEWLINE: + // Unicode: U+21B2 + ch.c1 = 0xE2; + ch.c2 = 0x86; + ch.c3 = 0xB2; + break; + + case CHAR_DOT: + // Unicode: U+23C5 + ch.c1 = 0xE2; + ch.c2 = 0x8F; + ch.c3 = 0x85; + break; + + case CHAR_SQUARE: + // Unicode: U+25FD + ch.c1 = 0xE2; + ch.c2 = 0x97; + ch.c3 = 0xBD; + break; + + case CHAR_SKIP_RIGHT: + // Unicode: U+25B6 + ch.c1 = 0xE2; + ch.c2 = 0x96; + ch.c3 = 0xB6; + break; + + case CHAR_SKIP_LEFT: + // Unicode: U+25C0 + ch.c1 = 0xE2; + ch.c2 = 0x97; + ch.c3 = 0x80; + break; + + default: + ch.c1 = '?'; + ch.c2 = 0; + ch.c3 = 0; + break; + } + + return ch; +} + void CText::DrawString(const std::string &text, std::vector<FontMetaChar>::iterator format, std::vector<FontMetaChar>::iterator end, float size, Math::Point pos, float width, int eol, Color color) @@ -532,7 +613,11 @@ void CText::DrawString(const std::string &text, std::vector<FontMetaChar>::itera float cw = GetCharWidth(ch, font, size, offset); if (offset + cw > width) // exceeds the maximum width? { - // TODO: special end-of-line char + ch = TranslateSpecialChar(CHAR_SKIP_RIGHT); + cw = GetCharWidth(ch, font, size, offset); + pos.x = start + width - cw; + color = Color(1.0f, 0.0f, 0.0f); + DrawCharAndAdjustPos(ch, font, size, pos, color); break; } @@ -550,7 +635,13 @@ void CText::DrawString(const std::string &text, std::vector<FontMetaChar>::itera fmtIndex++; } - // TODO: eol + if (eol != 0) + { + FontType font = FONT_COLOBOT; + UTF8Char ch = TranslateSpecialChar(eol); + color = Color(1.0f, 0.0f, 0.0f); + DrawCharAndAdjustPos(ch, font, size, pos, color); + } } void CText::StringToUTFCharList(const std::string &text, std::vector<UTF8Char> &chars) @@ -675,23 +766,18 @@ void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::P // TODO: if (font == FONT_BUTTON) if (font == FONT_BUTTON) return; - // TODO: special chars? - CachedFont* cf = GetOrOpenFont(font, size); if (cf == nullptr) return; int width = 1; - if (ch.c1 > 0 && ch.c1 < 32) { // FIXME add support for chars with code 9 10 23 - if (ch.c1 == '\t') { - ch.c1 = ':'; - width = 4; - } else { - ch.c1 = ' '; - } - ch.c2 = 0; - ch.c3 = 0; + if (ch.c1 > 0 && ch.c1 < 32) + { + if (ch.c1 == '\t') + width = m_tabSize; + + ch = TranslateSpecialChar(ch.c1); } auto it = cf->cache.find(ch); @@ -827,3 +913,4 @@ CharTexture CText::CreateCharTexture(UTF8Char ch, CachedFont* font) } // namespace Gfx + diff --git a/src/graphics/engine/text.h b/src/graphics/engine/text.h index 6bcc59b..3abb8b7 100644 --- a/src/graphics/engine/text.h +++ b/src/graphics/engine/text.h @@ -206,6 +206,20 @@ struct MultisizeFont }; /** + * \enum SpecialChar + * \brief Special codes for certain characters + */ +enum SpecialChar +{ + CHAR_TAB = '\t', //! Tab character - : + CHAR_NEWLINE = '\n', //! Newline character - arrow pointing down and left + CHAR_DOT = 1, //! Single dot in the middle + CHAR_SQUARE = 2, //! Square + CHAR_SKIP_RIGHT = 5, //! Filled triangle pointing right + CHAR_SKIP_LEFT = 6 //! Filled triangle pointing left +}; + +/** * \class CText * \brief Text rendering engine * @@ -240,6 +254,12 @@ public: //! Flushes cached textures void FlushCache(); + //@{ + //! Tab size management + void SetTabSize(int tabSize); + int GetTabSize(); + //@} + //! Draws text (multi-format) void DrawText(const std::string &text, std::vector<FontMetaChar>::iterator format, std::vector<FontMetaChar>::iterator end, @@ -268,11 +288,11 @@ public: float GetHeight(FontType font, float size); //! Returns width of string (multi-format) - TEST_VIRTUAL float GetStringWidth(const std::string &text, - std::vector<FontMetaChar>::iterator format, - std::vector<FontMetaChar>::iterator end, float size); + TEST_VIRTUAL float GetStringWidth(const std::string& text, + std::vector<FontMetaChar>::iterator format, + std::vector<FontMetaChar>::iterator end, float size); //! Returns width of string (single font) - TEST_VIRTUAL float GetStringWidth(const std::string &text, FontType font, float size); + TEST_VIRTUAL float GetStringWidth(std::string text, FontType font, float size); //! Returns width of single character TEST_VIRTUAL float GetCharWidth(UTF8Char ch, FontType font, float size, float offset); @@ -290,6 +310,8 @@ public: //! Returns the most suitable position to a given offset (one font) int Detect(const std::string &text, FontType font, float size, float offset); + UTF8Char TranslateSpecialChar(int specialChar); + protected: CachedFont* GetOrOpenFont(FontType type, float size); CharTexture CreateCharTexture(UTF8Char ch, CachedFont* font); @@ -309,6 +331,7 @@ protected: std::string m_error; float m_defaultSize; + int m_tabSize; std::map<FontType, MultisizeFont*> m_fonts; @@ -319,3 +342,4 @@ protected: } // namespace Gfx + diff --git a/src/graphics/engine/water.cpp b/src/graphics/engine/water.cpp index d90652b..d1f8d29 100644 --- a/src/graphics/engine/water.cpp +++ b/src/graphics/engine/water.cpp @@ -628,3 +628,4 @@ void CWater::AdjustEye(Math::Vector &eye) } // namespace Gfx + diff --git a/src/graphics/engine/water.h b/src/graphics/engine/water.h index bb113e0..5e9f4b2 100644 --- a/src/graphics/engine/water.h +++ b/src/graphics/engine/water.h @@ -204,3 +204,4 @@ protected: } // namespace Gfx + diff --git a/src/graphics/opengl/README.txt b/src/graphics/opengl/README.txt index c62166b..1a6bedd 100644 --- a/src/graphics/opengl/README.txt +++ b/src/graphics/opengl/README.txt @@ -5,3 +5,4 @@ * Contains the concrete implementation using OpenGL of abstract CDevice class * from src/graphics/core */ + diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp index df64e34..bbabdd6 100644 --- a/src/graphics/opengl/gldevice.cpp +++ b/src/graphics/opengl/gldevice.cpp @@ -79,6 +79,106 @@ void CGLDevice::DebugHook() glColor3i(0, 0, 0); } +void CGLDevice::DebugLights() +{ + Gfx::ColorHSV color(0.0, 1.0, 1.0); + + glLineWidth(3.0f); + glDisable(GL_LIGHTING); + glDepthMask(GL_FALSE); + glDisable(GL_BLEND); + + Math::Matrix saveWorldMat = m_worldMat; + m_worldMat.LoadIdentity(); + UpdateModelviewMatrix(); + + for (int i = 0; i < static_cast<int>( m_lights.size() ); ++i) + { + color.h = static_cast<float>(i) / static_cast<float>(m_lights.size()); + if (m_lightsEnabled[i]) + { + const Light& l = m_lights[i]; + if (l.type == LIGHT_DIRECTIONAL) + { + Gfx::VertexCol v[2]; + v[0].coord = -Math::Normalize(l.direction) * 100.0f + Math::Vector(0.0f, 0.0f, 1.0f) * i; + v[0].color = HSV2RGB(color); + v[1].coord = Math::Normalize(l.direction) * 100.0f + Math::Vector(0.0f, 0.0f, 1.0f) * i; + v[1].color = HSV2RGB(color); + while (v[0].coord.y < 60.0f && v[0].coord.y < 60.0f) + { + v[0].coord.y += 10.0f; + v[1].coord.y += 10.0f; + } + DrawPrimitive(PRIMITIVE_LINES, v, 2); + + v[0].coord = v[1].coord + Math::Normalize(v[0].coord - v[1].coord) * 50.0f; + + glLineWidth(10.0f); + DrawPrimitive(PRIMITIVE_LINES, v, 2); + glLineWidth(3.0f); + } + else if (l.type == LIGHT_POINT) + { + Gfx::VertexCol v[8]; + for (int i = 0; i < 8; ++i) + v[i].color = HSV2RGB(color); + + v[0].coord = l.position + Math::Vector(-1.0f, -1.0f, -1.0f) * 4.0f; + v[1].coord = l.position + Math::Vector( 1.0f, -1.0f, -1.0f) * 4.0f; + v[2].coord = l.position + Math::Vector( 1.0f, 1.0f, -1.0f) * 4.0f; + v[3].coord = l.position + Math::Vector(-1.0f, 1.0f, -1.0f) * 4.0f; + v[4].coord = l.position + Math::Vector(-1.0f, -1.0f, -1.0f) * 4.0f; + DrawPrimitive(PRIMITIVE_LINE_STRIP, v, 5); + + v[0].coord = l.position + Math::Vector(-1.0f, -1.0f, 1.0f) * 4.0f; + v[1].coord = l.position + Math::Vector( 1.0f, -1.0f, 1.0f) * 4.0f; + v[2].coord = l.position + Math::Vector( 1.0f, 1.0f, 1.0f) * 4.0f; + v[3].coord = l.position + Math::Vector(-1.0f, 1.0f, 1.0f) * 4.0f; + v[4].coord = l.position + Math::Vector(-1.0f, -1.0f, 1.0f) * 4.0f; + DrawPrimitive(PRIMITIVE_LINE_STRIP, v, 5); + + v[0].coord = l.position + Math::Vector(-1.0f, -1.0f, -1.0f) * 4.0f; + v[1].coord = l.position + Math::Vector(-1.0f, -1.0f, 1.0f) * 4.0f; + v[2].coord = l.position + Math::Vector( 1.0f, -1.0f, -1.0f) * 4.0f; + v[3].coord = l.position + Math::Vector( 1.0f, -1.0f, 1.0f) * 4.0f; + v[4].coord = l.position + Math::Vector( 1.0f, 1.0f, -1.0f) * 4.0f; + v[5].coord = l.position + Math::Vector( 1.0f, 1.0f, 1.0f) * 4.0f; + v[6].coord = l.position + Math::Vector(-1.0f, 1.0f, -1.0f) * 4.0f; + v[7].coord = l.position + Math::Vector(-1.0f, 1.0f, 1.0f) * 4.0f; + DrawPrimitive(PRIMITIVE_LINES, v, 8); + } + else if (l.type == LIGHT_SPOT) + { + Gfx::VertexCol v[5]; + for (int i = 0; i < 5; ++i) + v[i].color = HSV2RGB(color); + + v[0].coord = l.position + Math::Vector(-1.0f, 0.0f, -1.0f) * 4.0f; + v[1].coord = l.position + Math::Vector( 1.0f, 0.0f, -1.0f) * 4.0f; + v[2].coord = l.position + Math::Vector( 1.0f, 0.0f, 1.0f) * 4.0f; + v[3].coord = l.position + Math::Vector(-1.0f, 0.0f, 1.0f) * 4.0f; + v[4].coord = l.position + Math::Vector(-1.0f, 0.0f, -1.0f) * 4.0f; + DrawPrimitive(PRIMITIVE_LINE_STRIP, v, 5); + + v[0].coord = l.position; + v[1].coord = l.position + Math::Normalize(l.direction) * 100.0f; + glEnable(GL_LINE_STIPPLE); + glLineStipple(3.0, 0xFF); + DrawPrimitive(PRIMITIVE_LINES, v, 2); + glDisable(GL_LINE_STIPPLE); + } + } + } + + glLineWidth(1.0f); + glEnable(GL_LIGHTING); + glDepthMask(GL_TRUE); + glEnable(GL_BLEND); + m_worldMat = saveWorldMat; + UpdateModelviewMatrix(); +} + bool CGLDevice::Create() { GetLogger()->Info("Creating CDevice\n"); @@ -417,13 +517,21 @@ bool CGLDevice::GetLightEnabled(int index) Texture CGLDevice::CreateTexture(CImage *image, const TextureCreateParams ¶ms) { ImageData *data = image->GetData(); - if (data == NULL) + if (data == nullptr) { GetLogger()->Error("Invalid texture data\n"); return Texture(); // invalid texture } - return CreateTexture(data, params); + Math::IntPoint originalSize = image->GetSize(); + + if (params.padToNearestPowerOfTwo) + image->PadToNearestPowerOfTwo(); + + Texture tex = CreateTexture(data, params); + tex.originalSize = originalSize; + + return tex; } Texture CGLDevice::CreateTexture(ImageData *data, const TextureCreateParams ¶ms) @@ -433,6 +541,11 @@ Texture CGLDevice::CreateTexture(ImageData *data, const TextureCreateParams &par result.size.x = data->surface->w; result.size.y = data->surface->h; + if (!Math::IsPowerOfTwo(result.size.x) || !Math::IsPowerOfTwo(result.size.y)) + GetLogger()->Warn("Creating non-power-of-2 texture (%dx%d)!\n", result.size.x, result.size.y); + + result.originalSize = result.size; + // Use & enable 1st texture stage if (m_multitextureAvailable) glActiveTexture(GL_TEXTURE0); @@ -640,7 +753,7 @@ void CGLDevice::SetTexture(int index, const Texture &texture) glBindTexture(GL_TEXTURE_2D, texture.id); // Params need to be updated for the new bound texture - SetTextureStageParams(index, m_textureStageParams[index]); + UpdateTextureParams(index); } void CGLDevice::SetTexture(int index, unsigned int textureId) @@ -661,7 +774,7 @@ void CGLDevice::SetTexture(int index, unsigned int textureId) glBindTexture(GL_TEXTURE_2D, textureId); // Params need to be updated for the new bound texture - SetTextureStageParams(index, m_textureStageParams[index]); + UpdateTextureParams(index); } /** @@ -714,6 +827,13 @@ void CGLDevice::SetTextureStageParams(int index, const TextureStageParams ¶m // Remember the settings m_textureStageParams[index] = params; + UpdateTextureParams(index); +} + +void CGLDevice::UpdateTextureParams(int index) +{ + assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() )); + if (!m_multitextureAvailable && index != 0) return; @@ -721,6 +841,8 @@ void CGLDevice::SetTextureStageParams(int index, const TextureStageParams ¶m if (! m_currentTextures[index].Valid()) return; + const TextureStageParams ¶ms = m_textureStageParams[index]; + if (m_multitextureAvailable) glActiveTexture(GL_TEXTURE0 + index); @@ -1667,3 +1789,4 @@ FillMode CGLDevice::GetFillMode() } // namespace Gfx + diff --git a/src/graphics/opengl/gldevice.h b/src/graphics/opengl/gldevice.h index fe3f2a1..c648161 100644 --- a/src/graphics/opengl/gldevice.h +++ b/src/graphics/opengl/gldevice.h @@ -93,6 +93,7 @@ public: virtual ~CGLDevice(); virtual void DebugHook(); + virtual void DebugLights(); virtual bool Create(); virtual void Destroy(); @@ -192,6 +193,8 @@ private: void UpdateModelviewMatrix(); //! Updates position for given light based on transformation matrices void UpdateLightPosition(int index); + //! Updates the texture params for given texture stage + void UpdateTextureParams(int index); private: //! Current config @@ -255,3 +258,4 @@ private: } // namespace Gfx + |