1
// Copyright (C) 2002-2011 Nikolaus Gebhardt
2
// This file is part of the "Irrlicht Engine".
3
// For conditions of distribution and use, see copyright notice in irrlicht.h
5
#include "CMeshSceneNode.h"
6
#include "IVideoDriver.h"
7
#include "ISceneManager.h"
9
#include "ICameraSceneNode.h"
10
#include "IMeshCache.h"
11
#include "IAnimatedMesh.h"
12
#include "IMaterialRenderer.h"
13
#include "IFileSystem.h"
23
CMeshSceneNode::CMeshSceneNode(IMesh* mesh, ISceneNode* parent, ISceneManager* mgr, s32 id,
24
const core::vector3df& position, const core::vector3df& rotation,
25
const core::vector3df& scale)
26
: IMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0), PassCount(0),
27
ReadOnlyMaterials(false)
30
setDebugName("CMeshSceneNode");
38
CMeshSceneNode::~CMeshSceneNode()
46
void CMeshSceneNode::OnRegisterSceneNode()
50
// because this node supports rendering of mixed mode meshes consisting of
51
// transparent and solid material at the same time, we need to go through all
52
// materials, check of what type they are and register this node for the right
53
// render pass according to that.
55
video::IVideoDriver* driver = SceneManager->getVideoDriver();
58
int transparentCount = 0;
61
// count transparent and solid materials in this scene node
62
if (ReadOnlyMaterials && Mesh)
64
// count mesh materials
66
for (u32 i=0; i<Mesh->getMeshBufferCount(); ++i)
68
scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i);
69
video::IMaterialRenderer* rnd = mb ? driver->getMaterialRenderer(mb->getMaterial().MaterialType) : 0;
71
if (rnd && rnd->isTransparent())
76
if (solidCount && transparentCount)
82
// count copied materials
84
for (u32 i=0; i<Materials.size(); ++i)
86
video::IMaterialRenderer* rnd =
87
driver->getMaterialRenderer(Materials[i].MaterialType);
89
if (rnd && rnd->isTransparent())
94
if (solidCount && transparentCount)
99
// register according to material types counted
102
SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
104
if (transparentCount)
105
SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
107
ISceneNode::OnRegisterSceneNode();
112
//! renders the node.
113
void CMeshSceneNode::render()
115
video::IVideoDriver* driver = SceneManager->getVideoDriver();
117
if (!Mesh || !driver)
120
bool isTransparentPass =
121
SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT;
125
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
126
Box = Mesh->getBoundingBox();
128
// for debug purposes only:
130
bool renderMeshes = true;
131
video::SMaterial mat;
132
if (DebugDataVisible && PassCount==1)
134
// overwrite half transparency
135
if (DebugDataVisible & scene::EDS_HALF_TRANSPARENCY)
137
for (u32 g=0; g<Mesh->getMeshBufferCount(); ++g)
140
mat.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
141
driver->setMaterial(mat);
142
driver->drawMeshBuffer(Mesh->getMeshBuffer(g));
144
renderMeshes = false;
148
// render original meshes
151
for (u32 i=0; i<Mesh->getMeshBufferCount(); ++i)
153
scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i);
156
const video::SMaterial& material = ReadOnlyMaterials ? mb->getMaterial() : Materials[i];
158
video::IMaterialRenderer* rnd = driver->getMaterialRenderer(material.MaterialType);
159
bool transparent = (rnd && rnd->isTransparent());
161
// only render transparent buffer if this is the transparent render pass
162
// and solid only in solid pass
163
if (transparent == isTransparentPass)
165
driver->setMaterial(material);
166
driver->drawMeshBuffer(mb);
172
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
174
// for debug purposes only:
175
if (DebugDataVisible && PassCount==1)
180
driver->setMaterial(m);
182
if (DebugDataVisible & scene::EDS_BBOX)
184
driver->draw3DBox(Box, video::SColor(255,255,255,255));
186
if (DebugDataVisible & scene::EDS_BBOX_BUFFERS)
188
for (u32 g=0; g<Mesh->getMeshBufferCount(); ++g)
191
Mesh->getMeshBuffer(g)->getBoundingBox(),
192
video::SColor(255,190,128,128));
196
if (DebugDataVisible & scene::EDS_NORMALS)
200
core::vector3df normalizedNormal;
201
const f32 DebugNormalLength = SceneManager->getParameters()->getAttributeAsFloat(DEBUG_NORMAL_LENGTH);
202
const video::SColor DebugNormalColor = SceneManager->getParameters()->getAttributeAsColor(DEBUG_NORMAL_COLOR);
204
for (u32 g=0; g<Mesh->getMeshBufferCount(); ++g)
206
const scene::IMeshBuffer* mb = Mesh->getMeshBuffer(g);
207
const u32 vSize = video::getVertexPitchFromType(mb->getVertexType());
208
const video::S3DVertex* v = ( const video::S3DVertex*)mb->getVertices();
209
const bool normalize = mb->getMaterial().NormalizeNormals;
211
for (u32 i=0; i != mb->getVertexCount(); ++i)
213
normalizedNormal = v->Normal;
215
normalizedNormal.normalize();
217
driver->draw3DLine(v->Pos, v->Pos + (normalizedNormal * DebugNormalLength), DebugNormalColor);
219
v = (const video::S3DVertex*) ( (u8*) v+vSize );
222
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
226
if (DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY)
229
driver->setMaterial(m);
231
for (u32 g=0; g<Mesh->getMeshBufferCount(); ++g)
233
driver->drawMeshBuffer(Mesh->getMeshBuffer(g));
240
//! returns the axis aligned bounding box of this node
241
const core::aabbox3d<f32>& CMeshSceneNode::getBoundingBox() const
243
return Mesh ? Mesh->getBoundingBox() : Box;
247
//! returns the material based on the zero based index i. To get the amount
248
//! of materials used by this scene node, use getMaterialCount().
249
//! This function is needed for inserting the node into the scene hierarchy on a
250
//! optimal position for minimizing renderstate changes, but can also be used
251
//! to directly modify the material of a scene node.
252
video::SMaterial& CMeshSceneNode::getMaterial(u32 i)
254
if (Mesh && ReadOnlyMaterials && i<Mesh->getMeshBufferCount())
256
ReadOnlyMaterial = Mesh->getMeshBuffer(i)->getMaterial();
257
return ReadOnlyMaterial;
260
if (i >= Materials.size())
261
return ISceneNode::getMaterial(i);
267
//! returns amount of materials used by this scene node.
268
u32 CMeshSceneNode::getMaterialCount() const
270
if (Mesh && ReadOnlyMaterials)
271
return Mesh->getMeshBufferCount();
273
return Materials.size();
278
void CMeshSceneNode::setMesh(IMesh* mesh)
292
void CMeshSceneNode::copyMaterials()
298
video::SMaterial mat;
300
for (u32 i=0; i<Mesh->getMeshBufferCount(); ++i)
302
IMeshBuffer* mb = Mesh->getMeshBuffer(i);
304
mat = mb->getMaterial();
306
Materials.push_back(mat);
312
//! Writes attributes of the scene node.
313
void CMeshSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
315
IMeshSceneNode::serializeAttributes(out, options);
317
if (options && (options->Flags&io::EARWF_USE_RELATIVE_PATHS) && options->Filename)
319
const io::path path = SceneManager->getFileSystem()->getRelativeFilename(
320
SceneManager->getFileSystem()->getAbsolutePath(SceneManager->getMeshCache()->getMeshName(Mesh).getPath()),
322
out->addString("Mesh", path.c_str());
325
out->addString("Mesh", SceneManager->getMeshCache()->getMeshName(Mesh).getPath().c_str());
326
out->addBool("ReadOnlyMaterials", ReadOnlyMaterials);
330
//! Reads attributes of the scene node.
331
void CMeshSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
333
io::path oldMeshStr = SceneManager->getMeshCache()->getMeshName(Mesh);
334
io::path newMeshStr = in->getAttributeAsString("Mesh");
335
ReadOnlyMaterials = in->getAttributeAsBool("ReadOnlyMaterials");
337
if (newMeshStr != "" && oldMeshStr != newMeshStr)
340
IAnimatedMesh* newAnimatedMesh = SceneManager->getMesh(newMeshStr.c_str());
343
newMesh = newAnimatedMesh->getMesh(0);
349
// optional attribute to assign the hint to the whole mesh
350
if (in->existsAttribute("HardwareMappingHint") &&
351
in->existsAttribute("HardwareMappingBufferType"))
353
scene::E_HARDWARE_MAPPING mapping = scene::EHM_NEVER;
354
scene::E_BUFFER_TYPE bufferType = scene::EBT_NONE;
356
core::stringc smapping = in->getAttributeAsString("HardwareMappingHint");
357
if (smapping.equals_ignore_case("static"))
358
mapping = scene::EHM_STATIC;
359
else if (smapping.equals_ignore_case("dynamic"))
360
mapping = scene::EHM_DYNAMIC;
361
else if (smapping.equals_ignore_case("stream"))
362
mapping = scene::EHM_STREAM;
364
core::stringc sbufferType = in->getAttributeAsString("HardwareMappingBufferType");
365
if (sbufferType.equals_ignore_case("vertex"))
366
bufferType = scene::EBT_VERTEX;
367
else if (sbufferType.equals_ignore_case("index"))
368
bufferType = scene::EBT_INDEX;
369
else if (sbufferType.equals_ignore_case("vertexindex"))
370
bufferType = scene::EBT_VERTEX_AND_INDEX;
372
IMesh* mesh = getMesh();
374
mesh->setHardwareMappingHint(mapping, bufferType);
377
IMeshSceneNode::deserializeAttributes(in, options);
381
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
382
/* In this way it is possible to change the materials a mesh causing all mesh scene nodes
383
referencing this mesh to change too. */
384
void CMeshSceneNode::setReadOnlyMaterials(bool readonly)
386
ReadOnlyMaterials = readonly;
390
//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style
391
bool CMeshSceneNode::isReadOnlyMaterials() const
393
return ReadOnlyMaterials;
397
//! Creates a clone of this scene node and its children.
398
ISceneNode* CMeshSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
403
newManager = SceneManager;
405
CMeshSceneNode* nb = new CMeshSceneNode(Mesh, newParent,
406
newManager, ID, RelativeTranslation, RelativeRotation, RelativeScale);
408
nb->cloneMembers(this, newManager);
409
nb->ReadOnlyMaterials = ReadOnlyMaterials;
410
nb->Materials = Materials;
418
} // end namespace scene
419
} // end namespace irr