xoreos  0.0.5
modelnode.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include <cassert>
26 #include <cstring>
27 
28 #include "glm/gtc/type_ptr.hpp"
29 #include "glm/gtc/matrix_transform.hpp"
30 
31 #include "src/common/util.h"
32 #include "src/common/maths.h"
33 #include "src/common/error.h"
34 
35 #include "src/graphics/camera.h"
36 
38 
43 
46 
48 
50 
51 namespace Graphics {
52 
53 namespace Aurora {
54 
55 static bool nodeComp(ModelNode *a, ModelNode *b) {
56  return a->isInFrontOf(*b);
57 }
58 
59 ModelNode::Skin::Skin() : boneMappingCount(0) {
60 }
61 
62 ModelNode::Dangly::Dangly() : period(1.0f), tightness(1.0f), displacement(1.0f),
63  data(0) {
64 }
65 
67 }
68 
69 ModelNode::Mesh::Mesh() : shininess(1.0f), alpha(1.0f), tilefade(0), render(false),
70  shadow(false), beaming(false), inheritcolor(false), rotatetexture(false),
71  isTransparent(false), hasTransparencyHint(false), transparencyHint(false),
72  data(0), dangly(0), skin(0) {
73 }
74 
75 
77  : _model(&model),
78  _parent(0),
79  _attachedModel(0),
80  _level(0),
81  _alpha(1.0f),
82  _render(false),
83  _dirtyRender(true),
84  _dirtyMesh(false),
85  _mesh(0),
86  _rootStateNode(0),
87  _nodeNumber(0),
88  _positionBuffered(false),
89  _orientationBuffered(false),
90  _vertexCoordsBuffered(false) {
91 
92  _position[0] = 0.0f; _position[1] = 0.0f; _position[2] = 0.0f;
93  _rotation[0] = 0.0f; _rotation[1] = 0.0f; _rotation[2] = 0.0f;
94 
95  _orientation[0] = 0.0f;
96  _orientation[1] = 0.0f;
97  _orientation[2] = 0.0f;
98  _orientation[3] = 0.0f;
99 
100  _scale[0] = 1.0f;
101  _scale[1] = 1.0f;
102  _scale[2] = 1.0f;
103 
104  _positionBuffer[0] = 0.0f;
105  _positionBuffer[1] = 0.0f;
106  _positionBuffer[2] = 0.0f;
107 
108  _orientationBuffer[0] = 0.0f;
109  _orientationBuffer[1] = 0.0f;
110  _orientationBuffer[2] = 0.0f;
111  _orientationBuffer[3] = 0.0f;
112 }
113 
115  if (_mesh) {
116  if (_mesh->dangly) {
117  delete _mesh->dangly->data;
118  delete _mesh->dangly;
119  }
120  if (_mesh->skin) {
121  delete _mesh->skin;
122  }
123  if (_mesh->data) {
124  delete _mesh->data;
125  }
126  }
127 
128  delete _mesh;
129  _mesh = 0;
130 
131  delete _attachedModel;
132  _attachedModel = 0;
133 }
134 
136  return _parent;
137 }
138 
140  return _parent;
141 }
142 
144  _parent = parent;
145 
146  if (_parent) {
147  _level = parent->_level + 1;
148  _parent->_children.push_back(this);
149  }
150 }
151 
152 std::list<ModelNode *> &ModelNode::getChildren() {
153  return _children;
154 }
155 
157  return _name;
158 }
159 
160 float ModelNode::getWidth() const {
161  return _boundBox.getWidth() * _model->_scale[0];
162 }
163 
164 float ModelNode::getHeight() const {
165  return _boundBox.getHeight() * _model->_scale[1];
166 }
167 
168 float ModelNode::getDepth() const {
169  return _boundBox.getDepth() * _model->_scale[2];
170 }
171 
172 bool ModelNode::isInFrontOf(const ModelNode &node) const {
173  assert(_model == node._model);
174 
176  return _position[2] > node._position[2];
177 
178  return _position[2] < node._position[2];
179 }
180 
181 void ModelNode::getPosition(float &x, float &y, float &z) const {
182  x = _position[0] * _model->_scale[0];
183  y = _position[1] * _model->_scale[1];
184  z = _position[2] * _model->_scale[2];
185 }
186 
187 void ModelNode::getRotation(float &x, float &y, float &z) const {
188  x = _rotation[0];
189  y = _rotation[1];
190  z = _rotation[2];
191 }
192 
193 void ModelNode::getOrientation(float &x, float &y, float &z, float &a) const {
194  x = _orientation[0];
195  y = _orientation[1];
196  z = _orientation[2];
197  a = _orientation[3];
198 }
199 
200 void ModelNode::getAbsolutePosition(float &x, float &y, float &z) const {
201  x = _absolutePosition[3][0] * _model->_scale[0];
202  y = _absolutePosition[3][1] * _model->_scale[1];
203  z = _absolutePosition[3][2] * _model->_scale[2];
204 }
205 
207  glm::mat4 absolutePosition = _absolutePosition;
208  absolutePosition = glm::scale(absolutePosition, glm::vec3(_model->_scale[0], _model->_scale[1], _model->_scale[2]));
209 
210  return absolutePosition;
211 }
212 
214  return _nodeNumber;
215 }
216 
217 void ModelNode::setPosition(float x, float y, float z) {
219 
220  _position[0] = x / _model->_scale[0];
221  _position[1] = y / _model->_scale[1];
222  _position[2] = z / _model->_scale[2];
223 
224  if (_parent)
226 
228 }
229 
230 void ModelNode::setRotation(float x, float y, float z) {
232 
233  _rotation[0] = x;
234  _rotation[1] = y;
235  _rotation[2] = z;
236 
238 }
239 
240 void ModelNode::setOrientation(float x, float y, float z, float a) {
242 
243  _orientation[0] = x;
244  _orientation[1] = y;
245  _orientation[2] = z;
246  _orientation[3] = a;
247 
249 }
250 
251 void ModelNode::move(float x, float y, float z) {
252  float curX, curY, curZ;
253  getPosition(curX, curY, curZ);
254 
255  setPosition(curX + x, curY + y, curZ + z);
256 }
257 
258 void ModelNode::rotate(float x, float y, float z) {
259  setRotation(_rotation[0] + x, _rotation[1] + y, _rotation[2] + z);
260 }
261 
263  node._position[0] = _position[0];
264  node._position[1] = _position[1];
265  node._position[2] = _position[2];
266 }
267 
269  node._orientation[0] = _orientation[0];
270  node._orientation[1] = _orientation[1];
271  node._orientation[2] = _orientation[2];
272  node._orientation[3] = _orientation[3];
273 }
274 
275 void ModelNode::setEnvironmentMap(const Common::UString &environmentMap) {
276  if (_attachedModel)
277  _attachedModel->setEnvironmentMap(environmentMap);
278 
279  if (!_mesh || !_mesh->data)
280  return;
281 
282  _mesh->data->envMap.clear();
283 
284  if (!environmentMap.empty()) {
285  try {
286  _mesh->data->envMap = TextureMan.get(environmentMap);
287  } catch (...) {
288  }
289  }
290  _dirtyRender = true;
291 }
292 
293 void ModelNode::setInvisible(bool invisible) {
294  _render = !invisible;
295 }
296 
297 void ModelNode::setTextures(const std::vector<Common::UString> &textures) {
298  if (!_mesh || !_mesh->data)
299  return;
300 
302 
303  // NOTE: loadTextures() will automatically disable rendering of the node
304  // again when texture loading fails.
305  _render = true;
306  loadTextures(textures);
307 
309 }
310 
312  _material = material;
313  if (_shaderRenderable) {
315  }
316 }
317 
319  if (!_mesh) {
320  return _alpha;
321  } else {
322  return _mesh->alpha;
323  }
324 }
325 
326 void ModelNode::setAlpha(float alpha, bool isRecursive) {
327  if (!_mesh) {
328  _alpha = alpha;
329  } else {
330  _mesh->alpha = alpha;
331  }
332 
333  if (isRecursive) {
334  for (std::list<ModelNode *>::iterator c = _children.begin(); c != _children.end(); ++c) {
335  (*c)->setAlpha(alpha, true);
336  }
337  }
338 }
339 
340 void ModelNode::loadTextures(const std::vector<Common::UString> &textures) {
341  bool hasTexture = false;
342 
343  _mesh->data->textures.resize(textures.size());
344 
345  bool hasAlpha = true;
346  bool isDecal = true;
347 
348  Common::UString envMap;
349 
350  for (size_t t = 0; t != textures.size(); t++) {
351 
352  try {
353 
354  if (!textures[t].empty() && (textures[t] != "NULL")) {
355  _mesh->data->textures[t] = TextureMan.get(textures[t]);
356  if (_mesh->data->textures[t].empty())
357  continue;
358 
359  hasTexture = true;
360 
361  if (!_mesh->data->textures[t].getTexture().hasAlpha())
362  hasAlpha = false;
363  if (_mesh->data->textures[t].getTexture().getTXI().getFeatures().alphaMean == 1.0f)
364  hasAlpha = false;
365 
366  if (!_mesh->data->textures[t].getTexture().getTXI().getFeatures().decal)
367  isDecal = false;
368 
369  if (!_mesh->data->textures[t].getTexture().getTXI().getFeatures().bumpyShinyTexture.empty())
370  envMap = _mesh->data->textures[t].getTexture().getTXI().getFeatures().bumpyShinyTexture;
371  if (!_mesh->data->textures[t].getTexture().getTXI().getFeatures().envMapTexture.empty())
372  envMap = _mesh->data->textures[t].getTexture().getTXI().getFeatures().envMapTexture;
373  }
374 
375  } catch (...) {
377  }
378 
379  }
380 
381  envMap.trim();
382  if (!envMap.empty()) {
383  try {
384  _mesh->data->envMap = TextureMan.get(envMap);
385  } catch (...) {
387  }
388  }
389 
390  if (_mesh->hasTransparencyHint) {
392  if (isDecal)
393  _mesh->isTransparent = true;
394  } else {
395  _mesh->isTransparent = hasAlpha;
396  }
397 
398  _dirtyRender = true;
399  // If the node has no actual texture, we just assume
400  // that the geometry shouldn't be rendered.
401  if (!hasTexture)
402  _render = false;
403 }
404 
406  _boundBox.clear();
407 
408  if (!_mesh || !_mesh->data)
409  return;
410 
411  VertexBuffer *vertexBuffer = _mesh->data->rawMesh->getVertexBuffer();
412 
413  const VertexDecl &vertexDecl = vertexBuffer->getVertexDecl();
414  for (VertexDecl::const_iterator vA = vertexDecl.begin(); vA != vertexDecl.end(); ++vA) {
415  if (vA->pointer) {
416  if ((vA->index != VPOSITION) || (vA->type != GL_FLOAT))
417  continue;
418 
419  const uint32 stride = MAX<uint32>(vA->size, vA->stride / sizeof(float));
420 
421  const float *vertexData = reinterpret_cast<const float *>(vA->pointer);
422 
423  const float *vX = vertexData + 0;
424  const float *vY = vertexData + 1;
425  const float *vZ = vertexData + 2;
426 
427  for (uint32 v = 0; v < vertexBuffer->getCount(); v++)
428  _boundBox.add(vX[v * stride], vY[v * stride], vZ[v * stride]);
429  }
430  }
431 
432  createCenter();
433 }
434 
436 
437  float minX, minY, minZ, maxX, maxY, maxZ;
438  _boundBox.getMin(minX, minY, minZ);
439  _boundBox.getMax(maxX, maxY, maxZ);
440 
441  _center[0] = minX + ((maxX - minX) / 2.0f);
442  _center[1] = minY + ((maxY - minY) / 2.0f);
443  _center[2] = minZ + ((maxZ - minZ) / 2.0f);
444 }
445 
447  return _absoluteBoundBox;
448 }
449 
451  Common::BoundingBox bound;
452 
453  createAbsoluteBound(bound);
454 }
455 
457  // Transform by our position/orientation/rotation
458  parentPosition.translate(_position[0], _position[1], _position[2]);
459  parentPosition.rotate(_orientation[3], _orientation[0], _orientation[1], _orientation[2]);
460 
461  parentPosition.rotate(_rotation[0], 1.0f, 0.0f, 0.0f);
462  parentPosition.rotate(_rotation[1], 0.0f, 1.0f, 0.0f);
463  parentPosition.rotate(_rotation[2], 0.0f, 0.0f, 1.0f);
464 
465  parentPosition.scale(_scale[0], _scale[1], _scale[2]);
466 
467  // That's our absolute position
468  _absolutePosition = parentPosition.getOrigin();
469 
470 
471  // Add our bounding box, creating the absolute bounding box
472  _absoluteBoundBox = parentPosition;
474 
475  // If this node is empty, add the root state node
476  if (_boundBox.empty()) {
477  ModelNode *rootStateNode = _model->getNode("", _name);
478  if (rootStateNode)
479  _absoluteBoundBox.add(rootStateNode->_boundBox);
480  }
481 
483 
484  // Recurse into the children
485  for (std::list<ModelNode *>::iterator c = _children.begin(); c != _children.end(); ++c) {
486  (*c)->createAbsoluteBound(parentPosition);
487 
488  _absoluteBoundBox.add((*c)->getAbsoluteBound());
489  }
490 
491  if (_attachedModel) {
492  glm::mat4 modelPosition = _absoluteBoundBox.getOrigin();
493 
494  modelPosition = glm::translate(modelPosition, glm::vec3(_attachedModel->_position[0],
497 
498  if (_attachedModel->_orientation[0] != 0 ||
499  _attachedModel->_orientation[1] != 0 ||
500  _attachedModel->_orientation[2] != 0)
501  modelPosition = glm::rotate(modelPosition,
503  glm::vec3(_attachedModel->_orientation[0],
506 
507  modelPosition = glm::scale(modelPosition, glm::vec3(_attachedModel->_scale[0],
509  _attachedModel->_scale[2]));
510 
511 
519  glm::mat4 apos = _attachedModel->_absolutePosition; // Hack part A.
520  _attachedModel->_absolutePosition = modelPosition;
522 
524  _attachedModel->_absolutePosition = apos; // Hack part B.
525  }
526 }
527 
529  _children.sort(nodeComp);
530 
531  // Order the children's children
532  for (std::list<ModelNode *>::iterator c = _children.begin(); c != _children.end(); ++c)
533  (*c)->orderChildren();
534 }
535 
537  renderGeometryNormal(mesh);
538 }
539 
541  for (size_t t = 0; t < mesh.data->textures.size(); t++) {
542  TextureMan.activeTexture(t);
543  TextureMan.set(mesh.data->textures[t]);
544  }
545 
546  if (mesh.data->textures.empty())
547  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
548 
549  mesh.data->rawMesh->renderImmediate();
550 
551  for (size_t t = 0; t < mesh.data->textures.size(); t++) {
552  TextureMan.activeTexture(t);
553  TextureMan.set();
554  }
555 
556  if (mesh.data->textures.empty())
557  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
558 }
559 
561  /* First draw the node with only the environment map, then simply
562  * blend a semi-transparent diffuse texture on top.
563  *
564  * Neverwinter Nights uses this method.
565  */
566 
567  mesh.data->rawMesh->renderBind();
568 
570  mesh.data->rawMesh->render();
571 
572  for (size_t t = 0; t < mesh.data->textures.size(); t++) {
573  TextureMan.activeTexture(t);
575  }
576 
577  mesh.data->rawMesh->render();
578 
579  for (size_t t = 0; t < mesh.data->textures.size(); t++) {
580  TextureMan.activeTexture(t);
581  TextureMan.set();
582  }
583 
584  mesh.data->rawMesh->renderUnbind();
585 }
586 
588  /* First draw the node with diffuse textures, then draw it again with
589  * only the environment map. This performs a more complex blending of
590  * the textures, allowing the color of a transparent diffuse texture
591  * to modulate the color of the environment map.
592  *
593  * KotOR and KotOR2 use this method.
594  */
595 
596  mesh.data->rawMesh->renderBind();
597 
598  if (!mesh.data->textures.empty()) {
599  for (size_t t = 0; t < mesh.data->textures.size(); t++) {
600  TextureMan.activeTexture(t);
602  }
603 
604  glBlendFunc(GL_ONE, GL_ZERO);
605 
606  mesh.data->rawMesh->render();
607 
608  for (size_t t = 0; t < mesh.data->textures.size(); t++) {
609  TextureMan.activeTexture(t);
610  TextureMan.set();
611  }
612 
613  TextureMan.activeTexture(0);
615 
616  glDisable(GL_ALPHA_TEST);
617  glBlendFunc(GL_ZERO, GL_ONE);
618 
619  mesh.data->rawMesh->render();
620  }
621 
622  TextureMan.activeTexture(0);
624 
625  glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
626 
627  mesh.data->rawMesh->render();
628 
629  TextureMan.set();
630 
631  glEnable(GL_ALPHA_TEST);
632  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
633  mesh.data->rawMesh->renderUnbind();
634 }
635 
637  return mesh && mesh->data && mesh->data->rawMesh;
638 }
639 
641  // Apply the node's transformation
642 
643  glTranslatef(_position[0], _position[1], _position[2]);
644  glRotatef(_orientation[3], _orientation[0], _orientation[1], _orientation[2]);
645 
646  glRotatef(_rotation[0], 1.0f, 0.0f, 0.0f);
647  glRotatef(_rotation[1], 0.0f, 1.0f, 0.0f);
648  glRotatef(_rotation[2], 0.0f, 0.0f, 1.0f);
649 
650  glScalef(_scale[0], _scale[1], _scale[2]);
651 
652  Mesh *mesh = _mesh;
653  bool doRender = _render;
654  if (!_model->getState().empty() && !renderableMesh(mesh)) {
655  ModelNode *rootStateNode = _model->getNode("", _name);
656  if (rootStateNode && renderableMesh(rootStateNode->_mesh)) {
657  mesh = rootStateNode->_mesh;
658  doRender = rootStateNode->_render;
659  }
660  }
661 
662  if (_dirtyMesh) {
664  _dirtyMesh = false;
665  }
666 
667  // Render the node's geometry
668 
669  bool isTransparent = mesh && mesh->isTransparent;
670  bool shouldRender = doRender && renderableMesh(mesh);
671  if (((pass == kRenderPassOpaque) && isTransparent) ||
672  ((pass == kRenderPassTransparent) && !isTransparent))
673  shouldRender = false;
674 
675  if (shouldRender)
676  renderGeometry(*mesh);
677 
678  if (_attachedModel) {
679  glPushMatrix();
681  glPopMatrix();
682  }
683 
684  // Render the node's children
685  for (std::list<ModelNode *>::iterator c = _children.begin(); c != _children.end(); ++c) {
686  glPushMatrix();
687  (*c)->render(pass);
688  glPopMatrix();
689  }
690 }
691 
692 void ModelNode::calcRenderTransform(const glm::mat4 &parentTransform) {
693  // Apply the node's transformation
694  _renderTransform = parentTransform;
695  _renderTransform = glm::translate(_renderTransform, glm::vec3(_position[0], _position[1], _position[2]));
696  if (_orientation[0] != 0.0f ||
697  _orientation[1] != 0.0f ||
698  _orientation[2] != 0.0f) {
699  _renderTransform = glm::rotate(_renderTransform,
701  glm::vec3(_orientation[0], _orientation[1], _orientation[2]));
702  }
703  _renderTransform = glm::rotate(_renderTransform, _rotation[0], glm::vec3(1.0f, 0.0f, 0.0f));
704  _renderTransform = glm::rotate(_renderTransform, _rotation[1], glm::vec3(0.0f, 1.0f, 0.0f));
705  _renderTransform = glm::rotate(_renderTransform, _rotation[2], glm::vec3(0.0f, 0.0f, 1.0f));
706  _renderTransform = glm::scale(_renderTransform, glm::vec3(_scale[0], _scale[1], _scale[2]));
707 }
708 
709 void ModelNode::renderImmediate(const glm::mat4 &parentTransform) {
710  calcRenderTransform(parentTransform);
714  /* if (_render) {} */
715 
716  if (_dirtyRender) {
722  buildMaterial();
723  } else {
728  if (_renderableArray.size() == 0) {
729  if (_rootStateNode) {
730  for (size_t i = 0; i < _rootStateNode->_renderableArray.size(); ++i) {
731  _rootStateNode->_renderableArray[i].renderImmediate(_renderTransform, this->getAlpha());
732  }
733  }
734  } else {
735  for (size_t i = 0; i < _renderableArray.size(); ++i) {
736  _renderableArray[i].renderImmediate(_renderTransform, this->getAlpha());
737  }
738  }
739  }
740 
741  if (_attachedModel) {
743  }
744  // Render the node's children
745  for (std::list<ModelNode *>::iterator c = _children.begin(); c != _children.end(); ++c) {
746  (*c)->renderImmediate(_renderTransform);
747  }
748 }
749 
750 void ModelNode::queueRender(const glm::mat4 &parentTransform) {
751  calcRenderTransform(parentTransform);
755  /* if (_render) {} */
756 
757  if (_dirtyRender) {
763  buildMaterial();
764  } else {
769  if (_renderableArray.size() == 0) {
770  if (_rootStateNode) {
771  for (size_t i = 0; i < _rootStateNode->_renderableArray.size(); ++i) {
772  RenderMan.queueRenderable(&(_rootStateNode->_renderableArray[i]), &_renderTransform, this->getAlpha());
773  }
774  }
775  } else {
776  for (size_t i = 0; i < _renderableArray.size(); ++i) {
777  RenderMan.queueRenderable(&_renderableArray[i], &_renderTransform, this->getAlpha());
778  }
779  }
780  }
781 
782  if (_attachedModel) {
784  }
785  // Render the node's children
786  for (std::list<ModelNode *>::iterator c = _children.begin(); c != _children.end(); ++c) {
787  (*c)->queueRender(_renderTransform);
788  }
789 }
790 
791 void ModelNode::drawSkeleton(const glm::mat4 &parent, bool showInvisible) {
792  glm::mat4 mine = parent;
793 
794  if (_orientation[0] != 0 || _orientation[1] != 0 || _orientation[2] != 0)
795  mine = glm::rotate(mine,
797  glm::vec3(_orientation[0], _orientation[1], _orientation[2]));
798 
799  mine = glm::scale(mine, glm::vec3(_scale[0], _scale[1], _scale[2]));
800 
801  if (_render || showInvisible) {
802  glPointSize(5.0f);
803 
804  if (_render)
805  glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
806  else
807  glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
808 
809  glBegin(GL_POINTS);
810  glVertex3f(mine[3][0], mine[3][1], mine[3][2]);
811  glEnd();
812 
813  glLineWidth(2.0f);
814  glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
815 
816  glBegin(GL_LINES);
817  glVertex3f(parent[3][0], parent[3][1], parent[3][2]);
818  glVertex3f(mine[3][0], mine[3][1], mine[3][2]);
819  glEnd();
820  }
821 
822  for (std::list<ModelNode *>::iterator c = _children.begin(); c != _children.end(); ++c)
823  (*c)->drawSkeleton(mine, showInvisible);
824 }
825 
827  _model->lockFrame();
828 }
829 
831  _model->unlockFrame();
832 }
833 
836 }
837 
840 }
841 
842 void ModelNode::setBufferedPosition(float x, float y, float z) {
843  _positionBuffer[0] = x;
844  _positionBuffer[1] = y;
845  _positionBuffer[2] = z;
846  _positionBuffered = true;
847 }
848 
849 void ModelNode::setBufferedOrientation(float x, float y, float z, float angle) {
850  _orientationBuffer[0] = x;
851  _orientationBuffer[1] = y;
852  _orientationBuffer[2] = z;
853  _orientationBuffer[3] = angle;
854  _orientationBuffered = true;
855 }
856 
858  if (_positionBuffered) {
859  _position[0] = _positionBuffer[0] / _model->_scale[0];
860  _position[1] = _positionBuffer[1] / _model->_scale[1];
861  _position[2] = _positionBuffer[2] / _model->_scale[2];
862  _positionBuffered = false;
863  }
864 
865  if (_orientationBuffered) {
870  _orientationBuffered = false;
871  }
872 
873  if (_vertexCoordsBuffered) {
874  const float *vcb = &_vertexCoordsBuffer[0];
876  int vertexCount = vb.getCount();
877  int stride = vb.getSize() / sizeof(float);
878  float *v = reinterpret_cast<float *>(vb.getData());
879  for (int i = 0; i < vertexCount; ++i) {
880  v[0] = vcb[0];
881  v[1] = vcb[1];
882  v[2] = vcb[2];
883  v += stride;
884  vcb += 3;
885  }
886  _vertexCoordsBuffered = false;
887  _dirtyMesh = true;
888  }
889 }
890 
892  std::vector<ModelNode *> nodeChain;
893  for (ModelNode *node = this; node; node = node->_parent) {
894  nodeChain.push_back(node);
895  }
896 
897  _invBindPose = glm::mat4();
898 
899  for (std::vector<ModelNode *>::reverse_iterator n = nodeChain.rbegin();
900  n != nodeChain.rend();
901  ++n) {
902  const ModelNode *node = *n;
903 
904  if (node->_positionFrames.size() > 0) {
905  const PositionKeyFrame &pos = node->_positionFrames[0];
906  _invBindPose = glm::translate(_invBindPose, glm::vec3(pos.x, pos.y, pos.z));
907  }
908 
909  if (node->_orientationFrames.size() > 0) {
910  const QuaternionKeyFrame &ori = node->_orientationFrames[0];
911  if (ori.x != 0 || ori.y != 0 || ori.z != 0)
912  _invBindPose = glm::rotate(_invBindPose,
913  acosf(ori.q) * 2.0f,
914  glm::vec3(ori.x, ori.y, ori.z));
915  }
916  }
917 
919 }
920 
922  std::vector<ModelNode *> nodeChain;
923  for (ModelNode *node = this; node; node = node->_parent) {
924  nodeChain.push_back(node);
925  }
926 
927  _absoluteTransform = glm::mat4();
928 
929  for (std::vector<ModelNode *>::reverse_iterator n = nodeChain.rbegin();
930  n != nodeChain.rend();
931  ++n) {
932  const ModelNode *node = *n;
933 
934  _absoluteTransform = glm::translate(_absoluteTransform,
935  glm::vec3(node->_positionBuffer[0],
936  node->_positionBuffer[1],
937  node->_positionBuffer[2]));
938 
939  if (node->_orientationBuffer[0] != 0 ||
940  node->_orientationBuffer[1] != 0 ||
941  node->_orientationBuffer[2] != 0)
944  glm::vec3(node->_orientationBuffer[0],
945  node->_orientationBuffer[1],
946  node->_orientationBuffer[2]));
947  }
948 }
949 
951  if (_mesh) {
952  return _mesh;
953  }
954 
955  if (_model->getState().empty()) {
956  return NULL; // Stateless and no internal _mesh.
957  }
958 
959  ModelNode *rootStateNode = _model->getNode("", _name);
960  if (rootStateNode && rootStateNode != this) {
961  return rootStateNode->_mesh;
962  }
963 
964  return NULL; // No mesh found in the root state.
965 }
966 
968  TextureHandle *rval = NULL;
969  count = 0;
970  if (_mesh && _mesh->data) {
971  count = _mesh->data->textures.size();
972  if (count) {
973  rval = &(_mesh->data->textures[0]);
974  }
975  }
976 
977  if (!rval) {
978  // Nothing here, see if the parent has something for us.
979  ModelNode *rootStateNode = _model->getNode("", _name);
980  if (rootStateNode && rootStateNode != this) {
981  rval = rootStateNode->getTextures(count);
982  }
983  }
984 
985  return rval;
986 }
987 
989  TextureHandle *rval = NULL;
990  if (_mesh && _mesh->data) {
991  if (!_mesh->data->envMap.empty()) {
992  rval = &(_mesh->data->envMap);
993  mode = _mesh->data->envMapMode;
994  }
995  }
996 
997  if (!rval) {
998  // Nothing here, see if the parent has something for us.
999  ModelNode *rootStateNode = _model->getNode("", _name);
1000  if (rootStateNode && rootStateNode != this) {
1001  rval = rootStateNode->getEnvironmentMap(mode);
1002  }
1003  }
1004 
1005  return rval;
1006 }
1007 
1009  ModelNode::Mesh *pmesh = 0; // TODO: if anything is changed in here, ensure there's a local copy instead that shares the root data.
1010  TextureHandle *phandles = 0; // Take from self first, or root state, if there is one, otherwise.
1011  TextureHandle *penvmap = 0; // Maybe it's only the environment map that's overriden.
1012  EnvironmentMapMode envmapmode;
1013 
1014  uint32 textureCount = 0;
1015 
1016  _renderableArray.clear();
1017 
1026  if (!_model->getState().empty()) {
1028  if (_rootStateNode == this) {
1029  _rootStateNode = 0;
1030  }
1031  } else {
1032  _rootStateNode = 0;
1033  }
1034 
1035  _dirtyRender = false;
1036 
1037  if (!_mesh) {
1038  return;
1039  }
1040 
1041  if (!_mesh->data) {
1042  return;
1043  }
1044 
1045  if (_mesh->data->textures.size() == 0 && _mesh->data->envMap.empty() && !_mesh->data->rawMesh) {
1046  return;
1047  }
1055  pmesh = _mesh;
1056  phandles = getTextures(textureCount);
1057  penvmap = getEnvironmentMap(envmapmode);
1058 
1059  if (textureCount == 0) {
1060  return;
1061  }
1062 
1063  if (!_render) {
1064  return;
1065  }
1066 
1067  if (!pmesh->data->rawMesh) {
1068  return;
1069  }
1070 
1071  if (phandles[0].empty()) {
1072  return;
1073  }
1074 
1075  Common::UString vertexShaderName;
1076  Common::UString fragmentShaderName;
1077  Common::UString materialName = "xoreos.";
1079 
1080  Shader::ShaderMaterial *material;
1081  Shader::ShaderSampler *sampler;
1082  Shader::ShaderSurface *surface;
1083 
1084  uint32 materialFlags = 0;
1085 
1086  _renderableArray.clear();
1090 
1091  if (_name == "Plane237") {
1092  pmesh->isTransparent = true; // Hack hack hack hack. For NWN.
1093  }
1094 
1095  if (penvmap) {
1096  if (penvmap->getTexture().getImage().isCubeMap()) {
1103  } else {
1110  }
1111 
1112  if (envmapmode == kModeEnvironmentBlendedUnder) {
1113  materialName += penvmap->getName();
1114  // Figure out if a cube or sphere map is used.
1115  if (penvmap->getTexture().getImage().isCubeMap()) {
1116  if (!pmesh->isTransparent) {
1117  materialFlags |= Shader::ShaderMaterial::MATERIAL_OPAQUE;
1118  }
1121  } else {
1127  materialFlags |= Shader::ShaderMaterial::MATERIAL_OPAQUE;
1130  // pmesh->isTransparent = false;
1131  }
1132  }
1133  }
1134 
1135  if (pmesh->isTransparent && !(materialFlags & Shader::ShaderMaterial::MATERIAL_OPAQUE)) {
1137  }
1138 
1144  if (textureCount >= 1) {
1145  if (!phandles[0].empty()) {
1146  materialName += phandles[0].getName();
1152 
1153  if (phandles[0].getTexture().getTXI().getFeatures().blending) {
1155  // For KotOR2, this is required to get some windows showing up properly.
1156  if (pmesh->hasTransparencyHint && !(materialFlags & Shader::ShaderMaterial::MATERIAL_OPAQUE)) {
1158  }
1159  }
1160  // Check to see if it's actually a decal texture.
1161  if (phandles[0].getTexture().getTXI().getFeatures().decal) {
1162  materialFlags |= Shader::ShaderMaterial::MATERIAL_DECAL;
1163  }
1164  if (penvmap && envmapmode == kModeEnvironmentBlendedUnder) {
1167  } else {
1170  }
1171  }
1172  }
1173 
1174  if (textureCount >= 2) {
1175  if (!phandles[1].empty()) {
1176  materialName += ".";
1177  materialName += phandles[1].getName();
1185  } else {
1188  }
1189  }
1190 
1191  if (textureCount >= 3) {
1192  if (!phandles[2].empty()) {
1193  materialName += ".";
1194  materialName += phandles[2].getName();
1197  } else {
1200  }
1201  }
1202 
1203  if (textureCount >= 4) {
1204  // Don't know yet what this extra texture is supposed to be.
1207  }
1208 
1209  if (penvmap) {
1210  if (envmapmode == kModeEnvironmentBlendedOver) {
1211  materialName += penvmap->getName();
1212  // Figure out if a cube or sphere map is used.
1213  if (penvmap->getTexture().getImage().isCubeMap()) {
1216  } else {
1219  }
1220  }
1221  }
1222 
1223  if (materialFlags & Shader::ShaderMaterial::MATERIAL_OPAQUE) {
1226  }
1227 
1228  if (materialFlags & Shader::ShaderMaterial::MATERIAL_TRANSPARENT) {
1229  if (pmesh->data->rawMesh->getVertexBuffer()->getCount() <= 6) {
1231  }
1232  }
1233 
1234  material = MaterialMan.getMaterial(materialName);
1235  if (material) {
1236  surface = SurfaceMan.getSurface(materialName);
1237  _renderableArray.push_back(Shader::ShaderRenderable(surface, material, pmesh->data->rawMesh));
1238  return;
1239  }
1240 
1241  if (_mesh->alpha < 1.0f) {
1242  materialFlags &= ~Shader::ShaderMaterial::MATERIAL_OPAQUE; // Make sure it's not actually opaque.
1244  }
1245 
1246  cripter.genName(vertexShaderName);
1247  fragmentShaderName = vertexShaderName + ".frag";
1248  vertexShaderName += ".vert";
1249 
1250  // Ok, material doesn't exist. Check on the shaders.
1251  Shader::ShaderObject *vertexObject = ShaderMan.getShaderObject(vertexShaderName, Shader::SHADER_VERTEX);
1252  Shader::ShaderObject *fragmentObject = ShaderMan.getShaderObject(fragmentShaderName, Shader::SHADER_FRAGMENT);
1253 
1254  // Should be checking vert and frag shader separately, but they really should exist together anyway.
1255  if (!vertexObject) {
1256  // No object found. Generate a shader then.
1257  bool isGL3 = GfxMan.isGL3();
1258 
1259  Common::UString vertexStringFinal;
1260  Common::UString fragmentStringFinal;
1261 
1262  cripter.build(isGL3, vertexStringFinal, fragmentStringFinal);
1263  vertexObject = ShaderMan.getShaderObject(vertexShaderName, vertexStringFinal, Shader::SHADER_VERTEX);
1264  fragmentObject = ShaderMan.getShaderObject(fragmentShaderName, fragmentStringFinal, Shader::SHADER_FRAGMENT);
1265  }
1266 
1267  // Shader objects should now exist, so go ahead and make the material and surface.
1268  surface = new Shader::ShaderSurface(vertexObject, materialName);
1269  material = new Shader::ShaderMaterial(fragmentObject, materialName);
1270  material->setFlags(materialFlags);
1271  MaterialMan.addMaterial(material);
1272  SurfaceMan.addSurface(surface);
1273 
1274  if (penvmap) {
1275  sampler = (Shader::ShaderSampler *)(material->getVariableData("sampler_7_id"));
1276  sampler->handle = *penvmap;
1277  }
1278 
1279  if (textureCount >= 1) {
1280  if (!phandles[0].empty()) {
1281  sampler = (Shader::ShaderSampler *)(material->getVariableData("sampler_0_id"));
1282  sampler->handle = phandles[0];
1283  }
1284  }
1285 
1286  if (textureCount >= 2) {
1287  if (!phandles[1].empty()) {
1288  sampler = (Shader::ShaderSampler *)(material->getVariableData("sampler_1_id"));
1289  sampler->handle = phandles[1];
1290  }
1291  }
1292 
1293  _renderableArray.push_back(Shader::ShaderRenderable(surface, material, pmesh->data->rawMesh));
1294 }
1295 
1296 } // End of namespace Aurora
1297 
1298 } // End of namespace Graphics
void setBufferedPosition(float x, float y, float z)
Definition: modelnode.cpp:842
const Common::UString & getState() const
Return the name of the current state.
Definition: model.cpp:361
Generic image decoder interface.
void setEnvironmentMap(const Common::UString &environmentMap="")
Change the environment map on this model node.
Definition: modelnode.cpp:275
EnvironmentMapMode
The way the environment map is applied to a model node.
Definition: modelnode.h:129
void build(bool isGL3, Common::UString &v_string, Common::UString &f_string)
static void renderGeometryEnvMappedOver(Mesh &mesh)
Definition: modelnode.cpp:587
Only render transparent parts.
Definition: types.h:99
Common::BoundingBox _absoluteBoundBox
The model&#39;s box after translate/rotate.
Definition: model.h:248
Not strictly speaking an input, but generated for an output.
Definition: shaderbuilder.h:63
An element of the front GUI.
Definition: types.h:53
void setInvisible(bool invisible)
Should the node never be rendered at all?
Definition: modelnode.cpp:293
A class holding an UTF-8 string.
Definition: ustring.h:48
#define TextureMan
Shortcut for accessing the texture manager.
Definition: textureman.h:127
uint32 getCount() const
Get vertex count.
void setPosition(float x, float y, float z)
Set the position of the node.
Definition: modelnode.cpp:217
Vertex position.
Definition: vertexbuffer.h:36
VertexBuffer * getVertexBuffer()
Definition: mesh.cpp:39
#define SurfaceMan
Shortcut for accessing the shader manager.
Definition: surfaceman.h:74
Shader::ShaderRenderable * _shaderRenderable
Definition: modelnode.h:260
float getDepth() const
Get the depth of the bounding box.
void loadTextures(const std::vector< Common::UString > &textures)
Definition: modelnode.cpp:340
void * getVariableData(uint32 index) const
The Aurora texture manager.
void getRotation(float &x, float &y, float &z) const
Get the rotation of the node.
Definition: modelnode.cpp:187
std::list< ModelNode * > & getChildren()
Get the node&#39;s children.
Definition: modelnode.cpp:152
void setBufferedOrientation(float x, float y, float z, float angle)
Definition: modelnode.cpp:849
glm::mat4 _invBindPose
Inverse bind pose matrix used for animations.
Definition: modelnode.h:247
Mathematical helpers.
Camera management.
float _rotation[3]
Node rotation.
Definition: modelnode.h:222
bool _dirtyMesh
Mesh data needs updating.
Definition: modelnode.h:237
float getHeight() const
Get the height of the node&#39;s bounding box.
Definition: modelnode.cpp:164
void queueRender(const glm::mat4 &parentTransform)
Definition: modelnode.cpp:750
void setParent(ModelNode *parent)
Set the node&#39;s parent.
Definition: modelnode.cpp:143
void rotate(float x, float y, float z)
Rotate the node, relative to its current rotation.
Definition: modelnode.cpp:258
Render hint; material has no transparency.
Diffuse textures first, then blend the environment map in.
Definition: modelnode.h:131
bool _render
Render the node?
Definition: modelnode.h:235
void scale(float x, float y, float z)
Different to default blending. Maybe this should be extended one day.
TextureHandle * getEnvironmentMap(EnvironmentMapMode &mode)
Definition: modelnode.cpp:988
void getPosition(float &x, float &y, float &z) const
Get the position of the node.
Definition: modelnode.cpp:181
void declareSampler(ShaderDescriptor::Sampler sampler, ShaderDescriptor::SamplerType type)
bool isCubeMap() const
Is this image a cube map?
Definition: decoder.cpp:198
float _alpha
Alpha of the node, used if no _mesh is present in this node.
Definition: modelnode.h:226
TextureHandle * getTextures(uint32 &count)
Definition: modelnode.cpp:967
std::vector< VertexAttrib > VertexDecl
Vertex data layout.
Definition: vertexbuffer.h:63
A bounding box around 3D points.
Definition: boundingbox.h:33
bool empty() const
Definition: boundingbox.cpp:60
void connect(ShaderDescriptor::Sampler sampler, ShaderDescriptor::Input input, ShaderDescriptor::Action action)
Connect an input to a sampler and an action.
float getAlpha()
Get the alpha (transparency) of the node.
Definition: modelnode.cpp:318
const VertexDecl & getVertexDecl() const
Access vertex declaration.
const glm::mat4 & getOrigin() const
Definition: boundingbox.cpp:64
Environment map first, then blend the diffuse textures in.
Definition: modelnode.h:130
Model * _model
The model this node belongs to.
Definition: modelnode.h:207
void exceptionDispatcherWarning(const char *s,...)
Exception dispatcher that prints the exception as a warning, and adds another reason on top...
Definition: error.cpp:158
float getHeight() const
Get the height of the bounding box.
const ImageDecoder & getImage() const
Return the image.
Definition: texture.cpp:106
float _scale[3]
Scale of the node.
Definition: modelnode.h:224
void setAlpha(float alpha, bool isRecursive=true)
Set the alpha (transparency) of the node.
Definition: modelnode.cpp:326
bool _dirtyRender
Rendering information needs updating.
Definition: modelnode.h:236
void getMin(float &x, float &y, float &z) const
Definition: boundingbox.cpp:68
Basic exceptions to throw.
RenderPass
Definition: types.h:97
float _position[3]
Model&#39;s position.
Definition: model.h:239
Not strictly speaking an input, but generated for an output.
Definition: shaderbuilder.h:64
Graphics::Aurora::TextureHandle handle
Definition: shader.h:176
uint16_t uint16
Definition: types.h:202
Utility templates and functions.
void getMax(float &x, float &y, float &z) const
Definition: boundingbox.cpp:87
void setRotation(float x, float y, float z)
Set the rotation of the node.
Definition: modelnode.cpp:230
float getWidth() const
Get the width of the bounding box.
TextureHandle envMap
The environment map texture.
Definition: modelnode.h:165
float getWidth() const
Get the width of the node&#39;s bounding box.
Definition: modelnode.cpp:160
Not really blending, but component-wise multiply.
static bool nodeComp(ModelNode *a, ModelNode *b)
Definition: modelnode.cpp:55
void renderUnbind()
Definition: mesh.cpp:227
virtual void buildMaterial()
Definition: modelnode.cpp:1008
static bool renderableMesh(Mesh *mesh)
Definition: modelnode.cpp:636
glm::mat4 _absoluteTransform
Absolute transformation matrix used for animations.
Definition: modelnode.h:248
A node within a 3D model.
Material definitely has transparency.
float getDepth() const
Get the depth of the node&#39;s bounding box.
Definition: modelnode.cpp:168
A 3D model of an object.
uint32 getSize() const
Get vertex element size in bytes.
The global shader material manager.
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
The global shader surface manager.
void setMaterial(Shader::ShaderMaterial *material)
Definition: modelnode.cpp:311
Buffer containing vertex data.
Definition: vertexbuffer.h:68
#define MaterialMan
Shortcut for accessing the shader material manager.
Definition: materialman.h:74
Texture information.
std::vector< QuaternionKeyFrame > _orientationFrames
Keyframes for orientation animation.
Definition: modelnode.h:229
bool isInFrontOf(const ModelNode &node) const
Is this node in front of that other node?
Definition: modelnode.cpp:172
void absolutize()
Apply the origin transformations directly to the coordinates.
float _position[3]
Position of the node.
Definition: modelnode.h:221
void rotate(float angle, float x, float y, float z)
static void renderGeometry(Mesh &mesh)
Definition: modelnode.cpp:536
void render(RenderPass pass)
Definition: modelnode.cpp:640
std::vector< TextureHandle > textures
Textures.
Definition: modelnode.h:163
void renderImmediate()
Definition: mesh.cpp:171
void renderImmediate(const glm::mat4 &parentTransform)
Definition: modelnode.cpp:709
float _scale[3]
Model&#39;s scale.
Definition: model.h:237
void renderBind()
Follows the steps of renderImmediate, but broken into different functions.
Definition: mesh.cpp:177
Material definitely has transparency.
void render(RenderPass pass)
Render the object.
Definition: model.cpp:632
Render queue manager.
void add(float x, float y, float z)
float _orientation[4]
Model&#39;s orientation.
Definition: model.h:238
Shader sampler is used to bind a texture to a texture unit.
Definition: shader.h:174
Common::BoundingBox _boundBox
Definition: modelnode.h:242
void createBound()
Create the model&#39;s bounding box.
Definition: model.cpp:848
Graphics::Mesh::Mesh * rawMesh
Node raw mesh data.
Definition: modelnode.h:159
void inheritPosition(ModelNode &node) const
Definition: modelnode.cpp:262
Common::UString _name
The node&#39;s name.
Definition: modelnode.h:216
std::vector< Shader::ShaderRenderable > _renderableArray
Damn you bioware.
Definition: modelnode.h:218
A texture as used in the Aurora engines.
Blending not applicable to the component.
EnvironmentMapMode envMapMode
The way the environment map is applied.
Definition: modelnode.h:166
#define ShaderMan
Shortcut for accessing the shader manager.
Definition: shader.h:293
uint32_t uint32
Definition: types.h:204
void genName(Common::UString &n_string)
Generate a name to asscoiate with the current description.
static glm::mat4 inverse(const glm::mat4 &m)
Definition: graphics.cpp:1363
glm::mat4 getAbsolutePosition() const
Get the position of the node after translate/rotate.
Definition: modelnode.cpp:206
void setEnvironmentMap(const Common::UString &environmentMap="")
Change the environment map on this model.
Definition: model.cpp:183
GLvoid * getData()
Access buffer data.
float _orientation[4]
Orientation of the node.
Definition: modelnode.h:223
const Common::UString & getName() const
Get the node&#39;s name.
Definition: modelnode.cpp:156
void move(float x, float y, float z)
Move the node, relative to its current position.
Definition: modelnode.cpp:251
void addPass(ShaderDescriptor::Action action, ShaderDescriptor::Blend blend)
glm::mat4 _absolutePosition
Definition: model.h:243
std::vector< float > _vertexCoordsBuffer
Definition: modelnode.h:255
static void renderGeometryEnvMappedUnder(Mesh &mesh)
Definition: modelnode.cpp:560
ModelType getType() const
Return the model&#39;s type.
Definition: model.cpp:121
uint16 getNodeNumber() const
Definition: modelnode.cpp:213
std::list< ModelNode * > _children
The node&#39;s children.
Definition: modelnode.h:210
#define pass
Definition: fft.cpp:257
const Common::UString & getName() const
Common::BoundingBox _absoluteBoundBox
Definition: modelnode.h:243
std::vector< PositionKeyFrame > _positionFrames
Keyframes for position animation.
Definition: modelnode.h:228
void declareInput(ShaderDescriptor::Input input)
glm::mat4 _absolutePosition
Position of the node after translate/rotate.
Definition: modelnode.h:232
const Common::BoundingBox & getAbsoluteBound() const
Definition: modelnode.cpp:446
void calcRenderTransform(const glm::mat4 &parentTransform)
Calculate the transform used for rendering.
Definition: modelnode.cpp:692
void queueRender(const glm::mat4 &parentTransform)
Queue the object for later rendering.
Definition: model.cpp:681
ModelNode * getParent()
Get the node&#39;s parent.
Definition: modelnode.cpp:135
ModelNode * _parent
The node&#39;s parent.
Definition: modelnode.h:209
Model * _attachedModel
The model that is attached to this node.
Definition: modelnode.h:212
float _center[3]
The node&#39;s center.
Definition: modelnode.h:220
ModelNode * getNode(const Common::UString &node)
Get the specified node, from the current state.
Definition: model.cpp:379
A handle to a texture.
Definition: texturehandle.h:51
void updateGL()
Update existing GL buffer object.
static float deg2rad(float deg)
Definition: maths.h:97
void translate(float x, float y, float z)
void getOrientation(float &x, float &y, float &z, float &a) const
Get the orientation of the node.
Definition: modelnode.cpp:193
#define GfxMan
Shortcut for accessing the graphics manager.
Definition: graphics.h:299
Only render opaque parts.
Definition: types.h:98
void renderImmediate(const glm::mat4 &parentTransform)
For shader based systems, don&#39;t sort anything, render this right_now.
Definition: model.cpp:666
Shader::ShaderMaterial * _material
Definition: modelnode.h:259
void drawSkeleton(const glm::mat4 &parent, bool showInvisible)
Definition: modelnode.cpp:791
static void renderGeometryNormal(Mesh &mesh)
Definition: modelnode.cpp:540
void setOrientation(float x, float y, float z, float a)
Set the orientation of the node.
Definition: modelnode.cpp:240
void setMaterial(Shader::ShaderMaterial *material, bool rebuildProgram=true)
void setTextures(const std::vector< Common::UString > &textures)
Set textures to the node.
Definition: modelnode.cpp:297
#define RenderMan
Shortcut for accessing the render manager.
Definition: renderman.h:84
void inheritOrientation(ModelNode &node) const
Definition: modelnode.cpp:268