Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ParticleRenderer.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2011 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 "ParticleRenderer.h"
21 
23 #include "graphics/ShaderManager.h"
25 #include "ps/Profile.h"
26 #include "renderer/Renderer.h"
27 
29 {
32  std::vector<CParticleEmitter*> emitters;
33 };
34 
36 {
38 }
39 
41 {
42  delete m;
43 }
44 
46 {
47  m->emitters.push_back(emitter);
48 }
49 
51 {
52  m->emitters.clear();
53  // this should leave the capacity unchanged, which is okay since it
54  // won't be very large or very variable
55 }
56 
58 {
60 
61  // TODO: if this is slow, we should pre-compute the distance for each emitter
62 
63  bool operator()(CParticleEmitter* const& a, CParticleEmitter* const& b)
64  {
65  CVector3D posa = a->GetPosition();
66  CVector3D posb = b->GetPosition();
67  if (posa == posb)
68  return false;
69  float dista = worldToCam.Transform(posa).LengthSquared();
70  float distb = worldToCam.Transform(posb).LengthSquared();
71  return distb < dista;
72  }
73 
75 };
76 
78 {
79  PROFILE3("prepare particles");
80 
81  // Can't load the shader in the constructor because it's called before the
82  // renderer initialisation is complete, so load it the first time through here
83  if (!m->shader)
84  {
85  // Only construct the shaders when shaders are supported and enabled; otherwise
86  // RenderParticles will never be called so it's safe to leave the shaders as null
87  if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
88  {
89  m->shader = g_Renderer.GetShaderManager().LoadEffect(str_particle, context, CShaderDefines());
90  m->shaderSolid = g_Renderer.GetShaderManager().LoadEffect(str_particle_solid, context, CShaderDefines());
91  }
92  }
93 
94  {
95  PROFILE("update emitters");
96  for (size_t i = 0; i < m->emitters.size(); ++i)
97  {
98  CParticleEmitter* emitter = m->emitters[i];
99  emitter->UpdateArrayData();
100  }
101  }
102 
103  {
104  // Sort back-to-front by distance from camera
105  PROFILE("sort emitters");
106  CMatrix3D worldToCam;
107  g_Renderer.GetViewCamera().m_Orientation.GetInverse(worldToCam);
108  std::stable_sort(m->emitters.begin(), m->emitters.end(), SortEmitterDistance(worldToCam));
109  }
110 
111  // TODO: should batch by texture here when possible, maybe
112 }
113 
115 {
116  CShaderTechniquePtr shader = solidColor ? m->shaderSolid : m->shader;
117 
118  shader->BeginPass();
119 
120  shader->GetShader()->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection());
121 
122  if (!solidColor)
123  glEnable(GL_BLEND);
124  glDepthMask(0);
125 
126  for (size_t i = 0; i < m->emitters.size(); ++i)
127  {
128  CParticleEmitter* emitter = m->emitters[i];
129 
130  emitter->Bind(shader->GetShader());
131  emitter->RenderArray(shader->GetShader());
132  }
133 
135 
136  pglBlendEquationEXT(GL_FUNC_ADD);
137  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
138 
139  glDisable(GL_BLEND);
140  glDepthMask(1);
141 
142  shader->EndPass();
143 }
144 
146 {
147  for (size_t i = 0; i < m->emitters.size(); ++i)
148  {
149  CParticleEmitter* emitter = m->emitters[i];
150 
151  CBoundingBoxAligned bounds = emitter->m_Type->CalculateBounds(emitter->GetPosition(), emitter->GetParticleBounds());
152  bounds.Render(shader);
153  }
154 }
void RenderBounds(CShaderProgramPtr &shader)
Render bounding boxes for all the submitted emitters.
Particle emitter.
void UpdateArrayData()
Update particle and vertex array data.
void RenderParticles(bool solidColor=false)
Render all the submitted particles.
void EndFrame()
Reset the list of submitted overlays.
CShaderTechniquePtr shader
CVector3D Transform(const CVector3D &vector) const
Definition: Matrix3D.h:272
shared_ptr< CShaderTechnique > CShaderTechniquePtr
SortEmitterDistance(const CMatrix3D &m)
void RenderArray(const CShaderProgramPtr &shader)
Draw the vertex array.
CShaderTechniquePtr shaderSolid
#define g_Renderer
Definition: Renderer.h:61
std::vector< CParticleEmitter * > emitters
void Bind(const CShaderProgramPtr &shader)
Bind rendering state (textures and blend modes).
void PrepareForRendering(const CShaderDefines &context)
Prepare internal data structures for rendering.
#define PROFILE(name)
Definition: Profile.h:195
CBoundingBoxAligned GetParticleBounds()
Get the bounding box of the center points of particles at their current positions.
void Submit(CParticleEmitter *emitter)
Add an emitter for rendering in this frame.
Represents a mapping of name strings to value strings, for use with #if and #ifdef and similar condit...
#define PROFILE3(name)
Definition: Profile.h:201
ParticleRendererInternals * m
float LengthSquared() const
Definition: Vector3D.cpp:67
static void Unbind()
Unbind any currently-bound buffer, so glVertexPointer etc calls will not attempt to use it...
CVector3D GetPosition() const
void Render(CShaderProgramPtr &shader) const
Render: Render the surfaces of the bound object as triangles.
shared_ptr< CShaderProgram > CShaderProgramPtr
bool operator()(CParticleEmitter *const &a, CParticleEmitter *const &b)
CParticleEmitterTypePtr m_Type