1 | /* |
---|
2 | ----------------------------------------------------------------------------- |
---|
3 | This source file is part of OGRE |
---|
4 | (Object-oriented Graphics Rendering Engine) |
---|
5 | For the latest info, see http://www.ogre3d.org/ |
---|
6 | |
---|
7 | Copyright (c) 2000-2006 Torus Knot Software Ltd |
---|
8 | Also see acknowledgements in Readme.html |
---|
9 | |
---|
10 | This program is free software; you can redistribute it and/or modify it under |
---|
11 | the terms of the GNU Lesser General Public License as published by the Free Software |
---|
12 | Foundation; either version 2 of the License, or (at your option) any later |
---|
13 | version. |
---|
14 | |
---|
15 | This program is distributed in the hope that it will be useful, but WITHOUT |
---|
16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
---|
17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. |
---|
18 | |
---|
19 | You should have received a copy of the GNU Lesser General Public License along with |
---|
20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
---|
21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to |
---|
22 | http://www.gnu.org/copyleft/lesser.txt. |
---|
23 | |
---|
24 | You may alternatively use this source under the terms of a specific version of |
---|
25 | the OGRE Unrestricted License provided you have obtained such a license from |
---|
26 | Torus Knot Software Ltd. |
---|
27 | ----------------------------------------------------------------------------- |
---|
28 | */ |
---|
29 | |
---|
30 | // Thanks to Vincent Cantin (karmaGfa) for the original implementation of this |
---|
31 | // class, although it has now been mostly rewritten |
---|
32 | |
---|
33 | #include "OgreStableHeaders.h" |
---|
34 | #include "OgreBillboardChain.h" |
---|
35 | |
---|
36 | #include "OgreSimpleRenderable.h" |
---|
37 | #include "OgreHardwareBufferManager.h" |
---|
38 | #include "OgreNode.h" |
---|
39 | #include "OgreCamera.h" |
---|
40 | #include "OgreRoot.h" |
---|
41 | #include "OgreMaterialManager.h" |
---|
42 | #include "OgreLogManager.h" |
---|
43 | #include "OgreStringConverter.h" |
---|
44 | |
---|
45 | namespace Ogre { |
---|
46 | const size_t BillboardChain::SEGMENT_EMPTY = 0xffffffff; |
---|
47 | //----------------------------------------------------------------------- |
---|
48 | BillboardChain::Element::Element() |
---|
49 | { |
---|
50 | } |
---|
51 | //----------------------------------------------------------------------- |
---|
52 | BillboardChain::Element::Element(Vector3 _position, |
---|
53 | Real _width, |
---|
54 | Real _texCoord, |
---|
55 | ColourValue _colour) : |
---|
56 | position(_position), |
---|
57 | width(_width), |
---|
58 | texCoord(_texCoord), |
---|
59 | colour(_colour) |
---|
60 | { |
---|
61 | } |
---|
62 | //----------------------------------------------------------------------- |
---|
63 | BillboardChain::BillboardChain(const String& name, size_t maxElements, |
---|
64 | size_t numberOfChains, bool useTextureCoords, bool useColours, bool dynamic) |
---|
65 | :MovableObject(name), |
---|
66 | mMaxElementsPerChain(maxElements), |
---|
67 | mChainCount(numberOfChains), |
---|
68 | mUseTexCoords(useTextureCoords), |
---|
69 | mUseVertexColour(useColours), |
---|
70 | mDynamic(dynamic), |
---|
71 | mVertexDeclDirty(true), |
---|
72 | mBuffersNeedRecreating(true), |
---|
73 | mBoundsDirty(true), |
---|
74 | mIndexContentDirty(true), |
---|
75 | mRadius(0.0f), |
---|
76 | mTexCoordDir(TCD_U) |
---|
77 | { |
---|
78 | mVertexData = new VertexData(); |
---|
79 | mIndexData = new IndexData(); |
---|
80 | |
---|
81 | mOtherTexCoordRange[0] = 0.0f; |
---|
82 | mOtherTexCoordRange[1] = 1.0f; |
---|
83 | |
---|
84 | setupChainContainers(); |
---|
85 | |
---|
86 | mVertexData->vertexStart = 0; |
---|
87 | // index data set up later |
---|
88 | // set basic white material |
---|
89 | this->setMaterialName("BaseWhiteNoLighting"); |
---|
90 | |
---|
91 | } |
---|
92 | //----------------------------------------------------------------------- |
---|
93 | BillboardChain::~BillboardChain() |
---|
94 | { |
---|
95 | delete mVertexData; |
---|
96 | delete mIndexData; |
---|
97 | } |
---|
98 | //----------------------------------------------------------------------- |
---|
99 | void BillboardChain::setupChainContainers(void) |
---|
100 | { |
---|
101 | // Allocate enough space for everything |
---|
102 | mChainElementList.resize(mChainCount * mMaxElementsPerChain); |
---|
103 | mVertexData->vertexCount = mChainElementList.size() * 2; |
---|
104 | |
---|
105 | // Configure chains |
---|
106 | mChainSegmentList.resize(mChainCount); |
---|
107 | for (size_t i = 0; i < mChainCount; ++i) |
---|
108 | { |
---|
109 | ChainSegment& seg = mChainSegmentList[i]; |
---|
110 | seg.start = i * mMaxElementsPerChain; |
---|
111 | seg.tail = seg.head = SEGMENT_EMPTY; |
---|
112 | |
---|
113 | } |
---|
114 | |
---|
115 | |
---|
116 | } |
---|
117 | //----------------------------------------------------------------------- |
---|
118 | void BillboardChain::setupVertexDeclaration(void) |
---|
119 | { |
---|
120 | if (mVertexDeclDirty) |
---|
121 | { |
---|
122 | VertexDeclaration* decl = mVertexData->vertexDeclaration; |
---|
123 | decl->removeAllElements(); |
---|
124 | |
---|
125 | size_t offset = 0; |
---|
126 | // Add a description for the buffer of the positions of the vertices |
---|
127 | decl->addElement(0, offset, VET_FLOAT3, VES_POSITION); |
---|
128 | offset += VertexElement::getTypeSize(VET_FLOAT3); |
---|
129 | |
---|
130 | if (mUseVertexColour) |
---|
131 | { |
---|
132 | decl->addElement(0, offset, VET_COLOUR, VES_DIFFUSE); |
---|
133 | offset += VertexElement::getTypeSize(VET_COLOUR); |
---|
134 | } |
---|
135 | |
---|
136 | if (mUseTexCoords) |
---|
137 | { |
---|
138 | decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES); |
---|
139 | offset += VertexElement::getTypeSize(VET_FLOAT2); |
---|
140 | } |
---|
141 | |
---|
142 | if (!mUseTexCoords && !mUseVertexColour) |
---|
143 | { |
---|
144 | LogManager::getSingleton().logMessage( |
---|
145 | "Error - BillboardChain '" + mName + "' is using neither " |
---|
146 | "texture coordinates or vertex colours; it will not be " |
---|
147 | "visible on some rendering APIs so you should change this " |
---|
148 | "so you use one or the other."); |
---|
149 | } |
---|
150 | mVertexDeclDirty = false; |
---|
151 | } |
---|
152 | } |
---|
153 | //----------------------------------------------------------------------- |
---|
154 | void BillboardChain::setupBuffers(void) |
---|
155 | { |
---|
156 | setupVertexDeclaration(); |
---|
157 | if (mBuffersNeedRecreating) |
---|
158 | { |
---|
159 | // Create the vertex buffer (always dynamic due to the camera adjust) |
---|
160 | HardwareVertexBufferSharedPtr pBuffer = |
---|
161 | HardwareBufferManager::getSingleton().createVertexBuffer( |
---|
162 | mVertexData->vertexDeclaration->getVertexSize(0), |
---|
163 | mVertexData->vertexCount, |
---|
164 | HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE); |
---|
165 | |
---|
166 | // (re)Bind the buffer |
---|
167 | // Any existing buffer will lose its reference count and be destroyed |
---|
168 | mVertexData->vertexBufferBinding->setBinding(0, pBuffer); |
---|
169 | |
---|
170 | mIndexData->indexBuffer = |
---|
171 | HardwareBufferManager::getSingleton().createIndexBuffer( |
---|
172 | HardwareIndexBuffer::IT_16BIT, |
---|
173 | mChainCount * mMaxElementsPerChain * 6, // max we can use |
---|
174 | mDynamic? HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY : HardwareBuffer::HBU_STATIC_WRITE_ONLY); |
---|
175 | // NB we don't set the indexCount on IndexData here since we will |
---|
176 | // probably use less than the maximum number of indices |
---|
177 | |
---|
178 | mBuffersNeedRecreating = false; |
---|
179 | } |
---|
180 | } |
---|
181 | //----------------------------------------------------------------------- |
---|
182 | void BillboardChain::setMaxChainElements(size_t maxElements) |
---|
183 | { |
---|
184 | mMaxElementsPerChain = maxElements; |
---|
185 | setupChainContainers(); |
---|
186 | mBuffersNeedRecreating = mIndexContentDirty = true; |
---|
187 | } |
---|
188 | //----------------------------------------------------------------------- |
---|
189 | void BillboardChain::setNumberOfChains(size_t numChains) |
---|
190 | { |
---|
191 | mChainCount = numChains; |
---|
192 | setupChainContainers(); |
---|
193 | mBuffersNeedRecreating = mIndexContentDirty = true; |
---|
194 | } |
---|
195 | //----------------------------------------------------------------------- |
---|
196 | void BillboardChain::setUseTextureCoords(bool use) |
---|
197 | { |
---|
198 | mUseTexCoords = use; |
---|
199 | mVertexDeclDirty = mBuffersNeedRecreating = true; |
---|
200 | mIndexContentDirty = true; |
---|
201 | } |
---|
202 | //----------------------------------------------------------------------- |
---|
203 | void BillboardChain::setTextureCoordDirection(BillboardChain::TexCoordDirection dir) |
---|
204 | { |
---|
205 | mTexCoordDir = dir; |
---|
206 | } |
---|
207 | //----------------------------------------------------------------------- |
---|
208 | void BillboardChain::setOtherTextureCoordRange(Real start, Real end) |
---|
209 | { |
---|
210 | mOtherTexCoordRange[0] = start; |
---|
211 | mOtherTexCoordRange[1] = end; |
---|
212 | } |
---|
213 | //----------------------------------------------------------------------- |
---|
214 | void BillboardChain::setUseVertexColours(bool use) |
---|
215 | { |
---|
216 | mUseVertexColour = use; |
---|
217 | mVertexDeclDirty = mBuffersNeedRecreating = true; |
---|
218 | mIndexContentDirty = true; |
---|
219 | } |
---|
220 | //----------------------------------------------------------------------- |
---|
221 | void BillboardChain::setDynamic(bool dyn) |
---|
222 | { |
---|
223 | mDynamic = dyn; |
---|
224 | mBuffersNeedRecreating = mIndexContentDirty = true; |
---|
225 | } |
---|
226 | //----------------------------------------------------------------------- |
---|
227 | void BillboardChain::addChainElement(size_t chainIndex, |
---|
228 | const BillboardChain::Element& dtls) |
---|
229 | { |
---|
230 | |
---|
231 | if (chainIndex >= mChainCount) |
---|
232 | { |
---|
233 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
---|
234 | "chainIndex out of bounds", |
---|
235 | "BillboardChain::addChainElement"); |
---|
236 | } |
---|
237 | ChainSegment& seg = mChainSegmentList[chainIndex]; |
---|
238 | if (seg.head == SEGMENT_EMPTY) |
---|
239 | { |
---|
240 | // Tail starts at end, head grows backwards |
---|
241 | seg.tail = mMaxElementsPerChain - 1; |
---|
242 | seg.head = seg.tail; |
---|
243 | mIndexContentDirty = true; |
---|
244 | } |
---|
245 | else |
---|
246 | { |
---|
247 | if (seg.head == 0) |
---|
248 | { |
---|
249 | // Wrap backwards |
---|
250 | seg.head = mMaxElementsPerChain - 1; |
---|
251 | } |
---|
252 | else |
---|
253 | { |
---|
254 | // Just step backward |
---|
255 | --seg.head; |
---|
256 | } |
---|
257 | // Run out of elements? |
---|
258 | if (seg.head == seg.tail) |
---|
259 | { |
---|
260 | // Move tail backwards too, losing the end of the segment and re-using |
---|
261 | // it in the head |
---|
262 | if (seg.tail == 0) |
---|
263 | seg.tail = mMaxElementsPerChain - 1; |
---|
264 | else |
---|
265 | --seg.tail; |
---|
266 | } |
---|
267 | } |
---|
268 | |
---|
269 | // Set the details |
---|
270 | mChainElementList[seg.start + seg.head] = dtls; |
---|
271 | |
---|
272 | mIndexContentDirty = true; |
---|
273 | mBoundsDirty = true; |
---|
274 | // tell parent node to update bounds |
---|
275 | if (mParentNode) |
---|
276 | mParentNode->needUpdate(); |
---|
277 | |
---|
278 | } |
---|
279 | //----------------------------------------------------------------------- |
---|
280 | void BillboardChain::removeChainElement(size_t chainIndex) |
---|
281 | { |
---|
282 | if (chainIndex >= mChainCount) |
---|
283 | { |
---|
284 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
---|
285 | "chainIndex out of bounds", |
---|
286 | "BillboardChain::removeChainElement"); |
---|
287 | } |
---|
288 | ChainSegment& seg = mChainSegmentList[chainIndex]; |
---|
289 | if (seg.head == SEGMENT_EMPTY) |
---|
290 | return; // do nothing, nothing to remove |
---|
291 | |
---|
292 | |
---|
293 | if (seg.tail == seg.head) |
---|
294 | { |
---|
295 | // last item |
---|
296 | seg.head = seg.tail = SEGMENT_EMPTY; |
---|
297 | } |
---|
298 | else if (seg.tail == 0) |
---|
299 | { |
---|
300 | seg.tail = mMaxElementsPerChain - 1; |
---|
301 | } |
---|
302 | else |
---|
303 | { |
---|
304 | --seg.tail; |
---|
305 | } |
---|
306 | |
---|
307 | // we removed an entry so indexes need updating |
---|
308 | mIndexContentDirty = true; |
---|
309 | mBoundsDirty = true; |
---|
310 | // tell parent node to update bounds |
---|
311 | if (mParentNode) |
---|
312 | mParentNode->needUpdate(); |
---|
313 | |
---|
314 | } |
---|
315 | //----------------------------------------------------------------------- |
---|
316 | void BillboardChain::clearChain(size_t chainIndex) |
---|
317 | { |
---|
318 | if (chainIndex >= mChainCount) |
---|
319 | { |
---|
320 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
---|
321 | "chainIndex out of bounds", |
---|
322 | "BillboardChain::removeChainElement"); |
---|
323 | } |
---|
324 | ChainSegment& seg = mChainSegmentList[chainIndex]; |
---|
325 | |
---|
326 | // Just reset head & tail |
---|
327 | seg.tail = seg.head = SEGMENT_EMPTY; |
---|
328 | |
---|
329 | // we removed an entry so indexes need updating |
---|
330 | mIndexContentDirty = true; |
---|
331 | mBoundsDirty = true; |
---|
332 | // tell parent node to update bounds |
---|
333 | if (mParentNode) |
---|
334 | mParentNode->needUpdate(); |
---|
335 | |
---|
336 | } |
---|
337 | //----------------------------------------------------------------------- |
---|
338 | void BillboardChain::clearAllChains(void) |
---|
339 | { |
---|
340 | for (size_t i = 0; i < mChainCount; ++i) |
---|
341 | { |
---|
342 | clearChain(i); |
---|
343 | } |
---|
344 | |
---|
345 | } |
---|
346 | //----------------------------------------------------------------------- |
---|
347 | void BillboardChain::updateChainElement(size_t chainIndex, size_t elementIndex, |
---|
348 | const BillboardChain::Element& dtls) |
---|
349 | { |
---|
350 | if (chainIndex >= mChainCount) |
---|
351 | { |
---|
352 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
---|
353 | "chainIndex out of bounds", |
---|
354 | "BillboardChain::updateChainElement"); |
---|
355 | } |
---|
356 | ChainSegment& seg = mChainSegmentList[chainIndex]; |
---|
357 | if (seg.head == SEGMENT_EMPTY) |
---|
358 | { |
---|
359 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
---|
360 | "Chain segment is empty", |
---|
361 | "BillboardChain::updateChainElement"); |
---|
362 | } |
---|
363 | |
---|
364 | size_t idx = seg.head + elementIndex; |
---|
365 | // adjust for the edge and start |
---|
366 | idx = (idx % mMaxElementsPerChain) + seg.start; |
---|
367 | |
---|
368 | mChainElementList[idx] = dtls; |
---|
369 | |
---|
370 | mBoundsDirty = true; |
---|
371 | // tell parent node to update bounds |
---|
372 | if (mParentNode) |
---|
373 | mParentNode->needUpdate(); |
---|
374 | |
---|
375 | |
---|
376 | } |
---|
377 | //----------------------------------------------------------------------- |
---|
378 | const BillboardChain::Element& |
---|
379 | BillboardChain::getChainElement(size_t chainIndex, size_t elementIndex) const |
---|
380 | { |
---|
381 | |
---|
382 | if (chainIndex >= mChainCount) |
---|
383 | { |
---|
384 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
---|
385 | "chainIndex out of bounds", |
---|
386 | "BillboardChain::updateChainElement"); |
---|
387 | } |
---|
388 | const ChainSegment& seg = mChainSegmentList[chainIndex]; |
---|
389 | |
---|
390 | size_t idx = seg.head + elementIndex; |
---|
391 | // adjust for the edge and start |
---|
392 | idx = (idx % mMaxElementsPerChain) + seg.start; |
---|
393 | |
---|
394 | return mChainElementList[idx]; |
---|
395 | } |
---|
396 | //----------------------------------------------------------------------- |
---|
397 | void BillboardChain::updateBoundingBox(void) const |
---|
398 | { |
---|
399 | if (mBoundsDirty) |
---|
400 | { |
---|
401 | mAABB.setNull(); |
---|
402 | Vector3 widthVector; |
---|
403 | for (ChainSegmentList::const_iterator segi = mChainSegmentList.begin(); |
---|
404 | segi != mChainSegmentList.end(); ++segi) |
---|
405 | { |
---|
406 | const ChainSegment& seg = *segi; |
---|
407 | |
---|
408 | if (seg.head != SEGMENT_EMPTY) |
---|
409 | { |
---|
410 | |
---|
411 | for(size_t e = seg.head; ; ++e) // until break |
---|
412 | { |
---|
413 | // Wrap forwards |
---|
414 | if (e == mMaxElementsPerChain) |
---|
415 | e = 0; |
---|
416 | |
---|
417 | const Element& elem = mChainElementList[seg.start + e]; |
---|
418 | |
---|
419 | widthVector.x = widthVector.y = widthVector.z = elem.width; |
---|
420 | mAABB.merge(elem.position - widthVector); |
---|
421 | mAABB.merge(elem.position + widthVector); |
---|
422 | |
---|
423 | if (e == seg.tail) |
---|
424 | break; |
---|
425 | |
---|
426 | } |
---|
427 | } |
---|
428 | |
---|
429 | } |
---|
430 | |
---|
431 | // Set the current radius |
---|
432 | if (mAABB.isNull()) |
---|
433 | { |
---|
434 | mRadius = 0.0f; |
---|
435 | } |
---|
436 | else |
---|
437 | { |
---|
438 | mRadius = Math::Sqrt( |
---|
439 | std::max(mAABB.getMinimum().squaredLength(), |
---|
440 | mAABB.getMaximum().squaredLength())); |
---|
441 | } |
---|
442 | |
---|
443 | mBoundsDirty = false; |
---|
444 | } |
---|
445 | } |
---|
446 | //----------------------------------------------------------------------- |
---|
447 | void BillboardChain::updateVertexBuffer(Camera* cam) |
---|
448 | { |
---|
449 | setupBuffers(); |
---|
450 | HardwareVertexBufferSharedPtr pBuffer = |
---|
451 | mVertexData->vertexBufferBinding->getBuffer(0); |
---|
452 | void* pBufferStart = pBuffer->lock(HardwareBuffer::HBL_DISCARD); |
---|
453 | |
---|
454 | const Vector3& camPos = cam->getDerivedPosition(); |
---|
455 | Vector3 eyePos = mParentNode->_getDerivedOrientation().Inverse() * |
---|
456 | (camPos - mParentNode->_getDerivedPosition()) / mParentNode->_getDerivedScale(); |
---|
457 | |
---|
458 | Vector3 chainTangent; |
---|
459 | for (ChainSegmentList::iterator segi = mChainSegmentList.begin(); |
---|
460 | segi != mChainSegmentList.end(); ++segi) |
---|
461 | { |
---|
462 | ChainSegment& seg = *segi; |
---|
463 | |
---|
464 | // Skip 0 or 1 element segment counts |
---|
465 | if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail) |
---|
466 | { |
---|
467 | size_t laste = seg.head; |
---|
468 | for (size_t e = seg.head; ; ++e) // until break |
---|
469 | { |
---|
470 | // Wrap forwards |
---|
471 | if (e == mMaxElementsPerChain) |
---|
472 | e = 0; |
---|
473 | |
---|
474 | Element& elem = mChainElementList[e + seg.start]; |
---|
475 | assert (((e + seg.start) * 2) < 65536 && "Too many elements!"); |
---|
476 | uint16 baseIdx = static_cast<uint16>((e + seg.start) * 2); |
---|
477 | |
---|
478 | // Determine base pointer to vertex #1 |
---|
479 | void* pBase = static_cast<void*>( |
---|
480 | static_cast<char*>(pBufferStart) + |
---|
481 | pBuffer->getVertexSize() * baseIdx); |
---|
482 | |
---|
483 | // Get index of next item |
---|
484 | size_t nexte = e + 1; |
---|
485 | if (nexte == mMaxElementsPerChain) |
---|
486 | nexte = 0; |
---|
487 | |
---|
488 | if (e == seg.head) |
---|
489 | { |
---|
490 | // No laste, use next item |
---|
491 | chainTangent = mChainElementList[nexte + seg.start].position - elem.position; |
---|
492 | } |
---|
493 | else if (e == seg.tail) |
---|
494 | { |
---|
495 | // No nexte, use only last item |
---|
496 | chainTangent = elem.position - mChainElementList[laste + seg.start].position; |
---|
497 | } |
---|
498 | else |
---|
499 | { |
---|
500 | // A mid position, use tangent across both prev and next |
---|
501 | chainTangent = mChainElementList[nexte + seg.start].position - mChainElementList[laste + seg.start].position; |
---|
502 | |
---|
503 | } |
---|
504 | |
---|
505 | Vector3 vP1ToEye = eyePos - elem.position; |
---|
506 | Vector3 vPerpendicular = chainTangent.crossProduct(vP1ToEye); |
---|
507 | vPerpendicular.normalise(); |
---|
508 | vPerpendicular *= (elem.width * 0.5); |
---|
509 | |
---|
510 | Vector3 pos0 = elem.position - vPerpendicular; |
---|
511 | Vector3 pos1 = elem.position + vPerpendicular; |
---|
512 | |
---|
513 | float* pFloat = static_cast<float*>(pBase); |
---|
514 | // pos1 |
---|
515 | *pFloat++ = pos0.x; |
---|
516 | *pFloat++ = pos0.y; |
---|
517 | *pFloat++ = pos0.z; |
---|
518 | |
---|
519 | pBase = static_cast<void*>(pFloat); |
---|
520 | |
---|
521 | if (mUseVertexColour) |
---|
522 | { |
---|
523 | RGBA* pCol = static_cast<RGBA*>(pBase); |
---|
524 | Root::getSingleton().convertColourValue(elem.colour, pCol); |
---|
525 | pCol++; |
---|
526 | pBase = static_cast<void*>(pCol); |
---|
527 | } |
---|
528 | |
---|
529 | if (mUseTexCoords) |
---|
530 | { |
---|
531 | pFloat = static_cast<float*>(pBase); |
---|
532 | if (mTexCoordDir == TCD_U) |
---|
533 | { |
---|
534 | *pFloat++ = elem.texCoord; |
---|
535 | *pFloat++ = mOtherTexCoordRange[0]; |
---|
536 | } |
---|
537 | else |
---|
538 | { |
---|
539 | *pFloat++ = mOtherTexCoordRange[0]; |
---|
540 | *pFloat++ = elem.texCoord; |
---|
541 | } |
---|
542 | pBase = static_cast<void*>(pFloat); |
---|
543 | } |
---|
544 | |
---|
545 | // pos2 |
---|
546 | pFloat = static_cast<float*>(pBase); |
---|
547 | *pFloat++ = pos1.x; |
---|
548 | *pFloat++ = pos1.y; |
---|
549 | *pFloat++ = pos1.z; |
---|
550 | pBase = static_cast<void*>(pFloat); |
---|
551 | |
---|
552 | if (mUseVertexColour) |
---|
553 | { |
---|
554 | RGBA* pCol = static_cast<RGBA*>(pBase); |
---|
555 | Root::getSingleton().convertColourValue(elem.colour, pCol); |
---|
556 | pCol++; |
---|
557 | pBase = static_cast<void*>(pCol); |
---|
558 | } |
---|
559 | |
---|
560 | if (mUseTexCoords) |
---|
561 | { |
---|
562 | pFloat = static_cast<float*>(pBase); |
---|
563 | if (mTexCoordDir == TCD_U) |
---|
564 | { |
---|
565 | *pFloat++ = elem.texCoord; |
---|
566 | *pFloat++ = mOtherTexCoordRange[1]; |
---|
567 | } |
---|
568 | else |
---|
569 | { |
---|
570 | *pFloat++ = mOtherTexCoordRange[1]; |
---|
571 | *pFloat++ = elem.texCoord; |
---|
572 | } |
---|
573 | pBase = static_cast<void*>(pFloat); |
---|
574 | } |
---|
575 | |
---|
576 | if (e == seg.tail) |
---|
577 | break; // last one |
---|
578 | |
---|
579 | laste = e; |
---|
580 | |
---|
581 | } // element |
---|
582 | } // segment valid? |
---|
583 | |
---|
584 | } // each segment |
---|
585 | |
---|
586 | |
---|
587 | |
---|
588 | pBuffer->unlock(); |
---|
589 | |
---|
590 | |
---|
591 | } |
---|
592 | //----------------------------------------------------------------------- |
---|
593 | void BillboardChain::updateIndexBuffer(void) |
---|
594 | { |
---|
595 | |
---|
596 | setupBuffers(); |
---|
597 | if (mIndexContentDirty) |
---|
598 | { |
---|
599 | |
---|
600 | uint16* pShort = static_cast<uint16*>( |
---|
601 | mIndexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD)); |
---|
602 | mIndexData->indexCount = 0; |
---|
603 | // indexes |
---|
604 | for (ChainSegmentList::iterator segi = mChainSegmentList.begin(); |
---|
605 | segi != mChainSegmentList.end(); ++segi) |
---|
606 | { |
---|
607 | ChainSegment& seg = *segi; |
---|
608 | |
---|
609 | // Skip 0 or 1 element segment counts |
---|
610 | if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail) |
---|
611 | { |
---|
612 | // Start from head + 1 since it's only useful in pairs |
---|
613 | size_t laste = seg.head; |
---|
614 | while(1) // until break |
---|
615 | { |
---|
616 | size_t e = laste + 1; |
---|
617 | // Wrap forwards |
---|
618 | if (e == mMaxElementsPerChain) |
---|
619 | e = 0; |
---|
620 | // indexes of this element are (e * 2) and (e * 2) + 1 |
---|
621 | // indexes of the last element are the same, -2 |
---|
622 | assert (((e + seg.start) * 2) < 65536 && "Too many elements!"); |
---|
623 | uint16 baseIdx = static_cast<uint16>((e + seg.start) * 2); |
---|
624 | uint16 lastBaseIdx = static_cast<uint16>((laste + seg.start) * 2); |
---|
625 | *pShort++ = lastBaseIdx; |
---|
626 | *pShort++ = lastBaseIdx + 1; |
---|
627 | *pShort++ = baseIdx; |
---|
628 | *pShort++ = lastBaseIdx + 1; |
---|
629 | *pShort++ = baseIdx + 1; |
---|
630 | *pShort++ = baseIdx; |
---|
631 | |
---|
632 | mIndexData->indexCount += 6; |
---|
633 | |
---|
634 | |
---|
635 | if (e == seg.tail) |
---|
636 | break; // last one |
---|
637 | |
---|
638 | laste = e; |
---|
639 | |
---|
640 | } |
---|
641 | } |
---|
642 | |
---|
643 | } |
---|
644 | mIndexData->indexBuffer->unlock(); |
---|
645 | |
---|
646 | mIndexContentDirty = false; |
---|
647 | } |
---|
648 | |
---|
649 | } |
---|
650 | //----------------------------------------------------------------------- |
---|
651 | void BillboardChain::_notifyCurrentCamera(Camera* cam) |
---|
652 | { |
---|
653 | updateVertexBuffer(cam); |
---|
654 | } |
---|
655 | //----------------------------------------------------------------------- |
---|
656 | Real BillboardChain::getSquaredViewDepth(const Camera* cam) const |
---|
657 | { |
---|
658 | Vector3 min, max, mid, dist; |
---|
659 | min = mAABB.getMinimum(); |
---|
660 | max = mAABB.getMaximum(); |
---|
661 | mid = ((max - min) * 0.5) + min; |
---|
662 | dist = cam->getDerivedPosition() - mid; |
---|
663 | |
---|
664 | return dist.squaredLength(); |
---|
665 | } |
---|
666 | //----------------------------------------------------------------------- |
---|
667 | Real BillboardChain::getBoundingRadius(void) const |
---|
668 | { |
---|
669 | return mRadius; |
---|
670 | } |
---|
671 | //----------------------------------------------------------------------- |
---|
672 | const AxisAlignedBox& BillboardChain::getBoundingBox(void) const |
---|
673 | { |
---|
674 | updateBoundingBox(); |
---|
675 | return mAABB; |
---|
676 | } |
---|
677 | //----------------------------------------------------------------------- |
---|
678 | const MaterialPtr& BillboardChain::getMaterial(void) const |
---|
679 | { |
---|
680 | return mMaterial; |
---|
681 | } |
---|
682 | //----------------------------------------------------------------------- |
---|
683 | void BillboardChain::setMaterialName(const String& name) |
---|
684 | { |
---|
685 | mMaterialName = name; |
---|
686 | mMaterial = MaterialManager::getSingleton().getByName(mMaterialName); |
---|
687 | |
---|
688 | if (mMaterial.isNull()) |
---|
689 | { |
---|
690 | LogManager::getSingleton().logMessage("Can't assign material " + name + |
---|
691 | " to BillboardChain " + mName + " because this " |
---|
692 | "Material does not exist. Have you forgotten to define it in a " |
---|
693 | ".material script?"); |
---|
694 | mMaterial = MaterialManager::getSingleton().getByName("BaseWhiteNoLighting"); |
---|
695 | if (mMaterial.isNull()) |
---|
696 | { |
---|
697 | OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Can't assign default material " |
---|
698 | "to BillboardChain of " + mName + ". Did " |
---|
699 | "you forget to call MaterialManager::initialise()?", |
---|
700 | "BillboardChain.setMaterialName"); |
---|
701 | } |
---|
702 | } |
---|
703 | // Ensure new material loaded (will not load again if already loaded) |
---|
704 | mMaterial->load(); |
---|
705 | } |
---|
706 | //----------------------------------------------------------------------- |
---|
707 | const String& BillboardChain::getMovableType(void) const |
---|
708 | { |
---|
709 | return BillboardChainFactory::FACTORY_TYPE_NAME; |
---|
710 | } |
---|
711 | //----------------------------------------------------------------------- |
---|
712 | void BillboardChain::_updateRenderQueue(RenderQueue* queue) |
---|
713 | { |
---|
714 | updateIndexBuffer(); |
---|
715 | |
---|
716 | if (mIndexData->indexCount > 0) |
---|
717 | { |
---|
718 | if (mRenderQueueIDSet) |
---|
719 | queue->addRenderable(this, mRenderQueueID); |
---|
720 | else |
---|
721 | queue->addRenderable(this); |
---|
722 | } |
---|
723 | |
---|
724 | } |
---|
725 | //----------------------------------------------------------------------- |
---|
726 | void BillboardChain::getRenderOperation(RenderOperation& op) |
---|
727 | { |
---|
728 | op.indexData = mIndexData; |
---|
729 | op.operationType = RenderOperation::OT_TRIANGLE_LIST; |
---|
730 | op.srcRenderable = this; |
---|
731 | op.useIndexes = true; |
---|
732 | op.vertexData = mVertexData; |
---|
733 | } |
---|
734 | //----------------------------------------------------------------------- |
---|
735 | void BillboardChain::getWorldTransforms(Matrix4* xform) const |
---|
736 | { |
---|
737 | *xform = _getParentNodeFullTransform(); |
---|
738 | } |
---|
739 | //----------------------------------------------------------------------- |
---|
740 | const Quaternion& BillboardChain::getWorldOrientation(void) const |
---|
741 | { |
---|
742 | return getParentNode()->_getDerivedOrientation(); |
---|
743 | } |
---|
744 | //----------------------------------------------------------------------- |
---|
745 | const Vector3& BillboardChain::getWorldPosition(void) const |
---|
746 | { |
---|
747 | return getParentNode()->_getDerivedPosition(); |
---|
748 | } |
---|
749 | //----------------------------------------------------------------------- |
---|
750 | const LightList& BillboardChain::getLights(void) const |
---|
751 | { |
---|
752 | return queryLights(); |
---|
753 | } |
---|
754 | //----------------------------------------------------------------------- |
---|
755 | //----------------------------------------------------------------------- |
---|
756 | String BillboardChainFactory::FACTORY_TYPE_NAME = "BillboardChain"; |
---|
757 | //----------------------------------------------------------------------- |
---|
758 | const String& BillboardChainFactory::getType(void) const |
---|
759 | { |
---|
760 | return FACTORY_TYPE_NAME; |
---|
761 | } |
---|
762 | //----------------------------------------------------------------------- |
---|
763 | MovableObject* BillboardChainFactory::createInstanceImpl( const String& name, |
---|
764 | const NameValuePairList* params) |
---|
765 | { |
---|
766 | size_t maxElements = 20; |
---|
767 | size_t numberOfChains = 1; |
---|
768 | bool useTex = true; |
---|
769 | bool useCol = true; |
---|
770 | bool dynamic = true; |
---|
771 | // optional params |
---|
772 | if (params != 0) |
---|
773 | { |
---|
774 | NameValuePairList::const_iterator ni = params->find("maxElements"); |
---|
775 | if (ni != params->end()) |
---|
776 | { |
---|
777 | maxElements = StringConverter::parseUnsignedLong(ni->second); |
---|
778 | } |
---|
779 | ni = params->find("numberOfChains"); |
---|
780 | if (ni != params->end()) |
---|
781 | { |
---|
782 | numberOfChains = StringConverter::parseUnsignedLong(ni->second); |
---|
783 | } |
---|
784 | ni = params->find("useTextureCoords"); |
---|
785 | if (ni != params->end()) |
---|
786 | { |
---|
787 | useTex = StringConverter::parseBool(ni->second); |
---|
788 | } |
---|
789 | ni = params->find("useVertexColours"); |
---|
790 | if (ni != params->end()) |
---|
791 | { |
---|
792 | useCol = StringConverter::parseBool(ni->second); |
---|
793 | } |
---|
794 | ni = params->find("dynamic"); |
---|
795 | if (ni != params->end()) |
---|
796 | { |
---|
797 | dynamic = StringConverter::parseBool(ni->second); |
---|
798 | } |
---|
799 | |
---|
800 | } |
---|
801 | |
---|
802 | return new BillboardChain(name, maxElements, numberOfChains, useTex, useCol, dynamic); |
---|
803 | |
---|
804 | } |
---|
805 | //----------------------------------------------------------------------- |
---|
806 | void BillboardChainFactory::destroyInstance( MovableObject* obj) |
---|
807 | { |
---|
808 | delete obj; |
---|
809 | } |
---|
810 | |
---|
811 | } |
---|
812 | |
---|