1 /* Copyright (C) 2015 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 "DecalRData.h"
22 #include "graphics/Decal.h"
23 #include "graphics/LightEnv.h"
24 #include "graphics/Model.h"
25 #include "graphics/ShaderManager.h"
26 #include "graphics/Terrain.h"
27 #include "graphics/TextureManager.h"
28 #include "ps/CLogger.h"
30 #include "ps/Profile.h"
31 #include "renderer/Renderer.h"
32 #include "renderer/TerrainRenderer.h"
33 #include "simulation2/Simulation2.h"
34 #include "simulation2/components/ICmpWaterManager.h"
36 // TODO: Currently each decal is a separate CDecalRData. We might want to use
37 // lots of decals for special effects like shadows, footprints, etc, in which
38 // case we should probably redesign this to batch them all together for more
39 // efficient rendering.
41 CDecalRData::CDecalRData(CModelDecal
* decal
, CSimulation2
* simulation
)
42 : m_Decal(decal
), m_IndexArray(GL_STATIC_DRAW
), m_Array(GL_STATIC_DRAW
), m_Simulation(simulation
)
44 m_Position
.type
= GL_FLOAT
;
46 m_Array
.AddAttribute(&m_Position
);
48 m_Normal
.type
= GL_FLOAT
;
50 m_Array
.AddAttribute(&m_Normal
);
52 m_DiffuseColor
.type
= GL_UNSIGNED_BYTE
;
53 m_DiffuseColor
.elems
= 4;
54 m_Array
.AddAttribute(&m_DiffuseColor
);
58 m_Array
.AddAttribute(&m_UV
);
63 CDecalRData::~CDecalRData()
67 void CDecalRData::Update(CSimulation2
* simulation
)
69 m_Simulation
= simulation
;
70 if (m_UpdateFlags
!= 0)
77 void CDecalRData::RenderDecals(std::vector
<CDecalRData
*>& decals
, const CShaderDefines
& context
,
78 ShadowMap
* shadow
, bool isDummyShader
, const CShaderProgramPtr
& dummy
)
80 CShaderDefines contextDecal
= context
;
81 contextDecal
.Add(str_DECAL
, str_1
);
83 for (size_t i
= 0; i
< decals
.size(); ++i
)
85 CDecalRData
*decal
= decals
[i
];
87 CMaterial
&material
= decal
->m_Decal
->m_Decal
.m_Material
;
89 if (material
.GetShaderEffect().length() == 0)
91 LOGERROR("Terrain renderer failed to load shader effect.\n");
96 CShaderTechniquePtr techBase
;
100 techBase
= g_Renderer
.GetShaderManager().LoadEffect(
101 material
.GetShaderEffect(), contextDecal
, material
.GetShaderDefines(0));
105 LOGERROR("Terrain renderer failed to load shader effect (%s)\n",
106 material
.GetShaderEffect().string().c_str());
110 numPasses
= techBase
->GetNumPasses();
113 for (int pass
= 0; pass
< numPasses
; ++pass
)
117 techBase
->BeginPass(pass
);
118 TerrainRenderer::PrepareShader(techBase
->GetShader(), shadow
);
121 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
124 const CShaderProgramPtr
& shader
= isDummyShader
? dummy
: techBase
->GetShader(pass
);
126 if (material
.GetSamplers().size() != 0)
128 const CMaterial::SamplersVector
& samplers
= material
.GetSamplers();
129 size_t samplersNum
= samplers
.size();
131 for (size_t s
= 0; s
< samplersNum
; ++s
)
133 const CMaterial::TextureSampler
& samp
= samplers
[s
];
134 shader
->BindTexture(samp
.Name
, samp
.Sampler
);
137 material
.GetStaticUniforms().BindUniforms(shader
);
139 // TODO: Need to handle floating decals correctly. In particular, we need
140 // to render non-floating before water and floating after water (to get
141 // the blending right), and we also need to apply the correct lighting in
142 // each case, which doesn't really seem possible with the current
144 // Also, need to mark the decals as dirty when water height changes.
146 // glDisable(GL_TEXTURE_2D);
147 // m_Decal->GetBounds().Render();
148 // glEnable(GL_TEXTURE_2D);
150 u8
* base
= decal
->m_Array
.Bind();
151 GLsizei stride
= (GLsizei
)decal
->m_Array
.GetStride();
153 u8
* indexBase
= decal
->m_IndexArray
.Bind();
158 glColor3fv(decal
->m_Decal
->GetShadingColor().FloatArray());
164 shader
->Uniform(str_shadingColor
, decal
->m_Decal
->GetShadingColor());
167 shader
->VertexPointer(3, GL_FLOAT
, stride
, base
+ decal
->m_Position
.offset
);
168 shader
->NormalPointer(GL_FLOAT
, stride
, base
+ decal
->m_Normal
.offset
);
169 shader
->ColorPointer(4, GL_UNSIGNED_BYTE
, stride
, base
+ decal
->m_DiffuseColor
.offset
);
170 shader
->TexCoordPointer(GL_TEXTURE0
, 2, GL_FLOAT
, stride
, base
+ decal
->m_UV
.offset
);
172 shader
->AssertPointersBound();
174 if (!g_Renderer
.m_SkipSubmit
)
176 glDrawElements(GL_TRIANGLES
, (GLsizei
)decal
->m_IndexArray
.GetNumVertices(), GL_UNSIGNED_SHORT
, indexBase
);
180 g_Renderer
.m_Stats
.m_DrawCalls
++;
181 g_Renderer
.m_Stats
.m_TerrainTris
+= decal
->m_IndexArray
.GetNumVertices() / 3;
183 CVertexBuffer::Unbind();
195 void CDecalRData::BuildArrays()
197 PROFILE("decal build");
199 const SDecal
& decal
= m_Decal
->m_Decal
;
201 // TODO: Currently this constructs an axis-aligned bounding rectangle around
202 // the decal. It would be more efficient for rendering if we excluded tiles
203 // that are outside the (non-axis-aligned) decal rectangle.
205 ssize_t i0
, j0
, i1
, j1
;
206 m_Decal
->CalcVertexExtents(i0
, j0
, i1
, j1
);
208 // Construct vertex data arrays
210 CmpPtr
<ICmpWaterManager
> cmpWaterManager(*m_Simulation
, SYSTEM_ENTITY
);
212 m_Array
.SetNumVertices((i1
-i0
+1)*(j1
-j0
+1));
214 VertexArrayIterator
<CVector3D
> Position
= m_Position
.GetIterator
<CVector3D
>();
215 VertexArrayIterator
<CVector3D
> Normal
= m_Normal
.GetIterator
<CVector3D
>();
216 VertexArrayIterator
<SColor4ub
> DiffuseColor
= m_DiffuseColor
.GetIterator
<SColor4ub
>();
217 VertexArrayIterator
<float[2]> UV
= m_UV
.GetIterator
<float[2]>();
219 const CLightEnv
& lightEnv
= g_Renderer
.GetLightEnv();
220 bool cpuLighting
= (g_Renderer
.GetRenderPath() == CRenderer::RP_FIXED
);
222 for (ssize_t j
= j0
; j
<= j1
; ++j
)
224 for (ssize_t i
= i0
; i
<= i1
; ++i
)
227 m_Decal
->m_Terrain
->CalcPosition(i
, j
, pos
);
229 if (decal
.m_Floating
&& cmpWaterManager
)
230 pos
.Y
= std::max(pos
.Y
, cmpWaterManager
->GetExactWaterLevel(pos
.X
, pos
.Z
));
236 m_Decal
->m_Terrain
->CalcNormal(i
, j
, normal
);
240 *DiffuseColor
= cpuLighting
? lightEnv
.EvaluateTerrainDiffuseScaled(normal
) : lightEnv
.EvaluateTerrainDiffuseFactor(normal
);
243 // Map from world space back into decal texture space
244 CVector3D inv
= m_Decal
->GetInvTransform().Transform(pos
);
245 (*UV
)[0] = 0.5f
+ (inv
.X
- decal
.m_OffsetX
) / decal
.m_SizeX
;
246 (*UV
)[1] = 0.5f
- (inv
.Z
- decal
.m_OffsetZ
) / decal
.m_SizeZ
; // flip V to match our texture convention
252 m_Array
.FreeBackingStore();
254 // Construct index arrays for each terrain tile
256 m_IndexArray
.SetNumVertices((i1
-i0
)*(j1
-j0
)*6);
257 m_IndexArray
.Layout();
258 VertexArrayIterator
<u16
> Index
= m_IndexArray
.GetIterator();
262 for (ssize_t dj
= 0; dj
< j1
-j0
; ++dj
)
264 for (ssize_t di
= 0; di
< i1
-i0
; ++di
)
266 bool dir
= m_Decal
->m_Terrain
->GetTriangulationDir(i0
+di
, j0
+dj
);
269 *Index
++ = u16(((dj
+0)*w
+(di
+0))+base
);
270 *Index
++ = u16(((dj
+0)*w
+(di
+1))+base
);
271 *Index
++ = u16(((dj
+1)*w
+(di
+0))+base
);
273 *Index
++ = u16(((dj
+0)*w
+(di
+1))+base
);
274 *Index
++ = u16(((dj
+1)*w
+(di
+1))+base
);
275 *Index
++ = u16(((dj
+1)*w
+(di
+0))+base
);
279 *Index
++ = u16(((dj
+0)*w
+(di
+0))+base
);
280 *Index
++ = u16(((dj
+0)*w
+(di
+1))+base
);
281 *Index
++ = u16(((dj
+1)*w
+(di
+1))+base
);
283 *Index
++ = u16(((dj
+1)*w
+(di
+1))+base
);
284 *Index
++ = u16(((dj
+1)*w
+(di
+0))+base
);
285 *Index
++ = u16(((dj
+0)*w
+(di
+0))+base
);
290 m_IndexArray
.Upload();
291 m_IndexArray
.FreeBackingStore();