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