Merge 'remotes/trunk'
[0ad.git] / source / renderer / HWLightingModelRenderer.cpp
blobb7b69499b17f96279e65249ac24805f69095dde9
1 /* Copyright (C) 2012 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 "lib/bits.h"
21 #include "lib/ogl.h"
22 #include "lib/sysdep/rtl.h"
23 #include "maths/Vector3D.h"
25 #include "graphics/Color.h"
26 #include "graphics/LightEnv.h"
27 #include "graphics/Model.h"
28 #include "graphics/ModelDef.h"
29 #include "graphics/ShaderProgram.h"
31 #include "renderer/HWLightingModelRenderer.h"
32 #include "renderer/Renderer.h"
33 #include "renderer/RenderModifiers.h"
34 #include "renderer/VertexArray.h"
37 struct ShaderModelDef : public CModelDefRPrivate
39 /// Indices are the same for all models, so share them
40 VertexIndexArray m_IndexArray;
42 /// Static per-CModelDef vertex array
43 VertexArray m_Array;
45 /// UV coordinates are stored in the static array
46 VertexArray::Attribute m_UV;
48 ShaderModelDef(const CModelDefPtr& mdef);
52 ShaderModelDef::ShaderModelDef(const CModelDefPtr& mdef)
53 : m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW)
55 size_t numVertices = mdef->GetNumVertices();
57 m_UV.type = GL_FLOAT;
58 m_UV.elems = 2;
59 m_Array.AddAttribute(&m_UV);
61 m_Array.SetNumVertices(numVertices);
62 m_Array.Layout();
64 VertexArrayIterator<float[2]> UVit = m_UV.GetIterator<float[2]>();
66 ModelRenderer::BuildUV(mdef, UVit, 0);
68 m_Array.Upload();
69 m_Array.FreeBackingStore();
71 m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3);
72 m_IndexArray.Layout();
73 ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator());
74 m_IndexArray.Upload();
75 m_IndexArray.FreeBackingStore();
79 struct ShaderModel : public CModelRData
81 /// Dynamic per-CModel vertex array
82 VertexArray m_Array;
84 /// Position and normals/lighting are recalculated on CPU every frame
85 VertexArray::Attribute m_Position;
86 VertexArray::Attribute m_Normal; // valid iff cpuLighting == false
87 VertexArray::Attribute m_Color; // valid iff cpuLighting == true
89 ShaderModel(const void* key) : CModelRData(key), m_Array(GL_DYNAMIC_DRAW) { }
93 struct ShaderModelRendererInternals
95 bool cpuLighting;
97 /**
98 * Scratch space for normal vector calculation.
99 * Only used if cpuLighting == true.
100 * Space is reserved so we don't have to do frequent reallocations.
101 * Allocated with rtl_AllocateAligned(normalsNumVertices*16, 16) for SSE writes.
103 char* normals;
104 size_t normalsNumVertices;
106 /// Previously prepared modeldef
107 ShaderModelDef* shadermodeldef;
111 // Construction and Destruction
112 ShaderModelVertexRenderer::ShaderModelVertexRenderer(bool cpuLighting)
114 m = new ShaderModelRendererInternals;
115 m->cpuLighting = cpuLighting;
116 m->normals = NULL;
117 m->normalsNumVertices = 0;
118 m->shadermodeldef = NULL;
121 ShaderModelVertexRenderer::~ShaderModelVertexRenderer()
123 rtl_FreeAligned(m->normals);
125 delete m;
129 // Build model data (and modeldef data if necessary)
130 CModelRData* ShaderModelVertexRenderer::CreateModelData(const void* key, CModel* model)
132 CModelDefPtr mdef = model->GetModelDef();
133 ShaderModelDef* shadermodeldef = (ShaderModelDef*)mdef->GetRenderData(m);
135 if (!shadermodeldef)
137 shadermodeldef = new ShaderModelDef(mdef);
138 mdef->SetRenderData(m, shadermodeldef);
141 // Build the per-model data
142 ShaderModel* shadermodel = new ShaderModel(key);
144 if (m->cpuLighting)
146 // Positions must be 16-byte aligned for SSE writes.
147 // We can pack the color after the position; it will be corrupted by
148 // BuildPositionAndNormals, but that's okay since we'll recompute the
149 // colors afterwards.
151 shadermodel->m_Color.type = GL_UNSIGNED_BYTE;
152 shadermodel->m_Color.elems = 4;
153 shadermodel->m_Array.AddAttribute(&shadermodel->m_Color);
155 shadermodel->m_Position.type = GL_FLOAT;
156 shadermodel->m_Position.elems = 3;
157 shadermodel->m_Array.AddAttribute(&shadermodel->m_Position);
159 else
161 // Positions and normals must be 16-byte aligned for SSE writes.
163 shadermodel->m_Position.type = GL_FLOAT;
164 shadermodel->m_Position.elems = 4;
165 shadermodel->m_Array.AddAttribute(&shadermodel->m_Position);
167 shadermodel->m_Normal.type = GL_FLOAT;
168 shadermodel->m_Normal.elems = 4;
169 shadermodel->m_Array.AddAttribute(&shadermodel->m_Normal);
172 shadermodel->m_Array.SetNumVertices(mdef->GetNumVertices());
173 shadermodel->m_Array.Layout();
175 // Verify alignment
176 ENSURE(shadermodel->m_Position.offset % 16 == 0);
177 if (!m->cpuLighting)
178 ENSURE(shadermodel->m_Normal.offset % 16 == 0);
179 ENSURE(shadermodel->m_Array.GetStride() % 16 == 0);
181 return shadermodel;
185 // Fill in and upload dynamic vertex array
186 void ShaderModelVertexRenderer::UpdateModelData(CModel* model, CModelRData* data, int updateflags)
188 ShaderModel* shadermodel = static_cast<ShaderModel*>(data);
190 if (!m->cpuLighting && (updateflags & RENDERDATA_UPDATE_VERTICES))
192 // build vertices
193 VertexArrayIterator<CVector3D> Position = shadermodel->m_Position.GetIterator<CVector3D>();
194 VertexArrayIterator<CVector3D> Normal = shadermodel->m_Normal.GetIterator<CVector3D>();
196 ModelRenderer::BuildPositionAndNormals(model, Position, Normal);
198 // upload everything to vertex buffer
199 shadermodel->m_Array.Upload();
202 if (m->cpuLighting && (updateflags & (RENDERDATA_UPDATE_VERTICES|RENDERDATA_UPDATE_COLOR)))
204 CModelDefPtr mdef = model->GetModelDef();
205 size_t numVertices = mdef->GetNumVertices();
207 // allocate working space for computing normals
208 if (numVertices > m->normalsNumVertices)
210 rtl_FreeAligned(m->normals);
212 size_t newSize = round_up_to_pow2(numVertices);
213 m->normals = (char*)rtl_AllocateAligned(newSize*16, 16);
214 m->normalsNumVertices = newSize;
217 VertexArrayIterator<CVector3D> Position = shadermodel->m_Position.GetIterator<CVector3D>();
218 VertexArrayIterator<CVector3D> Normal = VertexArrayIterator<CVector3D>(m->normals, 16);
220 ModelRenderer::BuildPositionAndNormals(model, Position, Normal);
222 VertexArrayIterator<SColor4ub> Color = shadermodel->m_Color.GetIterator<SColor4ub>();
224 ModelRenderer::BuildColor4ub(model, Normal, Color);
226 // upload everything to vertex buffer
227 shadermodel->m_Array.Upload();
230 shadermodel->m_Array.PrepareForRendering();
234 // Setup one rendering pass
235 void ShaderModelVertexRenderer::BeginPass(int streamflags)
237 if (m->cpuLighting)
238 ENSURE(streamflags == (streamflags & (STREAM_POS | STREAM_UV0 | STREAM_UV1 | STREAM_COLOR)));
239 else
240 ENSURE(streamflags == (streamflags & (STREAM_POS | STREAM_UV0 | STREAM_UV1 | STREAM_NORMAL)));
243 // Cleanup one rendering pass
244 void ShaderModelVertexRenderer::EndPass(int UNUSED(streamflags))
246 CVertexBuffer::Unbind();
250 // Prepare UV coordinates for this modeldef
251 void ShaderModelVertexRenderer::PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def)
253 m->shadermodeldef = (ShaderModelDef*)def.GetRenderData(m);
255 ENSURE(m->shadermodeldef);
257 if (streamflags & STREAM_UV0)
259 u8* base = m->shadermodeldef->m_Array.Bind();
260 GLsizei stride = (GLsizei)m->shadermodeldef->m_Array.GetStride();
262 shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, stride, base + m->shadermodeldef->m_UV.offset);
267 // Render one model
268 void ShaderModelVertexRenderer::RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data)
270 CModelDefPtr mdldef = model->GetModelDef();
271 ShaderModel* shadermodel = static_cast<ShaderModel*>(data);
273 u8* base = shadermodel->m_Array.Bind();
274 GLsizei stride = (GLsizei)shadermodel->m_Array.GetStride();
276 u8* indexBase = m->shadermodeldef->m_IndexArray.Bind();
278 if (streamflags & STREAM_POS)
279 shader->VertexPointer(3, GL_FLOAT, stride, base + shadermodel->m_Position.offset);
281 if (streamflags & STREAM_NORMAL)
282 shader->NormalPointer(GL_FLOAT, stride, base + shadermodel->m_Normal.offset);
284 if (streamflags & STREAM_COLOR)
285 shader->ColorPointer(3, GL_UNSIGNED_BYTE, stride, base + shadermodel->m_Color.offset);
287 shader->AssertPointersBound();
289 // render the lot
290 size_t numFaces = mdldef->GetNumFaces();
292 if (!g_Renderer.m_SkipSubmit)
294 // Draw with DrawRangeElements where available, since it might be more efficient
295 #if CONFIG2_GLES
296 glDrawElements(GL_TRIANGLES, (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, indexBase);
297 #else
298 pglDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)mdldef->GetNumVertices()-1,
299 (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, indexBase);
300 #endif
303 // bump stats
304 g_Renderer.m_Stats.m_DrawCalls++;
305 g_Renderer.m_Stats.m_ModelTris += numFaces;