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"
28 #include "maths/MathUtil.h"
29 #include "maths/Quaternion.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"
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.
47 QuadBatchKey (const CTexturePtr
& texture
, const CTexturePtr
& textureMask
)
48 : m_Texture(texture
), m_TextureMask(textureMask
)
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
;
61 * Holds information about a single quad rendering batch.
63 class QuadBatchData
: public CRenderData
66 QuadBatchData() : m_IndicesBase(0), m_NumRenderQuads(0) { }
68 /// Holds the quad overlay structures requested to be rendered in this batch. Must be cleared
70 std::vector
<SOverlayQuad
*> m_Quads
;
72 /// Start index of this batch into the dedicated quad indices VertexArray (see OverlayInternals).
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.
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
)
177 quadIndices
.Upload();
178 quadIndices
.FreeBackingStore();
181 static size_t hash_value(const QuadBatchKey
& d
)
184 boost::hash_combine(seed
, d
.m_Texture
);
185 boost::hash_combine(seed
, d
.m_TextureMask
);
189 OverlayRenderer::OverlayRenderer()
191 m
= new OverlayRendererInternals();
194 OverlayRenderer::~OverlayRenderer()
199 void OverlayRenderer::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())
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()
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())
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
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
;
340 *vertexColor
++ = quadColor
;
341 *vertexColor
++ = quadColor
;
342 *vertexColor
++ = quadColor
;
343 *vertexColor
++ = quadColor
;
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)");
363 #warning TODO: implement OverlayRenderer::RenderOverlaysBeforeWater for GLES
365 pglActiveTextureARB(GL_TEXTURE0
);
366 glDisable(GL_TEXTURE_2D
);
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())
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
);
391 glDepthFunc(GL_LEQUAL
);
396 void OverlayRenderer::RenderOverlaysAfterWater()
398 PROFILE3_GPU("overlays (after)");
400 RenderTexturedOverlayLines();
401 RenderQuadOverlays();
402 RenderSphereOverlays();
405 void OverlayRenderer::RenderTexturedOverlayLines()
408 #warning TODO: implement OverlayRenderer::RenderTexturedOverlayLines for GLES
411 if (m
->texlines
.empty())
416 pglActiveTextureARB(GL_TEXTURE0
);
417 glEnable(GL_TEXTURE_2D
);
421 const char* shaderName
;
422 if (g_Renderer
.GetRenderPath() == CRenderer::RP_SHADER
)
423 shaderName
= "arb/overlayline";
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();
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
)
484 ENSURE(line
->m_RenderData
);
485 line
->m_RenderData
->Render(*line
, shader
);
489 void OverlayRenderer::RenderQuadOverlays()
492 #warning TODO: implement OverlayRenderer::RenderQuadOverlays for GLES
495 if (m
->quadBatchMap
.empty())
500 pglActiveTextureARB(GL_TEXTURE0
);
501 glEnable(GL_TEXTURE_2D
);
505 const char* shaderName
;
506 if (g_Renderer
.GetRenderPath() == CRenderer::RP_SHADER
)
507 shaderName
= "arb/overlayline";
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 // ----------------------------------------------------------------------------------------
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)
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;
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();
580 void OverlayRenderer::RenderForegroundOverlays(const CCamera
& viewCamera
)
582 PROFILE3_GPU("overlays (fg)");
585 #warning TODO: implement OverlayRenderer::RenderForegroundOverlays for GLES
587 pglActiveTextureARB(GL_TEXTURE0
);
588 glEnable(GL_TEXTURE_2D
);
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
);
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]);
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
);
624 sprite
->m_Texture
->Bind();
626 shader
->Uniform(str_colorMul
, sprite
->m_Color
);
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
);
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
)
649 glDisableClientState(GL_VERTEX_ARRAY
);
650 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
652 glEnable(GL_DEPTH_TEST
);
654 glDisable(GL_TEXTURE_2D
);
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
)
665 indexes
.push_back(ai
);
666 indexes
.push_back(bi
);
667 indexes
.push_back(ci
);
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);
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);
713 void OverlayRendererInternals::GenerateSphere()
715 if (sphereVertexes
.empty())
716 TessellateSphere(sphereVertexes
, sphereIndexes
, 3);
719 void OverlayRenderer::RenderSphereOverlays()
721 PROFILE3_GPU("overlays (spheres)");
724 #warning TODO: implement OverlayRenderer::RenderSphereOverlays for GLES
726 if (g_Renderer
.GetRenderPath() != CRenderer::RP_SHADER
)
729 if (m
->spheres
.empty())
732 glDisable(GL_TEXTURE_2D
);
736 glEnableClientState(GL_VERTEX_ARRAY
);
738 CShaderProgramPtr shader
;
739 CShaderTechniquePtr tech
;
741 tech
= g_Renderer
.GetShaderManager().LoadEffect(str_overlay_solid
);
743 shader
= tech
->GetShader();
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
];
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;
770 glDisableClientState(GL_VERTEX_ARRAY
);