/////////////////////////////////////////////////////////////////// // Calculate The blurred normal map to get an idea of where water ought to go. void WaterManager::RecomputeBlurredNormalMap() { // used to cache terrain normals since otherwise we'd recalculate them a lot (I'm blurring the "normal" map). // this might be updated to actually cache in the terrain manager but that's not for now. if (m_BlurredNormalMap == NULL) m_BlurredNormalMap = new CVector3D[m_MapSize*m_MapSize]; CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); // It's really slow to calculate normals so cache them first. CVector3D* normals = new CVector3D[m_MapSize*m_MapSize]; // Not the edges, we won't care about them. float ii = 8.0f, jj = 8.0f; for (size_t j = 2; j < m_MapSize-2; ++j, jj += 4.0f) for (size_t i = 2; i < m_MapSize-2; ++i, ii += 4.0f) { CVector3D norm; terrain->CalcNormal(i,j,norm); normals[j*m_MapSize + i] = norm; } // We could be way fancier (and faster) for our blur but we probably don't need the complexity. // Two pass filter, nothing complicated here. CVector3D blurValue; ii = 8.0f; jj = 8.0f; size_t idx = 2; for (size_t j = 2; j < m_MapSize-2; ++j, jj += 4.0f) for (size_t i = 2; i < m_MapSize-2; ++i, ii += 4.0f,++idx) { blurValue = normals[idx-2]; blurValue += normals[idx-1]; blurValue += normals[idx]; blurValue += normals[idx+1]; blurValue += normals[idx+2]; m_BlurredNormalMap[idx] = blurValue * 0.2f; } // y direction, probably slower because of cache misses but I don't see an easy way around that. ii = 8.0f; jj = 8.0f; for (size_t i = 2; i < m_MapSize-2; ++i, ii += 4.0f) { for (size_t j = 2; j < m_MapSize-2; ++j, jj += 4.0f) { blurValue = normals[(j-2)*m_MapSize + i]; blurValue += normals[(j-1)*m_MapSize + i]; blurValue += normals[j*m_MapSize + i]; blurValue += normals[(j+1)*m_MapSize + i]; blurValue += normals[(j+2)*m_MapSize + i]; m_BlurredNormalMap[j*m_MapSize + i] = blurValue * 0.2f; } } delete[] normals; }
void CPatchRData::AddBlend(std::vector<SBlendVertex>& blendVertices, std::vector<u16>& blendIndices, u16 i, u16 j, u8 shape, CTerrainTextureEntry* texture) { CTerrain* terrain = m_Patch->m_Parent; ssize_t gx = m_Patch->m_X * PATCH_SIZE + i; ssize_t gz = m_Patch->m_Z * PATCH_SIZE + j; // uses the current neighbour texture BlendShape8 shape8; for (size_t m = 0; m < 8; ++m) shape8[m] = (shape & (1 << m)) ? 0 : 1; // calculate the required alphamap and the required rotation of the alphamap from blendshape unsigned int alphamapflags; int alphamap = CAlphaMapCalculator::Calculate(shape8, alphamapflags); // now actually render the blend tile (if we need one) if (alphamap == -1) return; float u0 = texture->m_TerrainAlpha->second.m_AlphaMapCoords[alphamap].u0; float u1 = texture->m_TerrainAlpha->second.m_AlphaMapCoords[alphamap].u1; float v0 = texture->m_TerrainAlpha->second.m_AlphaMapCoords[alphamap].v0; float v1 = texture->m_TerrainAlpha->second.m_AlphaMapCoords[alphamap].v1; if (alphamapflags & BLENDMAP_FLIPU) std::swap(u0, u1); if (alphamapflags & BLENDMAP_FLIPV) std::swap(v0, v1); int base = 0; if (alphamapflags & BLENDMAP_ROTATE90) base = 1; else if (alphamapflags & BLENDMAP_ROTATE180) base = 2; else if (alphamapflags & BLENDMAP_ROTATE270) base = 3; SBlendVertex vtx[4]; vtx[(base + 0) % 4].m_AlphaUVs[0] = u0; vtx[(base + 0) % 4].m_AlphaUVs[1] = v0; vtx[(base + 1) % 4].m_AlphaUVs[0] = u1; vtx[(base + 1) % 4].m_AlphaUVs[1] = v0; vtx[(base + 2) % 4].m_AlphaUVs[0] = u1; vtx[(base + 2) % 4].m_AlphaUVs[1] = v1; vtx[(base + 3) % 4].m_AlphaUVs[0] = u0; vtx[(base + 3) % 4].m_AlphaUVs[1] = v1; SBlendVertex dst; const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); CVector3D normal; bool cpuLighting = (g_Renderer.GetRenderPath() == CRenderer::RP_FIXED); size_t index = blendVertices.size(); terrain->CalcPosition(gx, gz, dst.m_Position); terrain->CalcNormal(gx, gz, normal); dst.m_Normal = normal; dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); dst.m_AlphaUVs[0] = vtx[0].m_AlphaUVs[0]; dst.m_AlphaUVs[1] = vtx[0].m_AlphaUVs[1]; blendVertices.push_back(dst); terrain->CalcPosition(gx + 1, gz, dst.m_Position); terrain->CalcNormal(gx + 1, gz, normal); dst.m_Normal = normal; dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); dst.m_AlphaUVs[0] = vtx[1].m_AlphaUVs[0]; dst.m_AlphaUVs[1] = vtx[1].m_AlphaUVs[1]; blendVertices.push_back(dst); terrain->CalcPosition(gx + 1, gz + 1, dst.m_Position); terrain->CalcNormal(gx + 1, gz + 1, normal); dst.m_Normal = normal; dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); dst.m_AlphaUVs[0] = vtx[2].m_AlphaUVs[0]; dst.m_AlphaUVs[1] = vtx[2].m_AlphaUVs[1]; blendVertices.push_back(dst); terrain->CalcPosition(gx, gz + 1, dst.m_Position); terrain->CalcNormal(gx, gz + 1, normal); dst.m_Normal = normal; dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); dst.m_AlphaUVs[0] = vtx[3].m_AlphaUVs[0]; dst.m_AlphaUVs[1] = vtx[3].m_AlphaUVs[1]; blendVertices.push_back(dst); bool dir = terrain->GetTriangulationDir(gx, gz); if (dir) { blendIndices.push_back(index+0); blendIndices.push_back(index+1); blendIndices.push_back(index+3); blendIndices.push_back(index+1); blendIndices.push_back(index+2); blendIndices.push_back(index+3); } else { blendIndices.push_back(index+0); blendIndices.push_back(index+1); blendIndices.push_back(index+2); blendIndices.push_back(index+2); blendIndices.push_back(index+3); blendIndices.push_back(index+0); } }