From 4233acfa363fe0a6083f70e3629d30b9d58d834d Mon Sep 17 00:00:00 2001 From: wraitii Date: Sat, 27 Apr 2013 12:20:42 +0000 Subject: [PATCH] Slight clean up of the water code. Uses vertex data instead of a texture for foam. Should be faster to generate and render. Still no Atlas support. This was SVN commit r13374. --- .../mods/public/shaders/glsl/water_high.fs | 13 +- .../mods/public/shaders/glsl/water_high.vs | 4 +- .../mods/public/shaders/glsl/water_high.xml | 1 + source/renderer/PatchRData.cpp | 29 +- source/renderer/PatchRData.h | 3 +- source/renderer/TerrainRenderer.cpp | 18 +- source/renderer/WaterManager.cpp | 451 +++++++++--------- source/renderer/WaterManager.h | 10 +- .../components/CCmpWaterManager.cpp | 22 +- 9 files changed, 296 insertions(+), 255 deletions(-) diff --git a/binaries/data/mods/public/shaders/glsl/water_high.fs b/binaries/data/mods/public/shaders/glsl/water_high.fs index 22efca935a..e90256a81a 100644 --- a/binaries/data/mods/public/shaders/glsl/water_high.fs +++ b/binaries/data/mods/public/shaders/glsl/water_high.fs @@ -22,6 +22,7 @@ uniform float time; varying vec3 worldPos; varying float waterDepth; +varying vec4 waterInfo; uniform sampler2D normalMap; uniform sampler2D normalMap2; @@ -36,8 +37,6 @@ uniform sampler2D normalMap2; uniform sampler2D depthTex; #endif #if USE_FOAM || USE_WAVES - uniform sampler2D heightmap; - uniform sampler2D infoTex; uniform sampler2D Foam; uniform sampler2D waveTex; #endif @@ -97,9 +96,9 @@ vec3 get_fog(vec3 color) void main() { #if USE_FOAM || USE_WAVES - vec4 heightmapval = texture2D(heightmap, gl_TexCoord[3].zw); - vec2 beachOrientation = heightmapval.rb - vec2(0.5,0.5); - float distToShore = heightmapval.a; + vec4 heightmapval = waterInfo; + vec2 beachOrientation = heightmapval.rg; + float distToShore = heightmapval.b; #endif vec3 n, l, h, v; // Normal, light vector, half-vector and view vector (vector to eye) @@ -182,11 +181,11 @@ void main() // texture is not rotated, moves twice faster in the opposite direction, translated. vec2 foam2RC = gl_TexCoord[0].st*1.8 + vec2(time*-0.019,time*-0.012) - 0.012*n.xz + vec2(0.4,0.2); - vec2 WaveRocking = cos(time*1.2566) * beachOrientation * clamp(1.0 - distToShore*2.0,0.1,1.0)/3.0; + vec2 WaveRocking = cos(time*1.2566) * beachOrientation * clamp(1.0 - distToShore,0.1,1.0)/6.0; vec4 foam1 = texture2D(Foam, foam1RC + vec2(-WaveRocking.t,WaveRocking.s)); vec4 foam2 = foam1.r*texture2D(Foam, foam2RC + WaveRocking); - vec3 finalFoam = min((foam2).rrr * texture2D(infoTex,gl_TexCoord[3].zw).g,1.0); + vec3 finalFoam = min((foam2).rrr * waterInfo.a,1.0); if ((1.0 - finalFoam.r) >= wavyFactor) finalFoam = vec3(0.0); diff --git a/binaries/data/mods/public/shaders/glsl/water_high.vs b/binaries/data/mods/public/shaders/glsl/water_high.vs index 08d5c3a12b..b884934ddb 100644 --- a/binaries/data/mods/public/shaders/glsl/water_high.vs +++ b/binaries/data/mods/public/shaders/glsl/water_high.vs @@ -17,15 +17,17 @@ uniform float mapSize; varying vec3 worldPos; varying float waterDepth; +varying vec4 waterInfo; #if USE_SHADOW && USE_SHADOWS varying vec4 v_shadow; #endif attribute vec3 a_vertex; attribute vec4 a_encodedDepth; - +attribute vec4 a_waterInfo; void main() { worldPos = a_vertex; + waterInfo = a_waterInfo; waterDepth = dot(a_encodedDepth.xyz, vec3(255.0, -255.0, 1.0)); gl_TexCoord[0] = vec4(a_vertex.xz*repeatScale,translation); diff --git a/binaries/data/mods/public/shaders/glsl/water_high.xml b/binaries/data/mods/public/shaders/glsl/water_high.xml index 06ba83bee1..6b794524e8 100644 --- a/binaries/data/mods/public/shaders/glsl/water_high.xml +++ b/binaries/data/mods/public/shaders/glsl/water_high.xml @@ -6,6 +6,7 @@ + diff --git a/source/renderer/PatchRData.cpp b/source/renderer/PatchRData.cpp index 81583ec63b..78b8e473ce 100644 --- a/source/renderer/PatchRData.cpp +++ b/source/renderer/PatchRData.cpp @@ -45,6 +45,10 @@ #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpWaterManager.h" +#include "tools/atlas/GameInterface/GameLoop.h" + +extern GameLoopState* g_AtlasGameLoop; + const ssize_t BlendOffsets[9][2] = { { 0, -1 }, { -1, -1 }, @@ -1297,7 +1301,7 @@ void CPatchRData::BuildWater() CmpPtr cmpWaterManager(*m_Simulation, SYSTEM_ENTITY); if (!cmpWaterManager) return; - + // Build data for water std::vector water_vertex_data; std::vector water_indices; @@ -1307,9 +1311,16 @@ void CPatchRData::BuildWater() // TODO: This is not (yet) exported via the ICmp interface so... we stick to these values which can be compiled in defaults WaterManager* WaterMgr = g_Renderer.GetWaterManager(); + if (WaterMgr->m_NeedsFullReloading && !g_AtlasGameLoop->running) + { + WaterMgr->m_NeedsFullReloading = false; + WaterMgr->CreateSuperfancyInfo(m_Simulation); + } CPatch* patch = m_Patch; CTerrain* terrain = patch->m_Parent; + ssize_t mapSize = (size_t)terrain->GetVerticesPerSide(); + ssize_t x1 = m_Patch->m_X*PATCH_SIZE; ssize_t z1 = m_Patch->m_Z*PATCH_SIZE; @@ -1374,6 +1385,21 @@ void CPatchRData::BuildWater() u8(clamp(depthFrac*255.0f, 0.0f, 255.0f)), u8(clamp(alpha*255.0f, 0.0f, 255.0f))); + int tx = x+x1; + int ty = z+z1 + j*water_cell_size; + + if (g_AtlasGameLoop->running) + { + // currently no foam is used so push whatever + vertex.m_WaterData = CVector4D(0.0f,0.0f,0.0f,0.0f); + } + else + { + vertex.m_WaterData = CVector4D(WaterMgr->m_WaveX[tx + ty*mapSize], + WaterMgr->m_WaveZ[tx + ty*mapSize], + WaterMgr->m_DistanceToShore[tx + ty*mapSize], + WaterMgr->m_FoamFactor[tx + ty*mapSize]); + } water_index_map[z+j*water_cell_size][x] = water_vertex_data.size(); water_vertex_data.push_back(vertex); } @@ -1418,6 +1444,7 @@ void CPatchRData::RenderWater(CShaderProgramPtr& shader) GLsizei stride = sizeof(SWaterVertex); shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &base[m_VBWater->m_Index].m_DepthData); shader->VertexPointer(3, GL_FLOAT, stride, &base[m_VBWater->m_Index].m_Position); + shader->TexCoordPointer(GL_TEXTURE0, 4, GL_FLOAT, stride, &base[m_VBWater->m_Index].m_WaterData); shader->AssertPointersBound(); diff --git a/source/renderer/PatchRData.h b/source/renderer/PatchRData.h index de0bea4c1d..fba4110ae9 100644 --- a/source/renderer/PatchRData.h +++ b/source/renderer/PatchRData.h @@ -109,8 +109,9 @@ private: // p*255 + q*-255 + r = depth of water // a = depth-dependent alpha SColor4ub m_DepthData; + CVector4D m_WaterData; }; - cassert(sizeof(SWaterVertex) == 16); + cassert(sizeof(SWaterVertex) == 32); // build this renderdata object void Build(); diff --git a/source/renderer/TerrainRenderer.cpp b/source/renderer/TerrainRenderer.cpp index 76215babe1..0a3c0fad94 100644 --- a/source/renderer/TerrainRenderer.cpp +++ b/source/renderer/TerrainRenderer.cpp @@ -692,15 +692,10 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap* // we need to actually recompute the whole map settings. if (WaterMgr->m_NeedsFullReloading) { - delete[] WaterMgr->m_Heightmap; - WaterMgr->m_Heightmap = NULL; - glDeleteTextures(1, &WaterMgr->m_HeightmapTexture); - WaterMgr->m_NeedsReloading = false; - WaterMgr->m_NeedsFullReloading = false; - WaterMgr->m_waveTT = 0; WaterMgr->m_depthTT = 0; } + WaterMgr->m_NeedsReloading = false; } if (g_AtlasGameLoop->running) @@ -732,9 +727,12 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap* glBindTexture(GL_TEXTURE_2D, 0); } // Calculating the advanced informations about Foam and all if the quality calls for it. - if (WaterMgr->m_Heightmap == NULL && (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves)) + /*if (WaterMgr->m_NeedsFullReloading && (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves)) + { + WaterMgr->m_NeedsFullReloading = false; WaterMgr->CreateSuperfancyInfo(); - + }*/ + glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_DEPTH_TEST); @@ -783,7 +781,6 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap* // rendering m->wavesShader->Bind(); m->wavesShader->BindTexture("waveTex", WaterMgr->m_Wave); - m->wavesShader->BindTexture("infoTex", WaterMgr->m_OtherInfoTex); m->wavesShader->Uniform("time", (float)time); m->wavesShader->Uniform("waviness", WaterMgr->m_Waviness); m->wavesShader->Uniform("mapSize", (float)(WaterMgr->m_TexSize)); @@ -823,8 +820,6 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap* if (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves) { m->fancyWaterShader->BindTexture("Foam", WaterMgr->m_Foam); - m->fancyWaterShader->BindTexture("heightmap", WaterMgr->m_HeightmapTexture); - m->fancyWaterShader->BindTexture("infoTex", WaterMgr->m_OtherInfoTex); m->fancyWaterShader->Uniform("mapSize", (float)(WaterMgr->m_TexSize)); } if (WaterMgr->m_WaterRealDepth) @@ -840,7 +835,6 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap* const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); - // TODO: only bind what's really needed for that. m->fancyWaterShader->Uniform("sunDir", lightEnv.GetSunDir()); m->fancyWaterShader->Uniform("sunColor", lightEnv.m_SunColor.X); diff --git a/source/renderer/WaterManager.cpp b/source/renderer/WaterManager.cpp index 0fd7d2d580..10cb8cef12 100644 --- a/source/renderer/WaterManager.cpp +++ b/source/renderer/WaterManager.cpp @@ -38,6 +38,10 @@ #include "renderer/WaterManager.h" #include "renderer/Renderer.h" +#include "simulation2/Simulation2.h" +#include "simulation2/components/ICmpWaterManager.h" +#include "simulation2/components/ICmpRangeManager.h" + /////////////////////////////////////////////////////////////////////////////////////////////// // WaterManager implementation @@ -74,9 +78,10 @@ WaterManager::WaterManager() m_WaterTint = CColor(0.28f, 0.3f, 0.59f, 1.0f); m_Murkiness = 0.45f; m_RepeatPeriod = 16.0f; - m_Heightmap = NULL; - m_HeightmapTexture = 0; - m_OtherInfoTex = 0; + m_WaveX = NULL; + m_WaveZ = NULL; + m_DistanceToShore = NULL; + m_FoamFactor = NULL; m_WaterNormal = false; m_WaterRealDepth = false; @@ -87,12 +92,11 @@ WaterManager::WaterManager() m_WaterShadows = false; m_NeedsReloading = false; - m_NeedsFullReloading = false; + m_NeedsFullReloading = true; m_TerrainChangeThisTurn = false; m_VBWaves = NULL; m_VBWavesIndices = NULL; - m_TexSize = -1; m_depthTT = 0; m_waveTT = 0; @@ -103,9 +107,11 @@ WaterManager::~WaterManager() { // Cleanup if the caller messed up UnloadWaterTextures(); - delete[] m_Heightmap; - glDeleteTextures(1, &m_HeightmapTexture); - glDeleteTextures(1, &m_OtherInfoTex); + delete[] m_WaveX; + delete[] m_WaveZ; + delete[] m_DistanceToShore; + delete[] m_FoamFactor; + glDeleteTextures(1, &m_depthTT); glDeleteTextures(1, &m_waveTT); @@ -225,30 +231,55 @@ void WaterManager::UnloadWaterTextures() /////////////////////////////////////////////////////////////////// // Create information about the terrain and wave vertices. -void WaterManager::CreateSuperfancyInfo() +void WaterManager::CreateSuperfancyInfo(CSimulation2* simulation) { - ssize_t mapSize = g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide(); - ssize_t texSize = (GLsizei)round_up_to_pow2((size_t)mapSize); CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); + ssize_t mapSize = terrain->GetVerticesPerSide(); - u32* newHeightmap = NULL; - newHeightmap = new u32[texSize*texSize]; + CmpPtr cmpWaterManager(*simulation, SYSTEM_ENTITY); + if (!cmpWaterManager) + return; // REALLY shouldn't happen and will most likely crash. + + // Using this to get some more optimization on circular maps + CmpPtr cmpRangeManager(*simulation, SYSTEM_ENTITY); + if (!cmpRangeManager) + return; + bool circular = cmpRangeManager->GetLosCircular(); + float mSize = mapSize*mapSize; + float halfSize = (mapSize/2.0); + + // Warning: this won't work with multiple water planes + m_WaterHeight = cmpWaterManager->GetExactWaterLevel(0,0); - u32* otherInfo = NULL; - otherInfo = new u32[texSize*texSize]; + // TODO: change this whenever we incrementally update because it's def. not too efficient + delete[] m_WaveX; + delete[] m_WaveZ; + delete[] m_DistanceToShore; + delete[] m_FoamFactor; + m_WaveX = new float[mapSize*mapSize]; + m_WaveZ = new float[mapSize*mapSize]; + m_DistanceToShore = new float[mapSize*mapSize]; + m_FoamFactor = new float[mapSize*mapSize]; + u16* heightmap = terrain->GetHeightMap(); - // Recovering wave intensity - u8* waveForceHQ = new u8[(mapSize+1)*(mapSize+1)]; // high qual map. - u16 waterHeightInu16 = this->m_WaterHeight/HEIGHT_SCALE; + // some temporary stuff for wave intensity + // not really used too much right now. + u8* waveForceHQ = new u8[mapSize*mapSize]; + u16 waterHeightInu16 = m_WaterHeight/HEIGHT_SCALE; for (ssize_t i = 0; i < mapSize; ++i) { for (ssize_t j = 0; j < mapSize; ++j) { + if (circular && (i-halfSize)*(i-halfSize)+(j-halfSize)*(j-halfSize) > mSize) + { + waveForceHQ[j*mapSize + i] = 255; + continue; + } u8 color = 0; - for (int v = 0; v < 20; v++){ + for (int v = 0; v <= 18; v += 3){ if (j-v >= 0 && i-v >= 0 && heightmap[(j-v)*mapSize + i-v] > waterHeightInu16) { if (color == 0) @@ -257,21 +288,28 @@ void WaterManager::CreateSuperfancyInfo() color++; } } - waveForceHQ[j*mapSize + i] = 255 - color * 7; + waveForceHQ[j*mapSize + i] = 255 - color * 40; } } - // this creates information for waves and stores it in a texture. - // texture "newHeightmap" is [x vector of wave direction, coefficient of "water raise", y vector of waves, distance to shore.] - // texture "OtherInfo" stores the intensity of actual waves and of foam. + // this creates information for waves and stores it in float arrays. PatchRData then puts it in the vertex info for speed. for (ssize_t i = 0; i < mapSize; ++i) { for (ssize_t j = 0; j < mapSize; ++j) { - - float depth = this->m_WaterHeight - heightmap[j*mapSize + i]*HEIGHT_SCALE; + if (circular && (i-halfSize)*(i-halfSize)+(j-halfSize)*(j-halfSize) > mSize) + { + m_WaveX[j*mapSize + i] = 0.0f; + m_WaveZ[j*mapSize + i] = 0.0f; + m_DistanceToShore[j*mapSize + i] = 100; + m_FoamFactor[j*mapSize + i] = 0.0f; + continue; + } + float depth = m_WaterHeight - heightmap[j*mapSize + i]*HEIGHT_SCALE; int distanceToShore = 10000; + // calculation of the distance to the shore. - // this is pretty exact. + // TODO: this is fairly dumb, though it returns a good result + // Could be sped up a fair bit. if (depth >= 0) { // check in the square around. @@ -282,246 +320,231 @@ void WaterManager::CreateSuperfancyInfo() if (i+xx >= 0 && i + xx < mapSize) if (j + yy >= 0 && j + yy < mapSize) { - float hereDepth = this->m_WaterHeight - heightmap[(j+yy)*mapSize + (i+xx)]*HEIGHT_SCALE; + float hereDepth = m_WaterHeight - heightmap[(j+yy)*mapSize + (i+xx)]*HEIGHT_SCALE; if (hereDepth < 0 && xx*xx + yy*yy < distanceToShore) distanceToShore = xx*xx + yy*yy; } } } - // finer check - for (float xx = -2.5f; xx <= 2.5f; ++xx) + // refine the calculation if we're close enough + if (distanceToShore < 9) { - for (float yy = -2.5f; yy <= 2.5f; ++yy) + for (float xx = -2.5f; xx <= 2.5f; ++xx) { - float hereDepth = this->m_WaterHeight - terrain->GetExactGroundLevel( (i+xx)*4, (j+yy)*4 ); - if (hereDepth < 0 && xx*xx + yy*yy < distanceToShore) - distanceToShore = xx*xx + yy*yy; + for (float yy = -2.5f; yy <= 2.5f; ++yy) + { + float hereDepth = m_WaterHeight - terrain->GetExactGroundLevel( (i+xx)*4, (j+yy)*4 ); + if (hereDepth < 0 && xx*xx + yy*yy < distanceToShore) + distanceToShore = xx*xx + yy*yy; + } } } } else { - for (float xx = -2.0f; xx <= 2.0f; xx+=0.5f) + for (int xx = -2; xx <= 2; ++xx) { - for (float yy = -2.0f; yy <= 2.0f; yy+=0.5f) + for (int yy = -2; yy <= 2; ++yy) { - float hereDepth = this->m_WaterHeight - terrain->GetExactGroundLevel( (i+xx)*4, (j+yy)*4 ); + float hereDepth = m_WaterHeight - terrain->GetVertexGroundLevel(i+xx, j+yy); if (hereDepth > 0) distanceToShore = 0; } } } - distanceToShore = (int)sqrt((float)distanceToShore); - // Compute the normals - // Also create the waves quad. - CVector3D normal; - - int waterRaise = 0; - for (int xx = -4; xx <= 4; ++xx) + // speedup with default values for land squares + if (distanceToShore == 10000) { - for (int yy = -4; yy <= 4; ++yy) + m_WaveX[j*mapSize + i] = 0.0f; + m_WaveZ[j*mapSize + i] = 0.0f; + m_DistanceToShore[j*mapSize + i] = 100; + m_FoamFactor[j*mapSize + i] = 0.0f; + continue; + } + // We'll compute the normals and the "water raise", to know about foam + // Normals are a pretty good calculation but it's slow since we normalize so much. + CVector3D normal; + int waterRaise = 0; + for (int xx = -4; xx <= 4; xx += 2) // every 2 tile is good enough. + { + for (int yy = -4; yy <= 4; yy += 2) { normal += terrain->CalcExactNormal(((float)i+xx)*4.0f,((float)j+yy)*4.0f); if (terrain->GetVertexGroundLevel(i+xx,j+yy) < heightmap[j*mapSize + i]*HEIGHT_SCALE) waterRaise += heightmap[j*mapSize + i]*HEIGHT_SCALE - terrain->GetVertexGroundLevel(i+xx,j+yy); } } - waterRaise = waterRaise > 255 ? 255 : waterRaise; // gives a very good result, actually. - normal *= 1.0f/81.0f; - normal[1] = 0.1f; // acts as an anti distorter + // normalizes the terrain info to avoid foam moving at too different speeds. + normal *= 0.012345679f; + normal[1] = 0.1; normal = normal.Normalized(); - - u8 r = static_cast(normal[0]*128 + 127); - u8 b = static_cast(normal[2]*128 + 127); - distanceToShore = distanceToShore > 10 ? 10 : distanceToShore; - newHeightmap[j*texSize + i] = (r << 24) + (waterRaise << 16) + (b << 8) + (distanceToShore*25 << 0); - - depth = clamp(depth,0.0f,10.0f); - - float wvness = this->m_Waviness; - + + m_WaveX[j*mapSize + i] = normal[0]; + m_WaveZ[j*mapSize + i] = normal[2]; + // distance is /5.0 to be a [0,1] value. + + m_DistanceToShore[j*mapSize + i] = sqrt(distanceToShore)/5.0; // TODO: this can probably be cached as I'm integer here. + // computing the amount of foam I want - float foamAmount = (waterRaise/255.0f) * (1.0f - depth/10.0f) * (waveForceHQ[j*mapSize+i]/255.0f) * (wvness/8.0f); - foamAmount += clamp(wvness/2.0f - distanceToShore,0.0f,wvness/2.0f)/(wvness/2.0f) * clamp(wvness/9.0f,0.3f,1.0f); - + + depth = clamp(depth,0.0f,10.0f); + float foamAmount = (waterRaise/255.0f) * (1.0f - depth/10.0f) * (waveForceHQ[j*mapSize+i]/255.0f) * (m_Waviness/8.0f); + foamAmount += clamp(m_Waviness/2.0f - distanceToShore,0.0f,m_Waviness/2.0f)/(m_Waviness/2.0f) * clamp(m_Waviness/9.0f,0.3f,1.0f); foamAmount = foamAmount > 1.0f ? 1.0f: foamAmount; - otherInfo[j*texSize + i] = (waveForceHQ[j*mapSize+i] << 24) + ((u8)(foamAmount*255) << 16) + (0x00 << 8) + (0x00 << 0); + m_FoamFactor[j*mapSize + i] = foamAmount; } } - this->m_TexSize = texSize*4; - this->m_Heightmap = newHeightmap; - delete[] waveForceHQ; - GLuint heightName; - glGenTextures(1, &heightName); - glBindTexture(GL_TEXTURE_2D, heightName); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texSize,texSize, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,newHeightmap); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - this->m_HeightmapTexture = heightName; - glBindTexture(GL_TEXTURE_2D, 0); + // TODO: The rest should be cleaned up - GLuint otherInfoId; - glGenTextures(1, &otherInfoId); - glBindTexture(GL_TEXTURE_2D, otherInfoId); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texSize,texSize, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,otherInfo); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - this->m_OtherInfoTex = otherInfoId; + // okay let's create the waves squares. i'll divide the map in arbitrary squares + // For each of these squares, check if waves are needed. + // If yes, look for the best positionning (in order to have a nice blending with the shore) + // Then clean-up: remove squares that are too close to each other - glBindTexture(GL_TEXTURE_2D, 0); + std::vector waveSquares; - if (this->m_WaterCoastalWaves) + int size = 8; // I think this is the size of the squares. + for (int i = 0; i < mapSize/size; ++i) { - // okay let's create the waves squares. i'll divide the map in arbitrary squares - // For each of these squares, check if waves are needed. - // If yes, look for the best positionning (in order to have a nice blending with the shore) - // Then clean-up: remove squares that are too close to each other - - std::vector waveSquares; - - int size = 8; // I think this is the size of the squares. - for (int i = 0; i < mapSize/size; ++i) + for (int j = 0; j < mapSize/size; ++j) { - for (int j = 0; j < mapSize/size; ++j) + + int landTexel = 0; + int waterTexel = 0; + CVector3D avnormal (0.0f,0.0f,0.0f); + CVector2D landPosition(0.0f,0.0f); + CVector2D waterPosition(0.0f,0.0f); + for (int xx = 0; xx < size; ++xx) { - - int landTexel = 0; - int waterTexel = 0; - CVector3D avnormal (0.0f,0.0f,0.0f); - CVector2D landPosition(0.0f,0.0f); - CVector2D waterPosition(0.0f,0.0f); - for (int xx = 0; xx < size; ++xx) + for (int yy = 0; yy < size; ++yy) { - for (int yy = 0; yy < size; ++yy) + if (terrain->GetVertexGroundLevel(i*size+xx,j*size+yy) > m_WaterHeight) { - if (terrain->GetVertexGroundLevel(i*size+xx,j*size+yy) > this->m_WaterHeight) - { - landTexel++; - landPosition += CVector2D(i*size+xx,j*size+yy); - } - else - { - waterPosition += CVector2D(i*size+xx,j*size+yy); - waterTexel++; - } - avnormal += terrain->CalcExactNormal( (i*size+xx)*4.0f,(j*size+yy)*4.0f); + landTexel++; + landPosition += CVector2D(i*size+xx,j*size+yy); } - } - landPosition /= landTexel; - waterPosition /= waterTexel; - - avnormal[1] = 1.0f; - avnormal.Normalize(); - avnormal[1] = 0.0f; - - if (landTexel < size/2) - continue; - // this should help ensure that the shore is pretty flat. - if (avnormal.Length() <= 0.2f) - continue; - - // To get the best position for squares, I start at the mean "ocean" position - // And step by step go to the mean "land" position. I keep the position where I change from water to land. - // If this never happens, the square is scrapped. - if (terrain->GetExactGroundLevel(waterPosition.X*4.0f,waterPosition.Y*4.0f) > this->m_WaterHeight) - continue; - - CVector2D squarePos(-1,-1); - for (u8 i = 0; i < 40; i++) - { - squarePos = landPosition * (i/40.0f) + waterPosition * (1.0f-(i/40.0f)); - if (terrain->GetExactGroundLevel(squarePos.X*4.0f,squarePos.Y*4.0f) > this->m_WaterHeight) - break; - } - if (squarePos.X == -1) - continue; - - u8 enter = 1; - // okaaaaaay. Got a square. Check for proximity. - for (unsigned long i = 0; i < waveSquares.size(); i++) - { - if ( CVector2D(waveSquares[i]-squarePos).LengthSquared() < 80) { - enter = 0; - break; + else + { + waterPosition += CVector2D(i*size+xx,j*size+yy); + waterTexel++; } + avnormal += terrain->CalcExactNormal( (i*size+xx)*4.0f,(j*size+yy)*4.0f); } - if (enter == 1) - waveSquares.push_back(squarePos); } - } - - // Actually create the waves' meshes. - std::vector waves_vertex_data; - std::vector waves_indices; - - // loop through each square point. Look in the square around it, calculate the normal - // create the square. - for (unsigned long i = 0; i < waveSquares.size(); i++) - { - CVector2D pos(waveSquares[i]); + landPosition /= landTexel; + waterPosition /= waterTexel; - CVector3D avgnorm(0.0f,0.0f,0.0f); - for (int xx = -size/2; xx < size/2; ++xx) + avnormal[1] = 1.0f; + avnormal.Normalize(); + avnormal[1] = 0.0f; + + if (landTexel < size/2) + continue; + // this should help ensure that the shore is pretty flat. + if (avnormal.Length() <= 0.2f) + continue; + + // To get the best position for squares, I start at the mean "ocean" position + // And step by step go to the mean "land" position. I keep the position where I change from water to land. + // If this never happens, the square is scrapped. + if (terrain->GetExactGroundLevel(waterPosition.X*4.0f,waterPosition.Y*4.0f) > m_WaterHeight) + continue; + + CVector2D squarePos(-1,-1); + for (u8 i = 0; i < 40; i++) { - for (int yy = -size/2; yy < size/2; ++yy) - { - avgnorm += terrain->CalcExactNormal((pos.X+xx)*4.0f,(pos.Y+yy)*4.0f); + squarePos = landPosition * (i/40.0f) + waterPosition * (1.0f-(i/40.0f)); + if (terrain->GetExactGroundLevel(squarePos.X*4.0f,squarePos.Y*4.0f) > m_WaterHeight) + break; + } + if (squarePos.X == -1) + continue; + + u8 enter = 1; + // okaaaaaay. Got a square. Check for proximity. + for (unsigned long i = 0; i < waveSquares.size(); i++) + { + if ( CVector2D(waveSquares[i]-squarePos).LengthSquared() < 80) { + enter = 0; + break; } } - avgnorm[1] = 0.1f; - // okay crank out a square. - // we have the direction of the square. We'll get the perpendicular vector too - CVector2D perp(-avgnorm[2],avgnorm[0]); - perp = perp.Normalized(); - avgnorm = avgnorm.Normalized(); - - SWavesVertex vertex[4]; - vertex[0].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y + perp.Y*(size/2.2f) - avgnorm[2]*1.0f); - vertex[0].m_Position *= 4.0f; - vertex[0].m_Position.Y = this->m_WaterHeight + 1.0f; - vertex[0].m_UV[1] = 1; - vertex[0].m_UV[0] = 0; - - vertex[1].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y - perp.Y*(size/2.2f) - avgnorm[2]*1.0f); - vertex[1].m_Position *= 4.0f; - vertex[1].m_Position.Y = this->m_WaterHeight + 1.0f; - vertex[1].m_UV[1] = 1; - vertex[1].m_UV[0] = 1; - - vertex[3].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y + perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f)); - vertex[3].m_Position *= 4.0f; - vertex[3].m_Position.Y = this->m_WaterHeight + 1.0f; - vertex[3].m_UV[1] = 0; - vertex[3].m_UV[0] = 0; - - vertex[2].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y - perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f)); - vertex[2].m_Position *= 4.0f; - vertex[2].m_Position.Y = this->m_WaterHeight + 1.0f; - vertex[2].m_UV[1] = 0; - vertex[2].m_UV[0] = 1; - - waves_indices.push_back(waves_vertex_data.size()); - waves_vertex_data.push_back(vertex[0]); - waves_indices.push_back(waves_vertex_data.size()); - waves_vertex_data.push_back(vertex[1]); - waves_indices.push_back(waves_vertex_data.size()); - waves_vertex_data.push_back(vertex[2]); - waves_indices.push_back(waves_vertex_data.size()); - waves_vertex_data.push_back(vertex[3]); + if (enter == 1) + waveSquares.push_back(squarePos); } - - // waves - // allocate vertex buffer - this->m_VBWaves = g_VBMan.Allocate(sizeof(SWavesVertex), waves_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER); - this->m_VBWaves->m_Owner->UpdateChunkVertices(this->m_VBWaves, &waves_vertex_data[0]); - - // Construct indices buffer - this->m_VBWavesIndices = g_VBMan.Allocate(sizeof(GLushort), waves_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER); - this->m_VBWavesIndices->m_Owner->UpdateChunkVertices(this->m_VBWavesIndices, &waves_indices[0]); } + + // Actually create the waves' meshes. + std::vector waves_vertex_data; + std::vector waves_indices; + + // loop through each square point. Look in the square around it, calculate the normal + // create the square. + for (unsigned long i = 0; i < waveSquares.size(); i++) + { + CVector2D pos(waveSquares[i]); + + CVector3D avgnorm(0.0f,0.0f,0.0f); + for (int xx = -size/2; xx < size/2; ++xx) + { + for (int yy = -size/2; yy < size/2; ++yy) + { + avgnorm += terrain->CalcExactNormal((pos.X+xx)*4.0f,(pos.Y+yy)*4.0f); + } + } + avgnorm[1] = 0.1f; + // okay crank out a square. + // we have the direction of the square. We'll get the perpendicular vector too + CVector2D perp(-avgnorm[2],avgnorm[0]); + perp = perp.Normalized(); + avgnorm = avgnorm.Normalized(); + + SWavesVertex vertex[4]; + vertex[0].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y + perp.Y*(size/2.2f) - avgnorm[2]*1.0f); + vertex[0].m_Position *= 4.0f; + vertex[0].m_Position.Y = m_WaterHeight + 1.0f; + vertex[0].m_UV[1] = 1; + vertex[0].m_UV[0] = 0; + + vertex[1].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y - perp.Y*(size/2.2f) - avgnorm[2]*1.0f); + vertex[1].m_Position *= 4.0f; + vertex[1].m_Position.Y = m_WaterHeight + 1.0f; + vertex[1].m_UV[1] = 1; + vertex[1].m_UV[0] = 1; + + vertex[3].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y + perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f)); + vertex[3].m_Position *= 4.0f; + vertex[3].m_Position.Y = m_WaterHeight + 1.0f; + vertex[3].m_UV[1] = 0; + vertex[3].m_UV[0] = 0; + + vertex[2].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y - perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f)); + vertex[2].m_Position *= 4.0f; + vertex[2].m_Position.Y = m_WaterHeight + 1.0f; + vertex[2].m_UV[1] = 0; + vertex[2].m_UV[0] = 1; + + waves_indices.push_back(waves_vertex_data.size()); + waves_vertex_data.push_back(vertex[0]); + waves_indices.push_back(waves_vertex_data.size()); + waves_vertex_data.push_back(vertex[1]); + waves_indices.push_back(waves_vertex_data.size()); + waves_vertex_data.push_back(vertex[2]); + waves_indices.push_back(waves_vertex_data.size()); + waves_vertex_data.push_back(vertex[3]); + } + + // waves + // allocate vertex buffer + m_VBWaves = g_VBMan.Allocate(sizeof(SWavesVertex), waves_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER); + m_VBWaves->m_Owner->UpdateChunkVertices(m_VBWaves, &waves_vertex_data[0]); + + // Construct indices buffer + m_VBWavesIndices = g_VBMan.Allocate(sizeof(GLushort), waves_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER); + m_VBWavesIndices->m_Owner->UpdateChunkVertices(m_VBWavesIndices, &waves_indices[0]); } //////////////////////////////////////////////////////////////////////// diff --git a/source/renderer/WaterManager.h b/source/renderer/WaterManager.h index a361c8e9a4..a146a26b5a 100644 --- a/source/renderer/WaterManager.h +++ b/source/renderer/WaterManager.h @@ -28,6 +28,7 @@ #include "ps/Overlay.h" #include "renderer/VertexBufferManager.h" +class CSimulation2; struct SWavesVertex { // vertex position @@ -52,10 +53,11 @@ public: CTexturePtr m_NormalMap[60]; CTexturePtr m_Foam; CTexturePtr m_Wave; - u32* m_Heightmap; + float* m_WaveX; + float* m_WaveZ; + float* m_DistanceToShore; + float* m_FoamFactor; - GLuint m_HeightmapTexture; - GLuint m_OtherInfoTex; ssize_t m_TexSize; GLuint m_depthTT; @@ -143,7 +145,7 @@ public: /** * CreateSuperfancyInfo: creates textures and wave vertices for superfancy water */ - void CreateSuperfancyInfo(); + void CreateSuperfancyInfo(CSimulation2* simulation); /** * Updates the settings to the one from the renderer, and sets m_NeedsReloading. diff --git a/source/simulation2/components/CCmpWaterManager.cpp b/source/simulation2/components/CCmpWaterManager.cpp index 6fe8c14534..3bc3bf80e1 100644 --- a/source/simulation2/components/CCmpWaterManager.cpp +++ b/source/simulation2/components/CCmpWaterManager.cpp @@ -32,7 +32,6 @@ public: static void ClassInit(CComponentManager& componentManager) { componentManager.SubscribeToMessageType(MT_Interpolate); - componentManager.SubscribeToMessageType(MT_RenderSubmit); componentManager.SubscribeToMessageType(MT_TerrainChanged); } @@ -72,20 +71,13 @@ public: { switch (msg.GetType()) { - case MT_Interpolate: - { - const CMessageInterpolate& msgData = static_cast (msg); - if (CRenderer::IsInitialised()) - g_Renderer.GetWaterManager()->m_WaterTexTimer += msgData.deltaSimTime; - break; - } - case MT_RenderSubmit: - { - // Don't actually do rendering here, but tell the renderer how to draw water - if (CRenderer::IsInitialised()) - g_Renderer.GetWaterManager()->m_WaterHeight = m_WaterHeight.ToFloat(); - break; - } + case MT_Interpolate: + { + const CMessageInterpolate& msgData = static_cast (msg); + if (CRenderer::IsInitialised()) + g_Renderer.GetWaterManager()->m_WaterTexTimer += msgData.deltaSimTime; + break; + } case MT_TerrainChanged: { // Tell the renderer to redraw the map.