From ebed57aa22b772211387a5561f995eee8f5faed1 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Tue, 26 Jun 2012 22:23:05 +0200 Subject: Whitespace and language change - changed tabs to spaces and DOS line endings to Unix (except in CBot and metafile) - changed language to English - fixed #include in d3dengine.h --- src/old/water.cpp | 1688 ++++++++++++++++++++++++++--------------------------- 1 file changed, 844 insertions(+), 844 deletions(-) (limited to 'src/old/water.cpp') diff --git a/src/old/water.cpp b/src/old/water.cpp index 215bac9..dfde09e 100644 --- a/src/old/water.cpp +++ b/src/old/water.cpp @@ -1,844 +1,844 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - -// water.cpp - - -#include -#include -#include - -#include "common/struct.h" -#include "math/geometry.h" -#include "math/conv.h" -#include "old/d3dengine.h" -#include "old/d3dmath.h" -#include "old/d3dutil.h" -#include "common/event.h" -#include "common/misc.h" -#include "common/iman.h" -#include "old/math3d.h" -#include "old/particule.h" -#include "old/terrain.h" -#include "object/object.h" -#include "old/sound.h" -#include "old/water.h" - - - - -// Constructor of the terrain. - -CWater::CWater(CInstanceManager* iMan, CD3DEngine* engine) -{ - m_iMan = iMan; - m_iMan->AddInstance(CLASS_WATER, this); - - m_engine = engine; - m_terrain = 0; - m_particule = 0; - m_sound = 0; - - m_type[0] = WATER_NULL; - m_type[1] = WATER_NULL; - m_level = 0.0f; - m_bDraw = true; - m_bLava = false; - m_color = 0xffffffff; - m_subdiv = 4; - m_filename[0] = 0; -} - -// Destructor of the terrain. - -CWater::~CWater() -{ -} - - -bool CWater::EventProcess(const Event &event) -{ - if ( event.event == EVENT_FRAME ) - { - return EventFrame(event); - } - - if ( event.event == EVENT_KEYDOWN ) - { -#if 0 - if ( event.param == 'S' ) - { - if ( m_subdiv == 1 ) m_subdiv = 2; - else if ( m_subdiv == 2 ) m_subdiv = 4; - else if ( m_subdiv == 4 ) m_subdiv = 8; - else if ( m_subdiv == 8 ) m_subdiv = 1; - SetLevel(m_level); - } - if ( event.param == 'M' ) - { - SetLevel(m_level+1.0f); - } - if ( event.param == 'D' ) - { - SetLevel(m_level-1.0f); - } - if ( event.param == 'H' ) - { - m_bDraw = !m_bDraw; - } - if ( event.param == 'C' ) - { - if ( m_color == 0xffffffff ) m_color = 0xcccccccc; - else if ( m_color == 0xcccccccc ) m_color = 0x88888888; - else if ( m_color == 0x88888888 ) m_color = 0x44444444; - else if ( m_color == 0x44444444 ) m_color = 0x00000000; - else if ( m_color == 0x00000000 ) m_color = 0xffffffff; - } - if ( event.param == 'Q' ) - { - int i; - i = (m_color>>24); - i += 0x44; - i &= 0xff; - i = (i<<24); - m_color &= 0x00ffffff; - m_color |= i; - } - if ( event.param == 'W' ) - { - int i; - i = (m_color>>16); - i += 0x44; - i &= 0xff; - i = (i<<16); - m_color &= 0xff00ffff; - m_color |= i; - } - if ( event.param == 'E' ) - { - int i; - i = (m_color>>8); - i += 0x44; - i &= 0xff; - i = (i<<8); - m_color &= 0xffff00ff; - m_color |= i; - } - if ( event.param == 'R' ) - { - int i; - i = m_color; - i += 0x44; - i &= 0xff; - m_color &= 0xffffff00; - m_color |= i; - } -#endif - } - return true; -} - -// Makes water evolve. - -bool CWater::EventFrame(const Event &event) -{ - if ( m_engine->RetPause() ) return true; - - m_time += event.rTime; - - if ( m_type[0] == WATER_NULL ) return true; - - if ( m_bLava ) - { - LavaFrame(event.rTime); - } - return true; -} - -// Makes evolve the steam jets on the lava. - -void CWater::LavaFrame(float rTime) -{ - Math::Vector eye, lookat, dir, perp, pos; - float distance, shift, level; - int i; - - if ( m_particule == 0 ) - { - m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE); - } - - for ( i=0 ; i= 0.1f ) - { - eye = m_engine->RetEyePt(); - lookat = m_engine->RetLookatPt(); - - distance = Math::Rand()*200.0f; - shift = (Math::Rand()-0.5f)*200.0f; - - dir = Normalize(lookat-eye); - pos = eye + dir*distance; - - perp.x = -dir.z; - perp.y = dir.y; - perp.z = dir.x; - pos = pos + perp*shift; - - level = m_terrain->RetFloorLevel(pos, true); - if ( level < m_level ) - { - pos.y = m_level; - - level = Math::Rand(); - if ( level < 0.8f ) - { - if ( VaporCreate(PARTIFIRE, pos, 0.02f+Math::Rand()*0.06f) ) - { - m_lastLava = m_time; - } - } - else if ( level < 0.9f ) - { - if ( VaporCreate(PARTIFLAME, pos, 0.5f+Math::Rand()*3.0f) ) - { - m_lastLava = m_time; - } - } - else - { - if ( VaporCreate(PARTIVAPOR, pos, 0.2f+Math::Rand()*2.0f) ) - { - m_lastLava = m_time; - } - } - } - } -} - -// Removes all the steam jets. - -void CWater::VaporFlush() -{ - int i; - - for ( i=0 ; iPlay(SOUND_BLUP, pos, 1.0f, 1.0f-Math::Rand()*0.5f); - } - if ( m_vapor[i].type == PARTIFLAME ) - { -//? m_sound->Play(SOUND_SWIM, 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; -} - -// Makes evolve a steam jet, - -void CWater::VaporFrame(int i, float rTime) -{ - Math::Vector pos, speed; - Math::Point dim; - int j; - - m_vapor[i].time += rTime; - - if ( m_sound == 0 ) - { - m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND); - } - - if ( m_vapor[i].time <= m_vapor[i].delay ) - { - if ( m_time-m_vapor[i].last >= m_engine->ParticuleAdapt(0.02f) ) - { - m_vapor[i].last = m_time; - - if ( m_vapor[i].type == PARTIFIRE ) - { - for ( j=0 ; j<10 ; j++ ) - { - 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; - speed.x = (Math::Rand()-0.5f)*6.0f; - speed.z = (Math::Rand()-0.5f)*6.0f; - speed.y = 8.0f+Math::Rand()*5.0f; - dim.x = Math::Rand()*1.5f+1.5f; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIERROR, 2.0f, 10.0f); - } - } - else if ( m_vapor[i].type == PARTIFLAME ) - { - 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; - speed.x = (Math::Rand()-0.5f)*2.0f; - speed.z = (Math::Rand()-0.5f)*2.0f; - speed.y = 4.0f+Math::Rand()*4.0f; - dim.x = Math::Rand()*2.0f+2.0f; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIFLAME); - } - else - { - 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; - speed.x = (Math::Rand()-0.5f)*2.0f; - speed.z = (Math::Rand()-0.5f)*2.0f; - speed.y = 8.0f+Math::Rand()*8.0f; - dim.x = Math::Rand()*1.0f+1.0f; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIVAPOR); - } - } - } - else - { - m_vapor[i].bUsed = false; - } -} - - -// Adjusts the position to normal, to imitate reflections on an expanse of water at rest. - -void CWater::AdjustLevel(Math::Vector &pos, Math::Vector &norm, - Math::Point &uv1, Math::Point &uv2) -{ -#if 0 - float t1, t2; - - uv1.x = (pos.x+10000.0f)/40.0f; - uv1.y = (pos.z+10000.0f)/40.0f; - - t1 = m_time*1.5f + pos.x*0.1f * pos.z*0.2f; - pos.y += sinf(t1)*m_eddy.y; - - t1 = m_time*0.6f + pos.x*0.1f * pos.z*0.2f; - t2 = m_time*0.7f + pos.x*0.3f * pos.z*0.4f; - pos.x += sinf(t1)*m_eddy.x; - pos.z += sinf(t2)*m_eddy.z; - -//? uv2.x = (pos.x+10000.0f)/40.0f+0.3f; -//? uv2.y = (pos.z+10000.0f)/40.0f+0.4f; - uv2.x = (pos.x+10000.0f)/20.0f; - uv2.y = (pos.z+10000.0f)/20.0f; - - t1 = m_time*0.7f + pos.x*5.5f + pos.z*5.6f; - t2 = m_time*0.8f + pos.x*5.7f + pos.z*5.8f; - norm = Math::Vector(sinf(t1)*m_glint, 1.0f, sinf(t2)*m_glint); -#else - float t1, t2; - - 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; - 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); -#endif -} - -// Draw the back surface of the water. -// This surface prevents to see the sky (background) underwater! - -void CWater::DrawBack() -{ - 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->RetEyePt(); - lookat = m_engine->RetLookatPt(); - - ZeroMemory( &material, sizeof(D3DMATERIAL7) ); - material.diffuse = m_diffuse; - material.ambient = m_ambient; - m_engine->SetMaterial(material); - - m_engine->SetTexture("", 0); - - device = m_engine->RetD3DDevice(); - device->SetRenderState(D3DRENDERSTATE_LIGHTING, false); - device->SetRenderState(D3DRENDERSTATE_ZENABLE, false); - device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); - m_engine->SetState(D3DSTATENORMAL); - - deep = m_engine->RetDeepView(0); - m_engine->SetDeepView(deep*2.0f, 0); - m_engine->SetFocus(m_engine->RetFocus()); - 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->RetFocus()); - m_engine->UpdateMatProj(); // gives the initial depth of view - - device->SetRenderState(D3DRENDERSTATE_LIGHTING, true); - device->SetRenderState(D3DRENDERSTATE_ZENABLE, true); - device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); -} - -// Draws the flat surface of the water. - -void CWater::DrawSurf() -{ - 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_bDraw ) return; - if ( m_type[0] == WATER_NULL ) return; - if ( m_lineUsed == 0 ) return; - - vertex = (D3DVERTEX2*)malloc(sizeof(D3DVERTEX2)*(m_brick+2)*2); - - eye = m_engine->RetEyePt(); - lookat = m_engine->RetLookatPt(); - - rankview = m_engine->RetRankView(); - bUnder = ( rankview == 1); - - device = m_engine->RetD3DDevice(); -//? device->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff); -//? device->SetRenderState(D3DRENDERSTATE_LIGHTING, true); -//? device->SetRenderState(D3DRENDERSTATE_ZENABLE, false); - 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->RetDeepView(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); -} - - -// Indicates if there is water in a given position. - -bool CWater::RetWater(int x, int y) -{ - Math::Vector pos; - float size, offset, level; - int dx, dy; - - x *= m_subdiv; - y *= m_subdiv; - - size = m_size/m_subdiv; - offset = m_brick*m_size/2.0f; - - for ( dy=0 ; dy<=m_subdiv ; dy++ ) - { - for ( dx=0 ; dx<=m_subdiv ; dx++ ) - { - pos.x = (x+dx)*size - offset; - pos.z = (y+dy)*size - offset; - pos.y = 0.0f; - level = m_terrain->RetFloorLevel(pos, true); - if ( level < m_level+m_eddy.y ) return true; - } - } - return false; -} - -// Updates the positions, relative to the ground. - -bool CWater::CreateLine(int x, int y, int len) -{ - float offset; - - m_line[m_lineUsed].x = x; - m_line[m_lineUsed].y = y; - m_line[m_lineUsed].len = len; - - offset = m_brick*m_size/2.0f - m_size/2.0f; - - m_line[m_lineUsed].px1 = m_size* m_line[m_lineUsed].x - offset; - m_line[m_lineUsed].px2 = m_size*(m_line[m_lineUsed].x+m_line[m_lineUsed].len) - offset; - m_line[m_lineUsed].pz = m_size* m_line[m_lineUsed].y - offset; - - m_lineUsed ++; - - return ( m_lineUsed < MAXWATERLINE ); -} - -// Creates all expanses of water. - -bool CWater::Create(WaterType type1, WaterType type2, const char *filename, - D3DCOLORVALUE diffuse, D3DCOLORVALUE ambient, - float level, float glint, Math::Vector eddy) -{ - int x, y, len; - - 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; - strcpy(m_filename, filename); - - VaporFlush(); - - if ( m_filename[0] != 0 ) - { - m_engine->LoadTexture(m_filename, 0); - m_engine->LoadTexture(m_filename, 1); - } - - if ( m_terrain == 0 ) - { - m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); - } - m_brick = m_terrain->RetBrick()*m_terrain->RetMosaic(); - m_size = m_terrain->RetSize(); - - m_brick /= m_subdiv; - m_size *= m_subdiv; - - if ( m_type[0] == WATER_NULL ) return true; - - m_lineUsed = 0; - for ( y=0 ; y= 5 ) - { - if ( !CreateLine(x-len+1, y, len) ) return false; - len = 0; - } - } - else // dry? - { - if ( len != 0 ) - { - if ( !CreateLine(x-len, y, len) ) return false; - len = 0; - } - } - } - if ( len != 0 ) - { - if ( !CreateLine(x-len, y, len) ) return false; - } - } - return true; -} - -// Removes all the water. - -void CWater::Flush() -{ - m_type[0] = WATER_NULL; - m_type[1] = WATER_NULL; - m_level = 0.0f; - m_bLava = false; -} - - -// Changes the level of the water. - -bool CWater::SetLevel(float level) -{ - m_level = level; - - return Create(m_type[0], m_type[1], m_filename, m_diffuse, m_ambient, - m_level, m_glint, m_eddy); -} - -// Returns the current level of water. - -float CWater::RetLevel() -{ - return m_level; -} - -// Returns the current level of water for a given object. - -float CWater::RetLevel(CObject* object) -{ - ObjectType type; - - type = object->RetType(); - - 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; -} - - -// Management of the mode of lava/water. - -void CWater::SetLava(bool bLava) -{ - m_bLava = bLava; -} - -bool CWater::RetLava() -{ - return m_bLava; -} - - -// Adjusts the eye of the camera, not to be in the water. - -void CWater::AdjustEye(Math::Vector &eye) -{ - if ( m_bLava ) - { - 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 - } - } -} - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +// water.cpp + + +#include +#include +#include + +#include "common/struct.h" +#include "math/geometry.h" +#include "math/conv.h" +#include "old/d3dengine.h" +#include "old/d3dmath.h" +#include "old/d3dutil.h" +#include "common/event.h" +#include "common/misc.h" +#include "common/iman.h" +#include "old/math3d.h" +#include "old/particule.h" +#include "old/terrain.h" +#include "object/object.h" +#include "old/sound.h" +#include "old/water.h" + + + + +// Constructor of the terrain. + +CWater::CWater(CInstanceManager* iMan, CD3DEngine* engine) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_WATER, this); + + m_engine = engine; + m_terrain = 0; + m_particule = 0; + m_sound = 0; + + m_type[0] = WATER_NULL; + m_type[1] = WATER_NULL; + m_level = 0.0f; + m_bDraw = true; + m_bLava = false; + m_color = 0xffffffff; + m_subdiv = 4; + m_filename[0] = 0; +} + +// Destructor of the terrain. + +CWater::~CWater() +{ +} + + +bool CWater::EventProcess(const Event &event) +{ + if ( event.event == EVENT_FRAME ) + { + return EventFrame(event); + } + + if ( event.event == EVENT_KEYDOWN ) + { +#if 0 + if ( event.param == 'S' ) + { + if ( m_subdiv == 1 ) m_subdiv = 2; + else if ( m_subdiv == 2 ) m_subdiv = 4; + else if ( m_subdiv == 4 ) m_subdiv = 8; + else if ( m_subdiv == 8 ) m_subdiv = 1; + SetLevel(m_level); + } + if ( event.param == 'M' ) + { + SetLevel(m_level+1.0f); + } + if ( event.param == 'D' ) + { + SetLevel(m_level-1.0f); + } + if ( event.param == 'H' ) + { + m_bDraw = !m_bDraw; + } + if ( event.param == 'C' ) + { + if ( m_color == 0xffffffff ) m_color = 0xcccccccc; + else if ( m_color == 0xcccccccc ) m_color = 0x88888888; + else if ( m_color == 0x88888888 ) m_color = 0x44444444; + else if ( m_color == 0x44444444 ) m_color = 0x00000000; + else if ( m_color == 0x00000000 ) m_color = 0xffffffff; + } + if ( event.param == 'Q' ) + { + int i; + i = (m_color>>24); + i += 0x44; + i &= 0xff; + i = (i<<24); + m_color &= 0x00ffffff; + m_color |= i; + } + if ( event.param == 'W' ) + { + int i; + i = (m_color>>16); + i += 0x44; + i &= 0xff; + i = (i<<16); + m_color &= 0xff00ffff; + m_color |= i; + } + if ( event.param == 'E' ) + { + int i; + i = (m_color>>8); + i += 0x44; + i &= 0xff; + i = (i<<8); + m_color &= 0xffff00ff; + m_color |= i; + } + if ( event.param == 'R' ) + { + int i; + i = m_color; + i += 0x44; + i &= 0xff; + m_color &= 0xffffff00; + m_color |= i; + } +#endif + } + return true; +} + +// Makes water evolve. + +bool CWater::EventFrame(const Event &event) +{ + if ( m_engine->RetPause() ) return true; + + m_time += event.rTime; + + if ( m_type[0] == WATER_NULL ) return true; + + if ( m_bLava ) + { + LavaFrame(event.rTime); + } + return true; +} + +// Makes evolve the steam jets on the lava. + +void CWater::LavaFrame(float rTime) +{ + Math::Vector eye, lookat, dir, perp, pos; + float distance, shift, level; + int i; + + if ( m_particule == 0 ) + { + m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE); + } + + for ( i=0 ; i= 0.1f ) + { + eye = m_engine->RetEyePt(); + lookat = m_engine->RetLookatPt(); + + distance = Math::Rand()*200.0f; + shift = (Math::Rand()-0.5f)*200.0f; + + dir = Normalize(lookat-eye); + pos = eye + dir*distance; + + perp.x = -dir.z; + perp.y = dir.y; + perp.z = dir.x; + pos = pos + perp*shift; + + level = m_terrain->RetFloorLevel(pos, true); + if ( level < m_level ) + { + pos.y = m_level; + + level = Math::Rand(); + if ( level < 0.8f ) + { + if ( VaporCreate(PARTIFIRE, pos, 0.02f+Math::Rand()*0.06f) ) + { + m_lastLava = m_time; + } + } + else if ( level < 0.9f ) + { + if ( VaporCreate(PARTIFLAME, pos, 0.5f+Math::Rand()*3.0f) ) + { + m_lastLava = m_time; + } + } + else + { + if ( VaporCreate(PARTIVAPOR, pos, 0.2f+Math::Rand()*2.0f) ) + { + m_lastLava = m_time; + } + } + } + } +} + +// Removes all the steam jets. + +void CWater::VaporFlush() +{ + int i; + + for ( i=0 ; iPlay(SOUND_BLUP, pos, 1.0f, 1.0f-Math::Rand()*0.5f); + } + if ( m_vapor[i].type == PARTIFLAME ) + { +//? m_sound->Play(SOUND_SWIM, 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; +} + +// Makes evolve a steam jet, + +void CWater::VaporFrame(int i, float rTime) +{ + Math::Vector pos, speed; + Math::Point dim; + int j; + + m_vapor[i].time += rTime; + + if ( m_sound == 0 ) + { + m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND); + } + + if ( m_vapor[i].time <= m_vapor[i].delay ) + { + if ( m_time-m_vapor[i].last >= m_engine->ParticuleAdapt(0.02f) ) + { + m_vapor[i].last = m_time; + + if ( m_vapor[i].type == PARTIFIRE ) + { + for ( j=0 ; j<10 ; j++ ) + { + 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; + speed.x = (Math::Rand()-0.5f)*6.0f; + speed.z = (Math::Rand()-0.5f)*6.0f; + speed.y = 8.0f+Math::Rand()*5.0f; + dim.x = Math::Rand()*1.5f+1.5f; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIERROR, 2.0f, 10.0f); + } + } + else if ( m_vapor[i].type == PARTIFLAME ) + { + 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; + speed.x = (Math::Rand()-0.5f)*2.0f; + speed.z = (Math::Rand()-0.5f)*2.0f; + speed.y = 4.0f+Math::Rand()*4.0f; + dim.x = Math::Rand()*2.0f+2.0f; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIFLAME); + } + else + { + 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; + speed.x = (Math::Rand()-0.5f)*2.0f; + speed.z = (Math::Rand()-0.5f)*2.0f; + speed.y = 8.0f+Math::Rand()*8.0f; + dim.x = Math::Rand()*1.0f+1.0f; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIVAPOR); + } + } + } + else + { + m_vapor[i].bUsed = false; + } +} + + +// Adjusts the position to normal, to imitate reflections on an expanse of water at rest. + +void CWater::AdjustLevel(Math::Vector &pos, Math::Vector &norm, + Math::Point &uv1, Math::Point &uv2) +{ +#if 0 + float t1, t2; + + uv1.x = (pos.x+10000.0f)/40.0f; + uv1.y = (pos.z+10000.0f)/40.0f; + + t1 = m_time*1.5f + pos.x*0.1f * pos.z*0.2f; + pos.y += sinf(t1)*m_eddy.y; + + t1 = m_time*0.6f + pos.x*0.1f * pos.z*0.2f; + t2 = m_time*0.7f + pos.x*0.3f * pos.z*0.4f; + pos.x += sinf(t1)*m_eddy.x; + pos.z += sinf(t2)*m_eddy.z; + +//? uv2.x = (pos.x+10000.0f)/40.0f+0.3f; +//? uv2.y = (pos.z+10000.0f)/40.0f+0.4f; + uv2.x = (pos.x+10000.0f)/20.0f; + uv2.y = (pos.z+10000.0f)/20.0f; + + t1 = m_time*0.7f + pos.x*5.5f + pos.z*5.6f; + t2 = m_time*0.8f + pos.x*5.7f + pos.z*5.8f; + norm = Math::Vector(sinf(t1)*m_glint, 1.0f, sinf(t2)*m_glint); +#else + float t1, t2; + + 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; + 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); +#endif +} + +// Draw the back surface of the water. +// This surface prevents to see the sky (background) underwater! + +void CWater::DrawBack() +{ + 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->RetEyePt(); + lookat = m_engine->RetLookatPt(); + + ZeroMemory( &material, sizeof(D3DMATERIAL7) ); + material.diffuse = m_diffuse; + material.ambient = m_ambient; + m_engine->SetMaterial(material); + + m_engine->SetTexture("", 0); + + device = m_engine->RetD3DDevice(); + device->SetRenderState(D3DRENDERSTATE_LIGHTING, false); + device->SetRenderState(D3DRENDERSTATE_ZENABLE, false); + device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); + m_engine->SetState(D3DSTATENORMAL); + + deep = m_engine->RetDeepView(0); + m_engine->SetDeepView(deep*2.0f, 0); + m_engine->SetFocus(m_engine->RetFocus()); + 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->RetFocus()); + m_engine->UpdateMatProj(); // gives the initial depth of view + + device->SetRenderState(D3DRENDERSTATE_LIGHTING, true); + device->SetRenderState(D3DRENDERSTATE_ZENABLE, true); + device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); +} + +// Draws the flat surface of the water. + +void CWater::DrawSurf() +{ + 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_bDraw ) return; + if ( m_type[0] == WATER_NULL ) return; + if ( m_lineUsed == 0 ) return; + + vertex = (D3DVERTEX2*)malloc(sizeof(D3DVERTEX2)*(m_brick+2)*2); + + eye = m_engine->RetEyePt(); + lookat = m_engine->RetLookatPt(); + + rankview = m_engine->RetRankView(); + bUnder = ( rankview == 1); + + device = m_engine->RetD3DDevice(); +//? device->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff); +//? device->SetRenderState(D3DRENDERSTATE_LIGHTING, true); +//? device->SetRenderState(D3DRENDERSTATE_ZENABLE, false); + 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->RetDeepView(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); +} + + +// Indicates if there is water in a given position. + +bool CWater::RetWater(int x, int y) +{ + Math::Vector pos; + float size, offset, level; + int dx, dy; + + x *= m_subdiv; + y *= m_subdiv; + + size = m_size/m_subdiv; + offset = m_brick*m_size/2.0f; + + for ( dy=0 ; dy<=m_subdiv ; dy++ ) + { + for ( dx=0 ; dx<=m_subdiv ; dx++ ) + { + pos.x = (x+dx)*size - offset; + pos.z = (y+dy)*size - offset; + pos.y = 0.0f; + level = m_terrain->RetFloorLevel(pos, true); + if ( level < m_level+m_eddy.y ) return true; + } + } + return false; +} + +// Updates the positions, relative to the ground. + +bool CWater::CreateLine(int x, int y, int len) +{ + float offset; + + m_line[m_lineUsed].x = x; + m_line[m_lineUsed].y = y; + m_line[m_lineUsed].len = len; + + offset = m_brick*m_size/2.0f - m_size/2.0f; + + m_line[m_lineUsed].px1 = m_size* m_line[m_lineUsed].x - offset; + m_line[m_lineUsed].px2 = m_size*(m_line[m_lineUsed].x+m_line[m_lineUsed].len) - offset; + m_line[m_lineUsed].pz = m_size* m_line[m_lineUsed].y - offset; + + m_lineUsed ++; + + return ( m_lineUsed < MAXWATERLINE ); +} + +// Creates all expanses of water. + +bool CWater::Create(WaterType type1, WaterType type2, const char *filename, + D3DCOLORVALUE diffuse, D3DCOLORVALUE ambient, + float level, float glint, Math::Vector eddy) +{ + int x, y, len; + + 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; + strcpy(m_filename, filename); + + VaporFlush(); + + if ( m_filename[0] != 0 ) + { + m_engine->LoadTexture(m_filename, 0); + m_engine->LoadTexture(m_filename, 1); + } + + if ( m_terrain == 0 ) + { + m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); + } + m_brick = m_terrain->RetBrick()*m_terrain->RetMosaic(); + m_size = m_terrain->RetSize(); + + m_brick /= m_subdiv; + m_size *= m_subdiv; + + if ( m_type[0] == WATER_NULL ) return true; + + m_lineUsed = 0; + for ( y=0 ; y= 5 ) + { + if ( !CreateLine(x-len+1, y, len) ) return false; + len = 0; + } + } + else // dry? + { + if ( len != 0 ) + { + if ( !CreateLine(x-len, y, len) ) return false; + len = 0; + } + } + } + if ( len != 0 ) + { + if ( !CreateLine(x-len, y, len) ) return false; + } + } + return true; +} + +// Removes all the water. + +void CWater::Flush() +{ + m_type[0] = WATER_NULL; + m_type[1] = WATER_NULL; + m_level = 0.0f; + m_bLava = false; +} + + +// Changes the level of the water. + +bool CWater::SetLevel(float level) +{ + m_level = level; + + return Create(m_type[0], m_type[1], m_filename, m_diffuse, m_ambient, + m_level, m_glint, m_eddy); +} + +// Returns the current level of water. + +float CWater::RetLevel() +{ + return m_level; +} + +// Returns the current level of water for a given object. + +float CWater::RetLevel(CObject* object) +{ + ObjectType type; + + type = object->RetType(); + + 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; +} + + +// Management of the mode of lava/water. + +void CWater::SetLava(bool bLava) +{ + m_bLava = bLava; +} + +bool CWater::RetLava() +{ + return m_bLava; +} + + +// Adjusts the eye of the camera, not to be in the water. + +void CWater::AdjustEye(Math::Vector &eye) +{ + if ( m_bLava ) + { + 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 + } + } +} + -- cgit v1.2.3-1-g7c22