LCOV - code coverage report
Current view: top level - source/renderer - OverlayRenderer.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 0 344 0.0 %
Date: 2021-09-24 14:46:47 Functions: 0 25 0.0 %

          Line data    Source code
       1             : /* Copyright (C) 2021 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "OverlayRenderer.h"
      21             : 
      22             : #include "graphics/Camera.h"
      23             : #include "graphics/LOSTexture.h"
      24             : #include "graphics/Overlay.h"
      25             : #include "graphics/ShaderManager.h"
      26             : #include "graphics/Terrain.h"
      27             : #include "graphics/TextureManager.h"
      28             : #include "lib/hash.h"
      29             : #include "lib/ogl.h"
      30             : #include "maths/MathUtil.h"
      31             : #include "maths/Quaternion.h"
      32             : #include "ps/CStrInternStatic.h"
      33             : #include "ps/Game.h"
      34             : #include "ps/Profile.h"
      35             : #include "renderer/DebugRenderer.h"
      36             : #include "renderer/Renderer.h"
      37             : #include "renderer/TexturedLineRData.h"
      38             : #include "renderer/VertexArray.h"
      39             : #include "renderer/VertexBuffer.h"
      40             : #include "renderer/VertexBufferManager.h"
      41             : #include "simulation2/components/ICmpWaterManager.h"
      42             : #include "simulation2/Simulation2.h"
      43             : #include "simulation2/system/SimContext.h"
      44             : 
      45             : #include <unordered_map>
      46             : 
      47             : namespace
      48             : {
      49             : 
      50           0 : CShaderProgramPtr GetOverlayLineShader(const CShaderDefines& defines)
      51             : {
      52           0 :     const char* shaderName;
      53           0 :     if (g_RenderingOptions.GetPreferGLSL())
      54             :         shaderName = "glsl/overlayline";
      55             :     else
      56           0 :         shaderName = "arb/overlayline";
      57           0 :     return g_Renderer.GetShaderManager().LoadProgram(shaderName, defines);
      58             : }
      59             : 
      60             : } // anonymous namespace
      61             : 
      62             : /**
      63             :  * Key used to group quads into batches for more efficient rendering. Currently groups by the combination
      64             :  * of the main texture and the texture mask, to minimize texture swapping during rendering.
      65             :  */
      66           0 : struct QuadBatchKey
      67             : {
      68             :     QuadBatchKey (const CTexturePtr& texture, const CTexturePtr& textureMask)
      69           0 :         : m_Texture(texture), m_TextureMask(textureMask)
      70             :     { }
      71             : 
      72             :     bool operator==(const QuadBatchKey& other) const
      73             :     {
      74           0 :         return (m_Texture == other.m_Texture && m_TextureMask == other.m_TextureMask);
      75             :     }
      76             : 
      77             :     CTexturePtr m_Texture;
      78             :     CTexturePtr m_TextureMask;
      79             : };
      80             : 
      81             : struct QuadBatchHash
      82             : {
      83           0 :     std::size_t operator()(const QuadBatchKey& d) const
      84             :     {
      85           0 :         size_t seed = 0;
      86           0 :         hash_combine(seed, d.m_Texture);
      87           0 :         hash_combine(seed, d.m_TextureMask);
      88           0 :         return seed;
      89             :     }
      90             : };
      91             : 
      92             : /**
      93             :  * Holds information about a single quad rendering batch.
      94             :  */
      95             : class QuadBatchData : public CRenderData
      96             : {
      97             : public:
      98           0 :     QuadBatchData() : m_IndicesBase(0), m_NumRenderQuads(0) { }
      99             : 
     100             :     /// Holds the quad overlay structures requested to be rendered in this batch. Must be cleared
     101             :     /// after each frame.
     102             :     std::vector<SOverlayQuad*> m_Quads;
     103             : 
     104             :     /// Start index of this batch into the dedicated quad indices VertexArray (see OverlayInternals).
     105             :     size_t m_IndicesBase;
     106             :     /// Amount of quads to actually render in this batch. Potentially (although unlikely to be)
     107             :     /// different from m_Quads.size() due to restrictions on the total amount of quads that can be
     108             :     /// rendered. Must be reset after each frame.
     109             :     size_t m_NumRenderQuads;
     110             : };
     111             : 
     112             : struct OverlayRendererInternals
     113             : {
     114             :     using QuadBatchMap = std::unordered_map<QuadBatchKey, QuadBatchData, QuadBatchHash>;
     115             : 
     116             :     OverlayRendererInternals();
     117           0 :     ~OverlayRendererInternals(){ }
     118             : 
     119             :     std::vector<SOverlayLine*> lines;
     120             :     std::vector<SOverlayTexturedLine*> texlines;
     121             :     std::vector<SOverlaySprite*> sprites;
     122             :     std::vector<SOverlayQuad*> quads;
     123             :     std::vector<SOverlaySphere*> spheres;
     124             : 
     125             :     QuadBatchMap quadBatchMap;
     126             : 
     127             :     // Dedicated vertex/index buffers for rendering all quads (to within the limits set by
     128             :     // MAX_QUAD_OVERLAYS).
     129             :     VertexArray quadVertices;
     130             :     VertexArray::Attribute quadAttributePos;
     131             :     VertexArray::Attribute quadAttributeColor;
     132             :     VertexArray::Attribute quadAttributeUV;
     133             :     VertexIndexArray quadIndices;
     134             : 
     135             :     /// Maximum amount of quad overlays we support for rendering. This limit is set to be able to
     136             :     /// render all quads from a single dedicated VB without having to reallocate it, which is much
     137             :     /// faster in the typical case of rendering only a handful of quads. When modifying this value,
     138             :     /// you must take care for the new amount of quads to fit in a single VBO (which is not likely
     139             :     /// to be a problem).
     140             :     static const size_t MAX_QUAD_OVERLAYS = 1024;
     141             : 
     142             :     // Sets of commonly-(re)used shader defines.
     143             :     CShaderDefines defsOverlayLineNormal;
     144             :     CShaderDefines defsOverlayLineAlwaysVisible;
     145             :     CShaderDefines defsQuadOverlay;
     146             : 
     147             :     // Geometry for a unit sphere
     148             :     std::vector<float> sphereVertexes;
     149             :     std::vector<u16> sphereIndexes;
     150             :     void GenerateSphere();
     151             : 
     152             :     /// Performs one-time setup. Called from CRenderer::Open, after graphics capabilities have
     153             :     /// been detected. Note that no VBOs must be created before this is called, since the shader
     154             :     /// path and graphics capabilities are not guaranteed to be stable before this point.
     155             :     void Initialize();
     156             : };
     157             : 
     158             : const float OverlayRenderer::OVERLAY_VOFFSET = 0.2f;
     159             : 
     160           0 : OverlayRendererInternals::OverlayRendererInternals()
     161           0 :     : quadVertices(GL_DYNAMIC_DRAW), quadIndices(GL_STATIC_DRAW)
     162             : {
     163           0 :     quadAttributePos.elems = 3;
     164           0 :     quadAttributePos.type = GL_FLOAT;
     165           0 :     quadVertices.AddAttribute(&quadAttributePos);
     166             : 
     167           0 :     quadAttributeColor.elems = 4;
     168           0 :     quadAttributeColor.type = GL_FLOAT;
     169           0 :     quadVertices.AddAttribute(&quadAttributeColor);
     170             : 
     171           0 :     quadAttributeUV.elems = 2;
     172           0 :     quadAttributeUV.type = GL_SHORT; // don't use GL_UNSIGNED_SHORT here, TexCoordPointer won't accept it
     173           0 :     quadVertices.AddAttribute(&quadAttributeUV);
     174             : 
     175             :     // Note that we're reusing the textured overlay line shader for the quad overlay rendering. This
     176             :     // is because their code is almost identical; the only difference is that for the quad overlays
     177             :     // we want to use a vertex color stream as opposed to an objectColor uniform. To this end, the
     178             :     // shader has been set up to switch between the two behaviours based on the USE_OBJECTCOLOR define.
     179           0 :     defsOverlayLineNormal.Add(str_USE_OBJECTCOLOR, str_1);
     180           0 :     defsOverlayLineAlwaysVisible.Add(str_USE_OBJECTCOLOR, str_1);
     181           0 :     defsOverlayLineAlwaysVisible.Add(str_IGNORE_LOS, str_1);
     182           0 : }
     183             : 
     184           0 : void OverlayRendererInternals::Initialize()
     185             : {
     186             :     // Perform any initialization after graphics capabilities have been detected. Notably,
     187             :     // only at this point can we safely allocate VBOs (in contrast to e.g. in the constructor),
     188             :     // because their creation depends on the shader path, which is not reliably set before this point.
     189             : 
     190           0 :     quadVertices.SetNumVertices(MAX_QUAD_OVERLAYS * 4);
     191           0 :     quadVertices.Layout(); // allocate backing store
     192             : 
     193           0 :     quadIndices.SetNumVertices(MAX_QUAD_OVERLAYS * 6);
     194           0 :     quadIndices.Layout(); // allocate backing store
     195             : 
     196             :     // Since the quads in the vertex array are independent and always consist of exactly 4 vertices per quad, the
     197             :     // indices are always the same; we can therefore fill in all the indices once and pretty much forget about
     198             :     // them. We then also no longer need its backing store, since we never change any indices afterwards.
     199           0 :     VertexArrayIterator<u16> index = quadIndices.GetIterator();
     200           0 :     for (u16 i = 0; i < static_cast<u16>(MAX_QUAD_OVERLAYS); ++i)
     201             :     {
     202           0 :         *index++ = i * 4 + 0;
     203           0 :         *index++ = i * 4 + 1;
     204           0 :         *index++ = i * 4 + 2;
     205           0 :         *index++ = i * 4 + 2;
     206           0 :         *index++ = i * 4 + 3;
     207           0 :         *index++ = i * 4 + 0;
     208             :     }
     209           0 :     quadIndices.Upload();
     210           0 :     quadIndices.FreeBackingStore();
     211           0 : }
     212             : 
     213           0 : OverlayRenderer::OverlayRenderer()
     214             : {
     215           0 :     m = new OverlayRendererInternals();
     216           0 : }
     217             : 
     218           0 : OverlayRenderer::~OverlayRenderer()
     219             : {
     220           0 :     delete m;
     221           0 : }
     222             : 
     223           0 : void OverlayRenderer::Initialize()
     224             : {
     225           0 :     m->Initialize();
     226           0 : }
     227             : 
     228           0 : void OverlayRenderer::Submit(SOverlayLine* line)
     229             : {
     230           0 :     m->lines.push_back(line);
     231           0 : }
     232             : 
     233           0 : void OverlayRenderer::Submit(SOverlayTexturedLine* line)
     234             : {
     235             :     // Simplify the rest of the code by guaranteeing non-empty lines
     236           0 :     if (line->m_Coords.empty())
     237             :         return;
     238             : 
     239           0 :     m->texlines.push_back(line);
     240             : }
     241             : 
     242           0 : void OverlayRenderer::Submit(SOverlaySprite* overlay)
     243             : {
     244           0 :     m->sprites.push_back(overlay);
     245           0 : }
     246             : 
     247           0 : void OverlayRenderer::Submit(SOverlayQuad* overlay)
     248             : {
     249           0 :     m->quads.push_back(overlay);
     250           0 : }
     251             : 
     252           0 : void OverlayRenderer::Submit(SOverlaySphere* overlay)
     253             : {
     254           0 :     m->spheres.push_back(overlay);
     255           0 : }
     256             : 
     257           0 : void OverlayRenderer::EndFrame()
     258             : {
     259           0 :     m->lines.clear();
     260           0 :     m->texlines.clear();
     261           0 :     m->sprites.clear();
     262           0 :     m->quads.clear();
     263           0 :     m->spheres.clear();
     264             : 
     265             :     // this should leave the capacity unchanged, which is okay since it
     266             :     // won't be very large or very variable
     267             : 
     268             :     // Empty the batch rendering data structures, but keep their key mappings around for the next frames
     269           0 :     for (OverlayRendererInternals::QuadBatchMap::iterator it = m->quadBatchMap.begin(); it != m->quadBatchMap.end(); ++it)
     270             :     {
     271           0 :         QuadBatchData& quadBatchData = (it->second);
     272           0 :         quadBatchData.m_Quads.clear();
     273           0 :         quadBatchData.m_NumRenderQuads = 0;
     274           0 :         quadBatchData.m_IndicesBase = 0;
     275             :     }
     276           0 : }
     277             : 
     278           0 : void OverlayRenderer::PrepareForRendering()
     279             : {
     280           0 :     PROFILE3("prepare overlays");
     281             : 
     282             :     // This is where we should do something like sort the overlays by
     283             :     // color/sprite/etc for more efficient rendering
     284             : 
     285           0 :     for (size_t i = 0; i < m->texlines.size(); ++i)
     286             :     {
     287           0 :         SOverlayTexturedLine* line = m->texlines[i];
     288           0 :         if (!line->m_RenderData)
     289             :         {
     290           0 :             line->m_RenderData = std::make_shared<CTexturedLineRData>();
     291           0 :             line->m_RenderData->Update(*line);
     292             :             // We assume the overlay line will get replaced by the caller
     293             :             // if terrain changes, so we don't need to detect that here and
     294             :             // call Update again. Also we assume the caller won't change
     295             :             // any of the parameters after first submitting the line.
     296             :         }
     297             :     }
     298             : 
     299             :     // Group quad overlays by their texture/mask combination for efficient rendering
     300             :     // TODO: consider doing this directly in Submit()
     301           0 :     for (size_t i = 0; i < m->quads.size(); ++i)
     302             :     {
     303           0 :         SOverlayQuad* const quad = m->quads[i];
     304             : 
     305           0 :         QuadBatchKey textures(quad->m_Texture, quad->m_TextureMask);
     306           0 :         QuadBatchData& batchRenderData = m->quadBatchMap[textures]; // will create entry if it doesn't already exist
     307             : 
     308             :         // add overlay to list of quads
     309           0 :         batchRenderData.m_Quads.push_back(quad);
     310             :     }
     311             : 
     312           0 :     const CVector3D vOffset(0, OverlayRenderer::OVERLAY_VOFFSET, 0);
     313             : 
     314             :     // Write quad overlay vertices/indices to VA backing store
     315           0 :     VertexArrayIterator<CVector3D> vertexPos = m->quadAttributePos.GetIterator<CVector3D>();
     316           0 :     VertexArrayIterator<CVector4D> vertexColor = m->quadAttributeColor.GetIterator<CVector4D>();
     317           0 :     VertexArrayIterator<short[2]> vertexUV = m->quadAttributeUV.GetIterator<short[2]>();
     318             : 
     319           0 :     size_t indicesIdx = 0;
     320           0 :     size_t totalNumQuads = 0;
     321             : 
     322           0 :     for (OverlayRendererInternals::QuadBatchMap::iterator it = m->quadBatchMap.begin(); it != m->quadBatchMap.end(); ++it)
     323             :     {
     324           0 :         QuadBatchData& batchRenderData = (it->second);
     325           0 :         batchRenderData.m_NumRenderQuads = 0;
     326             : 
     327           0 :         if (batchRenderData.m_Quads.empty())
     328             :             continue;
     329             : 
     330             :         // Remember the current index into the (entire) indices array as our base offset for this batch
     331           0 :         batchRenderData.m_IndicesBase = indicesIdx;
     332             : 
     333             :         // points to the index where each iteration's vertices will be appended
     334           0 :         for (size_t i = 0; i < batchRenderData.m_Quads.size() && totalNumQuads < OverlayRendererInternals::MAX_QUAD_OVERLAYS; i++)
     335             :         {
     336           0 :             const SOverlayQuad* quad = batchRenderData.m_Quads[i];
     337             : 
     338             :             // TODO: this is kind of ugly, the iterator should use a type that can have quad->m_Color assigned
     339             :             // to it directly
     340           0 :             const CVector4D quadColor(quad->m_Color.r, quad->m_Color.g, quad->m_Color.b, quad->m_Color.a);
     341             : 
     342           0 :             *vertexPos++ = quad->m_Corners[0] + vOffset;
     343           0 :             *vertexPos++ = quad->m_Corners[1] + vOffset;
     344           0 :             *vertexPos++ = quad->m_Corners[2] + vOffset;
     345           0 :             *vertexPos++ = quad->m_Corners[3] + vOffset;
     346             : 
     347           0 :             (*vertexUV)[0] = 0;
     348           0 :             (*vertexUV)[1] = 0;
     349           0 :             ++vertexUV;
     350           0 :             (*vertexUV)[0] = 0;
     351           0 :             (*vertexUV)[1] = 1;
     352           0 :             ++vertexUV;
     353           0 :             (*vertexUV)[0] = 1;
     354           0 :             (*vertexUV)[1] = 1;
     355           0 :             ++vertexUV;
     356           0 :             (*vertexUV)[0] = 1;
     357           0 :             (*vertexUV)[1] = 0;
     358           0 :             ++vertexUV;
     359             : 
     360           0 :             *vertexColor++ = quadColor;
     361           0 :             *vertexColor++ = quadColor;
     362           0 :             *vertexColor++ = quadColor;
     363           0 :             *vertexColor++ = quadColor;
     364             : 
     365           0 :             indicesIdx += 6;
     366             : 
     367           0 :             totalNumQuads++;
     368           0 :             batchRenderData.m_NumRenderQuads++;
     369             :         }
     370             :     }
     371             : 
     372           0 :     m->quadVertices.Upload();
     373             :     // don't free the backing store! we'll overwrite it on the next frame to save a reallocation.
     374             : 
     375           0 :     m->quadVertices.PrepareForRendering();
     376           0 : }
     377             : 
     378           0 : void OverlayRenderer::RenderOverlaysBeforeWater()
     379             : {
     380           0 :     PROFILE3_GPU("overlays (before)");
     381             : 
     382             : #if CONFIG2_GLES
     383             : #warning TODO: implement OverlayRenderer::RenderOverlaysBeforeWater for GLES
     384             : #else
     385           0 :     glEnable(GL_BLEND);
     386             :     // Ignore z so that we draw behind terrain (but don't disable GL_DEPTH_TEST
     387             :     // since we still want to write to the z buffer)
     388           0 :     glDepthFunc(GL_ALWAYS);
     389             : 
     390           0 :     for (SOverlayLine* line : m->lines)
     391             :     {
     392           0 :         if (line->m_Coords.empty())
     393             :             continue;
     394             : 
     395           0 :         g_Renderer.GetDebugRenderer().DrawLine(line->m_Coords, line->m_Color, static_cast<float>(line->m_Thickness));
     396             :     }
     397             : 
     398           0 :     glDepthFunc(GL_LEQUAL);
     399           0 :     glDisable(GL_BLEND);
     400             : #endif
     401           0 : }
     402             : 
     403           0 : void OverlayRenderer::RenderOverlaysAfterWater()
     404             : {
     405           0 :     PROFILE3_GPU("overlays (after)");
     406             : 
     407           0 :     RenderTexturedOverlayLines();
     408           0 :     RenderQuadOverlays();
     409           0 :     RenderSphereOverlays();
     410           0 : }
     411             : 
     412           0 : void OverlayRenderer::RenderTexturedOverlayLines()
     413             : {
     414             : #if CONFIG2_GLES
     415             : #warning TODO: implement OverlayRenderer::RenderTexturedOverlayLines for GLES
     416             :     return;
     417             : #endif
     418           0 :     if (m->texlines.empty())
     419           0 :         return;
     420             : 
     421           0 :     ogl_WarnIfError();
     422             : 
     423           0 :     pglActiveTextureARB(GL_TEXTURE0);
     424           0 :     glEnable(GL_TEXTURE_2D);
     425           0 :     glEnable(GL_BLEND);
     426           0 :     glDepthMask(0);
     427             : 
     428           0 :     CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture();
     429             : 
     430           0 :     CShaderProgramPtr shaderTexLineNormal = GetOverlayLineShader(m->defsOverlayLineNormal);
     431           0 :     CShaderProgramPtr shaderTexLineAlwaysVisible = GetOverlayLineShader(m->defsOverlayLineAlwaysVisible);
     432             : 
     433             :     // ----------------------------------------------------------------------------------------
     434             : 
     435           0 :     if (shaderTexLineNormal)
     436             :     {
     437           0 :         shaderTexLineNormal->Bind();
     438           0 :         shaderTexLineNormal->BindTexture(str_losTex, los.GetTexture());
     439           0 :         shaderTexLineNormal->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
     440             : 
     441           0 :         shaderTexLineNormal->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection());
     442             : 
     443             :         // batch render only the non-always-visible overlay lines using the normal shader
     444           0 :         RenderTexturedOverlayLines(shaderTexLineNormal, false);
     445             : 
     446           0 :         shaderTexLineNormal->Unbind();
     447             :     }
     448             : 
     449             :     // ----------------------------------------------------------------------------------------
     450             : 
     451           0 :     if (shaderTexLineAlwaysVisible)
     452             :     {
     453           0 :         shaderTexLineAlwaysVisible->Bind();
     454             :         // TODO: losTex and losTransform are unused in the always visible shader; see if these can be safely omitted
     455           0 :         shaderTexLineAlwaysVisible->BindTexture(str_losTex, los.GetTexture());
     456           0 :         shaderTexLineAlwaysVisible->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
     457             : 
     458           0 :         shaderTexLineAlwaysVisible->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection());
     459             : 
     460             :         // batch render only the always-visible overlay lines using the LoS-ignored shader
     461           0 :         RenderTexturedOverlayLines(shaderTexLineAlwaysVisible, true);
     462             : 
     463           0 :         shaderTexLineAlwaysVisible->Unbind();
     464             :     }
     465             : 
     466             :     // ----------------------------------------------------------------------------------------
     467             : 
     468             :     // TODO: the shaders should probably be responsible for unbinding their textures
     469           0 :     g_Renderer.BindTexture(1, 0);
     470           0 :     g_Renderer.BindTexture(0, 0);
     471             : 
     472           0 :     CVertexBuffer::Unbind();
     473             : 
     474           0 :     glDepthMask(1);
     475           0 :     glDisable(GL_BLEND);
     476             : }
     477             : 
     478           0 : void OverlayRenderer::RenderTexturedOverlayLines(CShaderProgramPtr shader, bool alwaysVisible)
     479             : {
     480             : #if !CONFIG2_GLES
     481           0 :     if (g_Renderer.GetOverlayRenderMode() == WIREFRAME)
     482           0 :         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
     483             : #endif
     484           0 :     for (size_t i = 0; i < m->texlines.size(); ++i)
     485             :     {
     486           0 :         SOverlayTexturedLine* line = m->texlines[i];
     487             : 
     488             :         // render only those lines matching the requested alwaysVisible status
     489           0 :         if (!line->m_RenderData || line->m_AlwaysVisible != alwaysVisible)
     490             :             continue;
     491             : 
     492           0 :         ENSURE(line->m_RenderData);
     493           0 :         line->m_RenderData->Render(*line, shader);
     494             :     }
     495             : #if !CONFIG2_GLES
     496           0 :     if (g_Renderer.GetOverlayRenderMode() == WIREFRAME)
     497           0 :         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
     498             : #endif
     499           0 : }
     500             : 
     501           0 : void OverlayRenderer::RenderQuadOverlays()
     502             : {
     503             : #if CONFIG2_GLES
     504             : #warning TODO: implement OverlayRenderer::RenderQuadOverlays for GLES
     505             :     return;
     506             : #endif
     507           0 :     if (m->quadBatchMap.empty())
     508           0 :         return;
     509             : 
     510           0 :     CShaderProgramPtr shader = GetOverlayLineShader(m->defsQuadOverlay);
     511             : 
     512           0 :     if (!shader)
     513           0 :         return;
     514             : 
     515             : #if !CONFIG2_GLES
     516           0 :     if (g_Renderer.GetOverlayRenderMode() == WIREFRAME)
     517           0 :         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
     518             : #endif
     519             : 
     520           0 :     pglActiveTextureARB(GL_TEXTURE0);
     521           0 :     glEnable(GL_TEXTURE_2D);
     522           0 :     glEnable(GL_BLEND);
     523           0 :     glDepthMask(0);
     524             : 
     525           0 :     CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture();
     526             : 
     527           0 :     shader->Bind();
     528           0 :     shader->BindTexture(str_losTex, los.GetTexture());
     529           0 :     shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
     530             : 
     531           0 :     shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection());
     532             : 
     533             :     // Base offsets (in bytes) of the two backing stores relative to their owner VBO
     534           0 :     u8* indexBase = m->quadIndices.Bind();
     535           0 :     u8* vertexBase = m->quadVertices.Bind();
     536           0 :     GLsizei indexStride = m->quadIndices.GetStride();
     537           0 :     GLsizei vertexStride = m->quadVertices.GetStride();
     538             : 
     539           0 :     for (OverlayRendererInternals::QuadBatchMap::iterator it = m->quadBatchMap.begin(); it != m->quadBatchMap.end(); ++it)
     540             :     {
     541           0 :         QuadBatchData& batchRenderData = it->second;
     542           0 :         const size_t batchNumQuads = batchRenderData.m_NumRenderQuads;
     543             : 
     544             :         // Careful; some drivers don't like drawing calls with 0 stuff to draw.
     545           0 :         if (batchNumQuads == 0)
     546             :             continue;
     547             : 
     548           0 :         const QuadBatchKey& maskPair = it->first;
     549             : 
     550           0 :         shader->BindTexture(str_baseTex, maskPair.m_Texture->GetHandle());
     551           0 :         shader->BindTexture(str_maskTex, maskPair.m_TextureMask->GetHandle());
     552             : 
     553           0 :         int streamflags = shader->GetStreamFlags();
     554             : 
     555           0 :         if (streamflags & STREAM_POS)
     556           0 :             shader->VertexPointer(m->quadAttributePos.elems, m->quadAttributePos.type, vertexStride, vertexBase + m->quadAttributePos.offset);
     557             : 
     558           0 :         if (streamflags & STREAM_UV0)
     559           0 :             shader->TexCoordPointer(GL_TEXTURE0, m->quadAttributeUV.elems, m->quadAttributeUV.type, vertexStride, vertexBase + m->quadAttributeUV.offset);
     560             : 
     561           0 :         if (streamflags & STREAM_UV1)
     562           0 :             shader->TexCoordPointer(GL_TEXTURE1, m->quadAttributeUV.elems, m->quadAttributeUV.type, vertexStride, vertexBase + m->quadAttributeUV.offset);
     563             : 
     564           0 :         if (streamflags & STREAM_COLOR)
     565           0 :             shader->ColorPointer(m->quadAttributeColor.elems, m->quadAttributeColor.type, vertexStride, vertexBase + m->quadAttributeColor.offset);
     566             : 
     567           0 :         shader->AssertPointersBound();
     568           0 :         glDrawElements(GL_TRIANGLES, (GLsizei)(batchNumQuads * 6), GL_UNSIGNED_SHORT, indexBase + indexStride * batchRenderData.m_IndicesBase);
     569             : 
     570           0 :         g_Renderer.GetStats().m_DrawCalls++;
     571           0 :         g_Renderer.GetStats().m_OverlayTris += batchNumQuads*2;
     572             :     }
     573             : 
     574           0 :     shader->Unbind();
     575             : 
     576             :     // TODO: the shader should probably be responsible for unbinding its textures
     577           0 :     g_Renderer.BindTexture(1, 0);
     578           0 :     g_Renderer.BindTexture(0, 0);
     579             : 
     580           0 :     CVertexBuffer::Unbind();
     581             : 
     582           0 :     glDepthMask(1);
     583           0 :     glDisable(GL_BLEND);
     584             : 
     585             : #if !CONFIG2_GLES
     586           0 :     if (g_Renderer.GetOverlayRenderMode() == WIREFRAME)
     587           0 :         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
     588             : #endif
     589             : }
     590             : 
     591           0 : void OverlayRenderer::RenderForegroundOverlays(const CCamera& viewCamera)
     592             : {
     593           0 :     PROFILE3_GPU("overlays (fg)");
     594             : 
     595             : #if CONFIG2_GLES
     596             : #warning TODO: implement OverlayRenderer::RenderForegroundOverlays for GLES
     597             : #else
     598           0 :     if (g_Renderer.GetOverlayRenderMode() == WIREFRAME)
     599           0 :         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
     600             : 
     601           0 :     pglActiveTextureARB(GL_TEXTURE0);
     602           0 :     glEnable(GL_TEXTURE_2D);
     603           0 :     glEnable(GL_BLEND);
     604           0 :     glDisable(GL_DEPTH_TEST);
     605             : 
     606           0 :     CVector3D right = -viewCamera.GetOrientation().GetLeft();
     607           0 :     CVector3D up = viewCamera.GetOrientation().GetUp();
     608             : 
     609           0 :     CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_foreground_overlay);
     610           0 :     tech->BeginPass();
     611           0 :     CShaderProgramPtr shader = tech->GetShader();
     612             : 
     613           0 :     shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection());
     614             : 
     615           0 :     float uvs[8] = { 0,1, 1,1, 1,0, 0,0 };
     616             : 
     617           0 :     shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, sizeof(float)*2, &uvs[0]);
     618             : 
     619           0 :     for (size_t i = 0; i < m->sprites.size(); ++i)
     620             :     {
     621           0 :         SOverlaySprite* sprite = m->sprites[i];
     622           0 :         if (!i || sprite->m_Texture != m->sprites[i - 1]->m_Texture)
     623           0 :             shader->BindTexture(str_baseTex, sprite->m_Texture);
     624             : 
     625           0 :         shader->Uniform(str_colorMul, sprite->m_Color);
     626             : 
     627           0 :         CVector3D pos[4] = {
     628           0 :             sprite->m_Position + right*sprite->m_X0 + up*sprite->m_Y0,
     629           0 :             sprite->m_Position + right*sprite->m_X1 + up*sprite->m_Y0,
     630           0 :             sprite->m_Position + right*sprite->m_X1 + up*sprite->m_Y1,
     631           0 :             sprite->m_Position + right*sprite->m_X0 + up*sprite->m_Y1
     632             :         };
     633             : 
     634           0 :         shader->VertexPointer(3, GL_FLOAT, sizeof(float)*3, &pos[0].X);
     635             : 
     636           0 :         glDrawArrays(GL_QUADS, 0, (GLsizei)4);
     637             : 
     638           0 :         g_Renderer.GetStats().m_DrawCalls++;
     639           0 :         g_Renderer.GetStats().m_OverlayTris += 2;
     640             :     }
     641             : 
     642           0 :     tech->EndPass();
     643             : 
     644           0 :     glEnable(GL_DEPTH_TEST);
     645           0 :     glDisable(GL_BLEND);
     646           0 :     glDisable(GL_TEXTURE_2D);
     647             : 
     648           0 :     if (g_Renderer.GetOverlayRenderMode() == WIREFRAME)
     649           0 :         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
     650             : #endif
     651           0 : }
     652             : 
     653           0 : static void TessellateSphereFace(const CVector3D& a, u16 ai,
     654             :                                  const CVector3D& b, u16 bi,
     655             :                                  const CVector3D& c, u16 ci,
     656             :                                  std::vector<float>& vertexes, std::vector<u16>& indexes, int level)
     657             : {
     658           0 :     if (level == 0)
     659             :     {
     660           0 :         indexes.push_back(ai);
     661           0 :         indexes.push_back(bi);
     662           0 :         indexes.push_back(ci);
     663             :     }
     664             :     else
     665             :     {
     666           0 :         CVector3D d = (a + b).Normalized();
     667           0 :         CVector3D e = (b + c).Normalized();
     668           0 :         CVector3D f = (c + a).Normalized();
     669           0 :         int di = vertexes.size() / 3; vertexes.push_back(d.X); vertexes.push_back(d.Y); vertexes.push_back(d.Z);
     670           0 :         int ei = vertexes.size() / 3; vertexes.push_back(e.X); vertexes.push_back(e.Y); vertexes.push_back(e.Z);
     671           0 :         int fi = vertexes.size() / 3; vertexes.push_back(f.X); vertexes.push_back(f.Y); vertexes.push_back(f.Z);
     672           0 :         TessellateSphereFace(a,ai, d,di, f,fi, vertexes, indexes, level-1);
     673           0 :         TessellateSphereFace(d,di, b,bi, e,ei, vertexes, indexes, level-1);
     674           0 :         TessellateSphereFace(f,fi, e,ei, c,ci, vertexes, indexes, level-1);
     675           0 :         TessellateSphereFace(d,di, e,ei, f,fi, vertexes, indexes, level-1);
     676             :     }
     677           0 : }
     678             : 
     679           0 : static void TessellateSphere(std::vector<float>& vertexes, std::vector<u16>& indexes, int level)
     680             : {
     681             :     /* Start with a tetrahedron, then tessellate */
     682           0 :     float s = sqrtf(0.5f);
     683             : #define VERT(a,b,c) vertexes.push_back(a); vertexes.push_back(b); vertexes.push_back(c);
     684           0 :     VERT(-s,  0, -s);
     685           0 :     VERT( s,  0, -s);
     686           0 :     VERT( s,  0,  s);
     687           0 :     VERT(-s,  0,  s);
     688           0 :     VERT( 0, -1,  0);
     689           0 :     VERT( 0,  1,  0);
     690             : #define FACE(a,b,c) \
     691             :     TessellateSphereFace( \
     692             :         CVector3D(vertexes[a*3], vertexes[a*3+1], vertexes[a*3+2]), a, \
     693             :         CVector3D(vertexes[b*3], vertexes[b*3+1], vertexes[b*3+2]), b, \
     694             :         CVector3D(vertexes[c*3], vertexes[c*3+1], vertexes[c*3+2]), c, \
     695             :         vertexes, indexes, level);
     696           0 :     FACE(0,4,1);
     697           0 :     FACE(1,4,2);
     698           0 :     FACE(2,4,3);
     699           0 :     FACE(3,4,0);
     700           0 :     FACE(1,5,0);
     701           0 :     FACE(2,5,1);
     702           0 :     FACE(3,5,2);
     703           0 :     FACE(0,5,3);
     704             : #undef FACE
     705             : #undef VERT
     706           0 : }
     707             : 
     708           0 : void OverlayRendererInternals::GenerateSphere()
     709             : {
     710           0 :     if (sphereVertexes.empty())
     711           0 :         TessellateSphere(sphereVertexes, sphereIndexes, 3);
     712           0 : }
     713             : 
     714           0 : void OverlayRenderer::RenderSphereOverlays()
     715             : {
     716           0 :     PROFILE3_GPU("overlays (spheres)");
     717             : 
     718             : #if CONFIG2_GLES
     719             : #warning TODO: implement OverlayRenderer::RenderSphereOverlays for GLES
     720             : #else
     721           0 :     if (m->spheres.empty())
     722           0 :         return;
     723             : 
     724           0 :     glDisable(GL_TEXTURE_2D);
     725           0 :     glEnable(GL_BLEND);
     726           0 :     glDepthMask(0);
     727             : 
     728           0 :     CShaderProgramPtr shader;
     729           0 :     CShaderTechniquePtr tech;
     730             : 
     731           0 :     tech = g_Renderer.GetShaderManager().LoadEffect(str_overlay_solid);
     732           0 :     tech->BeginPass();
     733           0 :     shader = tech->GetShader();
     734             : 
     735           0 :     m->GenerateSphere();
     736             : 
     737           0 :     shader->VertexPointer(3, GL_FLOAT, 0, &m->sphereVertexes[0]);
     738             : 
     739           0 :     for (size_t i = 0; i < m->spheres.size(); ++i)
     740             :     {
     741           0 :         SOverlaySphere* sphere = m->spheres[i];
     742             : 
     743           0 :         CMatrix3D transform;
     744           0 :         transform.SetIdentity();
     745           0 :         transform.Scale(sphere->m_Radius, sphere->m_Radius, sphere->m_Radius);
     746           0 :         transform.Translate(sphere->m_Center);
     747             : 
     748           0 :         shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection());
     749           0 :         shader->Uniform(str_instancingTransform, transform);
     750             : 
     751           0 :         shader->Uniform(str_color, sphere->m_Color);
     752             : 
     753           0 :         glDrawElements(GL_TRIANGLES, m->sphereIndexes.size(), GL_UNSIGNED_SHORT, &m->sphereIndexes[0]);
     754             : 
     755           0 :         g_Renderer.GetStats().m_DrawCalls++;
     756           0 :         g_Renderer.GetStats().m_OverlayTris = m->sphereIndexes.size()/3;
     757             :     }
     758             : 
     759           0 :     tech->EndPass();
     760             : 
     761           0 :     glDepthMask(1);
     762           0 :     glDisable(GL_BLEND);
     763             : #endif
     764           0 : }

Generated by: LCOV version 1.13