summaryrefslogtreecommitdiffstats
path: root/src/graphics/engine
diff options
context:
space:
mode:
Diffstat (limited to 'src/graphics/engine')
-rw-r--r--src/graphics/engine/README.txt4
-rw-r--r--src/graphics/engine/engine.cpp107
-rw-r--r--src/graphics/engine/engine.h11
-rw-r--r--src/graphics/engine/lightman.cpp147
-rw-r--r--src/graphics/engine/lightman.h58
-rw-r--r--src/graphics/engine/planet.cpp5
-rw-r--r--src/graphics/engine/planet.h3
-rw-r--r--src/graphics/engine/terrain.cpp95
-rw-r--r--src/graphics/engine/text.cpp46
-rw-r--r--src/graphics/engine/text.h5
-rw-r--r--src/graphics/engine/water.cpp23
-rw-r--r--src/graphics/engine/water.h14
12 files changed, 297 insertions, 221 deletions
diff --git a/src/graphics/engine/README.txt b/src/graphics/engine/README.txt
index f64d3dd..05d2d76 100644
--- a/src/graphics/engine/README.txt
+++ b/src/graphics/engine/README.txt
@@ -1,9 +1,9 @@
/**
- * \dir graphics/engine
+ * \dir src/graphics/engine
* \brief Graphics engine
*
* CEngine class and various other classes implementing the main features
* of graphics engine from model loading to decorative particles
*
* Graphics operations are done on abstract interface from src/graphics/core
- */ \ No newline at end of file
+ */
diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp
index c170922..c094c63 100644
--- a/src/graphics/engine/engine.cpp
+++ b/src/graphics/engine/engine.cpp
@@ -186,6 +186,8 @@ CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
m_updateGeometry = false;
+ m_interfaceMode = 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));
@@ -215,6 +217,11 @@ CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
m_defaultTexParams.minFilter = TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR;
m_defaultTexParams.magFilter = TEX_MAG_FILTER_LINEAR;
+ m_terrainTexParams.format = TEX_IMG_AUTO;
+ m_terrainTexParams.mipmap = false;
+ m_terrainTexParams.minFilter = TEX_MIN_FILTER_LINEAR;
+ m_terrainTexParams.magFilter = TEX_MAG_FILTER_LINEAR;
+
m_objectTree.reserve(LEVEL1_PREALLOCATE_COUNT);
m_objects.reserve(OBJECT_PREALLOCATE_COUNT);
m_shadows.reserve(SHADOW_PREALLOCATE_COUNT);
@@ -1844,8 +1851,6 @@ void CEngine::SetState(int state, const Color& color)
m_device->SetRenderState(RENDER_STATE_BLENDING, true);
m_device->SetBlendFunc(BLEND_ONE, BLEND_INV_SRC_COLOR);
- m_device->SetRenderState(RENDER_STATE_TEXTURING, true);
-
m_device->SetTextureFactor(color);
TextureStageParams params;
@@ -1866,8 +1871,6 @@ void CEngine::SetState(int state, const Color& color)
m_device->SetRenderState(RENDER_STATE_BLENDING, true);
m_device->SetBlendFunc(BLEND_DST_COLOR, BLEND_ZERO);
- m_device->SetRenderState(RENDER_STATE_TEXTURING, true);
-
m_device->SetTextureFactor(color.Inverse());
TextureStageParams params;
@@ -1884,20 +1887,22 @@ void CEngine::SetState(int state, const Color& color)
m_device->SetRenderState(RENDER_STATE_FOG, false);
m_device->SetRenderState(RENDER_STATE_DEPTH_WRITE, false);
m_device->SetRenderState(RENDER_STATE_ALPHA_TEST, false);
- m_device->SetRenderState(RENDER_STATE_TEXTURING, false);
m_device->SetRenderState(RENDER_STATE_BLENDING, true);
m_device->SetBlendFunc(BLEND_ONE, BLEND_INV_SRC_COLOR);
+
+ m_device->SetTextureEnabled(0, false);
}
else if (state & ENG_RSTATE_TCOLOR_WHITE) // transparent white color?
{
m_device->SetRenderState(RENDER_STATE_FOG, false);
m_device->SetRenderState(RENDER_STATE_DEPTH_WRITE, false);
m_device->SetRenderState(RENDER_STATE_ALPHA_TEST, false);
- m_device->SetRenderState(RENDER_STATE_TEXTURING, false);
m_device->SetRenderState(RENDER_STATE_BLENDING, true);
m_device->SetBlendFunc(BLEND_DST_COLOR, BLEND_ZERO);
+
+ m_device->SetTextureEnabled(0, false);
}
else if (state & ENG_RSTATE_TDIFFUSE) // diffuse color as transparent?
{
@@ -1908,8 +1913,6 @@ void CEngine::SetState(int state, const Color& color)
m_device->SetRenderState(RENDER_STATE_BLENDING, true);
m_device->SetBlendFunc(BLEND_SRC_ALPHA, BLEND_DST_ALPHA);
- m_device->SetRenderState(RENDER_STATE_TEXTURING, true);
-
TextureStageParams params;
params.colorOperation = TEX_MIX_OPER_REPLACE;
params.colorArg1 = TEX_MIX_ARG_TEXTURE;
@@ -1925,7 +1928,6 @@ void CEngine::SetState(int state, const Color& color)
m_device->SetRenderState(RENDER_STATE_ALPHA_TEST, false);
m_device->SetRenderState(RENDER_STATE_BLENDING, false);
- m_device->SetRenderState(RENDER_STATE_TEXTURING, true);
m_device->SetTextureEnabled(0, true);
m_device->SetTextureStageParams(0, TextureStageParams()); // default operation
}
@@ -1935,7 +1937,8 @@ void CEngine::SetState(int state, const Color& color)
m_device->SetRenderState(RENDER_STATE_DEPTH_WRITE, false);
m_device->SetRenderState(RENDER_STATE_ALPHA_TEST, false);
m_device->SetRenderState(RENDER_STATE_BLENDING, false);
- m_device->SetRenderState(RENDER_STATE_TEXTURING, false);
+
+ m_device->SetTextureEnabled(0, false);
}
else if (state & ENG_RSTATE_TEXT) // font rendering?
{
@@ -1946,14 +1949,8 @@ void CEngine::SetState(int state, const Color& color)
m_device->SetRenderState(RENDER_STATE_BLENDING, true);
m_device->SetBlendFunc(BLEND_SRC_ALPHA, BLEND_INV_SRC_ALPHA);
- m_device->SetRenderState(RENDER_STATE_TEXTURING, true);
-
- TextureStageParams params;
- params.colorOperation = TEX_MIX_OPER_DEFAULT; // default modulate operation
- params.alphaOperation = TEX_MIX_OPER_DEFAULT; // default modulate operation
-
m_device->SetTextureEnabled(0, true);
- m_device->SetTextureStageParams(0, params);
+ m_device->SetTextureStageParams(0, TextureStageParams()); // default operation
}
else if (state & ENG_RSTATE_ALPHA) // image with alpha channel?
{
@@ -1966,8 +1963,6 @@ void CEngine::SetState(int state, const Color& color)
m_device->SetAlphaTestFunc(COMP_FUNC_GREATER, 0.5f);
- m_device->SetRenderState(RENDER_STATE_TEXTURING, true);
-
m_device->SetTextureFactor(color);
TextureStageParams params;
@@ -1988,8 +1983,6 @@ void CEngine::SetState(int state, const Color& color)
m_device->SetRenderState(RENDER_STATE_DEPTH_WRITE, true);
m_device->SetRenderState(RENDER_STATE_FOG, true);
- m_device->SetRenderState(RENDER_STATE_TEXTURING, true);
-
TextureStageParams params;
params.colorOperation = TEX_MIX_OPER_DEFAULT; // default modulate
params.alphaOperation = TEX_MIX_OPER_DEFAULT; // TODO: replace with src color ?
@@ -2014,7 +2007,7 @@ void CEngine::SetState(int state, const Color& color)
params.colorArg1 = TEX_MIX_ARG_TEXTURE;
params.colorArg2 = TEX_MIX_ARG_COMPUTED_COLOR;
params.alphaOperation = TEX_MIX_OPER_DEFAULT; // TODO: ???
- m_device->SetTextureEnabled(0, true);
+ m_device->SetTextureEnabled(1, true);
m_device->SetTextureStageParams(1, params);
}
else if ((state & ENG_RSTATE_DUAL_WHITE) && second)
@@ -2024,7 +2017,7 @@ void CEngine::SetState(int state, const Color& color)
params.colorArg1 = TEX_MIX_ARG_TEXTURE;
params.colorArg2 = TEX_MIX_ARG_COMPUTED_COLOR;
params.alphaOperation = TEX_MIX_OPER_DEFAULT; // TODO: ???
- m_device->SetTextureEnabled(0, true);
+ m_device->SetTextureEnabled(1, true);
m_device->SetTextureStageParams(1, params);
}
else
@@ -2034,25 +2027,13 @@ void CEngine::SetState(int state, const Color& color)
if (state & ENG_RSTATE_WRAP)
{
- // TODO: separate function for setting wrap mode?
-
- TextureStageParams p1 = m_device->GetTextureStageParams(0);
- p1.wrapS = p1.wrapT = TEX_WRAP_REPEAT;
- m_device->SetTextureStageParams(0, p1);
-
- TextureStageParams p2 = m_device->GetTextureStageParams(1);
- p2.wrapS = p2.wrapT = TEX_WRAP_REPEAT;
- m_device->SetTextureStageParams(1, p2);
+ m_device->SetTextureStageWrap(0, TEX_WRAP_REPEAT, TEX_WRAP_REPEAT);
+ m_device->SetTextureStageWrap(1, TEX_WRAP_REPEAT, TEX_WRAP_REPEAT);
}
else // if (state & ENG_RSTATE_CLAMP) or otherwise
{
- TextureStageParams p1 = m_device->GetTextureStageParams(0);
- p1.wrapS = p1.wrapT = TEX_WRAP_CLAMP;
- m_device->SetTextureStageParams(0, p1);
-
- TextureStageParams p2 = m_device->GetTextureStageParams(1);
- p2.wrapS = p2.wrapT = TEX_WRAP_CLAMP;
- m_device->SetTextureStageParams(1, p2);
+ m_device->SetTextureStageWrap(0, TEX_WRAP_CLAMP, TEX_WRAP_CLAMP);
+ m_device->SetTextureStageWrap(1, TEX_WRAP_CLAMP, TEX_WRAP_CLAMP);
}
if (state & ENG_RSTATE_2FACE)
@@ -2069,6 +2050,11 @@ void CEngine::SetState(int state, const Color& color)
m_device->SetGlobalAmbient(Color(1.0f, 1.0f, 1.0f, 1.0f));
else
m_device->SetGlobalAmbient(m_ambientColor[m_rankView]);
+
+
+ // In interface mode, disable lighting
+ if (m_interfaceMode)
+ m_device->SetRenderState(RENDER_STATE_LIGHTING, false);
}
void CEngine::SetMaterial(const Material& mat)
@@ -2177,16 +2163,35 @@ bool CEngine::LoadAllTextures()
EngineObjLevel1& p1 = m_objectTree[l1];
if (! p1.used) continue;
+ bool terrain = false;
+
+ for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
+ {
+ EngineObjLevel2& p2 = p1.next[l2];
+ if (! p2.used) continue;
+
+ if (m_objects[p2.objRank].type == ENG_OBJTYPE_TERRAIN)
+ terrain = true;
+ }
+
if (! p1.tex1Name.empty())
{
- p1.tex1 = LoadTexture(p1.tex1Name);
+ if (terrain)
+ p1.tex1 = LoadTexture(p1.tex1Name, m_terrainTexParams);
+ else
+ p1.tex1 = LoadTexture(p1.tex1Name);
+
if (! p1.tex1.Valid())
ok = false;
}
if (! p1.tex2Name.empty())
{
- p1.tex2 = LoadTexture(p1.tex2Name);
+ if (terrain)
+ p1.tex2 = LoadTexture(p1.tex2Name, m_terrainTexParams);
+ else
+ p1.tex2 = LoadTexture(p1.tex2Name);
+
if (! p1.tex2.Valid())
ok = false;
}
@@ -2810,7 +2815,7 @@ void CEngine::Draw3DScene()
if (m_shadowVisible)
{
- m_lightMan->UpdateLightsEnableState(ENG_OBJTYPE_TERRAIN);
+ m_lightMan->UpdateDeviceLights(ENG_OBJTYPE_TERRAIN);
// Draw the terrain
@@ -2910,7 +2915,7 @@ void CEngine::Draw3DScene()
if (! IsVisible(objRank))
continue;
- m_lightMan->UpdateLightsEnableState(m_objects[objRank].type);
+ m_lightMan->UpdateDeviceLights(m_objects[objRank].type);
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
@@ -2999,7 +3004,7 @@ void CEngine::Draw3DScene()
if (! IsVisible(objRank))
continue;
- m_lightMan->UpdateLightsEnableState(m_objects[objRank].type);
+ m_lightMan->UpdateDeviceLights(m_objects[objRank].type);
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
@@ -3041,7 +3046,7 @@ void CEngine::Draw3DScene()
}
}
- m_lightMan->UpdateLightsEnableState(ENG_OBJTYPE_TERRAIN);
+ m_lightMan->UpdateDeviceLights(ENG_OBJTYPE_TERRAIN);
if (m_waterMode) m_water->DrawSurf(); // draws water surface
@@ -3064,11 +3069,20 @@ void CEngine::DrawInterface()
m_device->SetTransform(TRANSFORM_PROJECTION, m_matProjInterface);
m_device->SetTransform(TRANSFORM_WORLD, m_matWorldInterface);
+ // Force new state to disable lighting
+ m_interfaceMode = true;
+ m_lastState = -1;
+ SetState(Gfx::ENG_RSTATE_NORMAL);
+
// Draw the entire interface
Ui::CInterface* interface = static_cast<Ui::CInterface*>( m_iMan->SearchInstance(CLASS_INTERFACE) );
if (interface != nullptr)
interface->Draw();
+ m_interfaceMode = false;
+ m_lastState = -1;
+ SetState(Gfx::ENG_RSTATE_NORMAL);
+
m_particle->DrawParticle(SH_INTERFACE); // draws the particles of the interface
// 3D objects drawn in front of interface
@@ -3117,7 +3131,7 @@ void CEngine::DrawInterface()
if (! IsVisible(objRank))
continue;
- m_lightMan->UpdateLightsEnableState(m_objects[objRank].type);
+ m_lightMan->UpdateDeviceLights(m_objects[objRank].type);
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
@@ -3559,7 +3573,6 @@ void CEngine::DrawOverColor()
m_device->SetRenderState(RENDER_STATE_DEPTH_WRITE, false);
m_device->SetRenderState(RENDER_STATE_LIGHTING, false);
m_device->SetRenderState(RENDER_STATE_FOG, false);
- m_device->SetRenderState(RENDER_STATE_TEXTURING, false);
m_device->SetTransform(TRANSFORM_VIEW, m_matViewInterface);
m_device->SetTransform(TRANSFORM_PROJECTION, m_matProjInterface);
diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h
index e36865c..6363fd3 100644
--- a/src/graphics/engine/engine.h
+++ b/src/graphics/engine/engine.h
@@ -568,7 +568,7 @@ struct EngineMouse
*
* It uses a lower-level CDevice object which is implementation-independent core engine.
*
- * \section 3DScene 3D Scene
+ * \section Scene 3D Scene
*
* The 3D scene is drawn with view coordinates set from camera position in 3D space and
* a perspective projection matrix. The world matrix depends on the object drawn.
@@ -588,7 +588,7 @@ struct EngineMouse
* - mouse cursor
* - animated highlight box of the selected object(s)
*
- * \section 2DInterface 2D Interface
+ * \section Interface 2D Interface
*
* The 2D interface is drawn in fixed XY coordinates, independent from window size.
* Lower-left corner of the screen is (0,0) and upper-right corner is (1,1).
@@ -601,7 +601,7 @@ struct EngineMouse
* are instances of CControl class. The source code for these classes is in
* src/ui directory.
*
- * \section Objecs Engine Objects
+ * \section Objects Engine Objects
*
* The 3D scene is composed of objects which are basically collections of triangles forming
* a surface or simply independent triangles in space.
@@ -1348,6 +1348,8 @@ protected:
//! Default texture create params
TextureCreateParams m_defaultTexParams;
+ //! Create params for terrain textures
+ TextureCreateParams m_terrainTexParams;
//! Map of loaded textures (by name)
std::map<std::string, Texture> m_texNameMap;
@@ -1375,6 +1377,9 @@ protected:
std::string m_lastTexture[2];
//! Last material
Material m_lastMaterial;
+
+ //! True when drawing 2D UI
+ bool m_interfaceMode;
};
diff --git a/src/graphics/engine/lightman.cpp b/src/graphics/engine/lightman.cpp
index 02719de..3055f08 100644
--- a/src/graphics/engine/lightman.cpp
+++ b/src/graphics/engine/lightman.cpp
@@ -18,6 +18,7 @@
#include "graphics/engine/lightman.h"
+#include "common/logger.h"
#include "common/iman.h"
#include "graphics/core/device.h"
@@ -28,6 +29,7 @@
#include <cmath>
+// Graphics module namespace
namespace Gfx {
@@ -70,6 +72,7 @@ void LightProgression::SetTarget(float value)
DynamicLight::DynamicLight()
{
used = enabled = false;
+ priority = LIGHT_PRI_LOW;
includeType = excludeType = ENG_OBJTYPE_NULL;
}
@@ -80,7 +83,7 @@ CLightManager::CLightManager(CInstanceManager* iMan, CEngine* engine)
m_iMan = iMan;
m_iMan->AddInstance(CLASS_LIGHT, this);
- m_device = NULL;
+ m_device = nullptr;
m_engine = engine;
m_time = 0.0f;
@@ -90,56 +93,54 @@ CLightManager::~CLightManager()
{
m_iMan->DeleteInstance(CLASS_LIGHT, this);
- m_iMan = NULL;
- m_device = NULL;
- m_engine = NULL;
+ m_iMan = nullptr;
+ m_device = nullptr;
+ m_engine = nullptr;
}
void CLightManager::SetDevice(CDevice* device)
{
m_device = device;
-
- m_dynLights = std::vector<DynamicLight>(m_device->GetMaxLightCount(), DynamicLight());
+ m_lightMap = std::vector<int>(m_device->GetMaxLightCount(), -1);
}
void CLightManager::FlushLights()
{
- for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
- {
- m_dynLights[i].used = false;
- m_device->SetLightEnabled(i, false);
- }
+ m_dynLights.clear();
}
-/** Returns the index of light created or -1 if all lights are used. */
-int CLightManager::CreateLight()
+/** Returns the index of light created. */
+int CLightManager::CreateLight(LightPriority priority)
{
- for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
+ int index = 0;
+ for (; index < static_cast<int>( m_dynLights.size() ); index++)
{
- if (m_dynLights[i].used) continue;
-
- m_dynLights[i] = DynamicLight();
+ if (! m_dynLights[index].used)
+ break;
+ }
- m_dynLights[i].used = true;
- m_dynLights[i].enabled = true;
+ if (index == static_cast<int>(m_dynLights.size()))
+ m_dynLights.push_back(DynamicLight());
- m_dynLights[i].includeType = ENG_OBJTYPE_NULL;
- m_dynLights[i].excludeType = ENG_OBJTYPE_NULL;
+ m_dynLights[index] = DynamicLight();
+ m_dynLights[index].used = true;
+ m_dynLights[index].enabled = true;
+ m_dynLights[index].priority = priority;
- m_dynLights[i].light.type = LIGHT_DIRECTIONAL;
- m_dynLights[i].light.diffuse = Color(0.5f, 0.5f, 0.5f);
- m_dynLights[i].light.position = Math::Vector(-100.0f, 100.0f, -100.0f);
- m_dynLights[i].light.direction = Math::Vector( 1.0f, -1.0f, 1.0f);
+ m_dynLights[index].includeType = ENG_OBJTYPE_NULL;
+ m_dynLights[index].excludeType = ENG_OBJTYPE_NULL;
- m_dynLights[i].intensity.Init(1.0f); // maximum
- m_dynLights[i].colorRed.Init(0.5f);
- m_dynLights[i].colorGreen.Init(0.5f);
- m_dynLights[i].colorBlue.Init(0.5f); // gray
+ m_dynLights[index].light.type = LIGHT_DIRECTIONAL;
+ m_dynLights[index].light.diffuse = Color(0.5f, 0.5f, 0.5f);
+ m_dynLights[index].light.position = Math::Vector(-100.0f, 100.0f, -100.0f);
+ m_dynLights[index].light.direction = Math::Vector( 1.0f, -1.0f, 1.0f);
- return i;
- }
+ m_dynLights[index].intensity.Init(1.0f); // maximum
+ m_dynLights[index].colorRed.Init(0.5f);
+ m_dynLights[index].colorGreen.Init(0.5f);
+ m_dynLights[index].colorBlue.Init(0.5f); // gray
- return -1;
+ return index;
}
bool CLightManager::DeleteLight(int lightRank)
@@ -148,8 +149,6 @@ bool CLightManager::DeleteLight(int lightRank)
return false;
m_dynLights[lightRank].used = false;
- m_device->SetLightEnabled(lightRank, false);
-
return true;
}
@@ -357,7 +356,6 @@ void CLightManager::UpdateProgression(float rTime)
}
}
-
void CLightManager::UpdateLights()
{
for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
@@ -366,7 +364,8 @@ void CLightManager::UpdateLights()
continue;
bool enabled = m_dynLights[i].enabled;
- if (m_dynLights[i].intensity.current == 0.0f)
+
+ if (Math::IsZero(m_dynLights[i].intensity.current))
enabled = false;
if (enabled)
@@ -379,42 +378,96 @@ void CLightManager::UpdateLights()
value = m_dynLights[i].colorBlue.current * m_dynLights[i].intensity.current;
m_dynLights[i].light.diffuse.b = value;
-
- m_device->SetLight(i, m_dynLights[i].light);
- m_device->SetLightEnabled(i, enabled);
}
else
{
m_dynLights[i].light.diffuse.r = 0.0f;
m_dynLights[i].light.diffuse.g = 0.0f;
m_dynLights[i].light.diffuse.b = 0.0f;
-
- m_device->SetLightEnabled(i, enabled);
}
}
}
-void CLightManager::UpdateLightsEnableState(EngineObjectType type)
+void CLightManager::UpdateDeviceLights(EngineObjectType type)
{
+ for (int i = 0; i < static_cast<int>( m_lightMap.size() ); ++i)
+ m_lightMap[i] = -1;
+
+ // High priority
for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
{
if (! m_dynLights[i].used)
continue;
if (! m_dynLights[i].enabled)
continue;
- if (m_dynLights[i].intensity.current == 0.0f)
+ if (Math::IsZero(m_dynLights[i].intensity.current))
+ continue;
+ if (m_dynLights[i].priority == LIGHT_PRI_LOW)
continue;
+ bool enabled = true;
if (m_dynLights[i].includeType != ENG_OBJTYPE_NULL)
+ enabled = (m_dynLights[i].includeType == type);
+
+ if (m_dynLights[i].excludeType != ENG_OBJTYPE_NULL)
+ enabled = (m_dynLights[i].excludeType != type);
+
+ if (enabled)
{
- bool enabled = (m_dynLights[i].includeType == type);
- m_device->SetLightEnabled(i, enabled);
+ for (int j = 0; j < static_cast<int>( m_lightMap.size() ); ++j)
+ {
+ if (m_lightMap[j] == -1)
+ {
+ m_lightMap[j] = i;
+ break;
+ }
+ }
}
+ }
+
+ // Low priority
+ for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
+ {
+ if (! m_dynLights[i].used)
+ continue;
+ if (! m_dynLights[i].enabled)
+ continue;
+ if (m_dynLights[i].intensity.current == 0.0f)
+ continue;
+ if (m_dynLights[i].priority == LIGHT_PRI_HIGH)
+ continue;
+
+ bool enabled = true;
+ if (m_dynLights[i].includeType != ENG_OBJTYPE_NULL)
+ enabled = (m_dynLights[i].includeType == type);
if (m_dynLights[i].excludeType != ENG_OBJTYPE_NULL)
+ enabled = (m_dynLights[i].excludeType != type);
+
+ if (enabled)
+ {
+ for (int j = 0; j < static_cast<int>( m_lightMap.size() ); ++j)
+ {
+ if (m_lightMap[j] == -1)
+ {
+ m_lightMap[j] = i;
+ break;
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < static_cast<int>( m_lightMap.size() ); ++i)
+ {
+ int rank = m_lightMap[i];
+ if (rank != -1)
+ {
+ m_device->SetLight(i, m_dynLights[rank].light);
+ m_device->SetLightEnabled(i, true);
+ }
+ else
{
- bool enabled = (m_dynLights[i].excludeType != type);
- m_device->SetLightEnabled(i, enabled);
+ m_device->SetLightEnabled(i, false);
}
}
}
diff --git a/src/graphics/engine/lightman.h b/src/graphics/engine/lightman.h
index c50d176..d83dfb3 100644
--- a/src/graphics/engine/lightman.h
+++ b/src/graphics/engine/lightman.h
@@ -34,8 +34,9 @@
namespace Gfx {
/**
- \struct LightProgression
- \brief Describes the progression of light parameters change */
+ * \struct LightProgression
+ * \brief Describes the progression of light parameters change
+ */
struct LightProgression
{
//! Starting value
@@ -65,11 +66,22 @@ struct LightProgression
};
/**
- \struct DynamicLight
- \brief Dynamic light in 3D scene
+ * \enum LightPriority
+ * \brief Priority in light assignment
+ */
+enum LightPriority
+{
+ LIGHT_PRI_HIGH,
+ LIGHT_PRI_LOW
+};
- It is an extension over standard light properties. Added are dynamic progressions for light
- colors and intensity and types of objects included/excluded in lighting. */
+/**
+ * \struct DynamicLight
+ * \brief Dynamic light in 3D scene
+ *
+ * It is an extension over standard light properties. Added are dynamic progressions for light
+ * colors and intensity and types of objects included/excluded in lighting.
+ */
struct DynamicLight
{
//! Whether the light is used
@@ -77,6 +89,9 @@ struct DynamicLight
//! Whether the light is turned on
bool enabled;
+ //! Priority in assignment
+ LightPriority priority;
+
//! Configuration of the light
Light light;
@@ -98,17 +113,18 @@ struct DynamicLight
};
/**
- \class CLightManager
- \brief Manager for dynamic lights in 3D scene
-
- (Old CLight class)
-
- The class is responsible for managing dynamic lights (struct DynamicLight) used in 3D scene.
- The dynamic lights are created, updated and deleted through the class' interface.
-
- Number of available lights depends on graphics device used. Class allocates vector
- for the total number of lights, but only some are used.
- */
+ * \class CLightManager
+ * \brief Manager for dynamic lights in 3D scene
+ *
+ * The class is responsible for managing dynamic lights (struct DynamicLight) used in 3D scene.
+ * The dynamic lights are created, updated and deleted through the class' interface.
+ *
+ * Since there is a limit on total number of lights available in OpenGL (usually up to 8), the dynamic lights
+ * must be emulated by displaying only some of them. All functions normally operate only on DynamicLight structs,
+ * updating the models with new values, while only one function, UpdateDeviceLights(), performs the actual
+ * synchronization to the device. It allocates device's light slots as necessary, with two priority levels
+ * for lights.
+ */
class CLightManager
{
public:
@@ -123,7 +139,7 @@ public:
//! Clears and disables all lights
void FlushLights();
//! Creates a new dynamic light and returns its index (lightRank)
- int CreateLight();
+ int CreateLight(LightPriority priority = LIGHT_PRI_LOW);
//! Deletes and disables the given dynamic light
bool DeleteLight(int lightRank);
//! Sets the light parameters for dynamic light
@@ -161,7 +177,7 @@ public:
//! Sets the destination color for dynamic light's color progression
bool SetLightColor(int lightRank, const Color &color);
//! Returns current light color
- Color GetLightColor(int lightRank);
+ Color GetLightColor(int lightRank);
//! Sets the rate of change for dynamic light colors (RGB)
bool SetLightColorSpeed(int lightRank, float speed);
@@ -170,7 +186,7 @@ public:
//! Updates (recalculates) all dynamic lights
void UpdateLights();
//! Enables or disables dynamic lights affecting the given object type
- void UpdateLightsEnableState(EngineObjectType type);
+ void UpdateDeviceLights(EngineObjectType type);
protected:
CInstanceManager* m_iMan;
@@ -181,6 +197,8 @@ protected:
float m_time;
//! List of dynamic lights
std::vector<DynamicLight> m_dynLights;
+ //! Map of current light allotment: graphics light -> dynamic light
+ std::vector<int> m_lightMap;
};
}; // namespace Gfx
diff --git a/src/graphics/engine/planet.cpp b/src/graphics/engine/planet.cpp
index 0ac2524..3b9aa6c 100644
--- a/src/graphics/engine/planet.cpp
+++ b/src/graphics/engine/planet.cpp
@@ -147,7 +147,8 @@ void CPlanet::Draw()
}
void CPlanet::Create(int mode, Math::Point start, float dim, float speed,
- float dir, const std::string& name, Math::Point uv1, Math::Point uv2)
+ float dir, const std::string& name, Math::Point uv1, Math::Point uv2,
+ bool transparent)
{
if (mode < 0) mode = 0;
if (mode > 1) mode = 1;
@@ -164,7 +165,7 @@ void CPlanet::Create(int mode, Math::Point start, float dim, float speed,
planet.uv1 = uv1;
planet.uv2 = uv2;
- planet.transparent = planet.name.find("planet") != std::string::npos;
+ planet.transparent = transparent;
m_planet[mode].push_back(planet);
diff --git a/src/graphics/engine/planet.h b/src/graphics/engine/planet.h
index 82c3aea..1b16da0 100644
--- a/src/graphics/engine/planet.h
+++ b/src/graphics/engine/planet.h
@@ -91,7 +91,8 @@ public:
bool EventProcess(const Event &event);
//! Creates a new planet
void Create(int mode, Math::Point start, float dim, float speed, float dir,
- const std::string& name, Math::Point uv1, Math::Point uv2);
+ const std::string& name, Math::Point uv1, Math::Point uv2,
+ bool transparent);
//! Indicates if there is at least one planet
bool PlanetExist();
//! Load all the textures for the planets
diff --git a/src/graphics/engine/terrain.cpp b/src/graphics/engine/terrain.cpp
index d2ddecc..4c22a32 100644
--- a/src/graphics/engine/terrain.cpp
+++ b/src/graphics/engine/terrain.cpp
@@ -74,7 +74,7 @@ CTerrain::~CTerrain()
}
bool CTerrain::Generate(int mosaicCount, int brickCountPow2, float brickSize,
- float vision, int depth, float hardness)
+ float vision, int depth, float hardness)
{
m_mosaicCount = mosaicCount;
m_brickCount = 1 << brickCountPow2;
@@ -162,8 +162,8 @@ void CTerrain::FlushMaterials()
}
void CTerrain::AddMaterial(int id, const std::string& texName, const Math::Point &uv,
- int up, int right, int down, int left,
- float hardness)
+ int up, int right, int down, int left,
+ float hardness)
{
InitMaterialPoints();
@@ -207,25 +207,41 @@ bool CTerrain::LoadResources(const std::string& fileName)
ImageData *data = img.GetData();
- int size = (m_mosaicCount*m_brickCount)+1;
-
- m_resources.clear();
+ int size = (m_mosaicCount*m_brickCount)+1;
- std::vector<unsigned char>(3*size*size).swap(m_resources);
+ std::vector<unsigned char>(size*size).swap(m_resources);
- if ( (data->surface->w != size) || (data->surface->h != size) ||
- (data->surface->format->BytesPerPixel != 3) )
+ if ( (data->surface->w != size) || (data->surface->h != size) )
{
GetLogger()->Error("Invalid resource file\n");
return false;
}
- unsigned char* pixels = static_cast<unsigned char*>(data->surface->pixels);
- int pitch = data->surface->pitch;
-
- for (int y = 0; y < size; y++)
+ for (int x = 0; x < size; ++x)
{
- memcpy(&m_resources[3*size*y], &pixels[pitch*y], 3*size);
+ for (int y = 0; y < size; ++y)
+ {
+ Gfx::IntColor pixel = img.GetPixelInt(Math::IntPoint(x, size - y - 1));
+ TerrainRes res = TR_NULL;
+
+ // values from original bitmap palette
+ if (pixel.r == 255 && pixel.g == 0 && pixel.b == 0)
+ res = TR_STONE;
+ else if (pixel.r == 255 && pixel.g == 255 && pixel.b == 0)
+ res = TR_URANIUM;
+ else if (pixel.r == 0 && pixel.g == 255 && pixel.b == 0)
+ res = TR_POWER;
+ else if (pixel.r == 0 && pixel.g == 204 && pixel.b == 0)
+ res = TR_KEY_A;
+ else if (pixel.r == 51 && pixel.g == 204 && pixel.b == 0)
+ res = TR_KEY_B;
+ else if (pixel.r == 102 && pixel.g == 204 && pixel.b == 0)
+ res = TR_KEY_C;
+ else if (pixel.r == 153 && pixel.g == 204 && pixel.b == 0)
+ res = TR_KEY_D;
+
+ m_resources[x+size*y] = static_cast<unsigned char>(res);
+ }
}
return true;
@@ -243,23 +259,9 @@ TerrainRes CTerrain::GetResource(const Math::Vector &p)
y < 0 || y > m_mosaicCount*m_brickCount )
return TR_NULL;
- int size = (m_mosaicCount*m_brickCount)+1;
-
- int resR = m_resources[3*x+3*size*(size-y-1)];
- int resG = m_resources[3*x+3*size*(size-y-1)+1];
- int resB = m_resources[3*x+3*size*(size-y-1)+2];
-
- if (resR == 255 && resG == 0 && resB == 0) return TR_STONE;
- if (resR == 255 && resG == 255 && resB == 0) return TR_URANIUM;
- if (resR == 0 && resG == 255 && resB == 0) return TR_POWER;
-
- // TODO key res values
- //if (ress == 24) return TR_KEY_A; // ~green?
- //if (ress == 25) return TR_KEY_B; // ~green?
- //if (ress == 26) return TR_KEY_C; // ~green?
- //if (ress == 27) return TR_KEY_D; // ~green?
+ int size = (m_mosaicCount*m_brickCount)+1;
- return TR_NULL;
+ return static_cast<TerrainRes>( m_resources[x+size*y] );
}
void CTerrain::FlushRelief()
@@ -287,22 +289,21 @@ bool CTerrain::LoadRelief(const std::string &fileName, float scaleRelief,
int size = (m_mosaicCount*m_brickCount)+1;
- if ( (data->surface->w != size) || (data->surface->h != size) ||
- (data->surface->format->BytesPerPixel != 3) )
+ if ( (data->surface->w != size) || (data->surface->h != size) )
{
GetLogger()->Error("Invalid relief file!\n");
return false;
}
- unsigned char* pixels = static_cast<unsigned char*>(data->surface->pixels);
- int pitch = data->surface->pitch;
-
float limit = 0.9f;
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
- float level = (255 - pixels[3*x+pitch*(size-y-1)]) * scaleRelief;
+ Gfx::IntColor color = img.GetPixelInt(Math::IntPoint(x, size - y - 1));
+
+ float avg = (color.r + color.g + color.b) / 3.0f; // to be sure it is grayscale
+ float level = (255.0f - avg) * scaleRelief;
float dist = Math::Max(fabs(static_cast<float>(x-size/2)),
fabs(static_cast<float>(y-size/2)));
@@ -492,8 +493,8 @@ VertexTex2 CTerrain::GetVertex(int x, int y, int step)
+-------------------> x
\endverbatim */
bool CTerrain::CreateMosaic(int ox, int oy, int step, int objRank,
- const Material &mat,
- float min, float max)
+ const Material &mat,
+ float min, float max)
{
std::string texName1;
std::string texName2;
@@ -1057,8 +1058,8 @@ bool CTerrain::InitMaterials(int id)
}
bool CTerrain::GenerateMaterials(int *id, float min, float max,
- float slope, float freq,
- Math::Vector center, float radius)
+ float slope, float freq,
+ Math::Vector center, float radius)
{
static char random[100] =
{
@@ -1454,13 +1455,14 @@ bool CTerrain::AdjustToFloor(Math::Vector &pos, bool brut, bool water)
}
/**
- * @returns \c false if the initial coordinate was outside terrain area; \c true otherwise
+ * \param pos position to adjust
+ * \returns \c false if the initial coordinate was outside terrain area; \c true otherwise
*/
bool CTerrain::AdjustToStandardBounds(Math::Vector& pos)
{
bool ok = true;
- // TODO: _TEEN ... * 0.98f;
+ // In _TEEN there used to be a limit of 0.98f
float limit = (m_mosaicCount*m_brickCount*m_brickSize)/2.0f*0.92f;
if (pos.x < -limit)
@@ -1491,8 +1493,9 @@ bool CTerrain::AdjustToStandardBounds(Math::Vector& pos)
}
/**
- * @param margin margin to the terrain border
- * @returns \c false if the initial coordinate was outside terrain area; \c true otherwise
+ * \param pos position to adjust
+ * \param margin margin to the terrain border
+ * \returns \c false if the initial coordinate was outside terrain area; \c true otherwise
*/
bool CTerrain::AdjustToBounds(Math::Vector& pos, float margin)
{
@@ -1718,14 +1721,14 @@ float CTerrain::GetFlatZoneRadius(Math::Vector center, float max)
float ref = GetFloorLevel(center, true);
Math::Point c(center.x, center.z);
float radius = 1.0f;
-
+
while (radius <= max)
{
angle = 0.0f;
int nb = static_cast<int>(2.0f*Math::PI*radius);
if (nb < 8) nb = 8;
- Math::Point p (center.x+radius, center.z);
+ Math::Point p (center.x+radius, center.z);
for (int i = 0; i < nb; i++)
{
Math::Point result = Math::RotatePoint(c, angle, p);
diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp
index a77a6fd..9091905 100644
--- a/src/graphics/engine/text.cpp
+++ b/src/graphics/engine/text.cpp
@@ -279,18 +279,14 @@ float CText::GetHeight(FontType font, float size)
float CText::GetStringWidth(const std::string &text,
std::map<unsigned int, FontMetaChar> &format, float size)
{
- // TODO assert was commented as new code uses map not vector and if's size doesn't have to match text length
- // this has to be tested if it's correct
- //assert(StrUtils::Utf8StringLength(text) == format.size());
-
float width = 0.0f;
unsigned int index = 0;
unsigned int fmtIndex = 0;
while (index < text.length())
{
FontType font = FONT_COLOBOT;
- if (format.count(fmtIndex))
- font = static_cast<FontType>(format[fmtIndex] & FONT_MASK_FONT);
+ if (format.count(fmtIndex))
+ font = static_cast<FontType>(format[fmtIndex] & FONT_MASK_FONT);
UTF8Char ch;
@@ -350,10 +346,6 @@ float CText::GetCharWidth(UTF8Char ch, FontType font, float size, float offset)
int CText::Justify(const std::string &text, std::map<unsigned int, FontMetaChar> &format,
float size, float width)
{
- // TODO assert was commented as new code uses map not vector and if's size doesn't have to match text length
- // this has to be tested if it's correct
- //assert(StrUtils::Utf8StringLength(text) == format.size());
-
float pos = 0.0f;
int cut = 0;
unsigned int index = 0;
@@ -361,8 +353,8 @@ int CText::Justify(const std::string &text, std::map<unsigned int, FontMetaChar>
while (index < text.length())
{
FontType font = FONT_COLOBOT;
- if (format.count(fmtIndex))
- font = static_cast<FontType>(format[fmtIndex] & FONT_MASK_FONT);
+ if (format.count(fmtIndex))
+ font = static_cast<FontType>(format[fmtIndex] & FONT_MASK_FONT);
UTF8Char ch;
@@ -437,18 +429,14 @@ int CText::Justify(const std::string &text, FontType font, float size, float wid
int CText::Detect(const std::string &text, std::map<unsigned int, FontMetaChar> &format,
float size, float offset)
{
- // TODO assert was commented as new code uses map not vector and if's size doesn't have to match text length
- // this has to be tested if it's correct
- //assert(StrUtils::Utf8StringLength(text) == format.size());
-
float pos = 0.0f;
unsigned int index = 0;
unsigned int fmtIndex = 0;
while (index < text.length())
{
FontType font = FONT_COLOBOT;
- if (format.count(fmtIndex))
- font = static_cast<FontType>(format[fmtIndex] & FONT_MASK_FONT);
+ if (format.count(fmtIndex))
+ font = static_cast<FontType>(format[fmtIndex] & FONT_MASK_FONT);
// TODO: if (font == FONT_BUTTON)
if (font == FONT_BUTTON) continue;
@@ -514,13 +502,8 @@ int CText::Detect(const std::string &text, FontType font, float size, float offs
void CText::DrawString(const std::string &text, std::map<unsigned int, FontMetaChar> &format,
float size, Math::Point pos, float width, int eol)
{
- // TODO assert was commented as new code uses map not vector and if's size doesn't have to match text length
- // this has to be tested if it's correct
- //assert(StrUtils::Utf8StringLength(text) == format.size());
-
m_engine->SetState(ENG_RSTATE_TEXT);
- FontType font = FONT_COLOBOT;
float start = pos.x;
unsigned int fmtIndex = 0;
@@ -530,8 +513,8 @@ void CText::DrawString(const std::string &text, std::map<unsigned int, FontMetaC
for (auto it = chars.begin(); it != chars.end(); ++it)
{
FontType font = FONT_COLOBOT;
- if (format.count(fmtIndex))
- font = static_cast<FontType>(format[fmtIndex] & FONT_MASK_FONT);
+ if (format.count(fmtIndex))
+ font = static_cast<FontType>(format[fmtIndex] & FONT_MASK_FONT);
// TODO: if (font == FONT_BUTTON)
if (font == FONT_BUTTON) continue;
@@ -566,17 +549,18 @@ void CText::DrawString(const std::string &text, std::map<unsigned int, FontMetaC
void CText::StringToUTFCharList(const std::string &text, std::vector<UTF8Char> &chars)
{
unsigned int index = 0;
- while (index < text.length())
+ unsigned int totalLength = text.length();
+ while (index < totalLength)
{
UTF8Char ch;
int len = StrUtils::Utf8CharSizeAt(text, index);
if (len >= 1)
- ch.c1 = text[index];
+ ch.c1 = text[index];
if (len >= 2)
- ch.c2 = text[index+1];
+ ch.c2 = text[index+1];
if (len >= 3)
- ch.c3 = text[index+2];
+ ch.c3 = text[index+2];
index += len;
@@ -663,7 +647,7 @@ void CText::DrawHighlight(FontHighlight hl, Math::Point pos, Math::Point size)
p2.y = pos.y + size.y;
}
- m_device->SetRenderState(RENDER_STATE_TEXTURING, false);
+ m_device->SetTextureEnabled(0, false);
VertexCol quad[] =
{
@@ -676,7 +660,7 @@ void CText::DrawHighlight(FontHighlight hl, Math::Point pos, Math::Point size)
m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, quad, 4);
m_engine->AddStatisticTriangle(2);
- m_device->SetRenderState(RENDER_STATE_TEXTURING, true);
+ m_device->SetTextureEnabled(0, true);
}
void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::Point &pos)
diff --git a/src/graphics/engine/text.h b/src/graphics/engine/text.h
index cc18f55..7fa8768 100644
--- a/src/graphics/engine/text.h
+++ b/src/graphics/engine/text.h
@@ -149,9 +149,12 @@ enum FontMask
struct UTF8Char
{
char c1, c2, c3;
+ // Padding for 4-byte alignment
+ // It also seems to fix some problems reported by valgrind
+ char pad;
explicit UTF8Char(char ch1 = '\0', char ch2 = '\0', char ch3 = '\0')
- : c1(ch1), c2(ch2), c3(ch3) {}
+ : c1(ch1), c2(ch2), c3(ch3), pad('\0') {}
inline bool operator<(const UTF8Char &other) const
{
diff --git a/src/graphics/engine/water.cpp b/src/graphics/engine/water.cpp
index 81034a3..18811eb 100644
--- a/src/graphics/engine/water.cpp
+++ b/src/graphics/engine/water.cpp
@@ -279,11 +279,9 @@ void CWater::DrawBack()
material.ambient = m_ambient;
m_engine->SetMaterial(material);
- m_engine->SetTexture("", 0); // TODO: disable texturing
-
CDevice* device = m_engine->GetDevice();
- m_engine->SetState(ENG_RSTATE_NORMAL);
+ m_engine->SetState(Gfx::ENG_RSTATE_OPAQUE_COLOR);
float deep = m_engine->GetDeepView(0);
m_engine->SetDeepView(deep*2.0f, 0);
@@ -310,17 +308,14 @@ void CWater::DrawBack()
p1.y = -50.0f;
p2.y = m_level;
- Math::Vector n;
- n.x = (lookat.x-eye.x)/dist;
- n.z = (lookat.z-eye.z)/dist;
- n.y = 0.0f;
+ Gfx::Color white = Gfx::Color(1.0f, 1.0f, 1.0f, 0.0f);
- Vertex vertices[4] =
+ VertexCol vertices[4] =
{
- Vertex(Math::Vector(p1.x, p2.y, p1.z), n),
- Vertex(Math::Vector(p1.x, p1.y, p1.z), n),
- Vertex(Math::Vector(p2.x, p2.y, p2.z), n),
- Vertex(Math::Vector(p2.x, p1.y, p2.z), n)
+ VertexCol(Math::Vector(p1.x, p2.y, p1.z), white),
+ VertexCol(Math::Vector(p1.x, p1.y, p1.z), white),
+ VertexCol(Math::Vector(p2.x, p2.y, p2.z), white),
+ VertexCol(Math::Vector(p2.x, p1.y, p2.z), white)
};
device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertices, 4);
@@ -480,8 +475,8 @@ void CWater::CreateLine(int x, int y, int len)
}
void CWater::Create(WaterType type1, WaterType type2, const std::string& fileName,
- Color diffuse, Color ambient,
- float level, float glint, Math::Vector eddy)
+ Color diffuse, Color ambient,
+ float level, float glint, Math::Vector eddy)
{
m_type[0] = type1;
m_type[1] = type2;
diff --git a/src/graphics/engine/water.h b/src/graphics/engine/water.h
index a43c740..21d96d4 100644
--- a/src/graphics/engine/water.h
+++ b/src/graphics/engine/water.h
@@ -169,10 +169,10 @@ protected:
protected:
CInstanceManager* m_iMan;
- CEngine* m_engine;
- CDevice* m_device;
- CTerrain* m_terrain;
- CParticle* m_particule;
+ CEngine* m_engine;
+ CDevice* m_device;
+ CTerrain* m_terrain;
+ CParticle* m_particule;
CSoundInterface* m_sound;
WaterType m_type[2];
@@ -184,9 +184,9 @@ protected:
//! Amplitude of swirls
Math::Vector m_eddy;
//! Diffuse color
- Color m_diffuse;
+ Color m_diffuse;
//! Ambient color
- Color m_ambient;
+ Color m_ambient;
float m_time;
float m_lastLava;
int m_subdiv;
@@ -201,7 +201,7 @@ protected:
bool m_draw;
bool m_lava;
- Color m_color;
+ Color m_color;
};