Index: ps/trunk/source/renderer/DebugRenderer.cpp =================================================================== --- ps/trunk/source/renderer/DebugRenderer.cpp (revision 25322) +++ ps/trunk/source/renderer/DebugRenderer.cpp (revision 25323) @@ -1,343 +1,364 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. 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 2 of the License, or * (at your option) any later version. * * 0 A.D. 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 0 A.D. If not, see . */ #include "precompiled.h" #include "renderer/DebugRenderer.h" #include "graphics/Camera.h" #include "graphics/Color.h" #include "graphics/ShaderManager.h" #include "graphics/ShaderProgram.h" #include "lib/ogl.h" #include "maths/BoundingBoxAligned.h" #include "maths/Brush.h" #include "maths/Vector3D.h" #include "renderer/Renderer.h" #include void CDebugRenderer::DrawLine(const CVector3D& from, const CVector3D& to, const CColor& color, const float width) { if (from == to) return; DrawLine({from, to}, color, width); } void CDebugRenderer::DrawLine(const std::vector& line, const CColor& color, const float width) { #if CONFIG2_GLES #warning TODO: implement drawing line for GLES #else CShaderTechniquePtr debugLineTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); debugLineTech->BeginPass(); CShaderProgramPtr debugLineShader = debugLineTech->GetShader(); debugLineShader->Bind(); debugLineShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); debugLineShader->Uniform(str_color, color); const CVector3D cameraIn = g_Renderer.GetViewCamera().GetOrientation().GetIn(); std::vector vertices; vertices.reserve(line.size() * 6 * 3); #define ADD(position) \ vertices.emplace_back((position).X); \ vertices.emplace_back((position).Y); \ vertices.emplace_back((position).Z); for (size_t idx = 1; idx < line.size(); ++idx) { const CVector3D from = line[idx - 1]; const CVector3D to = line[idx]; const CVector3D direction = (to - from).Normalized(); const CVector3D view = direction.Dot(cameraIn) > 0.9f ? CVector3D(0.0f, 1.0f, 0.0f) : cameraIn; const CVector3D offset = view.Cross(direction).Normalized() * width; ADD(from + offset) ADD(to - offset) ADD(to + offset) ADD(from + offset) ADD(from - offset) ADD(to - offset) } #undef ADD debugLineShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); debugLineShader->AssertPointersBound(); glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3); debugLineShader->Unbind(); debugLineTech->EndPass(); #endif } void CDebugRenderer::DrawCircle(const CVector3D& origin, const float radius, const CColor& color) { #if CONFIG2_GLES #warning TODO: implement drawing circle for GLES #else CShaderTechniquePtr debugCircleTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); debugCircleTech->BeginPass(); CShaderProgramPtr debugCircleShader = debugCircleTech->GetShader(); const CCamera& camera = g_Renderer.GetViewCamera(); debugCircleShader->Bind(); debugCircleShader->Uniform(str_transform, camera.GetViewProjection()); debugCircleShader->Uniform(str_color, color); const CVector3D cameraUp = camera.GetOrientation().GetUp(); const CVector3D cameraLeft = camera.GetOrientation().GetLeft(); std::vector vertices; #define ADD(position) \ vertices.emplace_back((position).X); \ vertices.emplace_back((position).Y); \ vertices.emplace_back((position).Z); ADD(origin) constexpr size_t segments = 16; for (size_t idx = 0; idx <= segments; ++idx) { const float angle = M_PI * 2.0f * idx / segments; const CVector3D offset = cameraUp * sin(angle) - cameraLeft * cos(angle); ADD(origin + offset * radius) } #undef ADD debugCircleShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); debugCircleShader->AssertPointersBound(); glDrawArrays(GL_TRIANGLE_FAN, 0, vertices.size() / 3); debugCircleShader->Unbind(); debugCircleTech->EndPass(); #endif } -void CDebugRenderer::DrawCameraFrustum(const CCamera& camera, int intermediates) const +void CDebugRenderer::DrawCameraFrustum(const CCamera& camera, const CColor& color, int intermediates) const { #if CONFIG2_GLES #warning TODO: implement camera frustum for GLES #else CCamera::Quad nearPoints; CCamera::Quad farPoints; camera.GetViewQuad(camera.GetNearPlane(), nearPoints); camera.GetViewQuad(camera.GetFarPlane(), farPoints); for(int i = 0; i < 4; i++) { nearPoints[i] = camera.m_Orientation.Transform(nearPoints[i]); farPoints[i] = camera.m_Orientation.Transform(farPoints[i]); } - // near plane - glBegin(GL_POLYGON); - glVertex3fv(&nearPoints[0].X); - glVertex3fv(&nearPoints[1].X); - glVertex3fv(&nearPoints[2].X); - glVertex3fv(&nearPoints[3].X); - glEnd(); - - // far plane - glBegin(GL_POLYGON); - glVertex3fv(&farPoints[0].X); - glVertex3fv(&farPoints[1].X); - glVertex3fv(&farPoints[2].X); - glVertex3fv(&farPoints[3].X); - glEnd(); - - // connection lines - glBegin(GL_QUAD_STRIP); - glVertex3fv(&nearPoints[0].X); - glVertex3fv(&farPoints[0].X); - glVertex3fv(&nearPoints[1].X); - glVertex3fv(&farPoints[1].X); - glVertex3fv(&nearPoints[2].X); - glVertex3fv(&farPoints[2].X); - glVertex3fv(&nearPoints[3].X); - glVertex3fv(&farPoints[3].X); - glVertex3fv(&nearPoints[0].X); - glVertex3fv(&farPoints[0].X); - glEnd(); + CShaderTechniquePtr overlayTech = + g_Renderer.GetShaderManager().LoadEffect(str_debug_line); + overlayTech->BeginPass(); + CShaderProgramPtr overlayShader = overlayTech->GetShader(); + + overlayShader->Bind(); + overlayShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + overlayShader->Uniform(str_color, color); + + std::vector vertices; +#define ADD(position) \ + vertices.emplace_back((position).X); \ + vertices.emplace_back((position).Y); \ + vertices.emplace_back((position).Z); + + // Near plane. + ADD(nearPoints[0]); + ADD(nearPoints[1]); + ADD(nearPoints[2]); + ADD(nearPoints[3]); + + // Far plane. + ADD(farPoints[0]); + ADD(farPoints[1]); + ADD(farPoints[2]); + ADD(farPoints[3]); - // intermediate planes + // Intermediate planes. CVector3D intermediatePoints[4]; for(int i = 0; i < intermediates; ++i) { - float t = (i + 1.0f) / (intermediates + 1.0f); + const float t = (i + 1.0f) / (intermediates + 1.0f); for(int j = 0; j < 4; ++j) intermediatePoints[j] = nearPoints[j] * t + farPoints[j] * (1.0f - t); - glBegin(GL_POLYGON); - glVertex3fv(&intermediatePoints[0].X); - glVertex3fv(&intermediatePoints[1].X); - glVertex3fv(&intermediatePoints[2].X); - glVertex3fv(&intermediatePoints[3].X); - glEnd(); + ADD(intermediatePoints[0]); + ADD(intermediatePoints[1]); + ADD(intermediatePoints[2]); + ADD(intermediatePoints[3]); } + + overlayShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); + overlayShader->AssertPointersBound(); + glDrawArrays(GL_QUADS, 0, vertices.size() / 3); + + vertices.clear(); + + // Connection lines. + ADD(nearPoints[0]); + ADD(farPoints[0]); + ADD(nearPoints[1]); + ADD(farPoints[1]); + ADD(nearPoints[2]); + ADD(farPoints[2]); + ADD(nearPoints[3]); + ADD(farPoints[3]); + ADD(nearPoints[0]); + ADD(farPoints[0]); + + overlayShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); + overlayShader->AssertPointersBound(); + glDrawArrays(GL_QUAD_STRIP, 0, vertices.size() / 3); +#undef ADD + + overlayShader->Unbind(); + overlayTech->EndPass(); #endif } void CDebugRenderer::DrawBoundingBox(const CBoundingBoxAligned& boundingBox, const CShaderProgramPtr& shader) const { std::vector data; #define ADD_FACE(x, y, z) \ ADD_PT(0, 0, x, y, z); ADD_PT(1, 0, x, y, z); ADD_PT(1, 1, x, y, z); \ ADD_PT(1, 1, x, y, z); ADD_PT(0, 1, x, y, z); ADD_PT(0, 0, x, y, z); #define ADD_PT(u_, v_, x, y, z) \ STMT(int u = u_; int v = v_; \ data.push_back(u); \ data.push_back(v); \ data.push_back(boundingBox[x].X); \ data.push_back(boundingBox[y].Y); \ data.push_back(boundingBox[z].Z); \ ) ADD_FACE(u, v, 0); ADD_FACE(0, u, v); ADD_FACE(u, 0, 1-v); ADD_FACE(u, 1-v, 1); ADD_FACE(1, u, 1-v); ADD_FACE(u, 1, v); #undef ADD_FACE shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 5*sizeof(float), &data[0]); shader->VertexPointer(3, GL_FLOAT, 5*sizeof(float), &data[2]); shader->AssertPointersBound(); glDrawArrays(GL_TRIANGLES, 0, 6*6); } void CDebugRenderer::DrawBoundingBoxOutline(const CBoundingBoxAligned& boundingBox, const CShaderProgramPtr& shader) const { std::vector data; #define ADD_FACE(x, y, z) \ ADD_PT(0, 0, x, y, z); ADD_PT(1, 0, x, y, z); \ ADD_PT(1, 0, x, y, z); ADD_PT(1, 1, x, y, z); \ ADD_PT(1, 1, x, y, z); ADD_PT(0, 1, x, y, z); \ ADD_PT(0, 1, x, y, z); ADD_PT(0, 0, x, y, z); #define ADD_PT(u_, v_, x, y, z) \ STMT(int u = u_; int v = v_; \ data.push_back(u); \ data.push_back(v); \ data.push_back(boundingBox[x].X); \ data.push_back(boundingBox[y].Y); \ data.push_back(boundingBox[z].Z); \ ) ADD_FACE(u, v, 0); ADD_FACE(0, u, v); ADD_FACE(u, 0, 1-v); ADD_FACE(u, 1-v, 1); ADD_FACE(1, u, 1-v); ADD_FACE(u, 1, v); #undef ADD_FACE shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 5*sizeof(float), &data[0]); shader->VertexPointer(3, GL_FLOAT, 5*sizeof(float), &data[2]); shader->AssertPointersBound(); glDrawArrays(GL_LINES, 0, 6*8); } void CDebugRenderer::DrawBrush(const CBrush& brush, const CShaderProgramPtr& shader) const { std::vector data; std::vector> faces; brush.GetFaces(faces); #define ADD_VERT(a) \ STMT( \ data.push_back(u); \ data.push_back(v); \ data.push_back(brush.GetVertices()[faces[i][a]].X); \ data.push_back(brush.GetVertices()[faces[i][a]].Y); \ data.push_back(brush.GetVertices()[faces[i][a]].Z); \ ) for (size_t i = 0; i < faces.size(); ++i) { // Triangulate into (0,1,2), (0,2,3), ... for (size_t j = 1; j < faces[i].size() - 2; ++j) { float u = 0; float v = 0; ADD_VERT(0); ADD_VERT(j); ADD_VERT(j+1); } } #undef ADD_VERT shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 5*sizeof(float), &data[0]); shader->VertexPointer(3, GL_FLOAT, 5*sizeof(float), &data[2]); shader->AssertPointersBound(); glDrawArrays(GL_TRIANGLES, 0, data.size() / 5); } void CDebugRenderer::DrawBrushOutline(const CBrush& brush, const CShaderProgramPtr& shader) const { std::vector data; std::vector> faces; brush.GetFaces(faces); #define ADD_VERT(a) \ STMT( \ data.push_back(u); \ data.push_back(v); \ data.push_back(brush.GetVertices()[faces[i][a]].X); \ data.push_back(brush.GetVertices()[faces[i][a]].Y); \ data.push_back(brush.GetVertices()[faces[i][a]].Z); \ ) for (size_t i = 0; i < faces.size(); ++i) { for (size_t j = 0; j < faces[i].size() - 1; ++j) { float u = 0; float v = 0; ADD_VERT(j); ADD_VERT(j+1); } } #undef ADD_VERT shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 5*sizeof(float), &data[0]); shader->VertexPointer(3, GL_FLOAT, 5*sizeof(float), &data[2]); shader->AssertPointersBound(); glDrawArrays(GL_LINES, 0, data.size() / 5); } Index: ps/trunk/source/renderer/DebugRenderer.h =================================================================== --- ps/trunk/source/renderer/DebugRenderer.h (revision 25322) +++ ps/trunk/source/renderer/DebugRenderer.h (revision 25323) @@ -1,78 +1,78 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. 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 2 of the License, or * (at your option) any later version. * * 0 A.D. 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 0 A.D. If not, see . */ #ifndef INCLUDED_DEBUGRENDERER #define INCLUDED_DEBUGRENDERER #include "graphics/ShaderProgramPtr.h" #include class CBoundingBoxAligned; class CBrush; class CCamera; class CVector3D; struct CColor; // Helper for unoptimized rendering of geometrics primitives. Should not be // used for regular passes. class CDebugRenderer { public: /** * Render the line in world space. */ void DrawLine(const CVector3D& from, const CVector3D& to, const CColor& color, const float width); void DrawLine(const std::vector& line, const CColor& color, const float width); /** * Render the circle in world space oriented to the view camera. */ void DrawCircle(const CVector3D& origin, const float radius, const CColor& color); /** * Render: Renders the camera's frustum in world space. * The caller should set the color using glColorXy before calling Render. * * @param intermediates determines how many intermediate distance planes should * be hinted at between the near and far planes */ - void DrawCameraFrustum(const CCamera& camera, int intermediates = 0) const; + void DrawCameraFrustum(const CCamera& camera, const CColor& color, int intermediates = 0) const; /** * Render the surfaces of the bound box as triangles. */ void DrawBoundingBox(const CBoundingBoxAligned& boundingBox, const CShaderProgramPtr& shader) const; /** * Render the outline of the bound box as lines. */ void DrawBoundingBoxOutline(const CBoundingBoxAligned& boundingBox, const CShaderProgramPtr& shader) const; /** * Render the surfaces of the brush as triangles. */ void DrawBrush(const CBrush& brush, const CShaderProgramPtr& shader) const; /** * Render the outline of the brush as lines. */ void DrawBrushOutline(const CBrush& brush, const CShaderProgramPtr& shader) const; }; #endif // INCLUDED_DEBUGRENDERER Index: ps/trunk/source/renderer/TerrainOverlay.cpp =================================================================== --- ps/trunk/source/renderer/TerrainOverlay.cpp (revision 25322) +++ ps/trunk/source/renderer/TerrainOverlay.cpp (revision 25323) @@ -1,351 +1,393 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. 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 2 of the License, or * (at your option) any later version. * * 0 A.D. 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 0 A.D. If not, see . */ #include "precompiled.h" #include "TerrainOverlay.h" #include "graphics/Color.h" +#include "graphics/ShaderManager.h" +#include "graphics/ShaderProgram.h" #include "graphics/Terrain.h" #include "lib/bits.h" #include "lib/ogl.h" #include "maths/MathUtil.h" #include "ps/Game.h" #include "ps/Profile.h" #include "ps/World.h" #include "renderer/Renderer.h" #include "renderer/TerrainRenderer.h" #include "simulation2/system/SimContext.h" #include // Global overlay list management: static std::vector > g_TerrainOverlayList; ITerrainOverlay::ITerrainOverlay(int priority) { // Add to global list of overlays g_TerrainOverlayList.emplace_back(this, priority); // Sort by overlays by priority. Do stable sort so that adding/removing // overlays doesn't randomly disturb all the existing ones (which would // be noticeable if they have the same priority and overlap). std::stable_sort(g_TerrainOverlayList.begin(), g_TerrainOverlayList.end(), [](const std::pair& a, const std::pair& b) { return a.second < b.second; }); } ITerrainOverlay::~ITerrainOverlay() { std::vector >::iterator newEnd = std::remove_if(g_TerrainOverlayList.begin(), g_TerrainOverlayList.end(), [this](const std::pair& a) { return a.first == this; }); g_TerrainOverlayList.erase(newEnd, g_TerrainOverlayList.end()); } void ITerrainOverlay::RenderOverlaysBeforeWater() { if (g_TerrainOverlayList.empty()) return; PROFILE3_GPU("terrain overlays (before)"); for (size_t i = 0; i < g_TerrainOverlayList.size(); ++i) g_TerrainOverlayList[i].first->RenderBeforeWater(); } void ITerrainOverlay::RenderOverlaysAfterWater(int cullGroup) { if (g_TerrainOverlayList.empty()) return; PROFILE3_GPU("terrain overlays (after)"); for (size_t i = 0; i < g_TerrainOverlayList.size(); ++i) g_TerrainOverlayList[i].first->RenderAfterWater(cullGroup); } ////////////////////////////////////////////////////////////////////////// TerrainOverlay::TerrainOverlay(const CSimContext& simContext, int priority /* = 100 */) : ITerrainOverlay(priority), m_Terrain(&simContext.GetTerrain()) { } void TerrainOverlay::StartRender() { } void TerrainOverlay::EndRender() { } void TerrainOverlay::GetTileExtents( ssize_t& min_i_inclusive, ssize_t& min_j_inclusive, ssize_t& max_i_inclusive, ssize_t& max_j_inclusive) { // Default to whole map min_i_inclusive = min_j_inclusive = 0; max_i_inclusive = max_j_inclusive = m_Terrain->GetTilesPerSide()-1; } void TerrainOverlay::RenderBeforeWater() { if (!m_Terrain) return; // should never happen, but let's play it safe #if CONFIG2_GLES #warning TODO: implement TerrainOverlay::RenderOverlays for GLES #else glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(GL_FALSE); // To ensure that outlines are drawn on top of the terrain correctly (and // don't Z-fight and flicker nastily), draw them as QUADS with the LINE // PolygonMode, and use PolygonOffset to pull them towards the camera. // (See e.g. http://www.opengl.org/resources/faq/technical/polygonoffset.htm) glPolygonOffset(-1.f, -1.f); //glEnable(GL_POLYGON_OFFSET_LINE); glEnable(GL_POLYGON_OFFSET_FILL); pglActiveTextureARB(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); StartRender(); ssize_t min_i, min_j, max_i, max_j; GetTileExtents(min_i, min_j, max_i, max_j); // Clamp the min to 0, but the max to -1 - so tile -1 can never be rendered, // but if unclamped_max<0 then no tiles at all will be rendered. And the same // for the upper limit. min_i = Clamp(min_i, 0, m_Terrain->GetTilesPerSide()); min_j = Clamp(min_j, 0, m_Terrain->GetTilesPerSide()); max_i = Clamp(max_i, -1, m_Terrain->GetTilesPerSide()-1); max_j = Clamp(max_j, -1, m_Terrain->GetTilesPerSide()-1); for (m_j = min_j; m_j <= max_j; ++m_j) for (m_i = min_i; m_i <= max_i; ++m_i) ProcessTile(m_i, m_j); EndRender(); // Clean up state changes glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); //glDisable(GL_POLYGON_OFFSET_LINE); glDisable(GL_POLYGON_OFFSET_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDepthMask(GL_TRUE); glDisable(GL_BLEND); #endif } void TerrainOverlay::RenderTile(const CColor& color, bool draw_hidden) { RenderTile(color, draw_hidden, m_i, m_j); } void TerrainOverlay::RenderTile(const CColor& color, bool draw_hidden, ssize_t i, ssize_t j) { // TODO: unnecessary computation calls has been removed but we should use // a vertex buffer or a vertex shader with a texture. // Not sure if it's possible on old OpenGL. if (draw_hidden) { glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); } else { glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); } #if CONFIG2_GLES #warning TODO: implement TerrainOverlay::RenderTile for GLES #else - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - CVector3D pos[2][2]; for (int di = 0; di < 2; ++di) for (int dj = 0; dj < 2; ++dj) m_Terrain->CalcPosition(i + di, j + dj, pos[di][dj]); - glBegin(GL_TRIANGLES); - glColor4fv(color.FloatArray()); - if (m_Terrain->GetTriangulationDir(i, j)) - { - glVertex3fv(pos[0][0].GetFloatArray()); - glVertex3fv(pos[1][0].GetFloatArray()); - glVertex3fv(pos[0][1].GetFloatArray()); - - glVertex3fv(pos[1][0].GetFloatArray()); - glVertex3fv(pos[1][1].GetFloatArray()); - glVertex3fv(pos[0][1].GetFloatArray()); - } - else - { - glVertex3fv(pos[0][0].GetFloatArray()); - glVertex3fv(pos[1][0].GetFloatArray()); - glVertex3fv(pos[1][1].GetFloatArray()); - - glVertex3fv(pos[1][1].GetFloatArray()); - glVertex3fv(pos[0][1].GetFloatArray()); - glVertex3fv(pos[0][0].GetFloatArray()); - } - glEnd(); + std::vector vertices; +#define ADD(position) \ + vertices.emplace_back((position).X); \ + vertices.emplace_back((position).Y); \ + vertices.emplace_back((position).Z); + + if (m_Terrain->GetTriangulationDir(i, j)) + { + ADD(pos[0][0]); + ADD(pos[1][0]); + ADD(pos[0][1]); + + ADD(pos[1][0]); + ADD(pos[1][1]); + ADD(pos[0][1]); + } + else + { + ADD(pos[0][0]); + ADD(pos[1][0]); + ADD(pos[1][1]); + + ADD(pos[1][1]); + ADD(pos[0][1]); + ADD(pos[0][0]); + } +#undef ADD + + CShaderTechniquePtr overlayTech = + g_Renderer.GetShaderManager().LoadEffect(str_debug_line); + overlayTech->BeginPass(); + CShaderProgramPtr overlayShader = overlayTech->GetShader(); + + overlayShader->Bind(); + overlayShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + overlayShader->Uniform(str_color, color); + + overlayShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); + overlayShader->AssertPointersBound(); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3); + overlayShader->Unbind(); + overlayTech->EndPass(); #endif } void TerrainOverlay::RenderTileOutline(const CColor& color, int line_width, bool draw_hidden) { RenderTileOutline(color, line_width, draw_hidden, m_i, m_j); } void TerrainOverlay::RenderTileOutline(const CColor& color, int line_width, bool draw_hidden, ssize_t i, ssize_t j) { if (draw_hidden) { glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); } else { glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); } #if CONFIG2_GLES #warning TODO: implement TerrainOverlay::RenderTileOutline for GLES #else glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); if (line_width != 1) glLineWidth((float)line_width); - CVector3D pos; - glBegin(GL_QUADS); - glColor4fv(color.FloatArray()); - m_Terrain->CalcPosition(i, j, pos); glVertex3fv(pos.GetFloatArray()); - m_Terrain->CalcPosition(i+1, j, pos); glVertex3fv(pos.GetFloatArray()); - m_Terrain->CalcPosition(i+1, j+1, pos); glVertex3fv(pos.GetFloatArray()); - m_Terrain->CalcPosition(i, j+1, pos); glVertex3fv(pos.GetFloatArray()); - glEnd(); + std::vector vertices; +#define ADD(i, j) \ + m_Terrain->CalcPosition(i, j, position); \ + vertices.emplace_back(position.X); \ + vertices.emplace_back(position.Y); \ + vertices.emplace_back(position.Z); + + CVector3D position; + ADD(i, j); + ADD(i+1, j); + ADD(i+1, j+1); + ADD(i, j+1); +#undef ADD + + CShaderTechniquePtr overlayTech = + g_Renderer.GetShaderManager().LoadEffect(str_debug_line); + overlayTech->BeginPass(); + CShaderProgramPtr overlayShader = overlayTech->GetShader(); + + overlayShader->Bind(); + overlayShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + overlayShader->Uniform(str_color, color); + + overlayShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); + overlayShader->AssertPointersBound(); + + glDrawArrays(GL_QUADS, 0, vertices.size() / 3); + + overlayShader->Unbind(); + overlayTech->EndPass(); if (line_width != 1) glLineWidth(1.0f); - #endif } ////////////////////////////////////////////////////////////////////////// TerrainTextureOverlay::TerrainTextureOverlay(float texelsPerTile, int priority) : ITerrainOverlay(priority), m_TexelsPerTile(texelsPerTile), m_Texture(0), m_TextureW(0), m_TextureH(0) { glGenTextures(1, &m_Texture); } TerrainTextureOverlay::~TerrainTextureOverlay() { glDeleteTextures(1, &m_Texture); } void TerrainTextureOverlay::RenderAfterWater(int cullGroup) { CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); ssize_t w = (ssize_t)(terrain->GetTilesPerSide() * m_TexelsPerTile); ssize_t h = (ssize_t)(terrain->GetTilesPerSide() * m_TexelsPerTile); pglActiveTextureARB(GL_TEXTURE0); // Recreate the texture with new size if necessary if (round_up_to_pow2(w) != m_TextureW || round_up_to_pow2(h) != m_TextureH) { m_TextureW = round_up_to_pow2(w); m_TextureH = round_up_to_pow2(h); glBindTexture(GL_TEXTURE_2D, m_Texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TextureW, m_TextureH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } u8* data = (u8*)calloc(w * h, 4); BuildTextureRGBA(data, w, h); glBindTexture(GL_TEXTURE_2D, m_Texture); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data); free(data); CMatrix3D matrix; matrix.SetZero(); matrix._11 = m_TexelsPerTile / (m_TextureW * TERRAIN_TILE_SIZE); matrix._23 = m_TexelsPerTile / (m_TextureH * TERRAIN_TILE_SIZE); matrix._44 = 1; g_Renderer.GetTerrainRenderer().RenderTerrainOverlayTexture(cullGroup, matrix, m_Texture); } SColor4ub TerrainTextureOverlay::GetColor(size_t idx, u8 alpha) const { static u8 colors[][3] = { { 255, 0, 0 }, { 0, 255, 0 }, { 0, 0, 255 }, { 255, 255, 0 }, { 255, 0, 255 }, { 0, 255, 255 }, { 255, 255, 255 }, { 127, 0, 0 }, { 0, 127, 0 }, { 0, 0, 127 }, { 127, 127, 0 }, { 127, 0, 127 }, { 0, 127, 127 }, { 127, 127, 127}, { 255, 127, 0 }, { 127, 255, 0 }, { 255, 0, 127 }, { 127, 0, 255}, { 0, 255, 127 }, { 0, 127, 255}, { 255, 127, 127}, { 127, 255, 127}, { 127, 127, 255}, { 127, 255, 255 }, { 255, 127, 255 }, { 255, 255, 127 }, }; size_t c = idx % ARRAY_SIZE(colors); return SColor4ub(colors[c][0], colors[c][1], colors[c][2], alpha); }