/////////////////////////////////////////////////////////////////// // Scissor rectangle of water patches CBoundingBoxAligned TerrainRenderer::ScissorWater(const CMatrix3D &viewproj) { CBoundingBoxAligned scissor; for (size_t i = 0; i < m->visiblePatches.size(); ++i) { CPatchRData* data = m->visiblePatches[i]; const CBoundingBoxAligned& waterBounds = data->GetWaterBounds(); if (waterBounds.IsEmpty()) continue; CVector4D v1 = viewproj.Transform(CVector4D(waterBounds[0].X, waterBounds[1].Y, waterBounds[0].Z, 1.0f)); CVector4D v2 = viewproj.Transform(CVector4D(waterBounds[1].X, waterBounds[1].Y, waterBounds[0].Z, 1.0f)); CVector4D v3 = viewproj.Transform(CVector4D(waterBounds[0].X, waterBounds[1].Y, waterBounds[1].Z, 1.0f)); CVector4D v4 = viewproj.Transform(CVector4D(waterBounds[1].X, waterBounds[1].Y, waterBounds[1].Z, 1.0f)); CBoundingBoxAligned screenBounds; #define ADDBOUND(v1, v2, v3, v4) \ if (v1[2] >= -v1[3]) \ screenBounds += CVector3D(v1[0], v1[1], v1[2]) * (1.0f / v1[3]); \ else \ { \ float t = v1[2] + v1[3]; \ if (v2[2] > -v2[3]) \ { \ CVector4D c2 = v1 + (v2 - v1) * (t / (t - (v2[2] + v2[3]))); \ screenBounds += CVector3D(c2[0], c2[1], c2[2]) * (1.0f / c2[3]); \ } \ if (v3[2] > -v3[3]) \ { \ CVector4D c3 = v1 + (v3 - v1) * (t / (t - (v3[2] + v3[3]))); \ screenBounds += CVector3D(c3[0], c3[1], c3[2]) * (1.0f / c3[3]); \ } \ if (v4[2] > -v4[3]) \ { \ CVector4D c4 = v1 + (v4 - v1) * (t / (t - (v4[2] + v4[3]))); \ screenBounds += CVector3D(c4[0], c4[1], c4[2]) * (1.0f / c4[3]); \ } \ } ADDBOUND(v1, v2, v3, v4); ADDBOUND(v2, v1, v3, v4); ADDBOUND(v3, v1, v2, v4); ADDBOUND(v4, v1, v2, v3); #undef ADDBOUND if (screenBounds[0].X >= 1.0f || screenBounds[1].X <= -1.0f || screenBounds[0].Y >= 1.0f || screenBounds[1].Y <= -1.0f) continue; scissor += screenBounds; } return CBoundingBoxAligned(CVector3D(clamp(scissor[0].X, -1.0f, 1.0f), clamp(scissor[0].Y, -1.0f, 1.0f), -1.0f), CVector3D(clamp(scissor[1].X, -1.0f, 1.0f), clamp(scissor[1].Y, -1.0f, 1.0f), 1.0f)); }
void TerrainRenderer::RenderTerrainOverlayTexture(CMatrix3D& textureMatrix) { #if CONFIG2_GLES #warning TODO: implement TerrainRenderer::RenderTerrainOverlayTexture for GLES UNUSED2(textureMatrix); #else ENSURE(m->phase == Phase_Render); std::vector<CPatchRData*>& visiblePatches = m->visiblePatches; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glMatrixMode(GL_TEXTURE); glLoadMatrixf(&textureMatrix._11); glMatrixMode(GL_MODELVIEW); CShaderProgramPtr dummyShader = g_Renderer.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines()); dummyShader->Bind(); CPatchRData::RenderStreams(visiblePatches, dummyShader, STREAM_POS|STREAM_POSTOUV0); dummyShader->Unbind(); // To make the overlay visible over water, render an additional map-sized // water-height patch CBoundingBoxAligned waterBounds; for (size_t i = 0; i < m->visiblePatches.size(); ++i) { CPatchRData* data = m->visiblePatches[i]; waterBounds += data->GetWaterBounds(); } if (!waterBounds.IsEmpty()) { float h = g_Renderer.GetWaterManager()->m_WaterHeight + 0.05f; // add a delta to avoid z-fighting float waterPos[] = { waterBounds[0].X, h, waterBounds[0].Z, waterBounds[1].X, h, waterBounds[0].Z, waterBounds[0].X, h, waterBounds[1].Z, waterBounds[1].X, h, waterBounds[1].Z }; glVertexPointer(3, GL_FLOAT, 3*sizeof(float), waterPos); glTexCoordPointer(3, GL_FLOAT, 3*sizeof(float), waterPos); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glDepthMask(1); glDisable(GL_BLEND); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); #endif }