1 /* Copyright (C) 2018 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 #include "graphics/ShaderProgram.h"
30
31 #include "renderer/HWLightingModelRenderer.h"
32 #include "renderer/Renderer.h"
33 #include "renderer/RenderModifiers.h"
34 #include "renderer/VertexArray.h"
35
36
37 struct ShaderModelDef : public CModelDefRPrivate
38 {
39 /// Indices are the same for all models, so share them
40 VertexIndexArray m_IndexArray;
41
42 /// Static per-CModelDef vertex array
43 VertexArray m_Array;
44
45 /// The number of UVs is determined by the model
46 std::vector<VertexArray::Attribute> m_UVs;
47
48 ShaderModelDef(const CModelDefPtr& mdef);
49 };
50
51
ShaderModelDef(const CModelDefPtr & mdef)52 ShaderModelDef::ShaderModelDef(const CModelDefPtr& mdef)
53 : m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW)
54 {
55 size_t numVertices = mdef->GetNumVertices();
56
57 m_UVs.resize(mdef->GetNumUVsPerVertex());
58 for (size_t i = 0; i < mdef->GetNumUVsPerVertex(); ++i)
59 {
60 m_UVs[i].type = GL_FLOAT;
61 m_UVs[i].elems = 2;
62 m_Array.AddAttribute(&m_UVs[i]);
63 }
64
65 m_Array.SetNumVertices(numVertices);
66 m_Array.Layout();
67
68 for (size_t i = 0; i < mdef->GetNumUVsPerVertex(); ++i)
69 {
70 VertexArrayIterator<float[2]> UVit = m_UVs[i].GetIterator<float[2]>();
71 ModelRenderer::BuildUV(mdef, UVit, i);
72 }
73
74 m_Array.Upload();
75 m_Array.FreeBackingStore();
76
77 m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3);
78 m_IndexArray.Layout();
79 ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator());
80 m_IndexArray.Upload();
81 m_IndexArray.FreeBackingStore();
82 }
83
84
85 struct ShaderModel : public CModelRData
86 {
87 /// Dynamic per-CModel vertex array
88 VertexArray m_Array;
89
90 /// Position and normals/lighting are recalculated on CPU every frame
91 VertexArray::Attribute m_Position;
92 VertexArray::Attribute m_Normal; // valid iff cpuLighting == false
93 VertexArray::Attribute m_Color; // valid iff cpuLighting == true
94
ShaderModelShaderModel95 ShaderModel(const void* key) : CModelRData(key), m_Array(GL_DYNAMIC_DRAW) { }
96 };
97
98
99 struct ShaderModelRendererInternals
100 {
101 bool cpuLighting;
102
103 /**
104 * Scratch space for normal vector calculation.
105 * Only used if cpuLighting == true.
106 * Space is reserved so we don't have to do frequent reallocations.
107 * Allocated with rtl_AllocateAligned(normalsNumVertices*16, 16) for SSE writes.
108 */
109 char* normals;
110 size_t normalsNumVertices;
111
112 /// Previously prepared modeldef
113 ShaderModelDef* shadermodeldef;
114 };
115
116
117 // Construction and Destruction
ShaderModelVertexRenderer(bool cpuLighting)118 ShaderModelVertexRenderer::ShaderModelVertexRenderer(bool cpuLighting)
119 {
120 m = new ShaderModelRendererInternals;
121 m->cpuLighting = cpuLighting;
122 m->normals = NULL;
123 m->normalsNumVertices = 0;
124 m->shadermodeldef = NULL;
125 }
126
~ShaderModelVertexRenderer()127 ShaderModelVertexRenderer::~ShaderModelVertexRenderer()
128 {
129 rtl_FreeAligned(m->normals);
130
131 delete m;
132 }
133
134
135 // Build model data (and modeldef data if necessary)
CreateModelData(const void * key,CModel * model)136 CModelRData* ShaderModelVertexRenderer::CreateModelData(const void* key, CModel* model)
137 {
138 CModelDefPtr mdef = model->GetModelDef();
139 ShaderModelDef* shadermodeldef = (ShaderModelDef*)mdef->GetRenderData(m);
140
141 if (!shadermodeldef)
142 {
143 shadermodeldef = new ShaderModelDef(mdef);
144 mdef->SetRenderData(m, shadermodeldef);
145 }
146
147 // Build the per-model data
148 ShaderModel* shadermodel = new ShaderModel(key);
149
150 if (m->cpuLighting)
151 {
152 // Positions must be 16-byte aligned for SSE writes.
153 // We can pack the color after the position; it will be corrupted by
154 // BuildPositionAndNormals, but that's okay since we'll recompute the
155 // colors afterwards.
156
157 shadermodel->m_Color.type = GL_UNSIGNED_BYTE;
158 shadermodel->m_Color.elems = 4;
159 shadermodel->m_Array.AddAttribute(&shadermodel->m_Color);
160
161 shadermodel->m_Position.type = GL_FLOAT;
162 shadermodel->m_Position.elems = 3;
163 shadermodel->m_Array.AddAttribute(&shadermodel->m_Position);
164 }
165 else
166 {
167 // Positions and normals must be 16-byte aligned for SSE writes.
168
169 shadermodel->m_Position.type = GL_FLOAT;
170 shadermodel->m_Position.elems = 4;
171 shadermodel->m_Array.AddAttribute(&shadermodel->m_Position);
172
173 shadermodel->m_Normal.type = GL_FLOAT;
174 shadermodel->m_Normal.elems = 4;
175 shadermodel->m_Array.AddAttribute(&shadermodel->m_Normal);
176 }
177
178 shadermodel->m_Array.SetNumVertices(mdef->GetNumVertices());
179 shadermodel->m_Array.Layout();
180
181 // Verify alignment
182 ENSURE(shadermodel->m_Position.offset % 16 == 0);
183 if (!m->cpuLighting)
184 ENSURE(shadermodel->m_Normal.offset % 16 == 0);
185 ENSURE(shadermodel->m_Array.GetStride() % 16 == 0);
186
187 return shadermodel;
188 }
189
190
191 // Fill in and upload dynamic vertex array
UpdateModelData(CModel * model,CModelRData * data,int updateflags)192 void ShaderModelVertexRenderer::UpdateModelData(CModel* model, CModelRData* data, int updateflags)
193 {
194 ShaderModel* shadermodel = static_cast<ShaderModel*>(data);
195
196 if (!m->cpuLighting && (updateflags & RENDERDATA_UPDATE_VERTICES))
197 {
198 // build vertices
199 VertexArrayIterator<CVector3D> Position = shadermodel->m_Position.GetIterator<CVector3D>();
200 VertexArrayIterator<CVector3D> Normal = shadermodel->m_Normal.GetIterator<CVector3D>();
201
202 ModelRenderer::BuildPositionAndNormals(model, Position, Normal);
203
204 // upload everything to vertex buffer
205 shadermodel->m_Array.Upload();
206 }
207
208 if (m->cpuLighting && (updateflags & (RENDERDATA_UPDATE_VERTICES|RENDERDATA_UPDATE_COLOR)))
209 {
210 CModelDefPtr mdef = model->GetModelDef();
211 size_t numVertices = mdef->GetNumVertices();
212
213 // allocate working space for computing normals
214 if (numVertices > m->normalsNumVertices)
215 {
216 rtl_FreeAligned(m->normals);
217
218 size_t newSize = round_up_to_pow2(numVertices);
219 m->normals = (char*)rtl_AllocateAligned(newSize*16, 16);
220 m->normalsNumVertices = newSize;
221 }
222
223 VertexArrayIterator<CVector3D> Position = shadermodel->m_Position.GetIterator<CVector3D>();
224 VertexArrayIterator<CVector3D> Normal = VertexArrayIterator<CVector3D>(m->normals, 16);
225
226 ModelRenderer::BuildPositionAndNormals(model, Position, Normal);
227
228 VertexArrayIterator<SColor4ub> Color = shadermodel->m_Color.GetIterator<SColor4ub>();
229
230 ModelRenderer::BuildColor4ub(model, Normal, Color);
231
232 // upload everything to vertex buffer
233 shadermodel->m_Array.Upload();
234 }
235
236 shadermodel->m_Array.PrepareForRendering();
237 }
238
239
240 // Setup one rendering pass
BeginPass(int streamflags)241 void ShaderModelVertexRenderer::BeginPass(int streamflags)
242 {
243 if (m->cpuLighting)
244 ENSURE(streamflags == (streamflags & (STREAM_POS | STREAM_UV0 | STREAM_UV1 | STREAM_COLOR)));
245 else
246 ENSURE(streamflags == (streamflags & (STREAM_POS | STREAM_UV0 | STREAM_UV1 | STREAM_NORMAL)));
247 }
248
249 // Cleanup one rendering pass
EndPass(int UNUSED (streamflags))250 void ShaderModelVertexRenderer::EndPass(int UNUSED(streamflags))
251 {
252 CVertexBuffer::Unbind();
253 }
254
255
256 // Prepare UV coordinates for this modeldef
PrepareModelDef(const CShaderProgramPtr & shader,int streamflags,const CModelDef & def)257 void ShaderModelVertexRenderer::PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def)
258 {
259 m->shadermodeldef = (ShaderModelDef*)def.GetRenderData(m);
260
261 ENSURE(m->shadermodeldef);
262
263 u8* base = m->shadermodeldef->m_Array.Bind();
264 GLsizei stride = (GLsizei)m->shadermodeldef->m_Array.GetStride();
265
266 if (streamflags & STREAM_UV0)
267 shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, stride, base + m->shadermodeldef->m_UVs[0].offset);
268
269 if ((streamflags & STREAM_UV1) && def.GetNumUVsPerVertex() >= 2)
270 shader->TexCoordPointer(GL_TEXTURE1, 2, GL_FLOAT, stride, base + m->shadermodeldef->m_UVs[1].offset);
271 }
272
273
274 // Render one model
RenderModel(const CShaderProgramPtr & shader,int streamflags,CModel * model,CModelRData * data)275 void ShaderModelVertexRenderer::RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data)
276 {
277 CModelDefPtr mdldef = model->GetModelDef();
278 ShaderModel* shadermodel = static_cast<ShaderModel*>(data);
279
280 u8* base = shadermodel->m_Array.Bind();
281 GLsizei stride = (GLsizei)shadermodel->m_Array.GetStride();
282
283 u8* indexBase = m->shadermodeldef->m_IndexArray.Bind();
284
285 if (streamflags & STREAM_POS)
286 shader->VertexPointer(3, GL_FLOAT, stride, base + shadermodel->m_Position.offset);
287
288 if (streamflags & STREAM_NORMAL)
289 shader->NormalPointer(GL_FLOAT, stride, base + shadermodel->m_Normal.offset);
290
291 if (streamflags & STREAM_COLOR)
292 shader->ColorPointer(3, GL_UNSIGNED_BYTE, stride, base + shadermodel->m_Color.offset);
293
294 shader->AssertPointersBound();
295
296 // render the lot
297 size_t numFaces = mdldef->GetNumFaces();
298
299 if (!g_Renderer.m_SkipSubmit)
300 {
301 // Draw with DrawRangeElements where available, since it might be more efficient
302 #if CONFIG2_GLES
303 glDrawElements(GL_TRIANGLES, (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, indexBase);
304 #else
305 pglDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)mdldef->GetNumVertices()-1,
306 (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, indexBase);
307 #endif
308 }
309
310 // bump stats
311 g_Renderer.m_Stats.m_DrawCalls++;
312 g_Renderer.m_Stats.m_ModelTris += numFaces;
313 }
314
315