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/water.cpp | 640 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 639 insertions(+), 1 deletion(-) (limited to 'src/graphics/engine/water.cpp') 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 -- cgit v1.2.3-1-g7c22