Merge 'remotes/trunk'
[0ad.git] / source / renderer / OverlayRenderer.cpp
blob9324169ac9199787c4b8cbf5f48a5b206eb7147b
1 /* Copyright (C) 2015 Wildfire Games.
2 * This file is part of 0 A.D.
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.
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.
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/>.
18 #include "precompiled.h"
20 #include "OverlayRenderer.h"
22 #include <boost/unordered_map.hpp>
23 #include "graphics/LOSTexture.h"
24 #include "graphics/Overlay.h"
25 #include "graphics/Terrain.h"
26 #include "graphics/TextureManager.h"
27 #include "lib/ogl.h"
28 #include "maths/MathUtil.h"
29 #include "maths/Quaternion.h"
30 #include "ps/Game.h"
31 #include "ps/Profile.h"
32 #include "renderer/Renderer.h"
33 #include "renderer/TexturedLineRData.h"
34 #include "renderer/VertexArray.h"
35 #include "renderer/VertexBuffer.h"
36 #include "renderer/VertexBufferManager.h"
37 #include "simulation2/Simulation2.h"
38 #include "simulation2/components/ICmpWaterManager.h"
39 #include "simulation2/system/SimContext.h"
41 /**
42 * Key used to group quads into batches for more efficient rendering. Currently groups by the combination
43 * of the main texture and the texture mask, to minimize texture swapping during rendering.
45 struct QuadBatchKey
47 QuadBatchKey (const CTexturePtr& texture, const CTexturePtr& textureMask)
48 : m_Texture(texture), m_TextureMask(textureMask)
49 { }
51 bool operator==(const QuadBatchKey& other) const
53 return (m_Texture == other.m_Texture && m_TextureMask == other.m_TextureMask);
56 CTexturePtr m_Texture;
57 CTexturePtr m_TextureMask;
60 /**
61 * Holds information about a single quad rendering batch.
63 class QuadBatchData : public CRenderData
65 public:
66 QuadBatchData() : m_IndicesBase(0), m_NumRenderQuads(0) { }
68 /// Holds the quad overlay structures requested to be rendered in this batch. Must be cleared
69 /// after each frame.
70 std::vector<SOverlayQuad*> m_Quads;
72 /// Start index of this batch into the dedicated quad indices VertexArray (see OverlayInternals).
73 size_t m_IndicesBase;
74 /// Amount of quads to actually render in this batch. Potentially (although unlikely to be)
75 /// different from m_Quads.size() due to restrictions on the total amount of quads that can be
76 /// rendered. Must be reset after each frame.
77 size_t m_NumRenderQuads;
80 struct OverlayRendererInternals
82 typedef boost::unordered_map<QuadBatchKey, QuadBatchData> QuadBatchMap;
84 OverlayRendererInternals();
85 ~OverlayRendererInternals(){ }
87 std::vector<SOverlayLine*> lines;
88 std::vector<SOverlayTexturedLine*> texlines;
89 std::vector<SOverlaySprite*> sprites;
90 std::vector<SOverlayQuad*> quads;
91 std::vector<SOverlaySphere*> spheres;
93 QuadBatchMap quadBatchMap;
95 // Dedicated vertex/index buffers for rendering all quads (to within the limits set by
96 // MAX_QUAD_OVERLAYS).
97 VertexArray quadVertices;
98 VertexArray::Attribute quadAttributePos;
99 VertexArray::Attribute quadAttributeColor;
100 VertexArray::Attribute quadAttributeUV;
101 VertexIndexArray quadIndices;
103 /// Maximum amount of quad overlays we support for rendering. This limit is set to be able to
104 /// render all quads from a single dedicated VB without having to reallocate it, which is much
105 /// faster in the typical case of rendering only a handful of quads. When modifying this value,
106 /// you must take care for the new amount of quads to fit in a single VBO (which is not likely
107 /// to be a problem).
108 static const size_t MAX_QUAD_OVERLAYS = 1024;
110 // Sets of commonly-(re)used shader defines.
111 CShaderDefines defsOverlayLineNormal;
112 CShaderDefines defsOverlayLineAlwaysVisible;
113 CShaderDefines defsQuadOverlay;
115 // Geometry for a unit sphere
116 std::vector<float> sphereVertexes;
117 std::vector<u16> sphereIndexes;
118 void GenerateSphere();
120 /// Performs one-time setup. Called from CRenderer::Open, after graphics capabilities have
121 /// been detected. Note that no VBOs must be created before this is called, since the shader
122 /// path and graphics capabilities are not guaranteed to be stable before this point.
123 void Initialize();
126 const float OverlayRenderer::OVERLAY_VOFFSET = 0.2f;
128 OverlayRendererInternals::OverlayRendererInternals()
129 : quadVertices(GL_DYNAMIC_DRAW), quadIndices(GL_STATIC_DRAW)
131 quadAttributePos.elems = 3;
132 quadAttributePos.type = GL_FLOAT;
133 quadVertices.AddAttribute(&quadAttributePos);
135 quadAttributeColor.elems = 4;
136 quadAttributeColor.type = GL_FLOAT;
137 quadVertices.AddAttribute(&quadAttributeColor);
139 quadAttributeUV.elems = 2;
140 quadAttributeUV.type = GL_SHORT; // don't use GL_UNSIGNED_SHORT here, TexCoordPointer won't accept it
141 quadVertices.AddAttribute(&quadAttributeUV);
143 // Note that we're reusing the textured overlay line shader for the quad overlay rendering. This
144 // is because their code is almost identical; the only difference is that for the quad overlays
145 // we want to use a vertex color stream as opposed to an objectColor uniform. To this end, the
146 // shader has been set up to switch between the two behaviours based on the USE_OBJECTCOLOR define.
147 defsOverlayLineNormal.Add(str_USE_OBJECTCOLOR, str_1);
148 defsOverlayLineAlwaysVisible.Add(str_USE_OBJECTCOLOR, str_1);
149 defsOverlayLineAlwaysVisible.Add(str_IGNORE_LOS, str_1);
152 void OverlayRendererInternals::Initialize()
154 // Perform any initialization after graphics capabilities have been detected. Notably,
155 // only at this point can we safely allocate VBOs (in contrast to e.g. in the constructor),
156 // because their creation depends on the shader path, which is not reliably set before this point.
158 quadVertices.SetNumVertices(MAX_QUAD_OVERLAYS * 4);
159 quadVertices.Layout(); // allocate backing store
161 quadIndices.SetNumVertices(MAX_QUAD_OVERLAYS * 6);
162 quadIndices.Layout(); // allocate backing store
164 // Since the quads in the vertex array are independent and always consist of exactly 4 vertices per quad, the
165 // indices are always the same; we can therefore fill in all the indices once and pretty much forget about
166 // them. We then also no longer need its backing store, since we never change any indices afterwards.
167 VertexArrayIterator<u16> index = quadIndices.GetIterator();
168 for (size_t i = 0; i < MAX_QUAD_OVERLAYS; ++i)
170 *index++ = i*4 + 0;
171 *index++ = i*4 + 1;
172 *index++ = i*4 + 2;
173 *index++ = i*4 + 2;
174 *index++ = i*4 + 3;
175 *index++ = i*4 + 0;
177 quadIndices.Upload();
178 quadIndices.FreeBackingStore();
181 static size_t hash_value(const QuadBatchKey& d)
183 size_t seed = 0;
184 boost::hash_combine(seed, d.m_Texture);
185 boost::hash_combine(seed, d.m_TextureMask);
186 return seed;
189 OverlayRenderer::OverlayRenderer()
191 m = new OverlayRendererInternals();
194 OverlayRenderer::~OverlayRenderer()
196 delete m;
199 void OverlayRenderer::Initialize()
201 m->Initialize();
204 void OverlayRenderer::Submit(SOverlayLine* line)
206 ENSURE(line->m_Coords.size() % 3 == 0);
208 m->lines.push_back(line);
211 void OverlayRenderer::Submit(SOverlayTexturedLine* line)
213 // Simplify the rest of the code by guaranteeing non-empty lines
214 if (line->m_Coords.empty())
215 return;
217 ENSURE(line->m_Coords.size() % 2 == 0);
219 m->texlines.push_back(line);
222 void OverlayRenderer::Submit(SOverlaySprite* overlay)
224 m->sprites.push_back(overlay);
227 void OverlayRenderer::Submit(SOverlayQuad* overlay)
229 m->quads.push_back(overlay);
232 void OverlayRenderer::Submit(SOverlaySphere* overlay)
234 m->spheres.push_back(overlay);
237 void OverlayRenderer::EndFrame()
239 m->lines.clear();
240 m->texlines.clear();
241 m->sprites.clear();
242 m->quads.clear();
243 m->spheres.clear();
245 // this should leave the capacity unchanged, which is okay since it
246 // won't be very large or very variable
248 // Empty the batch rendering data structures, but keep their key mappings around for the next frames
249 for (OverlayRendererInternals::QuadBatchMap::iterator it = m->quadBatchMap.begin(); it != m->quadBatchMap.end(); ++it)
251 QuadBatchData& quadBatchData = (it->second);
252 quadBatchData.m_Quads.clear();
253 quadBatchData.m_NumRenderQuads = 0;
254 quadBatchData.m_IndicesBase = 0;
258 void OverlayRenderer::PrepareForRendering()
260 PROFILE3("prepare overlays");
262 // This is where we should do something like sort the overlays by
263 // color/sprite/etc for more efficient rendering
265 for (size_t i = 0; i < m->texlines.size(); ++i)
267 SOverlayTexturedLine* line = m->texlines[i];
268 if (!line->m_RenderData)
270 line->m_RenderData = shared_ptr<CTexturedLineRData>(new CTexturedLineRData());
271 line->m_RenderData->Update(*line);
272 // We assume the overlay line will get replaced by the caller
273 // if terrain changes, so we don't need to detect that here and
274 // call Update again. Also we assume the caller won't change
275 // any of the parameters after first submitting the line.
279 // Group quad overlays by their texture/mask combination for efficient rendering
280 // TODO: consider doing this directly in Submit()
281 for (size_t i = 0; i < m->quads.size(); ++i)
283 SOverlayQuad* const quad = m->quads[i];
285 QuadBatchKey textures(quad->m_Texture, quad->m_TextureMask);
286 QuadBatchData& batchRenderData = m->quadBatchMap[textures]; // will create entry if it doesn't already exist
288 // add overlay to list of quads
289 batchRenderData.m_Quads.push_back(quad);
292 const CVector3D vOffset(0, OverlayRenderer::OVERLAY_VOFFSET, 0);
294 // Write quad overlay vertices/indices to VA backing store
295 VertexArrayIterator<CVector3D> vertexPos = m->quadAttributePos.GetIterator<CVector3D>();
296 VertexArrayIterator<CVector4D> vertexColor = m->quadAttributeColor.GetIterator<CVector4D>();
297 VertexArrayIterator<short[2]> vertexUV = m->quadAttributeUV.GetIterator<short[2]>();
299 size_t indicesIdx = 0;
300 size_t totalNumQuads = 0;
302 for (OverlayRendererInternals::QuadBatchMap::iterator it = m->quadBatchMap.begin(); it != m->quadBatchMap.end(); ++it)
304 QuadBatchData& batchRenderData = (it->second);
305 batchRenderData.m_NumRenderQuads = 0;
307 if (batchRenderData.m_Quads.empty())
308 continue;
310 // Remember the current index into the (entire) indices array as our base offset for this batch
311 batchRenderData.m_IndicesBase = indicesIdx;
313 // points to the index where each iteration's vertices will be appended
314 for (size_t i = 0; i < batchRenderData.m_Quads.size() && totalNumQuads < OverlayRendererInternals::MAX_QUAD_OVERLAYS; i++)
316 const SOverlayQuad* quad = batchRenderData.m_Quads[i];
318 // TODO: this is kind of ugly, the iterator should use a type that can have quad->m_Color assigned
319 // to it directly
320 const CVector4D quadColor(quad->m_Color.r, quad->m_Color.g, quad->m_Color.b, quad->m_Color.a);
322 *vertexPos++ = quad->m_Corners[0] + vOffset;
323 *vertexPos++ = quad->m_Corners[1] + vOffset;
324 *vertexPos++ = quad->m_Corners[2] + vOffset;
325 *vertexPos++ = quad->m_Corners[3] + vOffset;
327 (*vertexUV)[0] = 0;
328 (*vertexUV)[1] = 0;
329 ++vertexUV;
330 (*vertexUV)[0] = 0;
331 (*vertexUV)[1] = 1;
332 ++vertexUV;
333 (*vertexUV)[0] = 1;
334 (*vertexUV)[1] = 1;
335 ++vertexUV;
336 (*vertexUV)[0] = 1;
337 (*vertexUV)[1] = 0;
338 ++vertexUV;
340 *vertexColor++ = quadColor;
341 *vertexColor++ = quadColor;
342 *vertexColor++ = quadColor;
343 *vertexColor++ = quadColor;
345 indicesIdx += 6;
347 totalNumQuads++;
348 batchRenderData.m_NumRenderQuads++;
352 m->quadVertices.Upload();
353 // don't free the backing store! we'll overwrite it on the next frame to save a reallocation.
355 m->quadVertices.PrepareForRendering();
358 void OverlayRenderer::RenderOverlaysBeforeWater()
360 PROFILE3_GPU("overlays (before)");
362 #if CONFIG2_GLES
363 #warning TODO: implement OverlayRenderer::RenderOverlaysBeforeWater for GLES
364 #else
365 pglActiveTextureARB(GL_TEXTURE0);
366 glDisable(GL_TEXTURE_2D);
367 glEnable(GL_BLEND);
369 // Ignore z so that we draw behind terrain (but don't disable GL_DEPTH_TEST
370 // since we still want to write to the z buffer)
371 glDepthFunc(GL_ALWAYS);
373 for (size_t i = 0; i < m->lines.size(); ++i)
375 SOverlayLine* line = m->lines[i];
376 if (line->m_Coords.empty())
377 continue;
379 ENSURE(line->m_Coords.size() % 3 == 0);
381 glColor4fv(line->m_Color.FloatArray());
382 glLineWidth((float)line->m_Thickness);
384 glInterleavedArrays(GL_V3F, sizeof(float)*3, &line->m_Coords[0]);
385 glDrawArrays(GL_LINE_STRIP, 0, (GLsizei)line->m_Coords.size()/3);
388 glDisableClientState(GL_VERTEX_ARRAY);
390 glLineWidth(1.f);
391 glDepthFunc(GL_LEQUAL);
392 glDisable(GL_BLEND);
393 #endif
396 void OverlayRenderer::RenderOverlaysAfterWater()
398 PROFILE3_GPU("overlays (after)");
400 RenderTexturedOverlayLines();
401 RenderQuadOverlays();
402 RenderSphereOverlays();
405 void OverlayRenderer::RenderTexturedOverlayLines()
407 #if CONFIG2_GLES
408 #warning TODO: implement OverlayRenderer::RenderTexturedOverlayLines for GLES
409 return;
410 #endif
411 if (m->texlines.empty())
412 return;
414 ogl_WarnIfError();
416 pglActiveTextureARB(GL_TEXTURE0);
417 glEnable(GL_TEXTURE_2D);
418 glEnable(GL_BLEND);
419 glDepthMask(0);
421 const char* shaderName;
422 if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
423 shaderName = "arb/overlayline";
424 else
425 shaderName = "fixed:overlayline";
427 CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture();
429 CShaderManager& shaderManager = g_Renderer.GetShaderManager();
430 CShaderProgramPtr shaderTexLineNormal(shaderManager.LoadProgram(shaderName, m->defsOverlayLineNormal));
431 CShaderProgramPtr shaderTexLineAlwaysVisible(shaderManager.LoadProgram(shaderName, m->defsOverlayLineAlwaysVisible));
433 // ----------------------------------------------------------------------------------------
435 if (shaderTexLineNormal)
437 shaderTexLineNormal->Bind();
438 shaderTexLineNormal->BindTexture(str_losTex, los.GetTexture());
439 shaderTexLineNormal->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
441 // batch render only the non-always-visible overlay lines using the normal shader
442 RenderTexturedOverlayLines(shaderTexLineNormal, false);
444 shaderTexLineNormal->Unbind();
447 // ----------------------------------------------------------------------------------------
449 if (shaderTexLineAlwaysVisible)
451 shaderTexLineAlwaysVisible->Bind();
452 // TODO: losTex and losTransform are unused in the always visible shader; see if these can be safely omitted
453 shaderTexLineAlwaysVisible->BindTexture(str_losTex, los.GetTexture());
454 shaderTexLineAlwaysVisible->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
456 // batch render only the always-visible overlay lines using the LoS-ignored shader
457 RenderTexturedOverlayLines(shaderTexLineAlwaysVisible, true);
459 shaderTexLineAlwaysVisible->Unbind();
462 // ----------------------------------------------------------------------------------------
464 // TODO: the shaders should probably be responsible for unbinding their textures
465 g_Renderer.BindTexture(1, 0);
466 g_Renderer.BindTexture(0, 0);
468 CVertexBuffer::Unbind();
470 glDepthMask(1);
471 glDisable(GL_BLEND);
474 void OverlayRenderer::RenderTexturedOverlayLines(CShaderProgramPtr shader, bool alwaysVisible)
476 for (size_t i = 0; i < m->texlines.size(); ++i)
478 SOverlayTexturedLine* line = m->texlines[i];
480 // render only those lines matching the requested alwaysVisible status
481 if (!line->m_RenderData || line->m_AlwaysVisible != alwaysVisible)
482 continue;
484 ENSURE(line->m_RenderData);
485 line->m_RenderData->Render(*line, shader);
489 void OverlayRenderer::RenderQuadOverlays()
491 #if CONFIG2_GLES
492 #warning TODO: implement OverlayRenderer::RenderQuadOverlays for GLES
493 return;
494 #endif
495 if (m->quadBatchMap.empty())
496 return;
498 ogl_WarnIfError();
500 pglActiveTextureARB(GL_TEXTURE0);
501 glEnable(GL_TEXTURE_2D);
502 glEnable(GL_BLEND);
503 glDepthMask(0);
505 const char* shaderName;
506 if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
507 shaderName = "arb/overlayline";
508 else
509 shaderName = "fixed:overlayline";
511 CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture();
513 CShaderManager& shaderManager = g_Renderer.GetShaderManager();
514 CShaderProgramPtr shader(shaderManager.LoadProgram(shaderName, m->defsQuadOverlay));
516 // ----------------------------------------------------------------------------------------
518 if (shader)
520 shader->Bind();
521 shader->BindTexture(str_losTex, los.GetTexture());
522 shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
524 // Base offsets (in bytes) of the two backing stores relative to their owner VBO
525 u8* indexBase = m->quadIndices.Bind();
526 u8* vertexBase = m->quadVertices.Bind();
527 GLsizei indexStride = m->quadIndices.GetStride();
528 GLsizei vertexStride = m->quadVertices.GetStride();
530 for (OverlayRendererInternals::QuadBatchMap::iterator it = m->quadBatchMap.begin(); it != m->quadBatchMap.end(); ++it)
532 QuadBatchData& batchRenderData = it->second;
533 const size_t batchNumQuads = batchRenderData.m_NumRenderQuads;
535 // Careful; some drivers don't like drawing calls with 0 stuff to draw.
536 if (batchNumQuads == 0)
537 continue;
539 const QuadBatchKey& maskPair = it->first;
541 shader->BindTexture(str_baseTex, maskPair.m_Texture->GetHandle());
542 shader->BindTexture(str_maskTex, maskPair.m_TextureMask->GetHandle());
544 int streamflags = shader->GetStreamFlags();
546 if (streamflags & STREAM_POS)
547 shader->VertexPointer(m->quadAttributePos.elems, m->quadAttributePos.type, vertexStride, vertexBase + m->quadAttributePos.offset);
549 if (streamflags & STREAM_UV0)
550 shader->TexCoordPointer(GL_TEXTURE0, m->quadAttributeUV.elems, m->quadAttributeUV.type, vertexStride, vertexBase + m->quadAttributeUV.offset);
552 if (streamflags & STREAM_UV1)
553 shader->TexCoordPointer(GL_TEXTURE1, m->quadAttributeUV.elems, m->quadAttributeUV.type, vertexStride, vertexBase + m->quadAttributeUV.offset);
555 if (streamflags & STREAM_COLOR)
556 shader->ColorPointer(m->quadAttributeColor.elems, m->quadAttributeColor.type, vertexStride, vertexBase + m->quadAttributeColor.offset);
558 shader->AssertPointersBound();
559 glDrawElements(GL_TRIANGLES, (GLsizei)(batchNumQuads * 6), GL_UNSIGNED_SHORT, indexBase + indexStride * batchRenderData.m_IndicesBase);
561 g_Renderer.GetStats().m_DrawCalls++;
562 g_Renderer.GetStats().m_OverlayTris += batchNumQuads*2;
565 shader->Unbind();
568 // ----------------------------------------------------------------------------------------
570 // TODO: the shader should probably be responsible for unbinding its textures
571 g_Renderer.BindTexture(1, 0);
572 g_Renderer.BindTexture(0, 0);
574 CVertexBuffer::Unbind();
576 glDepthMask(1);
577 glDisable(GL_BLEND);
580 void OverlayRenderer::RenderForegroundOverlays(const CCamera& viewCamera)
582 PROFILE3_GPU("overlays (fg)");
584 #if CONFIG2_GLES
585 #warning TODO: implement OverlayRenderer::RenderForegroundOverlays for GLES
586 #else
587 pglActiveTextureARB(GL_TEXTURE0);
588 glEnable(GL_TEXTURE_2D);
589 glEnable(GL_BLEND);
590 glDisable(GL_DEPTH_TEST);
592 CVector3D right = -viewCamera.m_Orientation.GetLeft();
593 CVector3D up = viewCamera.m_Orientation.GetUp();
595 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
597 glEnableClientState(GL_VERTEX_ARRAY);
598 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
600 CShaderProgramPtr shader;
601 CShaderTechniquePtr tech;
603 if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
605 tech = g_Renderer.GetShaderManager().LoadEffect(str_foreground_overlay);
606 tech->BeginPass();
607 shader = tech->GetShader();
610 float uvs[8] = { 0,1, 1,1, 1,0, 0,0 };
612 if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
613 shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, sizeof(float)*2, &uvs[0]);
614 else
615 glTexCoordPointer(2, GL_FLOAT, sizeof(float)*2, &uvs);
617 for (size_t i = 0; i < m->sprites.size(); ++i)
619 SOverlaySprite* sprite = m->sprites[i];
621 if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
622 shader->BindTexture(str_baseTex, sprite->m_Texture);
623 else
624 sprite->m_Texture->Bind();
626 shader->Uniform(str_colorMul, sprite->m_Color);
628 CVector3D pos[4] = {
629 sprite->m_Position + right*sprite->m_X0 + up*sprite->m_Y0,
630 sprite->m_Position + right*sprite->m_X1 + up*sprite->m_Y0,
631 sprite->m_Position + right*sprite->m_X1 + up*sprite->m_Y1,
632 sprite->m_Position + right*sprite->m_X0 + up*sprite->m_Y1
635 if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
636 shader->VertexPointer(3, GL_FLOAT, sizeof(float)*3, &pos[0].X);
637 else
638 glVertexPointer(3, GL_FLOAT, sizeof(float)*3, &pos[0].X);
640 glDrawArrays(GL_QUADS, 0, (GLsizei)4);
642 g_Renderer.GetStats().m_DrawCalls++;
643 g_Renderer.GetStats().m_OverlayTris += 2;
646 if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
647 tech->EndPass();
649 glDisableClientState(GL_VERTEX_ARRAY);
650 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
652 glEnable(GL_DEPTH_TEST);
653 glDisable(GL_BLEND);
654 glDisable(GL_TEXTURE_2D);
655 #endif
658 static void TessellateSphereFace(const CVector3D& a, u16 ai,
659 const CVector3D& b, u16 bi,
660 const CVector3D& c, u16 ci,
661 std::vector<float>& vertexes, std::vector<u16>& indexes, int level)
663 if (level == 0)
665 indexes.push_back(ai);
666 indexes.push_back(bi);
667 indexes.push_back(ci);
669 else
671 CVector3D d = (a + b).Normalized();
672 CVector3D e = (b + c).Normalized();
673 CVector3D f = (c + a).Normalized();
674 int di = vertexes.size() / 3; vertexes.push_back(d.X); vertexes.push_back(d.Y); vertexes.push_back(d.Z);
675 int ei = vertexes.size() / 3; vertexes.push_back(e.X); vertexes.push_back(e.Y); vertexes.push_back(e.Z);
676 int fi = vertexes.size() / 3; vertexes.push_back(f.X); vertexes.push_back(f.Y); vertexes.push_back(f.Z);
677 TessellateSphereFace(a,ai, d,di, f,fi, vertexes, indexes, level-1);
678 TessellateSphereFace(d,di, b,bi, e,ei, vertexes, indexes, level-1);
679 TessellateSphereFace(f,fi, e,ei, c,ci, vertexes, indexes, level-1);
680 TessellateSphereFace(d,di, e,ei, f,fi, vertexes, indexes, level-1);
684 static void TessellateSphere(std::vector<float>& vertexes, std::vector<u16>& indexes, int level)
686 /* Start with a tetrahedron, then tessellate */
687 float s = sqrtf(0.5f);
688 #define VERT(a,b,c) vertexes.push_back(a); vertexes.push_back(b); vertexes.push_back(c);
689 VERT(-s, 0, -s);
690 VERT( s, 0, -s);
691 VERT( s, 0, s);
692 VERT(-s, 0, s);
693 VERT( 0, -1, 0);
694 VERT( 0, 1, 0);
695 #define FACE(a,b,c) \
696 TessellateSphereFace( \
697 CVector3D(vertexes[a*3], vertexes[a*3+1], vertexes[a*3+2]), a, \
698 CVector3D(vertexes[b*3], vertexes[b*3+1], vertexes[b*3+2]), b, \
699 CVector3D(vertexes[c*3], vertexes[c*3+1], vertexes[c*3+2]), c, \
700 vertexes, indexes, level);
701 FACE(0,4,1);
702 FACE(1,4,2);
703 FACE(2,4,3);
704 FACE(3,4,0);
705 FACE(1,5,0);
706 FACE(2,5,1);
707 FACE(3,5,2);
708 FACE(0,5,3);
709 #undef FACE
710 #undef VERT
713 void OverlayRendererInternals::GenerateSphere()
715 if (sphereVertexes.empty())
716 TessellateSphere(sphereVertexes, sphereIndexes, 3);
719 void OverlayRenderer::RenderSphereOverlays()
721 PROFILE3_GPU("overlays (spheres)");
723 #if CONFIG2_GLES
724 #warning TODO: implement OverlayRenderer::RenderSphereOverlays for GLES
725 #else
726 if (g_Renderer.GetRenderPath() != CRenderer::RP_SHADER)
727 return;
729 if (m->spheres.empty())
730 return;
732 glDisable(GL_TEXTURE_2D);
733 glEnable(GL_BLEND);
734 glDepthMask(0);
736 glEnableClientState(GL_VERTEX_ARRAY);
738 CShaderProgramPtr shader;
739 CShaderTechniquePtr tech;
741 tech = g_Renderer.GetShaderManager().LoadEffect(str_overlay_solid);
742 tech->BeginPass();
743 shader = tech->GetShader();
745 m->GenerateSphere();
747 shader->VertexPointer(3, GL_FLOAT, 0, &m->sphereVertexes[0]);
749 for (size_t i = 0; i < m->spheres.size(); ++i)
751 SOverlaySphere* sphere = m->spheres[i];
753 CMatrix3D transform;
754 transform.SetIdentity();
755 transform.Scale(sphere->m_Radius, sphere->m_Radius, sphere->m_Radius);
756 transform.Translate(sphere->m_Center);
758 shader->Uniform(str_transform, transform);
760 shader->Uniform(str_color, sphere->m_Color);
762 glDrawElements(GL_TRIANGLES, m->sphereIndexes.size(), GL_UNSIGNED_SHORT, &m->sphereIndexes[0]);
764 g_Renderer.GetStats().m_DrawCalls++;
765 g_Renderer.GetStats().m_OverlayTris = m->sphereIndexes.size()/3;
768 tech->EndPass();
770 glDisableClientState(GL_VERTEX_ARRAY);
772 glDepthMask(1);
773 glDisable(GL_BLEND);
774 #endif