]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CMeshSceneNode.cpp
Reduce IrrCompileConfig usage to files that actually need it
[irrlicht.git] / source / Irrlicht / CMeshSceneNode.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "CMeshSceneNode.h"\r
6 #include "IVideoDriver.h"\r
7 #include "ISceneManager.h"\r
8 #include "S3DVertex.h"\r
9 #include "ICameraSceneNode.h"\r
10 #include "IMeshCache.h"\r
11 #include "IAnimatedMesh.h"\r
12 #include "IMaterialRenderer.h"\r
13 #include "IFileSystem.h"\r
14 \r
15 namespace irr\r
16 {\r
17 namespace scene\r
18 {\r
19 \r
20 \r
21 \r
22 //! constructor\r
23 CMeshSceneNode::CMeshSceneNode(IMesh* mesh, ISceneNode* parent, ISceneManager* mgr, s32 id,\r
24                         const core::vector3df& position, const core::vector3df& rotation,\r
25                         const core::vector3df& scale)\r
26 : IMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0),\r
27         PassCount(0), ReadOnlyMaterials(false)\r
28 {\r
29         #ifdef _DEBUG\r
30         setDebugName("CMeshSceneNode");\r
31         #endif\r
32 \r
33         setMesh(mesh);\r
34 }\r
35 \r
36 \r
37 //! destructor\r
38 CMeshSceneNode::~CMeshSceneNode()\r
39 {\r
40         if (Mesh)\r
41                 Mesh->drop();\r
42 }\r
43 \r
44 \r
45 //! frame\r
46 void CMeshSceneNode::OnRegisterSceneNode()\r
47 {\r
48         if (IsVisible && Mesh)\r
49         {\r
50                 // because this node supports rendering of mixed mode meshes consisting of\r
51                 // transparent and solid material at the same time, we need to go through all\r
52                 // materials, check of what type they are and register this node for the right\r
53                 // render pass according to that.\r
54 \r
55                 video::IVideoDriver* driver = SceneManager->getVideoDriver();\r
56 \r
57                 PassCount = 0;\r
58                 int transparentCount = 0;\r
59                 int solidCount = 0;\r
60 \r
61                 // count transparent and solid materials in this scene node\r
62                 const u32 numMaterials = ReadOnlyMaterials ? Mesh->getMeshBufferCount() : Materials.size();\r
63                 for (u32 i=0; i<numMaterials; ++i)\r
64                 {\r
65                         const video::SMaterial& material = ReadOnlyMaterials ? Mesh->getMeshBuffer(i)->getMaterial() : Materials[i];\r
66 \r
67                         if ( driver->needsTransparentRenderPass(material) )\r
68                                 ++transparentCount;\r
69                         else\r
70                                 ++solidCount;\r
71 \r
72                         if (solidCount && transparentCount)\r
73                                 break;\r
74                 }\r
75 \r
76                 // register according to material types counted\r
77 \r
78                 if (solidCount)\r
79                         SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);\r
80 \r
81                 if (transparentCount)\r
82                         SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);\r
83 \r
84                 ISceneNode::OnRegisterSceneNode();\r
85         }\r
86 }\r
87 \r
88 \r
89 //! renders the node.\r
90 void CMeshSceneNode::render()\r
91 {\r
92         video::IVideoDriver* driver = SceneManager->getVideoDriver();\r
93 \r
94         if (!Mesh || !driver)\r
95                 return;\r
96 \r
97         const bool isTransparentPass =\r
98                 SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT;\r
99 \r
100         ++PassCount;\r
101 \r
102         driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);\r
103         Box = Mesh->getBoundingBox();\r
104 \r
105         // for debug purposes only:\r
106 \r
107         bool renderMeshes = true;\r
108         video::SMaterial mat;\r
109         if (DebugDataVisible && PassCount==1)\r
110         {\r
111                 // overwrite half transparency\r
112                 if (DebugDataVisible & scene::EDS_HALF_TRANSPARENCY)\r
113                 {\r
114                         for (u32 g=0; g<Mesh->getMeshBufferCount(); ++g)\r
115                         {\r
116                                 mat = Materials[g];\r
117                                 mat.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;\r
118                                 driver->setMaterial(mat);\r
119                                 driver->drawMeshBuffer(Mesh->getMeshBuffer(g));\r
120                         }\r
121                         renderMeshes = false;\r
122                 }\r
123         }\r
124 \r
125         // render original meshes\r
126         if (renderMeshes)\r
127         {\r
128                 for (u32 i=0; i<Mesh->getMeshBufferCount(); ++i)\r
129                 {\r
130                         scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i);\r
131                         if (mb)\r
132                         {\r
133                                 const video::SMaterial& material = ReadOnlyMaterials ? mb->getMaterial() : Materials[i];\r
134 \r
135                                 const bool transparent = driver->needsTransparentRenderPass(material);\r
136 \r
137                                 // only render transparent buffer if this is the transparent render pass\r
138                                 // and solid only in solid pass\r
139                                 if (transparent == isTransparentPass)\r
140                                 {\r
141                                         driver->setMaterial(material);\r
142                                         driver->drawMeshBuffer(mb);\r
143                                 }\r
144                         }\r
145                 }\r
146         }\r
147 \r
148         // for debug purposes only:\r
149         if (DebugDataVisible && PassCount==1)\r
150         {\r
151                 video::SMaterial m;\r
152                 m.Lighting = false;\r
153                 m.AntiAliasing=0;\r
154                 driver->setMaterial(m);\r
155 \r
156                 if (DebugDataVisible & scene::EDS_BBOX)\r
157                 {\r
158                         driver->draw3DBox(Box, video::SColor(255,255,255,255));\r
159                 }\r
160                 if (DebugDataVisible & scene::EDS_BBOX_BUFFERS)\r
161                 {\r
162                         for (u32 g=0; g<Mesh->getMeshBufferCount(); ++g)\r
163                         {\r
164                                 driver->draw3DBox(\r
165                                         Mesh->getMeshBuffer(g)->getBoundingBox(),\r
166                                         video::SColor(255,190,128,128));\r
167                         }\r
168                 }\r
169 \r
170                 if (DebugDataVisible & scene::EDS_NORMALS)\r
171                 {\r
172                         // draw normals\r
173                         const f32 debugNormalLength = 1.f;\r
174                         const video::SColor debugNormalColor = video::SColor(255, 34, 221, 221);\r
175                         const u32 count = Mesh->getMeshBufferCount();\r
176 \r
177                         for (u32 i=0; i != count; ++i)\r
178                         {\r
179                                 driver->drawMeshBufferNormals(Mesh->getMeshBuffer(i), debugNormalLength, debugNormalColor);\r
180                         }\r
181                 }\r
182 \r
183                 // show mesh\r
184                 if (DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY)\r
185                 {\r
186                         m.Wireframe = true;\r
187                         driver->setMaterial(m);\r
188 \r
189                         for (u32 g=0; g<Mesh->getMeshBufferCount(); ++g)\r
190                         {\r
191                                 driver->drawMeshBuffer(Mesh->getMeshBuffer(g));\r
192                         }\r
193                 }\r
194         }\r
195 }\r
196 \r
197 \r
198 //! Removes a child from this scene node.\r
199 //! Implemented here, to be able to remove the shadow properly, if there is one,\r
200 //! or to remove attached childs.\r
201 bool CMeshSceneNode::removeChild(ISceneNode* child)\r
202 {\r
203         return ISceneNode::removeChild(child);\r
204 }\r
205 \r
206 \r
207 //! returns the axis aligned bounding box of this node\r
208 const core::aabbox3d<f32>& CMeshSceneNode::getBoundingBox() const\r
209 {\r
210         return Mesh ? Mesh->getBoundingBox() : Box;\r
211 }\r
212 \r
213 \r
214 //! returns the material based on the zero based index i. To get the amount\r
215 //! of materials used by this scene node, use getMaterialCount().\r
216 //! This function is needed for inserting the node into the scene hierarchy on a\r
217 //! optimal position for minimizing renderstate changes, but can also be used\r
218 //! to directly modify the material of a scene node.\r
219 video::SMaterial& CMeshSceneNode::getMaterial(u32 i)\r
220 {\r
221         if (Mesh && ReadOnlyMaterials && i<Mesh->getMeshBufferCount())\r
222         {\r
223                 ReadOnlyMaterial = Mesh->getMeshBuffer(i)->getMaterial();\r
224                 return ReadOnlyMaterial;\r
225         }\r
226 \r
227         if (i >= Materials.size())\r
228                 return ISceneNode::getMaterial(i);\r
229 \r
230         return Materials[i];\r
231 }\r
232 \r
233 \r
234 //! returns amount of materials used by this scene node.\r
235 u32 CMeshSceneNode::getMaterialCount() const\r
236 {\r
237         if (Mesh && ReadOnlyMaterials)\r
238                 return Mesh->getMeshBufferCount();\r
239 \r
240         return Materials.size();\r
241 }\r
242 \r
243 \r
244 //! Sets a new mesh\r
245 void CMeshSceneNode::setMesh(IMesh* mesh)\r
246 {\r
247         if (mesh)\r
248         {\r
249                 mesh->grab();\r
250                 if (Mesh)\r
251                         Mesh->drop();\r
252 \r
253                 Mesh = mesh;\r
254                 copyMaterials();\r
255         }\r
256 }\r
257 \r
258 \r
259 void CMeshSceneNode::copyMaterials()\r
260 {\r
261         Materials.clear();\r
262 \r
263         if (Mesh)\r
264         {\r
265                 video::SMaterial mat;\r
266 \r
267                 for (u32 i=0; i<Mesh->getMeshBufferCount(); ++i)\r
268                 {\r
269                         IMeshBuffer* mb = Mesh->getMeshBuffer(i);\r
270                         if (mb)\r
271                                 mat = mb->getMaterial();\r
272 \r
273                         Materials.push_back(mat);\r
274                 }\r
275         }\r
276 }\r
277 \r
278 \r
279 //! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.\r
280 /* In this way it is possible to change the materials a mesh causing all mesh scene nodes\r
281 referencing this mesh to change too. */\r
282 void CMeshSceneNode::setReadOnlyMaterials(bool readonly)\r
283 {\r
284         ReadOnlyMaterials = readonly;\r
285 }\r
286 \r
287 \r
288 //! Returns if the scene node should not copy the materials of the mesh but use them in a read only style\r
289 bool CMeshSceneNode::isReadOnlyMaterials() const\r
290 {\r
291         return ReadOnlyMaterials;\r
292 }\r
293 \r
294 \r
295 //! Creates a clone of this scene node and its children.\r
296 ISceneNode* CMeshSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)\r
297 {\r
298         if (!newParent)\r
299                 newParent = Parent;\r
300         if (!newManager)\r
301                 newManager = SceneManager;\r
302 \r
303         CMeshSceneNode* nb = new CMeshSceneNode(Mesh, newParent,\r
304                 newManager, ID, RelativeTranslation, RelativeRotation, RelativeScale);\r
305 \r
306         nb->cloneMembers(this, newManager);\r
307         nb->ReadOnlyMaterials = ReadOnlyMaterials;\r
308         nb->Materials = Materials;\r
309 \r
310         if (newParent)\r
311                 nb->drop();\r
312         return nb;\r
313 }\r
314 \r
315 \r
316 } // end namespace scene\r
317 } // end namespace irr\r
318 \r