From c1936514c054d6d7c85843bf2c3e0b97653ef651 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Wed, 8 Aug 2012 23:51:19 +0200 Subject: CWater and CCloud basic implementation Added rewritten implementation for CWater and CCloud Won't link yet because of missing functions --- src/graphics/engine/cloud.cpp | 267 +++++++++++++++++- src/graphics/engine/cloud.h | 74 +++-- src/graphics/engine/water.cpp | 640 +++++++++++++++++++++++++++++++++++++++++- src/graphics/engine/water.h | 137 +++++---- 4 files changed, 1043 insertions(+), 75 deletions(-) (limited to 'src/graphics') diff --git a/src/graphics/engine/cloud.cpp b/src/graphics/engine/cloud.cpp index d0e5ed8..e46b074 100644 --- a/src/graphics/engine/cloud.cpp +++ b/src/graphics/engine/cloud.cpp @@ -19,5 +19,270 @@ #include "graphics/engine/cloud.h" +#include "common/iman.h" +#include "graphics/engine/engine.h" +#include "graphics/engine/terrain.h" +#include "math/geometry.h" -// TODO implementation + +const int CLOUD_LINE_PREALLOCATE_COUNT = 100; + +const int DIMEXPAND = 4; // extension of the dimensions + + +Gfx::CCloud::CCloud(CInstanceManager* iMan, Gfx::CEngine* engine) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_CLOUD, this); + + m_engine = engine; + m_terrain = nullptr; + + m_level = 0.0f; + m_wind = Math::Vector(0.0f, 0.0f, 0.0f); + m_subdiv = 8; + m_enable = true; + + m_line.reserve(CLOUD_LINE_PREALLOCATE_COUNT); +} + +Gfx::CCloud::~CCloud() +{ + m_iMan = nullptr; + m_engine = nullptr; + m_terrain = nullptr; +} + +bool Gfx::CCloud::EventProcess(const Event &event) +{ + /* TODO! + if ( event.event == EVENT_FRAME ) + return EventFrame(event); */ + + return true; +} + +bool Gfx::CCloud::EventFrame(const Event &event) +{ + /* TODO! + if (m_engine->GetPause()) return true; + + m_time += event.rTime; + + if (m_level == 0.0f) return true; + + if (m_time - m_lastTest < 0.2f) return true; + + m_lastTest = m_time; */ + + return true; +} + +void Gfx::CCloud::AdjustLevel(Math::Vector &pos, Math::Vector &eye, float deep, + Math::Point &uv1, Math::Point &uv2) +{ + uv1.x = (pos.x+20000.0f)/1280.0f; + uv1.y = (pos.z+20000.0f)/1280.0f; + uv1.x -= m_time*(m_wind.x/100.0f); + uv1.y -= m_time*(m_wind.z/100.0f); + + uv2.x = 0.0f; + uv2.y = 0.0f; + + float dist = Math::DistanceProjected(pos, eye); + float factor = powf(dist/deep, 2.0f); + pos.y -= m_level*factor*10.0f; +} + +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_lineUsed == 0 ) return; + + vertex = (D3DVERTEX2*)malloc(sizeof(D3DVERTEX2)*(m_brick+2)*2); + + iDeep = m_engine->GetDeepView(); + 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; + + 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)); + + matView = m_engine->GetMatView(); + { + D3DMATRIX mat = MAT_TO_D3DMAT(*matView); + device->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); + } + + ZeroMemory( &material, sizeof(D3DMATERIAL7) ); + 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->SetState(D3DSTATETTb|D3DSTATEFOG|D3DSTATEWRAP); + + matrix.LoadIdentity(); + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + size = m_size/2.0f; + eye = m_engine->GetEyePt(); + n = Math::Vector(0.0f, -1.0f, 0.0f); + + // Draws all the lines. + for ( i=0 ; iDrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, u, NULL); + m_engine->AddStatisticTriangle(u-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) +{ + Gfx::CloudLine line; + + line.x = x; + line.y = y; + line.len = len; + + float offset = m_brick*m_size/2.0f - m_size/2.0f; + + line.px1 = m_size* line.x - offset; + line.px2 = m_size*(line.x+line.len) - offset; + line.pz = m_size* line.y - offset; + + m_line.push_back(line); +} + +void Gfx::CCloud::Create(const std::string& fileName, + Gfx::Color diffuse, Gfx::Color ambient, + float level) +{ + m_diffuse = diffuse; + m_ambient = ambient; + m_level = level; + m_time = 0.0f; + m_lastTest = 0.0f; + m_fileName = fileName; + + if (! m_fileName.empty()) + { + m_engine->LoadTexture(m_fileName, 0); + m_engine->LoadTexture(m_fileName, 1); + } + + if (m_terrain == nullptr) + m_terrain = static_cast(m_iMan->SearchInstance(CLASS_TERRAIN)); + + m_wind = m_terrain->GetWind(); + + m_brick = m_terrain->GetBrick()*m_terrain->GetMosaic()*DIMEXPAND; + m_size = m_terrain->GetSize(); + + m_brick /= m_subdiv*DIMEXPAND; + m_size *= m_subdiv*DIMEXPAND; + + if (m_level == 0.0f) + return; + + m_line.clear(); + for (int y = 0; y < m_brick; y++) + CreateLine(0, y, m_brick); + + return; +} + +void Gfx::CCloud::Flush() +{ + m_level = 0.0f; +} + + +void Gfx::CCloud::SetLevel(float level) +{ + m_level = level; + + Create(m_fileName, m_diffuse, m_ambient, m_level); +} + +float Gfx::CCloud::GetLevel() +{ + return m_level; +} + +void Gfx::CCloud::SetEnable(bool enable) +{ + m_enable = enable; +} + +bool Gfx::CCloud::GetEnable() +{ + return m_enable; +} diff --git a/src/graphics/engine/cloud.h b/src/graphics/engine/cloud.h index 562f651..676dfe8 100644 --- a/src/graphics/engine/cloud.h +++ b/src/graphics/engine/cloud.h @@ -24,6 +24,9 @@ #include "math/point.h" #include "math/vector.h" +#include +#include + class CInstanceManager; @@ -34,13 +37,20 @@ namespace Gfx { class CEngine; class CTerrain; -const short MAXCLOUDLINE = 100; - struct CloudLine { - short x, y; // beginning - short len; // in length x + //! Beginning + short x, y; + //! In length x + short len; float px1, px2, pz; + + CloudLine() + { + x = y = 0; + len = 0; + px1 = px2 = pz = 0; + } }; @@ -51,43 +61,59 @@ public: ~CCloud(); bool EventProcess(const Event &event); + //! Removes all the clouds void Flush(); - bool Create(const char *filename, Gfx::Color diffuse, Gfx::Color ambient, float level); + //! Creates all areas of cloud + void Create(const std::string& fileName, Gfx::Color diffuse, Gfx::Color ambient, float level); + //! Draw the clouds void Draw(); - bool SetLevel(float level); + //! Modifies the cloud level + void SetLevel(float level); + //! Returns the current level of clouds float GetLevel(); - void SetEnable(bool bEnable); + //! Activate management of clouds + void SetEnable(bool enable); bool GetEnable(); protected: + //! Makes the clouds evolve bool EventFrame(const Event &event); - void AdjustLevel(Math::Vector &pos, Math::Vector &eye, float deep, Math::Point &uv1, Math::Point &uv2); - bool CreateLine(int x, int y, int len); + //! Adjusts the position to normal, to imitate the clouds at movement + void AdjustLevel(Math::Vector &pos, Math::Vector &eye, float deep, + Math::Point &uv1, Math::Point &uv2); + //! Updates the positions, relative to the ground + void CreateLine(int x, int y, int len); protected: - CInstanceManager* m_iMan; - CEngine* m_engine; - CTerrain* m_terrain; - - char m_filename[100]; - float m_level; // overall level - Math::Point m_speed; // feedrate (wind) - Gfx::Color m_diffuse; // diffuse color - Gfx::Color m_ambient; // ambient color + CInstanceManager* m_iMan; + Gfx::CEngine* m_engine; + Gfx::CTerrain* m_terrain; + + std::string m_fileName; + //! Overall level + float m_level; + //! Feedrate (wind) + Math::Point m_speed; + //! Diffuse color + Gfx::Color m_diffuse; + //! Ambient color + Gfx::Color m_ambient; float m_time; float m_lastTest; int m_subdiv; - Math::Vector m_wind; // wind speed - int m_brick; // brick mosaic - float m_size; // size of a brick element + //! Wind speed + Math::Vector m_wind; + //! Brick mosaic + int m_brick; + //! Size of a brick element + float m_size; - int m_lineUsed; - CloudLine m_line[MAXCLOUDLINE]; + std::vector m_line; - bool m_bEnable; + bool m_enable; }; diff --git a/src/graphics/engine/water.cpp b/src/graphics/engine/water.cpp index a157e82..1f11671 100644 --- a/src/graphics/engine/water.cpp +++ b/src/graphics/engine/water.cpp @@ -19,5 +19,643 @@ #include "graphics/engine/water.h" +#include "common/iman.h" +#include "graphics/engine/engine.h" +#include "graphics/engine/terrain.h" +#include "sound/sound.h" + + +const int WATERLINE_PREALLOCATE_COUNT = 500; + +// TODO: remove the limit? +const int VAPOR_SIZE = 10; + + +Gfx::CWater::CWater(CInstanceManager* iMan, Gfx::CEngine* engine) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_WATER, this); + + m_engine = engine; + m_terrain = nullptr; + m_particule = nullptr; + m_sound = nullptr; + + m_type[0] = WATER_NULL; + m_type[1] = WATER_NULL; + m_level = 0.0f; + m_draw = true; + m_lava = false; + m_color = 0xffffffff; + m_subdiv = 4; + + m_line.reserve(WATERLINE_PREALLOCATE_COUNT); + + std::vector(VAPOR_SIZE).swap(m_vapor); +} + +Gfx::CWater::~CWater() +{ + m_iMan = nullptr; + m_engine = nullptr; + m_terrain = nullptr; + m_particule = nullptr; + m_sound = nullptr; +} + + +bool Gfx::CWater::EventProcess(const Event &event) +{ + /* TODO! + if (event.type == EVENT_FRAME) + return EventFrame(event); +*/ + return true; +} + +bool Gfx::CWater::EventFrame(const Event &event) +{ + /* TODO! + if (m_engine->GetPause()) return true; + + m_time += event.rTime; + + if (m_type[0] == WATER_NULL) return true; + + if (m_lava) + LavaFrame(event.rTime);*/ + + return true; +} + +void Gfx::CWater::LavaFrame(float rTime) +{ + if (m_particule == nullptr) + m_particule = static_cast( m_iMan->SearchInstance(CLASS_PARTICULE) ); + + for (int i = 0; i < static_cast( m_vapor.size() ); i++) + VaporFrame(i, rTime); + + if (m_time - m_lastLava >= 0.1f) + { + Math::Vector eye = m_engine->GetEyePt(); + Math::Vector lookat = m_engine->GetLookatPt(); + + float distance = Math::Rand()*200.0f; + float shift = (Math::Rand()-0.5f)*200.0f; + + Math::Vector dir = Normalize(lookat-eye); + Math::Vector pos = eye + dir*distance; + + Math::Vector perp; + perp.x = -dir.z; + perp.y = dir.y; + perp.z = dir.x; + pos = pos + perp*shift; + + float level = m_terrain->GetFloorLevel(pos, true); + if (level < m_level) + { + pos.y = m_level; + + level = Math::Rand(); + if (level < 0.8f) + { + if ( VaporCreate(Gfx::PARTIFIRE, pos, 0.02f+Math::Rand()*0.06f) ) + m_lastLava = m_time; + } + else if (level < 0.9f) + { + if ( VaporCreate(Gfx::PARTIFLAME, pos, 0.5f+Math::Rand()*3.0f) ) + m_lastLava = m_time; + } + else + { + if ( VaporCreate(Gfx::PARTIVAPOR, pos, 0.2f+Math::Rand()*2.0f) ) + m_lastLava = m_time; + } + } + } +} + +void Gfx::CWater::VaporFlush() +{ + m_vapor.clear(); +} + +bool Gfx::CWater::VaporCreate(Gfx::ParticleType type, Math::Vector pos, float delay) +{ + for (int i = 0; i < static_cast( m_vapor.size() ); i++) + { + if (! m_vapor[i].used) + { + m_vapor[i].used = true; + m_vapor[i].type = type; + m_vapor[i].pos = pos; + m_vapor[i].delay = delay; + m_vapor[i].time = 0.0f; + m_vapor[i].last = 0.0f; + + if (m_vapor[i].type == PARTIFIRE) + m_sound->Play(SOUND_BLUP, pos, 1.0f, 1.0f-Math::Rand()*0.5f); + + if (m_vapor[i].type == PARTIVAPOR) + m_sound->Play(SOUND_PSHHH, pos, 0.3f, 2.0f); + + return true; + } + } + + return false; +} + +void Gfx::CWater::VaporFrame(int i, float rTime) +{ + m_vapor[i].time += rTime; + + if (m_sound == nullptr) + m_sound = static_cast(m_iMan->SearchInstance(CLASS_SOUND)); + + if (m_vapor[i].time <= m_vapor[i].delay) + { + if (m_time-m_vapor[i].last >= m_engine->ParticleAdapt(0.02f)) + { + m_vapor[i].last = m_time; + + if (m_vapor[i].type == PARTIFIRE) + { + for (int j = 0; j < 10; j++) + { + Math::Vector pos = m_vapor[i].pos; + pos.x += (Math::Rand()-0.5f)*2.0f; + pos.z += (Math::Rand()-0.5f)*2.0f; + pos.y -= 1.0f; + Math::Vector speed; + speed.x = (Math::Rand()-0.5f)*6.0f; + speed.z = (Math::Rand()-0.5f)*6.0f; + speed.y = 8.0f+Math::Rand()*5.0f; + Math::Point dim; + dim.x = Math::Rand()*1.5f+1.5f; + dim.y = dim.x; + m_particule->CreateParticle(pos, speed, dim, PARTIERROR, 2.0f, 10.0f); + } + } + else if (m_vapor[i].type == PARTIFLAME) + { + Math::Vector pos = m_vapor[i].pos; + pos.x += (Math::Rand()-0.5f)*8.0f; + pos.z += (Math::Rand()-0.5f)*8.0f; + pos.y -= 2.0f; + Math::Vector speed; + speed.x = (Math::Rand()-0.5f)*2.0f; + speed.z = (Math::Rand()-0.5f)*2.0f; + speed.y = 4.0f+Math::Rand()*4.0f; + Math::Point dim; + dim.x = Math::Rand()*2.0f+2.0f; + dim.y = dim.x; + m_particule->CreateParticle(pos, speed, dim, PARTIFLAME); + } + else + { + Math::Vector pos = m_vapor[i].pos; + pos.x += (Math::Rand()-0.5f)*4.0f; + pos.z += (Math::Rand()-0.5f)*4.0f; + pos.y -= 2.0f; + Math::Vector speed; + speed.x = (Math::Rand()-0.5f)*2.0f; + speed.z = (Math::Rand()-0.5f)*2.0f; + speed.y = 8.0f+Math::Rand()*8.0f; + Math::Point dim; + dim.x = Math::Rand()*1.0f+1.0f; + dim.y = dim.x; + m_particule->CreateParticle(pos, speed, dim, PARTIVAPOR); + } + } + } + else + { + m_vapor[i].used = false; + } +} + +void Gfx::CWater::AdjustLevel(Math::Vector &pos, Math::Vector &norm, + Math::Point &uv1, Math::Point &uv2) +{ + float t1 = m_time*1.5f + pos.x*0.1f * pos.z*0.2f; + pos.y += sinf(t1)*m_eddy.y; + + t1 = m_time*1.5f; + uv1.x = (pos.x+10000.0f)/40.0f+sinf(t1)*m_eddy.x*0.02f; + uv1.y = (pos.z+10000.0f)/40.0f-cosf(t1)*m_eddy.z*0.02f; + uv2.x = (pos.x+10010.0f)/20.0f+cosf(-t1)*m_eddy.x*0.02f; + uv2.y = (pos.z+10010.0f)/20.0f-sinf(-t1)*m_eddy.z*0.02f; + + t1 = m_time*0.50f + pos.x*2.1f + pos.z*1.1f; + float t2 = m_time*0.75f + pos.x*2.0f + pos.z*1.0f; + norm = Math::Vector(sinf(t1)*m_glint, 1.0f, sinf(t2)*m_glint); +} + +/** This surface prevents to see the sky (background) underwater! */ +void Gfx::CWater::DrawBack() +{ + /* 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_bDraw ) return; + if ( m_type[0] == WATER_NULL ) return; + if ( m_lineUsed == 0 ) return; + + eye = m_engine->GetEyePt(); + lookat = m_engine->GetLookatPt(); + + ZeroMemory( &material, sizeof(D3DMATERIAL7) ); + material.diffuse = m_diffuse; + material.ambient = m_ambient; + m_engine->SetMaterial(material); + + m_engine->SetTexture("", 0); + + device = m_engine->GetD3DDevice(); + device->SetRenderState(D3DRENDERSTATE_LIGHTING, false); + device->SetRenderState(D3DRENDERSTATE_ZENABLE, false); + device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); + m_engine->SetState(D3DSTATENORMAL); + + 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 + + matrix.LoadIdentity(); + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + p.x = eye.x; + p.z = eye.z; + 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; + + 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; + p2.z = (lookat.x-eye.x)*deep*2.0f/dist + p.z; + + p1.y = -50.0f; + p2.y = m_level; + + 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; + + 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); + 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() +{ + /* 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; + + vertex = (D3DVERTEX2*)malloc(sizeof(D3DVERTEX2)*(m_brick+2)*2); + + eye = m_engine->GetEyePt(); + lookat = m_engine->GetLookatPt(); + + rankview = m_engine->GetRankView(); + bUnder = ( rankview == 1); + + device = m_engine->GetD3DDevice(); + device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); + + matrix.LoadIdentity(); + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + ZeroMemory( &material, sizeof(D3DMATERIAL7) ); + material.diffuse = m_diffuse; + material.ambient = m_ambient; + m_engine->SetMaterial(material); + + 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); + + size = m_size/2.0f; + if ( bUnder ) sizez = -size; + else sizez = size; + + // Draws all the lines. + deep = m_engine->GetDeepView(0)*1.5f; + + for ( i=0 ; i deep+radius ) continue; + + D3DVECTOR pD3D = VEC_TO_D3DVEC(p); + device->ComputeSphereVisibility(&pD3D, &radius, 1, 0, &flags); + + if ( flags & D3DSTATUS_CLIPINTERSECTIONALL ) continue; + + 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); + + 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); + + for ( j=0 ; jDrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, u, NULL); + m_engine->AddStatisticTriangle(u-2); + } + + free(vertex);*/ +} + +bool Gfx::CWater::GetWater(int x, int y) +{ + x *= m_subdiv; + y *= m_subdiv; + + float size = m_size/m_subdiv; + float offset = m_brick*m_size/2.0f; + + for (int dy = 0; dy <= m_subdiv; dy++) + { + for (int dx = 0; dx <= m_subdiv; dx++) + { + Math::Vector pos; + pos.x = (x+dx)*size - offset; + pos.z = (y+dy)*size - offset; + pos.y = 0.0f; + float level = m_terrain->GetFloorLevel(pos, true); + if (level < m_level+m_eddy.y) + return true; + } + } + return false; +} + +void Gfx::CWater::CreateLine(int x, int y, int len) +{ + Gfx::WaterLine line; + + line.x = x; + line.y = y; + line.len = len; + + float offset = m_brick*m_size/2.0f - m_size/2.0f; + + line.px1 = m_size* line.x - offset; + line.px2 = m_size*(line.x+line.len) - offset; + line.pz = m_size* line.y - offset; + + m_line.push_back(line); +} + +void Gfx::CWater::Create(Gfx::WaterType type1, Gfx::WaterType type2, const std::string& fileName, + Gfx::Color diffuse, Gfx::Color ambient, + float level, float glint, Math::Vector eddy) +{ + m_type[0] = type1; + m_type[1] = type2; + m_diffuse = diffuse; + m_ambient = ambient; + m_level = level; + m_glint = glint; + m_eddy = eddy; + m_time = 0.0f; + m_lastLava = 0.0f; + m_fileName = fileName; + + VaporFlush(); + + if (! m_fileName.empty()) + { + m_engine->LoadTexture(m_fileName, 0); + m_engine->LoadTexture(m_fileName, 1); + } + + if (m_terrain == nullptr) + m_terrain = static_cast(m_iMan->SearchInstance(CLASS_TERRAIN)); + + m_brick = m_terrain->GetBrick()*m_terrain->GetMosaic(); + m_size = m_terrain->GetSize(); + + m_brick /= m_subdiv; + m_size *= m_subdiv; + + if (m_type[0] == WATER_NULL) + return; + + m_line.clear(); + + for (int y = 0; y < m_brick; y++) + { + int len = 0; + for (int x = 0; x < m_brick; x++) + { + if (GetWater(x,y)) // water here? + { + len ++; + if (len >= 5) + { + CreateLine(x-len+1, y, len); + len = 0; + } + } + else // dry? + { + if (len != 0) + { + CreateLine(x-len, y, len); + len = 0; + } + } + } + if (len != 0) + CreateLine(m_brick - len, y, len); + } +} + +void Gfx::CWater::Flush() +{ + m_type[0] = Gfx::WATER_NULL; + m_type[1] = Gfx::WATER_NULL; + m_level = 0.0f; + m_lava = false; +} + +void Gfx::CWater::SetLevel(float level) +{ + m_level = level; + + Create(m_type[0], m_type[1], m_fileName, m_diffuse, m_ambient, + m_level, m_glint, m_eddy); +} + +float Gfx::CWater::GetLevel() +{ + return m_level; +} + +float Gfx::CWater::GetLevel(CObject* object) +{ + /* TODO! + ObjectType type = object->GetType(); + + if ( type == OBJECT_HUMAN || + type == OBJECT_TECH ) + { + return m_level-3.0f; + } + + if ( type == OBJECT_MOBILEfa || + type == OBJECT_MOBILEta || + type == OBJECT_MOBILEwa || + type == OBJECT_MOBILEia || + type == OBJECT_MOBILEfc || + type == OBJECT_MOBILEtc || + type == OBJECT_MOBILEwc || + type == OBJECT_MOBILEic || + type == OBJECT_MOBILEfi || + type == OBJECT_MOBILEti || + type == OBJECT_MOBILEwi || + type == OBJECT_MOBILEii || + type == OBJECT_MOBILEfs || + type == OBJECT_MOBILEts || + type == OBJECT_MOBILEws || + type == OBJECT_MOBILEis || + type == OBJECT_MOBILErt || + type == OBJECT_MOBILErc || + type == OBJECT_MOBILErr || + type == OBJECT_MOBILErs || + type == OBJECT_MOBILEsa || + type == OBJECT_MOBILEtg || + type == OBJECT_MOBILEft || + type == OBJECT_MOBILEtt || + type == OBJECT_MOBILEwt || + type == OBJECT_MOBILEit || + type == OBJECT_MOBILEdr ) + { + return m_level-2.0f; + } +*/ + return m_level; +} + +void Gfx::CWater::SetLava(bool lava) +{ + m_lava = lava; +} + +bool Gfx::CWater::GetLava() +{ + return m_lava; +} + +void Gfx::CWater::AdjustEye(Math::Vector &eye) +{ + if (m_lava) + { + if (eye.y < m_level+2.0f) + eye.y = m_level+2.0f; // never under the lava + } + else + { + if (eye.y >= m_level-2.0f && + eye.y <= m_level+2.0f) // close to the surface? + eye.y = m_level+2.0f; // bam, well above + } +} -// TODO implementation diff --git a/src/graphics/engine/water.h b/src/graphics/engine/water.h index 6d3736e..245baf7 100644 --- a/src/graphics/engine/water.h +++ b/src/graphics/engine/water.h @@ -19,50 +19,64 @@ #pragma once -#include "graphics/engine/engine.h" -#include "graphics/engine/particle.h" #include "common/event.h" +#include "graphics/engine/particle.h" class CInstanceManager; -class CSound; +class CSoundInterface; namespace Gfx { +class CEngine; class CTerrain; - -const short MAXWATERLINE = 500; - struct WaterLine { - short x, y; // beginning - short len; // length by x + //! Beginning + short x, y; + //! Length by x + short len; float px1, px2, pz; -}; - -const short MAXWATVAPOR = 10; + WaterLine() + { + x = y = 0; + len = 0; + px1 = px2 = pz = 0.0f; + } +}; struct WaterVapor { - bool bUsed; - ParticleType type; - Math::Vector pos; - float delay; - float time; - float last; + bool used; + Gfx::ParticleType type; + Math::Vector pos; + float delay; + float time; + float last; + + WaterVapor() + { + used = false; + type = Gfx::PARTIWATER; + delay = time = last = 0.0f; + } }; - enum WaterType { - WATER_NULL = 0, // no water - WATER_TT = 1, // transparent texture - WATER_TO = 2, // opaque texture - WATER_CT = 3, // transparent color - WATER_CO = 4, // opaque color + //! No water + WATER_NULL = 0, + //! Transparent texture + WATER_TT = 1, + //! Opaque texture + WATER_TO = 2, + //! Transparent color + WATER_CT = 3, + //! Opaque color + WATER_CO = 4, }; @@ -74,61 +88,86 @@ public: void SetDevice(Gfx::CDevice* device); bool EventProcess(const Event &event); + //! Removes all the water void Flush(); - bool Create(WaterType type1, WaterType type2, const char *filename, Gfx::Color diffuse, Gfx::Color ambient, float level, float glint, Math::Vector eddy); + //! Creates all expanses of water + void Create(WaterType type1, WaterType type2, const std::string& fileName, + Gfx::Color diffuse, Gfx::Color ambient, float level, float glint, Math::Vector eddy); + //! Draw the back surface of the water void DrawBack(); + //! Draws the flat surface of the water void DrawSurf(); - bool SetLevel(float level); + //! Changes the level of the water + void SetLevel(float level); + //! Returns the current level of water float GetLevel(); + //! Returns the current level of water for a given object float GetLevel(CObject* object); - void SetLava(bool bLava); + //@{ + //! Management of the mode of lava/water + void SetLava(bool lava); bool GetLava(); + //@} + //! Adjusts the eye of the camera, not to be in the water void AdjustEye(Math::Vector &eye); protected: + //! Makes water evolve bool EventFrame(const Event &event); + //! Makes evolve the steam jets on the lava void LavaFrame(float rTime); + //! Adjusts the position to normal, to imitate reflections on an expanse of water at rest void AdjustLevel(Math::Vector &pos, Math::Vector &norm, Math::Point &uv1, Math::Point &uv2); + //! Indicates if there is water in a given position bool GetWater(int x, int y); - bool CreateLine(int x, int y, int len); + //! Updates the positions, relative to the ground + void CreateLine(int x, int y, int len); + //! Removes all the steam jets void VaporFlush(); + //! Creates a new steam bool VaporCreate(ParticleType type, Math::Vector pos, float delay); + //! Makes evolve a steam jet void VaporFrame(int i, float rTime); protected: - CInstanceManager* m_iMan; - CEngine* m_engine; - CDevice* m_device; - CTerrain* m_terrain; - CParticle* m_particule; - CSound* m_sound; + CInstanceManager* m_iMan; + Gfx::CEngine* m_engine; + Gfx::CDevice* m_device; + Gfx::CTerrain* m_terrain; + Gfx::CParticle* m_particule; + CSoundInterface* m_sound; WaterType m_type[2]; - char m_filename[100]; - float m_level; // overall level - float m_glint; // amplitude of reflections - Math::Vector m_eddy; // amplitude of swirls - Gfx::Color m_diffuse; // diffuse color - Gfx::Color m_ambient; // ambient color + std::string m_fileName; + //! Overall level + float m_level; + //! Amplitude of reflections + float m_glint; + //! Amplitude of swirls + Math::Vector m_eddy; + //! Diffuse color + Gfx::Color m_diffuse; + //! Ambient color + Gfx::Color m_ambient; float m_time; float m_lastLava; - int m_subdiv; - - int m_brick; // number of brick*mosaics - float m_size; // size of a item in an brick + int m_subdiv; - int m_lineUsed; - WaterLine m_line[MAXWATERLINE]; + //! Number of brick*mosaics + int m_brick; + //! Size of a item in an brick + float m_size; - WaterVapor m_vapor[MAXWATVAPOR]; + std::vector m_line; + std::vector m_vapor; - bool m_bDraw; - bool m_bLava; - long m_color; + bool m_draw; + bool m_lava; + long m_color; }; }; // namespace Gfx -- cgit v1.2.3-1-g7c22