Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ModelRenderer.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2013 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 
21 #include "lib/allocators/arena.h"
22 #include "lib/ogl.h"
23 #include "maths/Vector3D.h"
24 #include "maths/Vector4D.h"
25 
26 #include "ps/CLogger.h"
27 #include "ps/Profile.h"
28 
29 #include "graphics/Color.h"
30 #include "graphics/LightEnv.h"
31 #include "graphics/Material.h"
32 #include "graphics/Model.h"
33 #include "graphics/ModelDef.h"
34 #include "graphics/ShaderManager.h"
36 
38 #include "renderer/ModelRenderer.h"
40 #include "renderer/Renderer.h"
42 #include "renderer/SkyManager.h"
43 #include "renderer/WaterManager.h"
44 
45 #include <boost/weak_ptr.hpp>
46 
47 #if ARCH_X86_X64
49 #endif
50 
51 ///////////////////////////////////////////////////////////////////////////////////////////////
52 // ModelRenderer implementation
53 
54 #if ARCH_X86_X64
55 static bool g_EnableSSE = false;
56 #endif
57 
59 {
60 #if ARCH_X86_X64
62  g_EnableSSE = true;
63 #endif
64 }
65 
66 // Helper function to copy object-space position and normal vectors into arrays.
68  const CModelDefPtr& mdef,
69  const VertexArrayIterator<CVector3D>& Position,
70  const VertexArrayIterator<CVector3D>& Normal)
71 {
72  size_t numVertices = mdef->GetNumVertices();
73  SModelVertex* vertices = mdef->GetVertices();
74 
75  for(size_t j = 0; j < numVertices; ++j)
76  {
77  Position[j] = vertices[j].m_Coords;
78  Normal[j] = vertices[j].m_Norm;
79  }
80 }
81 
82 // Helper function to transform position and normal vectors into world-space.
84  CModel* model,
85  const VertexArrayIterator<CVector3D>& Position,
86  const VertexArrayIterator<CVector3D>& Normal)
87 {
88  CModelDefPtr mdef = model->GetModelDef();
89  size_t numVertices = mdef->GetNumVertices();
90  SModelVertex* vertices=mdef->GetVertices();
91 
92  if (model->IsSkinned())
93  {
94  // boned model - calculate skinned vertex positions/normals
95 
96  // Avoid the noisy warnings that occur inside SkinPoint/SkinNormal in
97  // some broken situations
98  if (numVertices && vertices[0].m_Blend.m_Bone[0] == 0xff)
99  {
100  LOGERROR(L"Model %ls is boned with unboned animation", mdef->GetName().string().c_str());
101  return;
102  }
103 
104 #if HAVE_SSE
105  if (g_EnableSSE)
106  {
107  CModelDef::SkinPointsAndNormals_SSE(numVertices, Position, Normal, vertices, mdef->GetBlendIndices(), model->GetAnimatedBoneMatrices());
108  }
109  else
110 #endif
111  {
112  CModelDef::SkinPointsAndNormals(numVertices, Position, Normal, vertices, mdef->GetBlendIndices(), model->GetAnimatedBoneMatrices());
113  }
114  }
115  else
116  {
117  PROFILE( "software transform" );
118  // just copy regular positions, transform normals to world space
119  const CMatrix3D& transform = model->GetTransform();
120  const CMatrix3D& invtransform = model->GetInvTransform();
121  for (size_t j=0; j<numVertices; j++)
122  {
123  transform.Transform(vertices[j].m_Coords,Position[j]);
124  invtransform.RotateTransposed(vertices[j].m_Norm,Normal[j]);
125  }
126  }
127 }
128 
129 
130 // Helper function for lighting
132  CModel* model,
133  const VertexArrayIterator<CVector3D>& Normal,
134  const VertexArrayIterator<SColor4ub>& Color)
135 {
136  PROFILE( "lighting vertices" );
137 
138  CModelDefPtr mdef = model->GetModelDef();
139  size_t numVertices = mdef->GetNumVertices();
140  const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
141  CColor shadingColor = model->GetShadingColor();
142 
143  for (size_t j=0; j<numVertices; j++)
144  {
145  RGBColor tempcolor = lightEnv.EvaluateUnitScaled(Normal[j]);
146  tempcolor.X *= shadingColor.r;
147  tempcolor.Y *= shadingColor.g;
148  tempcolor.Z *= shadingColor.b;
149  Color[j] = ConvertRGBColorTo4ub(tempcolor);
150  }
151 }
152 
153 
154 void ModelRenderer::GenTangents(const CModelDefPtr& mdef, std::vector<float>& newVertices, bool gpuSkinning)
155 {
156  MikkTSpace ms(mdef, newVertices, gpuSkinning);
157 
158  ms.generate();
159 }
160 
161 
162 // Copy UV coordinates
164  const CModelDefPtr& mdef,
165  const VertexArrayIterator<float[2]>& UV,
166  int UVset)
167 {
168  size_t numVertices = mdef->GetNumVertices();
169  SModelVertex* vertices = mdef->GetVertices();
170 
171  for (size_t j=0; j < numVertices; ++j)
172  {
173  UV[j][0] = vertices[j].m_UVs[UVset * 2];
174  UV[j][1] = 1.0-vertices[j].m_UVs[UVset * 2 + 1];
175  }
176 }
177 
178 
179 // Build default indices array.
181  const CModelDefPtr& mdef,
182  const VertexArrayIterator<u16>& Indices)
183 {
184  size_t idxidx = 0;
185  SModelFace* faces = mdef->GetFaces();
186 
187  for (size_t j = 0; j < mdef->GetNumFaces(); ++j) {
188  SModelFace& face=faces[j];
189  Indices[idxidx++]=face.m_Verts[0];
190  Indices[idxidx++]=face.m_Verts[1];
191  Indices[idxidx++]=face.m_Verts[2];
192  }
193 }
194 
195 
196 
197 ///////////////////////////////////////////////////////////////////////////////////////////////
198 // ShaderModelRenderer implementation
199 
200 
201 /**
202  * Internal data of the ShaderModelRenderer.
203  *
204  * Separated into the source file to increase implementation hiding (and to
205  * avoid some causes of recompiles).
206  */
208 {
210 
211  /// Back-link to "our" renderer
213 
214  /// ModelVertexRenderer used for vertex transformations
216 
217  /// List of submitted models for rendering in this frame
218  std::vector<CModel*> submissions;
219 };
220 
221 
222 // Construction/Destruction
224 {
225  m = new ShaderModelRendererInternals(this);
226  m->vertexRenderer = vertexrenderer;
227 }
228 
230 {
231  delete m;
232 }
233 
234 // Submit one model.
236 {
237  CModelDefPtr mdef = model->GetModelDef();
238  CModelRData* rdata = (CModelRData*)model->GetRenderData();
239 
240  // Ensure model data is valid
241  const void* key = m->vertexRenderer.get();
242  if (!rdata || rdata->GetKey() != key)
243  {
244  rdata = m->vertexRenderer->CreateModelData(key, model);
245  model->SetRenderData(rdata);
246  model->SetDirty(~0u);
247  }
248 
249  m->submissions.push_back(model);
250 }
251 
252 
253 // Call update for all submitted models and enter the rendering phase
255 {
256  for (size_t i = 0; i < m->submissions.size(); ++i)
257  {
258  CModel* model = m->submissions[i];
259 
260  CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData());
261  ENSURE(rdata->GetKey() == m->vertexRenderer.get());
262 
263  m->vertexRenderer->UpdateModelData(model, rdata, rdata->m_UpdateFlags);
264  rdata->m_UpdateFlags = 0;
265  }
266 }
267 
268 
269 // Clear the submissions list
271 {
272  m->submissions.clear();
273 }
274 
275 
276 // Helper structs for ShaderModelRenderer::Render():
277 
279 {
280  size_t techIdx;
282  float dist;
283 };
284 
286 {
287  bool operator()(CModel* a, CModel* b)
288  {
289  if (a->GetModelDef() < b->GetModelDef())
290  return true;
291  if (b->GetModelDef() < a->GetModelDef())
292  return false;
293 
295  return true;
297  return false;
298 
300  }
301 };
302 
304 {
306  {
307  // Prefer items with greater distance, so we draw back-to-front
308  return (a.dist > b.dist);
309 
310  // (Distances will almost always be distinct, so we don't need to bother
311  // tie-breaking on modeldef/texture/etc)
312  }
313 };
314 
316 {
318  : effect(effect), defines(defines) { }
319 
322 
323  bool operator==(const SMRMaterialBucketKey& b) const
324  {
325  return (effect == b.effect && defines == b.defines);
326  }
327 
328 private:
330 };
331 
333 {
334  size_t operator()(const SMRMaterialBucketKey& key) const
335  {
336  size_t hash = 0;
337  boost::hash_combine(hash, key.effect.GetHash());
338  boost::hash_combine(hash, key.defines.GetHash());
339  return hash;
340  }
341 };
342 
344 {
347  size_t numModels;
348 
349  // Model list is stored as pointers, not as a std::vector,
350  // so that sorting lists of this struct is fast
351 };
352 
354 {
355  bool operator()(const SMRTechBucket& a, const SMRTechBucket& b)
356  {
357  return a.tech < b.tech;
358  }
359 };
360 
361 void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShaderDefines& context, int flags)
362 {
363  if (m->submissions.empty())
364  return;
365 
366  CMatrix3D worldToCam;
367  g_Renderer.GetViewCamera().m_Orientation.GetInverse(worldToCam);
368 
369  /*
370  * Rendering approach:
371  *
372  * m->submissions contains the list of CModels to render.
373  *
374  * The data we need to render a model is:
375  * - CShaderTechnique
376  * - CTexture
377  * - CShaderUniforms
378  * - CModelDef (mesh data)
379  * - CModel (model instance data)
380  *
381  * For efficient rendering, we need to batch the draw calls to minimise state changes.
382  * (Uniform and texture changes are assumed to be cheaper than binding new mesh data,
383  * and shader changes are assumed to be most expensive.)
384  * First, group all models that share a technique to render them together.
385  * Within those groups, sub-group by CModelDef.
386  * Within those sub-groups, sub-sub-group by CTexture.
387  * Within those sub-sub-groups, sub-sub-sub-group by CShaderUniforms.
388  *
389  * Alpha-blended models have to be sorted by distance from camera,
390  * then we can batch as long as the order is preserved.
391  * Non-alpha-blended models can be arbitrarily reordered to maximise batching.
392  *
393  * For each model, the CShaderTechnique is derived from:
394  * - The current global 'context' defines
395  * - The CModel's material's defines
396  * - The CModel's material's shader effect name
397  *
398  * There are a smallish number of materials, and a smaller number of techniques.
399  *
400  * To minimise technique lookups, we first group models by material,
401  * in 'materialBuckets' (a hash table).
402  *
403  * For each material bucket we then look up the appropriate shader technique.
404  * If the technique requires sort-by-distance, the model is added to the
405  * 'sortByDistItems' list with its computed distance.
406  * Otherwise, the bucket's list of models is sorted by modeldef+texture+uniforms,
407  * then the technique and model list is added to 'techBuckets'.
408  *
409  * 'techBuckets' is then sorted by technique, to improve batching when multiple
410  * materials map onto the same technique.
411  *
412  * (Note that this isn't perfect batching: we don't sort across models in
413  * multiple buckets that share a technique. In practice that shouldn't reduce
414  * batching much (we rarely have one mesh used with multiple materials),
415  * and it saves on copying and lets us sort smaller lists.)
416  *
417  * Extra tech buckets are added for the sorted-by-distance models without reordering.
418  * Finally we render by looping over each tech bucket, then looping over the model
419  * list in each, rebinding the GL state whenever it changes.
420  */
421 
422  Allocators::DynamicArena arena(256 * KiB);
423  typedef ProxyAllocator<void*, Allocators::DynamicArena > ArenaProxyAllocator;
424  typedef std::vector<CModel*, ArenaProxyAllocator> ModelList_t;
425  typedef boost::unordered_map<SMRMaterialBucketKey, ModelList_t, SMRMaterialBucketKeyHash,
426  std::equal_to<SMRMaterialBucketKey>, ProxyAllocator<void*, Allocators::DynamicArena >
427  > MaterialBuckets_t;
428  MaterialBuckets_t materialBuckets((MaterialBuckets_t::allocator_type(arena)));
429 
430  {
431  PROFILE3("bucketing by material");
432 
433  for (size_t i = 0; i < m->submissions.size(); ++i)
434  {
435  CModel* model = m->submissions[i];
436 
437  uint32_t condFlags = 0;
438 
439  const CShaderConditionalDefines& condefs = model->GetMaterial().GetConditionalDefines();
440  for (size_t j = 0; j < condefs.GetSize(); ++j)
441  {
442  const CShaderConditionalDefines::CondDefine& item = condefs.GetItem(j);
443  int type = item.m_CondType;
444  switch (type)
445  {
446  case DCOND_DISTANCE:
447  {
448  CVector3D modelpos = model->GetTransform().GetTranslation();
449  float dist = worldToCam.Transform(modelpos).Z;
450 
451  float dmin = item.m_CondArgs[0];
452  float dmax = item.m_CondArgs[1];
453 
454  if ((dmin < 0 || dist >= dmin) && (dmax < 0 || dist < dmax))
455  condFlags |= (1 << j);
456 
457  break;
458  }
459  }
460  }
461 
462  CShaderDefines defs = model->GetMaterial().GetShaderDefines(condFlags);
463  SMRMaterialBucketKey key(model->GetMaterial().GetShaderEffect(), defs);
464 
465  MaterialBuckets_t::iterator it = materialBuckets.find(key);
466  if (it == materialBuckets.end())
467  {
468  std::pair<MaterialBuckets_t::iterator, bool> inserted = materialBuckets.insert(
469  std::make_pair(key, ModelList_t(ModelList_t::allocator_type(arena))));
470  inserted.first->second.reserve(32);
471  inserted.first->second.push_back(model);
472  }
473  else
474  {
475  it->second.push_back(model);
476  }
477  }
478  }
479 
480  std::vector<SMRSortByDistItem, ArenaProxyAllocator> sortByDistItems((ArenaProxyAllocator(arena)));
481 
482  std::vector<CShaderTechniquePtr, ArenaProxyAllocator> sortByDistTechs((ArenaProxyAllocator(arena)));
483  // indexed by sortByDistItems[i].techIdx
484  // (which stores indexes instead of CShaderTechniquePtr directly
485  // to avoid the shared_ptr copy cost when sorting; maybe it'd be better
486  // if we just stored raw CShaderTechnique* and assumed the shader manager
487  // will keep it alive long enough)
488 
489  std::vector<SMRTechBucket, ArenaProxyAllocator> techBuckets((ArenaProxyAllocator(arena)));
490 
491  {
492  PROFILE3("processing material buckets");
493  for (MaterialBuckets_t::iterator it = materialBuckets.begin(); it != materialBuckets.end(); ++it)
494  {
495  CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(it->first.effect, context, it->first.defines);
496 
497  // Skip invalid techniques (e.g. from data file errors)
498  if (!tech)
499  continue;
500 
501  if (tech->GetSortByDistance())
502  {
503  // Add the tech into a vector so we can index it
504  // (There might be duplicates in this list, but that doesn't really matter)
505  if (sortByDistTechs.empty() || sortByDistTechs.back() != tech)
506  sortByDistTechs.push_back(tech);
507  size_t techIdx = sortByDistTechs.size()-1;
508 
509  // Add each model into sortByDistItems
510  for (size_t i = 0; i < it->second.size(); ++i)
511  {
512  SMRSortByDistItem itemWithDist;
513  itemWithDist.techIdx = techIdx;
514 
515  CModel* model = it->second[i];
516  itemWithDist.model = model;
517 
518  CVector3D modelpos = model->GetTransform().GetTranslation();
519  itemWithDist.dist = worldToCam.Transform(modelpos).Z;
520 
521  sortByDistItems.push_back(itemWithDist);
522  }
523  }
524  else
525  {
526  // Sort model list by modeldef+texture, for batching
527  // TODO: This only sorts by base texture. While this is an OK approximation
528  // for most cases (as related samplers are usually used together), it would be better
529  // to take all the samplers into account when sorting here.
530  std::sort(it->second.begin(), it->second.end(), SMRBatchModel());
531 
532  // Add a tech bucket pointing at this model list
533  SMRTechBucket techBucket = { tech, &it->second[0], it->second.size() };
534  techBuckets.push_back(techBucket);
535  }
536  }
537  }
538 
539  {
540  PROFILE3("sorting tech buckets");
541  // Sort by technique, for better batching
542  std::sort(techBuckets.begin(), techBuckets.end(), SMRCompareTechBucket());
543  }
544 
545  // List of models corresponding to sortByDistItems[i].model
546  // (This exists primarily because techBuckets wants a CModel**;
547  // we could avoid the cost of copying into this list by adding
548  // a stride length into techBuckets and not requiring contiguous CModel*s)
549  std::vector<CModel*, ArenaProxyAllocator> sortByDistModels((ArenaProxyAllocator(arena)));
550 
551  if (!sortByDistItems.empty())
552  {
553  {
554  PROFILE3("sorting items by dist");
555  std::sort(sortByDistItems.begin(), sortByDistItems.end(), SMRCompareSortByDistItem());
556  }
557 
558  {
559  PROFILE3("batching dist-sorted items");
560 
561  sortByDistModels.reserve(sortByDistItems.size());
562 
563  // Find runs of distance-sorted models that share a technique,
564  // and create a new tech bucket for each run
565 
566  size_t start = 0; // start of current run
567  size_t currentTechIdx = sortByDistItems[start].techIdx;
568 
569  for (size_t end = 0; end < sortByDistItems.size(); ++end)
570  {
571  sortByDistModels.push_back(sortByDistItems[end].model);
572 
573  size_t techIdx = sortByDistItems[end].techIdx;
574  if (techIdx != currentTechIdx)
575  {
576  // Start of a new run - push the old run into a new tech bucket
577  SMRTechBucket techBucket = { sortByDistTechs[currentTechIdx], &sortByDistModels[start], end-start };
578  techBuckets.push_back(techBucket);
579  start = end;
580  currentTechIdx = techIdx;
581  }
582  }
583 
584  // Add the tech bucket for the final run
585  SMRTechBucket techBucket = { sortByDistTechs[currentTechIdx], &sortByDistModels[start], sortByDistItems.size()-start };
586  techBuckets.push_back(techBucket);
587  }
588  }
589 
590  {
591  PROFILE3("rendering bucketed submissions");
592 
593  size_t idxTechStart = 0;
594 
595  // This vector keeps track of texture changes during rendering. It is kept outside the
596  // loops to avoid excessive reallocations. The token allocation of 64 elements
597  // should be plenty, though it is reallocated below (at a cost) if necessary.
598  std::vector<CTexture*, ArenaProxyAllocator> currentTexs((ArenaProxyAllocator(arena)));
599  currentTexs.reserve(64);
600 
601  // texBindings holds the identifier bindings in the shader, which can no longer be defined
602  // statically in the ShaderRenderModifier class. texBindingNames uses interned strings to
603  // keep track of when bindings need to be reevaluated.
604  std::vector<CShaderProgram::Binding, ArenaProxyAllocator> texBindings((ArenaProxyAllocator(arena)));
605  texBindings.reserve(64);
606  std::vector<CStrIntern, ArenaProxyAllocator> texBindingNames((ArenaProxyAllocator(arena)));
607  texBindingNames.reserve(64);
608 
609  while (idxTechStart < techBuckets.size())
610  {
611  CShaderTechniquePtr currentTech = techBuckets[idxTechStart].tech;
612 
613  // Find runs [idxTechStart, idxTechEnd) in techBuckets of the same technique
614  size_t idxTechEnd;
615  for (idxTechEnd = idxTechStart + 1; idxTechEnd < techBuckets.size(); ++idxTechEnd)
616  {
617  if (techBuckets[idxTechEnd].tech != currentTech)
618  break;
619  }
620 
621  // For each of the technique's passes, render all the models in this run
622  for (int pass = 0; pass < currentTech->GetNumPasses(); ++pass)
623  {
624  currentTech->BeginPass(pass);
625 
626  const CShaderProgramPtr& shader = currentTech->GetShader(pass);
627  int streamflags = shader->GetStreamFlags();
628 
629  modifier->BeginPass(shader);
630 
631  m->vertexRenderer->BeginPass(streamflags);
632 
633  // When the shader technique changes, textures need to be
634  // rebound, so ensure there are no remnants from the last pass.
635  // (the vector size is set to 0, but memory is not freed)
636  currentTexs.clear();
637  texBindings.clear();
638  texBindingNames.clear();
639 
640  CModelDef* currentModeldef = NULL;
641  CShaderUniforms currentStaticUniforms;
642 
643  for (size_t idx = idxTechStart; idx < idxTechEnd; ++idx)
644  {
645  CModel** models = techBuckets[idx].models;
646  size_t numModels = techBuckets[idx].numModels;
647  for (size_t i = 0; i < numModels; ++i)
648  {
649  CModel* model = models[i];
650 
651  if (flags && !(model->GetFlags() & flags))
652  continue;
653 
654  const CMaterial::SamplersVector& samplers = model->GetMaterial().GetSamplers();
655  size_t samplersNum = samplers.size();
656 
657  // make sure the vectors are the right virtual sizes, and also
658  // reallocate if there are more samplers than expected.
659  if (currentTexs.size() != samplersNum)
660  {
661  currentTexs.resize(samplersNum, NULL);
662  texBindings.resize(samplersNum, CShaderProgram::Binding());
663  texBindingNames.resize(samplersNum, CStrIntern());
664 
665  // ensure they are definitely empty
666  std::fill(texBindings.begin(), texBindings.end(), CShaderProgram::Binding());
667  std::fill(currentTexs.begin(), currentTexs.end(), (CTexture*)NULL);
668  std::fill(texBindingNames.begin(), texBindingNames.end(), CStrIntern());
669  }
670 
671  // bind the samplers to the shader
672  for (size_t s = 0; s < samplersNum; ++s)
673  {
674  const CMaterial::TextureSampler& samp = samplers[s];
675 
676  CShaderProgram::Binding bind = texBindings[s];
677  // check that the handles are current
678  // and reevaluate them if necessary
679  if (texBindingNames[s] == samp.Name && bind.Active())
680  {
681  bind = texBindings[s];
682  }
683  else
684  {
685  bind = shader->GetTextureBinding(samp.Name);
686  texBindings[s] = bind;
687  texBindingNames[s] = samp.Name;
688  }
689 
690  // same with the actual sampler bindings
691  CTexture* newTex = samp.Sampler.get();
692  if (bind.Active() && newTex != currentTexs[s])
693  {
694  shader->BindTexture(bind, samp.Sampler->GetHandle());
695  currentTexs[s] = newTex;
696  }
697  }
698 
699  // Bind modeldef when it changes
700  CModelDef* newModeldef = model->GetModelDef().get();
701  if (newModeldef != currentModeldef)
702  {
703  currentModeldef = newModeldef;
704  m->vertexRenderer->PrepareModelDef(shader, streamflags, *currentModeldef);
705  }
706 
707  // Bind all uniforms when any change
708  CShaderUniforms newStaticUniforms = model->GetMaterial().GetStaticUniforms();
709  if (newStaticUniforms != currentStaticUniforms)
710  {
711  currentStaticUniforms = newStaticUniforms;
712  currentStaticUniforms.BindUniforms(shader);
713  }
714 
715  const CShaderRenderQueries& renderQueries = model->GetMaterial().GetRenderQueries();
716 
717  for (size_t q = 0; q < renderQueries.GetSize(); q++)
718  {
719  CShaderRenderQueries::RenderQuery rq = renderQueries.GetItem(q);
720  if (rq.first == RQUERY_TIME)
721  {
722  CShaderProgram::Binding binding = shader->GetUniformBinding(rq.second);
723  if (binding.Active())
724  {
725  double time = g_Renderer.GetTimeManager().GetGlobalTime();
726  shader->Uniform(binding, time, 0,0,0);
727  }
728  }
729  else if (rq.first == RQUERY_WATER_TEX)
730  {
731  WaterManager* WaterMgr = g_Renderer.GetWaterManager();
732  double time = WaterMgr->m_WaterTexTimer;
733  double period = 1.6;
734  int curTex = (int)(time*60/period) % 60;
735 
736  if (WaterMgr->m_RenderWater && WaterMgr->WillRenderFancyWater())
737  shader->BindTexture(str_waterTex, WaterMgr->m_NormalMap[curTex]);
738  else
739  shader->BindTexture(str_waterTex, g_Renderer.GetTextureManager().GetErrorTexture());
740  }
741  else if (rq.first == RQUERY_SKY_CUBE)
742  {
743  shader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube());
744  }
745  }
746 
747  modifier->PrepareModel(shader, model);
748 
749  CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData());
750  ENSURE(rdata->GetKey() == m->vertexRenderer.get());
751 
752  m->vertexRenderer->RenderModel(shader, streamflags, model, rdata);
753  }
754  }
755 
756  m->vertexRenderer->EndPass(streamflags);
757 
758  currentTech->EndPass(pass);
759  }
760 
761  idxTechStart = idxTechEnd;
762  }
763  }
764 }
765 
766 void ShaderModelRenderer::Filter(CModelFilter& filter, int passed, int flags)
767 {
768  for (size_t i = 0; i < m->submissions.size(); ++i)
769  {
770  CModel* model = m->submissions[i];
771 
772  if (flags && !(model->GetFlags() & flags))
773  continue;
774 
775  if (filter.Filter(model))
776  model->SetFlags(model->GetFlags() | passed);
777  else
778  model->SetFlags(model->GetFlags() & ~passed);
779  }
780 }
virtual ~ShaderModelRenderer()
CModel ** models
const CShaderRenderQueries & GetRenderQueries() const
Definition: Material.h:75
virtual void EndFrame()
EndFrame: Remove all models from the list of submitted models.
static void BuildUV(const CModelDefPtr &mdef, const VertexArrayIterator< float[2]> &UV, int UVset)
BuildUV: Copy UV coordinates into the given vertex array.
float g
Definition: Overlay.h:57
CVector3D m_Norm
Definition: ModelDef.h:106
#define LOGERROR
Definition: CLogger.h:35
const CMatrix3D & GetInvTransform() const
bool operator()(const SMRSortByDistItem &a, const SMRSortByDistItem &b)
Definition: Overlay.h:34
ShaderModelRendererInternals * m
static void CopyPositionAndNormals(const CModelDefPtr &mdef, const VertexArrayIterator< CVector3D > &Position, const VertexArrayIterator< CVector3D > &Normal)
CopyPositionAndNormals: Copy unanimated object-space vertices and normals into the given vertex array...
size_t operator()(const SMRMaterialBucketKey &key) const
Internal data of the ShaderModelRenderer.
shared_ptr< RenderModifier > RenderModifierPtr
Definition: ModelRenderer.h:34
virtual void Render(const RenderModifierPtr &modifier, const CShaderDefines &context, int flags)
Render: Render submitted models, using the given RenderModifier to setup the fragment stage...
CVector3D Transform(const CVector3D &vector) const
Definition: Matrix3D.h:272
CTexturePtr m_NormalMap[60]
Definition: WaterManager.h:53
shared_ptr< CShaderTechnique > CShaderTechniquePtr
Implementation of ModelRenderer that loads the appropriate shaders for rendering each model...
CShaderDefines defines
bool operator==(const SMRMaterialBucketKey &b) const
virtual void PrepareModels()
PrepareModels: Calculate renderer data for all previously submitted models.
static void BuildColor4ub(CModel *model, const VertexArrayIterator< CVector3D > &Normal, const VertexArrayIterator< SColor4ub > &Color)
BuildColor4ub: Build lighting colors for the given model, based on previously calculated world space ...
Uniform values that need to be evaluated in the renderer.
const CTexturePtr & GetDiffuseTexture() const
Definition: Material.h:50
u16 m_Verts[3]
Definition: ModelDef.h:119
RenderQuery GetItem(size_t i) const
#define g_Renderer
Definition: Renderer.h:61
RGBColor EvaluateUnitScaled(const CVector3D &normal) const
Calculate brightness of a point of a unit with the given normal vector, for rendering with CPU lighti...
Definition: LightEnv.h:100
const CMatrix3D * GetAnimatedBoneMatrices()
Definition: Model.h:195
u32 GetHash() const
Returns cached FNV1-A hash of the string.
Definition: CStrIntern.cpp:135
virtual bool Filter(CModel *model)=0
static void SkinPointsAndNormals(size_t numVertices, const VertexArrayIterator< CVector3D > &Position, const VertexArrayIterator< CVector3D > &Normal, const SModelVertex *vertices, const size_t *blendIndices, const CMatrix3D newPoseMatrices[])
Transform vertices&#39; positions and normals.
Definition: ModelDef.cpp:90
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
static void Init()
Initialise global settings.
CRenderData * GetRenderData()
Return object renderdata - can be null if renderer hasn&#39;t yet created the renderdata.
float b
Definition: Overlay.h:57
friend struct ShaderModelRendererInternals
bool IsSkinned()
Return whether this is a skinned/skeletal model.
Definition: Model.h:192
Interned 8-bit strings.
Definition: CStrIntern.h:37
bool m_RenderWater
Definition: WaterManager.h:75
void BindUniforms(const CShaderProgramPtr &shader) const
Bind the collection of uniforms onto the given shader.
float X
Definition: Vector3D.h:31
static void BuildPositionAndNormals(CModel *model, const VertexArrayIterator< CVector3D > &Position, const VertexArrayIterator< CVector3D > &Normal)
BuildPositionAndNormals: Build animated vertices and normals, transformed into world space...
float Y
Definition: Vector3D.h:31
SMRMaterialBucketKey & operator=(const SMRMaterialBucketKey &)
shared_ptr< ModelVertexRenderer > ModelVertexRendererPtr
Definition: ModelRenderer.h:40
SColor4ub(* ConvertRGBColorTo4ub)(const RGBColor &src)
Definition: Color.cpp:45
static const size_t KiB
Definition: alignment.h:71
pthread_key_t key
Definition: wpthread.cpp:140
void SetRenderData(CRenderData *renderdata)
static void BuildIndices(const CModelDefPtr &mdef, const VertexArrayIterator< u16 > &Indices)
BuildIndices: Create the indices array for the given CModelDef.
Represents a texture object.
void SetDirty(u32 dirtyflags)
void RotateTransposed(const CVector3D &vector, CVector3D &result) const
Definition: Matrix3D.cpp:269
virtual void Submit(CModel *model)
Submit: Submit a model for rendering this frame.
#define PROFILE(name)
Definition: Profile.h:195
ShaderModelRenderer * m_Renderer
Back-link to &quot;our&quot; renderer.
SMRMaterialBucketKey(CStrIntern effect, const CShaderDefines &defines)
size_t GetHash() const
Return a hash of the current mapping.
Represents a mapping of name strings to value strings, for use with #if and #ifdef and similar condit...
Represents a mapping of name strings to value CVector4Ds, for use with uniforms in shaders...
fully STL-compatible allocator that simply draws upon another Allocator.
bool Cap(Caps cap)
Definition: x86_x64.cpp:142
static void GenTangents(const CModelDefPtr &mdef, std::vector< float > &newVertices, bool gpuSkinning)
GenTangents: Generate tangents for the given CModelDef.
bool WillRenderFancyWater()
Returns true if fancy water shaders will be used (i.e.
#define PROFILE3(name)
Definition: Profile.h:201
const SamplersVector & GetSamplers() const
Definition: Material.h:72
CVector3D m_Coords
Definition: ModelDef.h:104
static size_t model
Definition: x86_x64.cpp:211
const CondDefine & GetItem(size_t i) const
unsigned int uint32_t
Definition: wposix_types.h:53
Represents a uniform attribute or texture binding.
Class CModelRData: Render data that is maintained per CModel.
Definition: ModelRenderer.h:70
const CShaderUniforms & GetStaticUniforms() const
Definition: Material.h:69
bool operator()(const SMRTechBucket &a, const SMRTechBucket &b)
std::vector< TextureSampler > SamplersVector
Definition: Material.h:40
bool operator()(CModel *a, CModel *b)
allocator design parameters:
Definition: arena.h:93
float Z
Definition: Vector3D.h:31
double m_WaterTexTimer
Definition: WaterManager.h:102
const CMatrix3D & GetTransform() const
const void * GetKey() const
GetKey: Retrieve the key that can be used to identify the ModelRenderer that created this data...
Definition: ModelRenderer.h:81
Definition: Model.h:50
const CShaderDefines & GetShaderDefines(uint32_t conditionFlags) const
Definition: Material.h:61
virtual CColor GetShadingColor() const
const CModelDefPtr & GetModelDef()
Definition: Model.h:99
ShaderModelRendererInternals(ShaderModelRenderer *r)
ModelVertexRendererPtr vertexRenderer
ModelVertexRenderer used for vertex transformations.
const CShaderConditionalDefines & GetConditionalDefines() const
Definition: Material.h:66
size_t GetSize() const
CMaterial & GetMaterial()
Definition: Model.h:108
CVector3D GetTranslation() const
Definition: Matrix3D.cpp:195
Class CLightEnv: description of a lighting environment - contains all the necessary parameters for re...
Definition: LightEnv.h:36
CStrIntern GetShaderEffect() const
Definition: Material.h:53
virtual void Filter(CModelFilter &filter, int passed, int flags)
Filter: Filter submitted models, setting the passed flags on any models that pass the filter...
CShaderTechniquePtr tech
shared_ptr< CShaderProgram > CShaderProgramPtr
int GetFlags() const
Definition: Model.h:123
std::vector< CModel * > submissions
List of submitted models for rendering in this frame.
void SetFlags(int flags)
Definition: Model.h:121
bool Active()
Returns whether this uniform attribute is active in the shader.
float r
Definition: Overlay.h:57
ShaderModelRenderer(ModelVertexRendererPtr vertexrender)
std::pair< int, CStrIntern > RenderQuery
boost::shared_ptr< CModelDef > CModelDefPtr
Definition: MeshManager.h:27
Class WaterManager: Maintain water settings and textures.
Definition: WaterManager.h:49
std::vector< float > m_UVs
Definition: ModelDef.h:108