Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
HWLightingModelRenderer.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2012 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 "lib/bits.h"
21 #include "lib/ogl.h"
22 #include "lib/sysdep/rtl.h"
23 #include "maths/Vector3D.h"
24 
25 #include "graphics/Color.h"
26 #include "graphics/LightEnv.h"
27 #include "graphics/Model.h"
28 #include "graphics/ModelDef.h"
29 
31 #include "renderer/Renderer.h"
33 #include "renderer/VertexArray.h"
34 
35 
37 {
38  /// Indices are the same for all models, so share them
40 
41  /// Static per-CModelDef vertex array
43 
44  /// UV coordinates are stored in the static array
46 
47  ShaderModelDef(const CModelDefPtr& mdef);
48 };
49 
50 
52  : m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW)
53 {
54  size_t numVertices = mdef->GetNumVertices();
55 
56  m_UV.type = GL_FLOAT;
57  m_UV.elems = 2;
59 
60  m_Array.SetNumVertices(numVertices);
61  m_Array.Layout();
62 
64 
65  ModelRenderer::BuildUV(mdef, UVit, 0);
66 
67  m_Array.Upload();
69 
70  m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3);
75 }
76 
77 
78 struct ShaderModel : public CModelRData
79 {
80  /// Dynamic per-CModel vertex array
82 
83  /// Position and normals/lighting are recalculated on CPU every frame
85  VertexArray::Attribute m_Normal; // valid iff cpuLighting == false
86  VertexArray::Attribute m_Color; // valid iff cpuLighting == true
87 
88  ShaderModel(const void* key) : CModelRData(key), m_Array(GL_DYNAMIC_DRAW) { }
89 };
90 
91 
93 {
95 
96  /**
97  * Scratch space for normal vector calculation.
98  * Only used if cpuLighting == true.
99  * Space is reserved so we don't have to do frequent reallocations.
100  * Allocated with rtl_AllocateAligned(normalsNumVertices*16, 16) for SSE writes.
101  */
102  char* normals;
104 
105  /// Previously prepared modeldef
107 };
108 
109 
110 // Construction and Destruction
112 {
114  m->cpuLighting = cpuLighting;
115  m->normals = NULL;
116  m->normalsNumVertices = 0;
117  m->shadermodeldef = NULL;
118 }
119 
121 {
123 
124  delete m;
125 }
126 
127 
128 // Build model data (and modeldef data if necessary)
130 {
131  CModelDefPtr mdef = model->GetModelDef();
132  ShaderModelDef* shadermodeldef = (ShaderModelDef*)mdef->GetRenderData(m);
133 
134  if (!shadermodeldef)
135  {
136  shadermodeldef = new ShaderModelDef(mdef);
137  mdef->SetRenderData(m, shadermodeldef);
138  }
139 
140  // Build the per-model data
141  ShaderModel* shadermodel = new ShaderModel(key);
142 
143  if (m->cpuLighting)
144  {
145  // Positions must be 16-byte aligned for SSE writes.
146  // We can pack the color after the position; it will be corrupted by
147  // BuildPositionAndNormals, but that's okay since we'll recompute the
148  // colors afterwards.
149 
150  shadermodel->m_Color.type = GL_UNSIGNED_BYTE;
151  shadermodel->m_Color.elems = 4;
152  shadermodel->m_Array.AddAttribute(&shadermodel->m_Color);
153 
154  shadermodel->m_Position.type = GL_FLOAT;
155  shadermodel->m_Position.elems = 3;
156  shadermodel->m_Array.AddAttribute(&shadermodel->m_Position);
157  }
158  else
159  {
160  // Positions and normals must be 16-byte aligned for SSE writes.
161 
162  shadermodel->m_Position.type = GL_FLOAT;
163  shadermodel->m_Position.elems = 4;
164  shadermodel->m_Array.AddAttribute(&shadermodel->m_Position);
165 
166  shadermodel->m_Normal.type = GL_FLOAT;
167  shadermodel->m_Normal.elems = 4;
168  shadermodel->m_Array.AddAttribute(&shadermodel->m_Normal);
169  }
170 
171  shadermodel->m_Array.SetNumVertices(mdef->GetNumVertices());
172  shadermodel->m_Array.Layout();
173 
174  // Verify alignment
175  ENSURE(shadermodel->m_Position.offset % 16 == 0);
176  if (!m->cpuLighting)
177  ENSURE(shadermodel->m_Normal.offset % 16 == 0);
178  ENSURE(shadermodel->m_Array.GetStride() % 16 == 0);
179 
180  return shadermodel;
181 }
182 
183 
184 // Fill in and upload dynamic vertex array
186 {
187  ShaderModel* shadermodel = static_cast<ShaderModel*>(data);
188 
189  if (!m->cpuLighting && (updateflags & RENDERDATA_UPDATE_VERTICES))
190  {
191  // build vertices
194 
195  ModelRenderer::BuildPositionAndNormals(model, Position, Normal);
196 
197  // upload everything to vertex buffer
198  shadermodel->m_Array.Upload();
199  }
200 
201  if (m->cpuLighting && (updateflags & (RENDERDATA_UPDATE_VERTICES|RENDERDATA_UPDATE_COLOR)))
202  {
203  CModelDefPtr mdef = model->GetModelDef();
204  size_t numVertices = mdef->GetNumVertices();
205 
206  // allocate working space for computing normals
207  if (numVertices > m->normalsNumVertices)
208  {
210 
211  size_t newSize = round_up_to_pow2(numVertices);
212  m->normals = (char*)rtl_AllocateAligned(newSize*16, 16);
213  m->normalsNumVertices = newSize;
214  }
215 
218 
219  ModelRenderer::BuildPositionAndNormals(model, Position, Normal);
220 
222 
223  ModelRenderer::BuildColor4ub(model, Normal, Color);
224 
225  // upload everything to vertex buffer
226  shadermodel->m_Array.Upload();
227  }
228 }
229 
230 
231 // Setup one rendering pass
233 {
234  if (m->cpuLighting)
235  ENSURE(streamflags == (streamflags & (STREAM_POS | STREAM_UV0 | STREAM_UV1 | STREAM_COLOR)));
236  else
237  ENSURE(streamflags == (streamflags & (STREAM_POS | STREAM_UV0 | STREAM_UV1 | STREAM_NORMAL)));
238 }
239 
240 // Cleanup one rendering pass
242 {
244 }
245 
246 
247 // Prepare UV coordinates for this modeldef
248 void ShaderModelVertexRenderer::PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def)
249 {
251 
253 
254  if (streamflags & STREAM_UV0)
255  {
256  u8* base = m->shadermodeldef->m_Array.Bind();
257  GLsizei stride = (GLsizei)m->shadermodeldef->m_Array.GetStride();
258 
259  shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, stride, base + m->shadermodeldef->m_UV.offset);
260  }
261 }
262 
263 
264 // Render one model
266 {
267  CModelDefPtr mdldef = model->GetModelDef();
268  ShaderModel* shadermodel = static_cast<ShaderModel*>(data);
269 
270  u8* base = shadermodel->m_Array.Bind();
271  GLsizei stride = (GLsizei)shadermodel->m_Array.GetStride();
272 
273  u8* indexBase = m->shadermodeldef->m_IndexArray.Bind();
274 
275  if (streamflags & STREAM_POS)
276  shader->VertexPointer(3, GL_FLOAT, stride, base + shadermodel->m_Position.offset);
277 
278  if (streamflags & STREAM_NORMAL)
279  shader->NormalPointer(GL_FLOAT, stride, base + shadermodel->m_Normal.offset);
280 
281  if (streamflags & STREAM_COLOR)
282  shader->ColorPointer(3, GL_UNSIGNED_BYTE, stride, base + shadermodel->m_Color.offset);
283 
284  shader->AssertPointersBound();
285 
286  // render the lot
287  size_t numFaces = mdldef->GetNumFaces();
288 
289  if (!g_Renderer.m_SkipSubmit)
290  {
291  // Draw with DrawRangeElements where available, since it might be more efficient
292 #if CONFIG2_GLES
293  glDrawElements(GL_TRIANGLES, (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, indexBase);
294 #else
295  pglDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)mdldef->GetNumVertices()-1,
296  (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, indexBase);
297 #endif
298  }
299 
300  // bump stats
301  g_Renderer.m_Stats.m_DrawCalls++;
302  g_Renderer.m_Stats.m_ModelTris += numFaces;
303 }
304 
void * rtl_AllocateAligned(size_t size, size_t align)
Definition: gcc.cpp:66
VertexArray::Attribute m_Color
#define u8
Definition: types.h:39
static void BuildUV(const CModelDefPtr &mdef, const VertexArrayIterator< float[2]> &UV, int UVset)
BuildUV: Copy UV coordinates into the given vertex array.
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
void EndPass(int streamflags)
EndPass: Cleanup OpenGL state set up by BeginPass.
ShaderModelRendererInternals * m
void RenderModel(const CShaderProgramPtr &shader, int streamflags, CModel *model, CModelRData *data)
RenderModel: Invoke the rendering commands for the given model.
VertexArrayIterator< u16 > GetIterator() const
Gets the iterator over the (only) attribute in this array, i.e. a u16.
Internal data of the ShaderModelRenderer.
#define RENDERDATA_UPDATE_VERTICES
ShaderModel(const void *key)
VertexIndexArray m_IndexArray
Indices are the same for all models, so share them.
void AddAttribute(Attribute *attr)
Definition: VertexArray.cpp:75
VertexArray m_Array
Static per-CModelDef vertex array.
#define RENDERDATA_UPDATE_COLOR
void FreeBackingStore()
static void BuildColor4ub(CModel *model, const VertexArrayIterator< CVector3D > &Normal, const VertexArrayIterator< SColor4ub > &Color)
BuildColor4ub: Build lighting colors for the given model, based on previously calculated world space ...
VertexArray m_Array
Dynamic per-CModel vertex array.
VertexArray::Attribute m_Position
Position and normals/lighting are recalculated on CPU every frame.
A VertexArray that is specialised to handle 16-bit array indices.
Definition: VertexArray.h:212
#define g_Renderer
Definition: Renderer.h:61
void UpdateModelData(CModel *model, CModelRData *data, int updateflags)
UpdateModelData: Calculate per-model data for each frame.
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
T round_up_to_pow2(T x)
round up to next larger power of two.
Definition: bits.h:244
ShaderModelDef * shadermodeldef
Previously prepared modeldef.
static void BuildPositionAndNormals(CModel *model, const VertexArrayIterator< CVector3D > &Position, const VertexArrayIterator< CVector3D > &Normal)
BuildPositionAndNormals: Build animated vertices and normals, transformed into world space...
void PrepareModelDef(const CShaderProgramPtr &shader, int streamflags, const CModelDef &def)
PrepareModelDef: Setup OpenGL state for rendering of models that use the given CModelDef object as ba...
pthread_key_t key
Definition: wpthread.cpp:140
static void BuildIndices(const CModelDefPtr &mdef, const VertexArrayIterator< u16 > &Indices)
BuildIndices: Create the indices array for the given CModelDef.
void SetNumVertices(size_t num)
Definition: VertexArray.cpp:64
VertexArrayIterator< T > GetIterator() const
void BeginPass(int streamflags)
BeginPass: Setup global OpenGL state for this ModelVertexRenderer.
ShaderModelDef(const CModelDefPtr &mdef)
char * normals
Scratch space for normal vector calculation.
static size_t model
Definition: x86_x64.cpp:211
Class CModelRData: Render data that is maintained per CModel.
Definition: ModelRenderer.h:70
CModelRData * CreateModelData(const void *key, CModel *model)
CreateModelData: Create internal data for one model.
void rtl_FreeAligned(void *alignedPointer)
Definition: gcc.cpp:93
Definition: Model.h:50
const CModelDefPtr & GetModelDef()
Definition: Model.h:99
static void Unbind()
Unbind any currently-bound buffer, so glVertexPointer etc calls will not attempt to use it...
VertexArray::Attribute m_Normal
shared_ptr< CShaderProgram > CShaderProgramPtr
size_t GetStride() const
Definition: VertexArray.h:169
CModelDefRPrivate * GetRenderData(const void *key) const
Definition: ModelDef.cpp:465
VertexArray::Attribute m_UV
UV coordinates are stored in the static array.
boost::shared_ptr< CModelDef > CModelDefPtr
Definition: MeshManager.h:27