]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CBillboardSceneNode.cpp
a1464eb1aeb96a31dafae122f0a94fde3da0ad84
[irrlicht.git] / source / Irrlicht / CBillboardSceneNode.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 "IrrCompileConfig.h"\r
6 #ifdef _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_\r
7 #include "CBillboardSceneNode.h"\r
8 #include "IVideoDriver.h"\r
9 #include "ISceneManager.h"\r
10 #include "ICameraSceneNode.h"\r
11 #include "os.h"\r
12 \r
13 namespace irr\r
14 {\r
15 namespace scene\r
16 {\r
17 \r
18 //! constructor\r
19 CBillboardSceneNode::CBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,\r
20                         const core::vector3df& position, const core::dimension2d<f32>& size,\r
21                         video::SColor colorTop, video::SColor colorBottom)\r
22         : IBillboardSceneNode(parent, mgr, id, position)\r
23         , Buffer(new SMeshBuffer())\r
24 {\r
25         #ifdef _DEBUG\r
26         setDebugName("CBillboardSceneNode");\r
27         #endif\r
28 \r
29         setSize(size);\r
30 \r
31         Buffer->Vertices.set_used(4);\r
32         Buffer->Indices.set_used(6);\r
33 \r
34         Buffer->Indices[0] = 0;\r
35         Buffer->Indices[1] = 2;\r
36         Buffer->Indices[2] = 1;\r
37         Buffer->Indices[3] = 0;\r
38         Buffer->Indices[4] = 3;\r
39         Buffer->Indices[5] = 2;\r
40 \r
41         Buffer->Vertices[0].TCoords.set(1.0f, 1.0f);\r
42         Buffer->Vertices[0].Color = colorBottom;\r
43 \r
44         Buffer->Vertices[1].TCoords.set(1.0f, 0.0f);\r
45         Buffer->Vertices[1].Color = colorTop;\r
46 \r
47         Buffer->Vertices[2].TCoords.set(0.0f, 0.0f);\r
48         Buffer->Vertices[2].Color = colorTop;\r
49 \r
50         Buffer->Vertices[3].TCoords.set(0.0f, 1.0f);\r
51         Buffer->Vertices[3].Color = colorBottom;\r
52 }\r
53 \r
54 CBillboardSceneNode::~CBillboardSceneNode()\r
55 {\r
56         Buffer->drop();\r
57 }\r
58 \r
59 //! pre render event\r
60 void CBillboardSceneNode::OnRegisterSceneNode()\r
61 {\r
62         if (IsVisible)\r
63                 SceneManager->registerNodeForRendering(this);\r
64 \r
65         ISceneNode::OnRegisterSceneNode();\r
66 }\r
67 \r
68 \r
69 //! render\r
70 void CBillboardSceneNode::render()\r
71 {\r
72         video::IVideoDriver* driver = SceneManager->getVideoDriver();\r
73         ICameraSceneNode* camera = SceneManager->getActiveCamera();\r
74 \r
75         if (!camera || !driver)\r
76                 return;\r
77 \r
78         // make billboard look to camera\r
79         updateMesh(camera);\r
80 \r
81         driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);\r
82         driver->setMaterial(Buffer->Material);\r
83         driver->drawMeshBuffer(Buffer);\r
84 \r
85         if (DebugDataVisible & scene::EDS_BBOX)\r
86         {\r
87                 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);\r
88                 video::SMaterial m;\r
89                 m.Lighting = false;\r
90                 driver->setMaterial(m);\r
91                 driver->draw3DBox(BBoxSafe, video::SColor(0,208,195,152));\r
92         }\r
93 }\r
94 \r
95 void CBillboardSceneNode::updateMesh(const irr::scene::ICameraSceneNode* camera)\r
96 {\r
97         // billboard looks toward camera\r
98         core::vector3df pos = getAbsolutePosition();\r
99 \r
100         core::vector3df campos = camera->getAbsolutePosition();\r
101         core::vector3df target = camera->getTarget();\r
102         core::vector3df up = camera->getUpVector();\r
103         core::vector3df view = target - campos;\r
104         view.normalize();\r
105 \r
106         core::vector3df horizontal = up.crossProduct(view);\r
107         if ( horizontal.getLength() == 0 )\r
108         {\r
109                 horizontal.set(up.Y,up.X,up.Z);\r
110         }\r
111         horizontal.normalize();\r
112         core::vector3df topHorizontal = horizontal * 0.5f * TopEdgeWidth;\r
113         horizontal *= 0.5f * Size.Width;\r
114 \r
115         // pointing down!\r
116         core::vector3df vertical = horizontal.crossProduct(view);\r
117         vertical.normalize();\r
118         vertical *= 0.5f * Size.Height;\r
119 \r
120         view *= -1.0f;\r
121 \r
122         core::array<video::S3DVertex>& vertices = Buffer->Vertices;\r
123 \r
124         for (s32 i=0; i<4; ++i)\r
125                 vertices[i].Normal = view;\r
126 \r
127         /* Vertices are:\r
128         2--1\r
129         |\ |\r
130         | \|\r
131         3--0\r
132         */\r
133         vertices[0].Pos = pos + horizontal + vertical;\r
134         vertices[1].Pos = pos + topHorizontal - vertical;\r
135         vertices[2].Pos = pos - topHorizontal - vertical;\r
136         vertices[3].Pos = pos - horizontal + vertical;\r
137 \r
138         Buffer->setDirty(EBT_VERTEX);\r
139         Buffer->recalculateBoundingBox();\r
140 }\r
141 \r
142 \r
143 //! returns the axis aligned bounding box of this node\r
144 const core::aabbox3d<f32>& CBillboardSceneNode::getBoundingBox() const\r
145 {\r
146         // Really wrong when scaled.\r
147         return BBoxSafe;\r
148 }\r
149 \r
150 const core::aabbox3d<f32>& CBillboardSceneNode::getTransformedBillboardBoundingBox(const irr::scene::ICameraSceneNode* camera)\r
151 {\r
152         updateMesh(camera);\r
153         return Buffer->BoundingBox;\r
154 }\r
155 \r
156 void CBillboardSceneNode::setSize(const core::dimension2d<f32>& size)\r
157 {\r
158         Size = size;\r
159 \r
160         if (core::equals(Size.Width, 0.0f))\r
161                 Size.Width = 1.0f;\r
162         TopEdgeWidth = Size.Width;\r
163 \r
164         if (core::equals(Size.Height, 0.0f))\r
165                 Size.Height = 1.0f;\r
166 \r
167         const f32 avg = (Size.Width + Size.Height)/6;\r
168         BBoxSafe.MinEdge.set(-avg,-avg,-avg);\r
169         BBoxSafe.MaxEdge.set(avg,avg,avg);\r
170 }\r
171 \r
172 \r
173 void CBillboardSceneNode::setSize(f32 height, f32 bottomEdgeWidth, f32 topEdgeWidth)\r
174 {\r
175         Size.set(bottomEdgeWidth, height);\r
176         TopEdgeWidth = topEdgeWidth;\r
177 \r
178         if (core::equals(Size.Height, 0.0f))\r
179                 Size.Height = 1.0f;\r
180 \r
181         if (core::equals(Size.Width, 0.f) && core::equals(TopEdgeWidth, 0.f))\r
182         {\r
183                 Size.Width = 1.0f;\r
184                 TopEdgeWidth = 1.0f;\r
185         }\r
186 \r
187         const f32 avg = (core::max_(Size.Width,TopEdgeWidth) + Size.Height)/6;\r
188         BBoxSafe.MinEdge.set(-avg,-avg,-avg);\r
189         BBoxSafe.MaxEdge.set(avg,avg,avg);\r
190 }\r
191 \r
192 \r
193 video::SMaterial& CBillboardSceneNode::getMaterial(u32 i)\r
194 {\r
195         return Buffer->Material;\r
196 }\r
197 \r
198 \r
199 //! returns amount of materials used by this scene node.\r
200 u32 CBillboardSceneNode::getMaterialCount() const\r
201 {\r
202         return 1;\r
203 }\r
204 \r
205 \r
206 //! gets the size of the billboard\r
207 const core::dimension2d<f32>& CBillboardSceneNode::getSize() const\r
208 {\r
209         return Size;\r
210 }\r
211 \r
212 \r
213 //! Gets the widths of the top and bottom edges of the billboard.\r
214 void CBillboardSceneNode::getSize(f32& height, f32& bottomEdgeWidth,\r
215                 f32& topEdgeWidth) const\r
216 {\r
217         height = Size.Height;\r
218         bottomEdgeWidth = Size.Width;\r
219         topEdgeWidth = TopEdgeWidth;\r
220 }\r
221 \r
222 \r
223 //! Set the color of all vertices of the billboard\r
224 //! \param overallColor: the color to set\r
225 void CBillboardSceneNode::setColor(const video::SColor& overallColor)\r
226 {\r
227         for(u32 vertex = 0; vertex < 4; ++vertex)\r
228                 Buffer->Vertices[vertex].Color = overallColor;\r
229 }\r
230 \r
231 \r
232 //! Set the color of the top and bottom vertices of the billboard\r
233 //! \param topColor: the color to set the top vertices\r
234 //! \param bottomColor: the color to set the bottom vertices\r
235 void CBillboardSceneNode::setColor(const video::SColor& topColor,\r
236                 const video::SColor& bottomColor)\r
237 {\r
238         Buffer->Vertices[0].Color = bottomColor;\r
239         Buffer->Vertices[1].Color = topColor;\r
240         Buffer->Vertices[2].Color = topColor;\r
241         Buffer->Vertices[3].Color = bottomColor;\r
242 }\r
243 \r
244 \r
245 //! Gets the color of the top and bottom vertices of the billboard\r
246 //! \param[out] topColor: stores the color of the top vertices\r
247 //! \param[out] bottomColor: stores the color of the bottom vertices\r
248 void CBillboardSceneNode::getColor(video::SColor& topColor,\r
249                 video::SColor& bottomColor) const\r
250 {\r
251         bottomColor = Buffer->Vertices[0].Color;\r
252         topColor = Buffer->Vertices[1].Color;\r
253 }\r
254 \r
255 \r
256 //! Creates a clone of this scene node and its children.\r
257 ISceneNode* CBillboardSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)\r
258 {\r
259         if (!newParent)\r
260                 newParent = Parent;\r
261         if (!newManager)\r
262                 newManager = SceneManager;\r
263 \r
264         CBillboardSceneNode* nb = new CBillboardSceneNode(newParent,\r
265                 newManager, ID, RelativeTranslation, Size);\r
266 \r
267         nb->cloneMembers(this, newManager);\r
268         nb->Buffer->Material = Buffer->Material;\r
269         nb->Size = Size;\r
270         nb->TopEdgeWidth = this->TopEdgeWidth;\r
271 \r
272         video::SColor topColor,bottomColor;\r
273         getColor(topColor,bottomColor);\r
274         nb->setColor(topColor,bottomColor);\r
275 \r
276         if ( newParent )\r
277                 nb->drop();\r
278         return nb;\r
279 }\r
280 \r
281 \r
282 } // end namespace scene\r
283 } // end namespace irr\r
284 \r
285 #endif // _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_\r