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"
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
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();
59 m_Array
.AddAttribute(&m_UV
);
61 m_Array
.SetNumVertices(numVertices
);
64 VertexArrayIterator
<float[2]> UVit
= m_UV
.GetIterator
<float[2]>();
66 ModelRenderer::BuildUV(mdef
, UVit
, 0);
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
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
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.
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
;
117 m
->normalsNumVertices
= 0;
118 m
->shadermodeldef
= NULL
;
121 ShaderModelVertexRenderer::~ShaderModelVertexRenderer()
123 rtl_FreeAligned(m
->normals
);
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
);
137 shadermodeldef
= new ShaderModelDef(mdef
);
138 mdef
->SetRenderData(m
, shadermodeldef
);
141 // Build the per-model data
142 ShaderModel
* shadermodel
= new ShaderModel(key
);
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
);
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();
176 ENSURE(shadermodel
->m_Position
.offset
% 16 == 0);
178 ENSURE(shadermodel
->m_Normal
.offset
% 16 == 0);
179 ENSURE(shadermodel
->m_Array
.GetStride() % 16 == 0);
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
))
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
)
238 ENSURE(streamflags
== (streamflags
& (STREAM_POS
| STREAM_UV0
| STREAM_UV1
| STREAM_COLOR
)));
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
);
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();
290 size_t numFaces
= mdldef
->GetNumFaces();
292 if (!g_Renderer
.m_SkipSubmit
)
294 // Draw with DrawRangeElements where available, since it might be more efficient
296 glDrawElements(GL_TRIANGLES
, (GLsizei
)numFaces
*3, GL_UNSIGNED_SHORT
, indexBase
);
298 pglDrawRangeElementsEXT(GL_TRIANGLES
, 0, (GLuint
)mdldef
->GetNumVertices()-1,
299 (GLsizei
)numFaces
*3, GL_UNSIGNED_SHORT
, indexBase
);
304 g_Renderer
.m_Stats
.m_DrawCalls
++;
305 g_Renderer
.m_Stats
.m_ModelTris
+= numFaces
;