Rendering functions, documentation

- rewrote the render functions for CEngine, CCloud and CWater
- added documentation
dev-ui
Piotr Dziwinski 2012-08-13 00:14:42 +02:00
parent 146ad47e4a
commit 712154bc4f
12 changed files with 584 additions and 461 deletions

View File

@ -20,6 +20,7 @@
#include "graphics/engine/cloud.h"
#include "common/iman.h"
#include "graphics/core/device.h"
#include "graphics/engine/engine.h"
#include "graphics/engine/terrain.h"
#include "math/geometry.h"
@ -94,112 +95,96 @@ void Gfx::CCloud::AdjustLevel(Math::Vector &pos, Math::Vector &eye, float deep,
void Gfx::CCloud::Draw()
{
/* TODO!
LPDIRECT3DDEVICE7 device;
D3DVERTEX2* vertex;
Math::Matrix* matView;
D3DMATERIAL7 material;
Math::Matrix matrix;
Math::Vector n, pos, p, eye;
Math::Point uv1, uv2;
float iDeep, deep, size, fogStart, fogEnd;
int i, j, u;
if (! m_enable) return;
if (m_level == 0.0f) return;
if (m_lines.empty()) return;
if ( !m_enable ) return;
if ( m_level == 0.0f ) return;
if ( m_linesUsed == 0 ) return;
std::vector<Gfx::VertexTex2> vertices((m_brick+2)*2, Gfx::VertexTex2());
vertex = (D3DVERTEX2*)malloc(sizeof(D3DVERTEX2)*(m_brick+2)*2);
iDeep = m_engine->GetDeepView();
deep = (m_brick*m_size)/2.0f;
float iDeep = m_engine->GetDeepView();
float deep = (m_brick*m_size)/2.0f;
m_engine->SetDeepView(deep);
m_engine->SetFocus(m_engine->GetFocus());
m_engine->UpdateMatProj(); // increases the depth of view
fogStart = deep*0.15f;
fogEnd = deep*0.24f;
float fogStart = deep*0.15f;
float fogEnd = deep*0.24f;
device = m_engine->GetD3DDevice();
device->SetRenderState(D3DRENDERSTATE_AMBIENT, 0x00000000);
device->SetRenderState(D3DRENDERSTATE_LIGHTING, false);
device->SetRenderState(D3DRENDERSTATE_ZENABLE, false);
device->SetRenderState(D3DRENDERSTATE_FOGENABLE, true);
device->SetRenderState(D3DRENDERSTATE_FOGSTART, F2DW(fogStart));
device->SetRenderState(D3DRENDERSTATE_FOGEND, F2DW(fogEnd));
Gfx::CDevice* device = m_engine->GetDevice();
matView = m_engine->GetMatView();
{
D3DMATRIX mat = MAT_TO_D3DMAT(*matView);
device->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat);
}
// TODO: do this better?
device->SetFogParams(Gfx::FOG_LINEAR, m_engine->GetFogColor( m_engine->GetRankView() ),
fogStart, fogEnd, 1.0f);
ZeroMemory( &material, sizeof(D3DMATERIAL7) );
device->SetTransform(Gfx::TRANSFORM_VIEW, m_engine->GetMatView());
Gfx::Material material;
material.diffuse = m_diffuse;
material.ambient = m_ambient;
m_engine->SetMaterial(material);
m_engine->SetTexture(m_filename, 0);
m_engine->SetTexture(m_filename, 1);
m_engine->SetTexture(m_fileName, 0);
m_engine->SetTexture(m_fileName, 1);
m_engine->SetState(D3DSTATETTb|D3DSTATEFOG|D3DSTATEWRAP);
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK | Gfx::ENG_RSTATE_FOG | Gfx::ENG_RSTATE_WRAP);
Math::Matrix matrix;
matrix.LoadIdentity();
{
D3DMATRIX mat = MAT_TO_D3DMAT(matrix);
device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
}
device->SetTransform(Gfx::TRANSFORM_WORLD, matrix);
size = m_size/2.0f;
eye = m_engine->GetEyePt();
n = Math::Vector(0.0f, -1.0f, 0.0f);
float size = m_size/2.0f;
Math::Vector eye = m_engine->GetEyePt();
Math::Vector n = Math::Vector(0.0f, -1.0f, 0.0f);
// Draws all the lines.
for ( i=0 ; i<m_linesUsed ; i++ )
// Draws all the lines
for (int i = 0; i < static_cast<int>( m_lines.size() ); i++)
{
Math::Vector pos;
pos.y = m_level;
pos.z = m_lines[i].pz;
pos.x = m_lines[i].px1;
u = 0;
int vertexIndex = 0;
Math::Vector p;
Math::Point uv1, uv2;
p.x = pos.x-size;
p.z = pos.z+size;
p.y = pos.y;
AdjustLevel(p, eye, deep, uv1, uv2);
vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
vertices[vertexIndex++] = Gfx::VertexTex2(p, n, uv1, uv2);
p.x = pos.x-size;
p.z = pos.z-size;
p.y = pos.y;
AdjustLevel(p, eye, deep, uv1, uv2);
vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
vertices[vertexIndex++] = Gfx::VertexTex2(p, n, uv1, uv2);
for ( j=0 ; j<m_lines[i].len ; j++ )
for (int j = 0; j < m_lines[i].len; j++)
{
p.x = pos.x+size;
p.z = pos.z+size;
p.y = pos.y;
AdjustLevel(p, eye, deep, uv1, uv2);
vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
vertices[vertexIndex++] = Gfx::VertexTex2(p, n, uv1, uv2);
p.x = pos.x+size;
p.z = pos.z-size;
p.y = pos.y;
AdjustLevel(p, eye, deep, uv1, uv2);
vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
vertices[vertexIndex++] = Gfx::VertexTex2(p, n, uv1, uv2);
pos.x += size*2.0f;
}
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, u, NULL);
m_engine->AddStatisticTriangle(u-2);
device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, &vertices[0], vertexIndex);
m_engine->AddStatisticTriangle(vertexIndex - 2);
}
m_engine->SetDeepView(iDeep);
m_engine->SetFocus(m_engine->GetFocus());
m_engine->UpdateMatProj(); // gives depth to initial
free(vertex); */
}
void Gfx::CCloud::CreateLine(int x, int y, int len)

View File

@ -40,12 +40,19 @@ namespace Gfx {
class CEngine;
class CTerrain;
/**
* \struct CloudLine
* \brief Cloud strip
*/
struct CloudLine
{
//! Beginning
//@{
//! Beginning (terrain coordinates)
short x, y;
//! In length x
//@}
//! Length in X direction (terrain coordinates)
short len;
//! X (1, 2) and Z coordinates (world coordinates)
float px1, px2, pz;
CloudLine()
@ -57,6 +64,15 @@ struct CloudLine
};
/**
* \class CCloud
* \brief Cloud layer renderer
*
* Renders the cloud layer as fog. Cloud layer is similar to water layer
* - it occurs only at specified level of terrain. Cloud map is created
* the same way water is created. CloudLine structs are used to specify
* lines in X direction in XY terrain coordinates.
*/
class CCloud
{
public:

View File

@ -946,7 +946,7 @@ bool Gfx::CEngine::AddQuick(int objRank, const Gfx::EngineObjLevel4& buffer,
if (buffer.type == Gfx::ENG_TRIANGLE_TYPE_TRIANGLES)
m_objects[objRank].totalTriangles += buffer.vertices.size() / 3;
else // surfaces
else if (buffer.type == Gfx::ENG_TRIANGLE_TYPE_SURFACE)
m_objects[objRank].totalTriangles += buffer.vertices.size() - 2;
return true;
@ -2203,13 +2203,15 @@ bool Gfx::CEngine::LoadAllTextures()
if (! p1.tex1Name.empty())
{
if (! LoadTexture(p1.tex1Name).Valid())
p1.tex1 = LoadTexture(p1.tex1Name);
if (! p1.tex1.Valid())
ok = false;
}
if (! p1.tex2Name.empty())
{
if (! LoadTexture(p1.tex2Name).Valid())
p1.tex2 = LoadTexture(p1.tex2Name);
if (! p1.tex2.Valid())
ok = false;
}
}
@ -2865,15 +2867,6 @@ void Gfx::CEngine::Render()
void Gfx::CEngine::Draw3DScene()
{
/* TODO!
D3DObjLevel1* p1;
D3DObjLevel2* p2;
D3DObjLevel3* p3;
D3DObjLevel4* p4;
D3DObjLevel5* p5;
D3DVERTEX2* pv;
int l1, l2, l3, l4, l5, objRank;*/
if (m_groundSpotVisible)
UpdateGroundSpotTextures();
@ -2899,144 +2892,144 @@ void Gfx::CEngine::Draw3DScene()
if (m_shadowVisible)
{
// Draw the field
// TODO!
/*
p1 = m_objectPointer;
for ( l1=0 ; l1<p1->totalUsed ; l1++ )
// Draw the terrain
for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++)
{
p2 = p1->table[l1];
if ( p2 == 0 ) continue;
SetTexture(p2->tex1Name, 0);
SetTexture(p2->tex2Name, 1);
for ( l2=0 ; l2<p2->totalUsed ; l2++ )
Gfx::EngineObjLevel1& p1 = m_objectTree[l1];
if (! p1.used) continue;
// Should be loaded by now
SetTexture(p1.tex1, 0);
SetTexture(p1.tex2, 1);
for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
{
p3 = p2->table[l2];
if ( p3 == 0 ) continue;
objRank = p3->objRank;
if ( m_objects[objRank].type != TYPETERRAIN ) continue;
if ( !m_objects[objRank].bDrawWorld ) continue;
Gfx::EngineObjLevel2& p2 = p1.next[l2];
if (! p2.used) continue;
{
D3DMATRIX mat = MAT_TO_D3DMAT(m_objects[objRank].transform);
m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
}
int objRank = p2.objRank;
if (m_objects[objRank].type != Gfx::ENG_OBJTYPE_TERRAIN)
continue;
if (! m_objects[objRank].drawWorld)
continue;
if ( !IsVisible(objRank) ) continue;
m_light->LightUpdate(m_objects[objRank].type);
for ( l3=0 ; l3<p3->totalUsed ; l3++ )
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
p4 = p3->table[l3];
if ( p4 == 0 ) continue;
if ( m_objects[objRank].distance < p4->min ||
m_objects[objRank].distance >= p4->max ) continue;
for ( l4=0 ; l4<p4->totalUsed ; l4++ )
Gfx::EngineObjLevel3& p3 = p2.next[l1];
if (! p3.used) continue;
if ( m_objects[objRank].distance < p3.min ||
m_objects[objRank].distance >= p3.max ) continue;
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
{
p5 = p4->table[l4];
if ( p5 == 0 ) continue;
for ( l5=0 ; l5<p5->totalUsed ; l5++ )
Gfx::EngineObjLevel4& p4 = p3.next[l4];
if (! p4.used) continue;
SetMaterial(p4.material);
SetState(p4.state);
if (p4.type == Gfx::ENG_TRIANGLE_TYPE_TRIANGLES)
{
p6 = p5->table[l5];
if ( p6 == 0 ) continue;
SetMaterial(p6->material);
SetState(p6->state);
if ( p6->type == D3DTYPE6T )
{
pv = &p6->vertex[0];
m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
D3DFVF_VERTEX2,
pv, p6->totalUsed,
NULL);
m_statisticTriangle += p6->totalUsed/3;
}
if ( p6->type == D3DTYPE6S )
{
pv = &p6->vertex[0];
m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
D3DFVF_VERTEX2,
pv, p6->totalUsed,
NULL);
m_statisticTriangle += p6->totalUsed-2;
}
m_device->DrawPrimitive( Gfx::PRIMITIVE_TRIANGLES,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() / 3;
}
}
}
}
}*/
// Draws the shadows
DrawShadow();
}
// Draw objects
bool transparent = false;
/* TODO!
p1 = m_objectPointer;
for ( l1=0 ; l1<p1->totalUsed ; l1++ )
{
p2 = p1->table[l1];
if ( p2 == 0 ) continue;
SetTexture(p2->tex1Name, 0);
SetTexture(p2->tex2Name, 1);
for ( l2=0 ; l2<p2->totalUsed ; l2++ )
{
p3 = p2->table[l2];
if ( p3 == 0 ) continue;
objRank = p3->objRank;
if ( m_bShadow && m_objects[objRank].type == TYPETERRAIN ) continue;
if ( !m_objects[objRank].bDrawWorld ) continue;
{
D3DMATRIX mat = MAT_TO_D3DMAT(m_objects[objRank].transform);
m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
}
if ( !IsVisible(objRank) ) continue;
m_light->LightUpdate(m_objects[objRank].type);
for ( l3=0 ; l3<p3->totalUsed ; l3++ )
{
p4 = p3->table[l3];
if ( p4 == 0 ) continue;
if ( m_objects[objRank].distance < p4->min ||
m_objects[objRank].distance >= p4->max ) continue;
for ( l4=0 ; l4<p4->totalUsed ; l4++ )
{
p5 = p4->table[l4];
if ( p5 == 0 ) continue;
for ( l5=0 ; l5<p5->totalUsed ; l5++ )
{
p6 = p5->table[l5];
if ( p6 == 0 ) continue;
SetMaterial(p6->material);
if ( m_objects[objRank].transparency != 0.0f ) // transparent ?
if (p4.type == Gfx::ENG_TRIANGLE_TYPE_SURFACE)
{
transparent = true;
continue;
}
SetState(p6->state);
if ( p6->type == D3DTYPE6T )
{
pv = &p6->vertex[0];
m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
D3DFVF_VERTEX2,
pv, p6->totalUsed,
NULL);
m_statisticTriangle += p6->totalUsed/3;
}
if ( p6->type == D3DTYPE6S )
{
pv = &p6->vertex[0];
m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
D3DFVF_VERTEX2,
pv, p6->totalUsed,
NULL);
m_statisticTriangle += p6->totalUsed-2;
m_device->DrawPrimitive( Gfx::PRIMITIVE_TRIANGLE_STRIP,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() - 2;
}
}
}
}
}
}*/
// Draws the shadows
DrawShadow();
}
// Draw objects (non-terrain)
bool transparent = false;
for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++)
{
Gfx::EngineObjLevel1& p1 = m_objectTree[l1];
if (! p1.used) continue;
// Should be loaded by now
SetTexture(p1.tex1, 0);
SetTexture(p1.tex2, 1);
for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
{
Gfx::EngineObjLevel2& p2 = p1.next[l2];
if (! p2.used) continue;
int objRank = p2.objRank;
if (m_shadowVisible && m_objects[objRank].type == Gfx::ENG_OBJTYPE_TERRAIN)
continue;
if (! m_objects[objRank].drawWorld)
continue;
m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_objects[objRank].transform);
if (! IsVisible(objRank))
continue;
m_lightMan->UpdateLightsEnableState(m_objects[objRank].type);
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
Gfx::EngineObjLevel3& p3 = p2.next[l1];
if (! p3.used) continue;
if ( m_objects[objRank].distance < p3.min ||
m_objects[objRank].distance >= p3.max ) continue;
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
{
Gfx::EngineObjLevel4& p4 = p3.next[l4];
if (! p4.used) continue;
if (m_objects[objRank].transparency != 0.0f) // transparent ?
{
transparent = true;
continue;
}
SetMaterial(p4.material);
SetState(p4.state);
if (p4.type == Gfx::ENG_TRIANGLE_TYPE_TRIANGLES)
{
m_device->DrawPrimitive( Gfx::PRIMITIVE_TRIANGLES,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() / 3;
}
else if (p4.type == Gfx::ENG_TRIANGLE_TYPE_SURFACE)
{
m_device->DrawPrimitive( Gfx::PRIMITIVE_TRIANGLE_STRIP,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() - 2;
}
}
}
}
}
// Draw transparent objects
if (transparent)
{
@ -3053,70 +3046,73 @@ void Gfx::CEngine::Draw3DScene()
tColor = Gfx::Color(136.0f / 255.0f, 136.0f / 255.0f, 136.0f / 255.0f, 136.0f / 255.0f);
}
// Draw transparent objects.
/* TODO!
p1 = m_objectPointer;
for ( l1=0 ; l1<p1->totalUsed ; l1++ )
for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++)
{
p2 = p1->table[l1];
if ( p2 == 0 ) continue;
SetTexture(p2->tex1Name, 0);
SetTexture(p2->tex2Name, 1);
for ( l2=0 ; l2<p2->totalUsed ; l2++ )
Gfx::EngineObjLevel1& p1 = m_objectTree[l1];
if (! p1.used) continue;
// Should be loaded by now
SetTexture(p1.tex1, 0);
SetTexture(p1.tex2, 1);
for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
{
p3 = p2->table[l2];
if ( p3 == 0 ) continue;
objRank = p3->objRank;
if ( m_bShadow && m_objects[objRank].type == TYPETERRAIN ) continue;
if ( !m_objects[objRank].bDrawWorld ) continue;
Gfx::EngineObjLevel2& p2 = p1.next[l2];
if (! p2.used) continue;
{
D3DMATRIX mat = MAT_TO_D3DMAT(m_objects[objRank].transform);
m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
}
int objRank = p2.objRank;
if ( !IsVisible(objRank) ) continue;
m_light->LightUpdate(m_objects[objRank].type);
for ( l3=0 ; l3<p3->totalUsed ; l3++ )
if (m_shadowVisible && m_objects[objRank].type == Gfx::ENG_OBJTYPE_TERRAIN)
continue;
if (! m_objects[objRank].drawWorld)
continue;
m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_objects[objRank].transform);
if (! IsVisible(objRank))
continue;
m_lightMan->UpdateLightsEnableState(m_objects[objRank].type);
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
p4 = p3->table[l3];
if ( p4 == 0 ) continue;
if ( m_objects[objRank].distance < p4->min ||
m_objects[objRank].distance >= p4->max ) continue;
for ( l4=0 ; l4<p4->totalUsed ; l4++ )
Gfx::EngineObjLevel3& p3 = p2.next[l1];
if (! p3.used) continue;
if ( m_objects[objRank].distance < p3.min ||
m_objects[objRank].distance >= p3.max ) continue;
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
{
p5 = p4->table[l4];
if ( p5 == 0 ) continue;
for ( l5=0 ; l5<p5->totalUsed ; l5++ )
Gfx::EngineObjLevel4& p4 = p3.next[l4];
if (! p4.used) continue;
if (m_objects[objRank].transparency == 0.0f)
continue;
SetMaterial(p4.material);
SetState(tState, tColor);
if (p4.type == Gfx::ENG_TRIANGLE_TYPE_TRIANGLES)
{
p6 = p5->table[l5];
if ( p6 == 0 ) continue;
SetMaterial(p6->material);
if ( m_objects[objRank].transparency == 0.0f ) continue;
SetState(tState, tColor);
if ( p6->type == D3DTYPE6T )
{
pv = &p6->vertex[0];
m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
D3DFVF_VERTEX2,
pv, p6->totalUsed,
NULL);
m_statisticTriangle += p6->totalUsed/3;
}
if ( p6->type == D3DTYPE6S )
{
pv = &p6->vertex[0];
m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
D3DFVF_VERTEX2,
pv, p6->totalUsed,
NULL);
m_statisticTriangle += p6->totalUsed-2;
}
m_device->DrawPrimitive( Gfx::PRIMITIVE_TRIANGLES,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() / 3;
}
else if (p4.type == Gfx::ENG_TRIANGLE_TYPE_SURFACE)
{
m_device->DrawPrimitive( Gfx::PRIMITIVE_TRIANGLE_STRIP,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() - 2;
}
}
}
}
} */
}
}
m_lightMan->UpdateLightsEnableState(Gfx::ENG_OBJTYPE_TERRAIN);
@ -3165,68 +3161,70 @@ void Gfx::CEngine::DrawInterface()
m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matView);
// TODO!
/*
for (int l1 = 0; l1 < m_objectTree.size(); l1++)
for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++)
{
Gfx::EngineObjLevel1* p1 = &m_objectTree[l1];
p2 = p1->table[l1];
if ( p2 == 0 ) continue;
SetTexture(p2->tex1Name, 0);
SetTexture(p2->tex2Name, 1);
for ( l2=0 ; l2<p2->totalUsed ; l2++ )
Gfx::EngineObjLevel1& p1 = m_objectTree[l1];
if (! p1.used) continue;
// Should be loaded by now
SetTexture(p1.tex1, 0);
SetTexture(p1.tex2, 1);
for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
{
p3 = p2->table[l2];
if ( p3 == 0 ) continue;
objRank = p3->objRank;
if ( !m_objects[objRank].bDrawFront ) continue;
Gfx::EngineObjLevel2& p2 = p1.next[l2];
if (! p2.used) continue;
{
D3DMATRIX mat = MAT_TO_D3DMAT(m_objects[objRank].transform);
m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
}
int objRank = p2.objRank;
if ( !IsVisible(objRank) ) continue;
m_light->LightUpdate(m_objects[objRank].type);
for ( l3=0 ; l3<p3->totalUsed ; l3++ )
if (m_shadowVisible && m_objects[objRank].type == Gfx::ENG_OBJTYPE_TERRAIN)
continue;
if (! m_objects[objRank].drawFront)
continue;
m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_objects[objRank].transform);
if (! IsVisible(objRank))
continue;
m_lightMan->UpdateLightsEnableState(m_objects[objRank].type);
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
p4 = p3->table[l3];
if ( p4 == 0 ) continue;
if ( m_objects[objRank].distance < p4->min ||
m_objects[objRank].distance >= p4->max ) continue;
for ( l4=0 ; l4<p4->totalUsed ; l4++ )
Gfx::EngineObjLevel3& p3 = p2.next[l1];
if (! p3.used) continue;
if ( m_objects[objRank].distance < p3.min ||
m_objects[objRank].distance >= p3.max ) continue;
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
{
p5 = p4->table[l4];
if ( p5 == 0 ) continue;
for ( l5=0 ; l5<p5->totalUsed ; l5++ )
Gfx::EngineObjLevel4& p4 = p3.next[l4];
if (! p4.used) continue;
SetMaterial(p4.material);
SetState(p4.state);
if (p4.type == Gfx::ENG_TRIANGLE_TYPE_TRIANGLES)
{
p6 = p5->table[l5];
if ( p6 == 0 ) continue;
SetMaterial(p6->material);
SetState(p6->state);
if ( p6->type == D3DTYPE6T )
{
pv = &p6->vertex[0];
m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
D3DFVF_VERTEX2,
pv, p6->totalUsed,
NULL);
m_statisticTriangle += p6->totalUsed/3;
}
if ( p6->type == D3DTYPE6S )
{
pv = &p6->vertex[0];
m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
D3DFVF_VERTEX2,
pv, p6->totalUsed,
NULL);
m_statisticTriangle += p6->totalUsed-2;
}
m_device->DrawPrimitive( Gfx::PRIMITIVE_TRIANGLES,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() / 3;
}
else if (p4.type == Gfx::ENG_TRIANGLE_TYPE_SURFACE)
{
m_device->DrawPrimitive( Gfx::PRIMITIVE_TRIANGLE_STRIP,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() - 2;
}
}
}
}
}*/
}
m_particle->DrawParticle(Gfx::SH_FRONT); // draws the particles of the 3D world

View File

@ -539,24 +539,95 @@ struct EngineMouse
/**
\class CEngine
\brief The graphics engine
This is the main class for graphics engine. It is responsible for drawing the 3D scene,
setting various render states, and facilitating the drawing of 2D interface.
It uses a lower-level CDevice object which is implementation-independent core engine.
\section Objecs Engine objects
The 3D scene is composed of objects which are basically collections of triangles forming
a surface or simply independent triangles in space. Objects are stored in the engine
as a tree structure which is composed of 4 tiers (EngineObjLevel1, EngineObjLevel2 and so on).
Each tier stores some data about object triangle, like textures or materials used.
Additional information on objects stored are in EngineObject structure.
Each object is uniquely identified by its rank.
...
* \class CEngine
* \brief The graphics engine
*
* This is the main class for graphics engine. It is responsible for drawing the 3D scene,
* setting various render states, and facilitating the drawing of 2D interface.
*
* It uses a lower-level CDevice object which is implementation-independent core engine.
*
* \section 3DScene 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.
* The coordinate system is left-handed: X axis is to the right, Y axis to the top and Z axis
* is into the screen (Z = 0 is the sceen surface).
*
* In general, the 3D scene is composed of the following things:
* - sky background (gradient or texture image)
* - planets orbiting in the sky (drawn by CPlanet)
* - terrain - ground of the game level (part of engine objects)
* - main scene objects - robots, buildings, etc. (engine objects)
* - water/lava (drawn by CWater)
* - cloud layer (drawn by CCloud)
* - fire, lightning and particle effects (CPyro, CLightning and CParticle)
* - foreground image overlaid onto the scene at the end - for example, aiming crosshairs
* - 2D interface controls available in-game
* - mouse cursor
* - animated highlight box of the selected object(s)
*
* \section 2DInterface 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).
* Matrices for world, view and projection are therefore fixed and never change.
*
* The class tracks the change of window coordinates and conversion functions
* between the window and interface coordinates are provided.
*
* Interface drawing is delegated to CInterface class and particular controls
* are instances of CControl class. The source code for these classes is in
* src/ui directory.
*
* \section Objecs Engine Objects
*
* The 3D scene is composed of objects which are basically collections of triangles forming
* a surface or simply independent triangles in space.
*
* Objects are uniquely identified by object rank obtained at object creation. Creating an
* object equals to allocating space for EngineObject structure which holds object parameters.
* Object's geometric data is stored in a separate structure - a 4-tier tree which splits
* the information of each geometric triangle.
*
* The 4 tiers contain the following information:
* - level 1 (EngineObjLevel1) - two textures (names and structs) applied to triangles,
* - level 2 (EngineObjLevel2) - object rank
* - level 3 (EngineObjLevel3) - minumum and maximum LOD (=level of detail)
* - level 4 (EngineObjLevel4) - type of object*, material, render state and the actual triangle data
*
* NOTE: type of object in this context means only the internal type in 3D engine. It is not related
* to CObject types.
*
* Such tiered structure complicates loops over all object data, but saves a lot of memory and
* optimizes the rendering process (for instance, switching of textures is an expensive operation).
*
* \section Shadows Shadows
*
* Each engine object can be associated with a shadow (EngineShadow). Like objects, shadows are
* identified by their rank obtained upon creation.
*
* ...
*
* \section RenderStates Render States
*
* Almost every primitive drawn on screen is drawn in state set through EngineRenderState enum.
* In some functions, custom modes are still set, using CDevice's SetRenderState. However, it
* will be subject to removal in the future. Generally, setting render states should be minimized
* to avoid unnecessary overhead.
*
* Some states are clearly the result of legacy drawing and texturing methods. For example, TTEXTURE
* states should really be removed and the textures changed to ones with alpha channel. In the future,
* the whole modesetting code will probably be refactored to something more maintainable.
*
* \section Textures Textures
*
* Textures are loaded from a texture subdir in data directory. In the old code, textures were identified
* by file name and loaded using some D3D util code. With new code and OpenGL backend, this approach is not
* efficient - name comparison, etc. takes a lot of time. In the future, textures should be loaded once
* at object creation time, and then referenced to as Gfx::Texture structs, or even as unsigned int ID's
* which is what OpenGL actually wants. The old method is kept for now, with mapping between texture names
* and texture structs but it will also be subject to refactoring in the future.
*/
class CEngine
{

View File

@ -47,7 +47,12 @@ enum BlitzPhase
BPH_BLITZ,
};
/**
* \class CLightning
* \brief Lightning effect renderer
*
* Functions are only stubs for now.
*/
class CLightning
{
public:

View File

@ -723,25 +723,18 @@ bool Gfx::CModelFile::ReadDXF(std::istream &stream, float min, float max)
bool Gfx::CModelFile::CreateEngineObject(int objRank, int addState)
{
/*char texName1[20];
char texName2[20];
int texNum, i, state;
for (int i = 0; i < m_trianglesUsed; i++)
for (int i = 0; i < static_cast<int>( m_triangles.size() ); i++)
{
if (! m_triangles[i].used) continue;
int state = m_triangles[i].state;
state = m_triangles[i].state;
strcpy(texName1, m_triangles[i].texName);
texName2[0] = 0;
/* TODO ???
if (texName1 == "plant.png")
state |= Gfx::ENG_RSTATE_ALPHA;
if ( strcmp(texName1, "plant.tga") == 0 ) // ???
if (m_triangles[i].tex2Name.empty())
{
state |= D3DSTATEALPHA;
}
int texNum = 0;
if ( m_triangles[i].texNum2 != 0 )
{
if ( m_triangles[i].texNum2 == 1 )
{
texNum = m_engine->RetSecondTexture();
@ -760,15 +753,22 @@ bool Gfx::CModelFile::CreateEngineObject(int objRank, int addState)
state |= D3DSTATEDUALw;
}
sprintf(texName2, "dirty%.2d.tga", texNum); // ???
}
}*/
std::vector<Gfx::VertexTex2> vs;
vs.push_back(m_triangles[i].p1);
vs.push_back(m_triangles[i].p2);
vs.push_back(m_triangles[i].p3);
m_engine->AddTriangles(objRank, vs,
m_triangles[i].material,
state + addState,
m_triangles[i].tex1Name,
m_triangles[i].tex2Name,
m_triangles[i].min,
m_triangles[i].max, false);
}
m_engine->AddTriangle(objRank, &m_triangles[i].p1, 3,
m_triangles[i].material,
state + addState,
texName1, texName2,
m_triangles[i].min,
m_triangles[i].max, false);
}*/
return true;
}

View File

@ -256,7 +256,12 @@ struct WheelTrace
};
/**
* \class CParticle
* \brief Particle engine
*
* Functions are only stubs for now.
*/
class CParticle
{
public:

View File

@ -35,6 +35,10 @@ namespace Gfx {
class CEngine;
/**
* \struct Planet
* \brief Planet texture definition
*/
struct Planet
{
//! Initial position in degrees
@ -63,6 +67,15 @@ struct Planet
}
};
/**
* \class CPlanet
* \brief Planet manager
*
* Draws the planets orbiting in the sky.
*
* Planets are drawn in 2D mode, at coordinates calculated from camera position.
*/
class CPlanet
{
public:

View File

@ -90,7 +90,12 @@ struct PyroLightOper
};
/**
* \class CPyro
* \brief Fire effect renderer
*
* Functions are only stubs for now.
*/
class CPyro
{
public:

View File

@ -34,19 +34,31 @@ class CEngine;
class CWater;
//! Limit of slope considered a flat piece of land
const short FLATLIMIT = (5.0f*Math::PI/180.0f);
/**
* \enum TerrainRes
* \brief Underground resource type
*/
enum TerrainRes
{
TR_NULL = 0,
TR_STONE = 1,
TR_URANIUM = 2,
TR_POWER = 3,
//! No resource
TR_NULL = 0,
//! Titanium
TR_STONE = 1,
//! Uranium
TR_URANIUM = 2,
//! Energy
TR_POWER = 3,
//! Vault keys
//@{
TR_KEY_A = 4,
TR_KEY_B = 5,
TR_KEY_C = 6,
TR_KEY_D = 7,
TR_KEY_D = 7
//@}
};
struct BuildingLevel
@ -98,6 +110,10 @@ struct DotLevel
}
};
/**
* \struct FlyingLimit
* \brief Spherical limit of flight
*/
struct FlyingLimit
{
Math::Vector center;
@ -112,7 +128,22 @@ struct FlyingLimit
};
/**
* \class CTerrain
* \brief Terrain loader/generator and manager
*
* Terrain is created from relief textures specifying a XY plane with height
* values which are then scaled and translated into XZ surface forming the
* terrain of game level.
*
* The class also facilitates creating and searching for flat space expanses
* for construction of buildings.
*
* The terrain also specifies underground resources loaded from texture
* and flying limits for the player.
*
* ...
*/
class CTerrain
{
public:

View File

@ -21,8 +21,10 @@
#include "common/iman.h"
#include "common/logger.h"
#include "graphics/core/device.h"
#include "graphics/engine/engine.h"
#include "graphics/engine/terrain.h"
#include "math/geometry.h"
#include "object/object.h"
#include "sound/sound.h"
@ -258,53 +260,41 @@ void Gfx::CWater::AdjustLevel(Math::Vector &pos, Math::Vector &norm,
/** This surface prevents to see the sky (background) underwater! */
void Gfx::CWater::DrawBack()
{
GetLogger()->Trace("CWater::DrawBack(): stub!\n");
/* TODO!
LPDIRECT3DDEVICE7 device;
D3DVERTEX2 vertex[4]; // 2 triangles
D3DMATERIAL7 material;
Math::Matrix matrix;
Math::Vector eye, lookat, n, p, p1, p2;
Math::Point uv1, uv2;
float deep, dist;
if (! m_draw) return;
if (m_type[0] == WATER_NULL) return;
if (m_lines.empty()) return;
if ( !m_bDraw ) return;
if ( m_type[0] == WATER_NULL ) return;
if ( m_lineUsed == 0 ) return;
Math::Vector eye = m_engine->GetEyePt();
Math::Vector lookat = m_engine->GetLookatPt();
eye = m_engine->GetEyePt();
lookat = m_engine->GetLookatPt();
ZeroMemory( &material, sizeof(D3DMATERIAL7) );
Gfx::Material material;
material.diffuse = m_diffuse;
material.ambient = m_ambient;
m_engine->SetMaterial(material);
m_engine->SetTexture("", 0);
m_engine->SetTexture("", 0); // TODO: disable texturing
device = m_engine->GetD3DDevice();
device->SetRenderState(D3DRENDERSTATE_LIGHTING, false);
device->SetRenderState(D3DRENDERSTATE_ZENABLE, false);
device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false);
m_engine->SetState(D3DSTATENORMAL);
Gfx::CDevice* device = m_engine->GetDevice();
deep = m_engine->GetDeepView(0);
m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
float deep = m_engine->GetDeepView(0);
m_engine->SetDeepView(deep*2.0f, 0);
m_engine->SetFocus(m_engine->GetFocus());
m_engine->UpdateMatProj(); // twice the depth of view
Math::Matrix matrix;
matrix.LoadIdentity();
{
D3DMATRIX mat = MAT_TO_D3DMAT(matrix);
device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
}
device->SetTransform(Gfx::TRANSFORM_WORLD, matrix);
Math::Vector p;
p.x = eye.x;
p.z = eye.z;
dist = Math::DistanceProjected(eye, lookat);
float dist = Math::DistanceProjected(eye, lookat);
p.x = (lookat.x-eye.x)*deep*1.0f/dist + eye.x;
p.z = (lookat.z-eye.z)*deep*1.0f/dist + eye.z;
Math::Vector p1, p2;
p1.x = (lookat.z-eye.z)*deep*2.0f/dist + p.x;
p1.z = -(lookat.x-eye.x)*deep*2.0f/dist + p.z;
p2.x = -(lookat.z-eye.z)*deep*2.0f/dist + p.x;
@ -313,155 +303,132 @@ void Gfx::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;
uv1.x = uv1.y = 0.0f;
uv2.x = uv2.y = 0.0f;
Gfx::Vertex vertices[4] =
{
Gfx::Vertex(Math::Vector(p1.x, p2.y, p1.z), n),
Gfx::Vertex(Math::Vector(p1.x, p1.y, p1.z), n),
Gfx::Vertex(Math::Vector(p2.x, p2.y, p2.z), n),
Gfx::Vertex(Math::Vector(p2.x, p1.y, p2.z), n)
};
vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p2.y, p1.z), n, uv1.x,uv2.y);
vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p1.y, p1.z), n, uv1.x,uv1.y);
vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p2.y, p2.z), n, uv2.x,uv2.y);
vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p1.y, p2.z), n, uv2.x,uv1.y);
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertices, 4);
m_engine->AddStatisticTriangle(2);
m_engine->SetDeepView(deep, 0);
m_engine->SetFocus(m_engine->GetFocus());
m_engine->UpdateMatProj(); // gives the initial depth of view
device->SetRenderState(D3DRENDERSTATE_LIGHTING, true);
device->SetRenderState(D3DRENDERSTATE_ZENABLE, true);
device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false);*/
}
void Gfx::CWater::DrawSurf()
{
GetLogger()->Trace("CWater::DrawSurf(): stub!\n");
/* TODO!
LPDIRECT3DDEVICE7 device;
D3DVERTEX2* vertex; // triangles
D3DMATERIAL7 material;
Math::Matrix matrix;
Math::Vector eye, lookat, n, pos, p;
Math::Point uv1, uv2;
bool bUnder;
DWORD flags;
float deep, size, sizez, radius;
int rankview, i, j, u;
if (! m_draw) return;
if (m_type[0] == Gfx::WATER_NULL) return;
if (m_line.empty()) return;
if (m_lines.empty()) return;
vertex = (D3DVERTEX2*)malloc(sizeof(D3DVERTEX2)*(m_brick+2)*2);
std::vector<Gfx::VertexTex2> vertices((m_brick+2)*2, Gfx::VertexTex2());
eye = m_engine->GetEyePt();
lookat = m_engine->GetLookatPt();
Math::Vector eye = m_engine->GetEyePt();
rankview = m_engine->GetRankView();
bUnder = ( rankview == 1);
int rankview = m_engine->GetRankView();
bool under = ( rankview == 1);
device = m_engine->GetD3DDevice();
device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false);
Gfx::CDevice* device = m_engine->GetDevice();
Math::Matrix matrix;
matrix.LoadIdentity();
{
D3DMATRIX mat = MAT_TO_D3DMAT(matrix);
device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat);
}
device->SetTransform(Gfx::TRANSFORM_WORLD, matrix);
ZeroMemory( &material, sizeof(D3DMATERIAL7) );
Gfx::Material material;
material.diffuse = m_diffuse;
material.ambient = m_ambient;
m_engine->SetMaterial(material);
m_engine->SetTexture(m_filename, 0);
m_engine->SetTexture(m_filename, 1);
m_engine->SetTexture(m_fileName, 0);
m_engine->SetTexture(m_fileName, 1);
if ( m_type[rankview] == WATER_TT )
{
m_engine->SetState(D3DSTATETTb|D3DSTATEDUALw|D3DSTATEWRAP, m_color);
}
if ( m_type[rankview] == WATER_TO )
{
m_engine->SetState(D3DSTATENORMAL|D3DSTATEDUALw|D3DSTATEWRAP);
}
if ( m_type[rankview] == WATER_CT )
{
m_engine->SetState(D3DSTATETTb);
}
if ( m_type[rankview] == WATER_CO )
{
m_engine->SetState(D3DSTATENORMAL);
}
device->SetRenderState(D3DRENDERSTATE_FOGENABLE, true);
if (m_type[rankview] == WATER_TT)
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK | Gfx::ENG_RSTATE_DUAL_WHITE | Gfx::ENG_RSTATE_WRAP, m_color);
size = m_size/2.0f;
if ( bUnder ) sizez = -size;
else sizez = size;
else if (m_type[rankview] == WATER_TO)
m_engine->SetState(Gfx::ENG_RSTATE_NORMAL | Gfx::ENG_RSTATE_DUAL_WHITE | Gfx::ENG_RSTATE_WRAP);
// Draws all the lines.
deep = m_engine->GetDeepView(0)*1.5f;
else if (m_type[rankview] == WATER_CT)
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
for ( i=0 ; i<m_lineUsed ; i++ )
else if (m_type[rankview] == WATER_CO)
m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
device->SetRenderState(Gfx::RENDER_STATE_FOG, true);
float size = m_size/2.0f;
float sizez = 0.0f;
if (under) sizez = -size;
else sizez = size;
// Draws all the lines
float deep = m_engine->GetDeepView(0)*1.5f;
for (int i = 0; i < static_cast<int>( m_lines.size() ); i++)
{
Math::Vector pos;
pos.y = m_level;
pos.z = m_line[i].pz;
pos.x = m_line[i].px1;
pos.z = m_lines[i].pz;
pos.x = m_lines[i].px1;
// Visible line?
p = pos;
p.x += size*(m_line[i].len-1);
radius = sqrtf(powf(size, 2.0f)+powf(size*m_line[i].len, 2.0f));
Math::Vector p = pos;
p.x += size*(m_lines[i].len-1);
float radius = sqrtf(powf(size, 2.0f)+powf(size*m_lines[i].len, 2.0f));
if ( Math::Distance(p, eye) > deep+radius ) continue;
D3DVECTOR pD3D = VEC_TO_D3DVEC(p);
device->ComputeSphereVisibility(&pD3D, &radius, 1, 0, &flags);
// TODO: ComputeSphereVisibility
if ( flags & D3DSTATUS_CLIPINTERSECTIONALL ) continue;
int vertexIndex = 0;
Math::Point uv1, uv2;
Math::Vector n;
u = 0;
p.x = pos.x-size;
p.z = pos.z-sizez;
p.y = pos.y;
AdjustLevel(p, n, uv1, uv2);
if ( bUnder ) n.y = -n.y;
vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
if (under) n.y = -n.y;
vertices[vertexIndex++] = Gfx::VertexTex2(p, n, uv1, uv2);
p.x = pos.x-size;
p.z = pos.z+sizez;
p.y = pos.y;
AdjustLevel(p, n, uv1, uv2);
if ( bUnder ) n.y = -n.y;
vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
if (under) n.y = -n.y;
vertices[vertexIndex++] = Gfx::VertexTex2(p, n, uv1, uv2);
for ( j=0 ; j<m_line[i].len ; j++ )
for (int j = 0; j < m_lines[i].len; j++)
{
p.x = pos.x+size;
p.z = pos.z-sizez;
p.y = pos.y;
AdjustLevel(p, n, uv1, uv2);
if ( bUnder ) n.y = -n.y;
vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
if (under) n.y = -n.y;
vertices[vertexIndex++] = Gfx::VertexTex2(p, n, uv1, uv2);
p.x = pos.x+size;
p.z = pos.z+sizez;
p.y = pos.y;
AdjustLevel(p, n, uv1, uv2);
if ( bUnder ) n.y = -n.y;
vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
if (under) n.y = -n.y;
vertices[vertexIndex++] = Gfx::VertexTex2(p, n, uv1, uv2);
pos.x += size*2.0f;
}
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, u, NULL);
m_engine->AddStatisticTriangle(u-2);
device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, &vertices[0], vertexIndex);
m_engine->AddStatisticTriangle(vertexIndex - 2);
}
free(vertex);*/
}
bool Gfx::CWater::GetWater(int x, int y)

View File

@ -35,12 +35,19 @@ namespace Gfx {
class CEngine;
class CTerrain;
/**
* \struct WaterLine
* \brief Water strip
*/
struct WaterLine
{
//! Beginning
//@{
//! Beginning of line (terrain coordinates)
short x, y;
//! Length by x
//@}
//! Length in X direction (terrain coordinates)
short len;
//! X (1, 2) and Z coordinates (world coordinates)
float px1, px2, pz;
WaterLine()
@ -51,6 +58,10 @@ struct WaterLine
}
};
/**
* \struct WaterVapor
* \brief Water particle effect
*/
struct WaterVapor
{
bool used;
@ -68,6 +79,10 @@ struct WaterVapor
}
};
/**
* \enum WaterType
* \brief Mode of water display
*/
enum WaterType
{
//! No water
@ -82,7 +97,19 @@ enum WaterType
WATER_CO = 4,
};
/**
* \class CWater
* \brief Water manager/renderer
*
* Water is drawn where the terrain is below specified level. The mapping
* is based on terrain coordinates - for each "brick" coordinate, the level
* of terrain is tested. For every Y coordinate, many lines in X direction
* are created (WaterLines).
*
* There are two parts of drawing process: drawing the background image
* blocking the normal sky layer and drawing the surface of water.
* The surface is drawn with texture, so with proper texture it can be lava.
*/
class CWater
{
public: