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