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-2014 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 
29 // Thanks to Vincent Cantin (karmaGfa) for the original implementation of this
30 // class, although it has now been mostly rewritten
31 
32 #include "OgreStableHeaders.h"
33 #include "OgreBillboardChain.h"
34 #include "OgreViewport.h"
35 
36 #include <limits>
37 
38 namespace Ogre {
39     const size_t BillboardChain::SEGMENT_EMPTY = std::numeric_limits<size_t>::max();
40     //-----------------------------------------------------------------------
Element()41     BillboardChain::Element::Element()
42     {
43     }
44     //-----------------------------------------------------------------------
Element(const Vector3 & _position,Real _width,Real _texCoord,const ColourValue & _colour,const Quaternion & _orientation)45     BillboardChain::Element::Element(const Vector3 &_position,
46         Real _width,
47         Real _texCoord,
48         const ColourValue &_colour,
49         const Quaternion &_orientation) :
50     position(_position),
51         width(_width),
52         texCoord(_texCoord),
53         colour(_colour),
54         orientation(_orientation)
55     {
56     }
57     //-----------------------------------------------------------------------
BillboardChain(const String & name,size_t maxElements,size_t numberOfChains,bool useTextureCoords,bool useColours,bool dynamic)58     BillboardChain::BillboardChain(const String& name, size_t maxElements,
59         size_t numberOfChains, bool useTextureCoords, bool useColours, bool dynamic)
60         :MovableObject(name),
61         mMaxElementsPerChain(maxElements),
62         mChainCount(numberOfChains),
63         mUseTexCoords(useTextureCoords),
64         mUseVertexColour(useColours),
65         mDynamic(dynamic),
66         mVertexDeclDirty(true),
67         mBuffersNeedRecreating(true),
68         mBoundsDirty(true),
69         mIndexContentDirty(true),
70         mVertexContentDirty(true),
71         mRadius(0.0f),
72         mTexCoordDir(TCD_U),
73         mVertexCameraUsed(0),
74         mFaceCamera(true),
75         mNormalBase(Vector3::UNIT_X)
76     {
77         mVertexData.reset(new VertexData());
78         mIndexData.reset(new IndexData());
79 
80         mOtherTexCoordRange[0] = 0.0f;
81         mOtherTexCoordRange[1] = 1.0f;
82 
83         setupChainContainers();
84 
85         mVertexData->vertexStart = 0;
86         // index data set up later
87         // set basic white material
88         mMaterial = MaterialManager::getSingleton().getDefaultMaterial(false);
89         mMaterial->load();
90     }
91 
92     BillboardChain::~BillboardChain() = default; // ensure unique_ptr destructors are in cpp
93 
94     //-----------------------------------------------------------------------
setupChainContainers(void)95     void BillboardChain::setupChainContainers(void)
96     {
97         // Allocate enough space for everything
98         mChainElementList.resize(mChainCount * mMaxElementsPerChain);
99         mVertexData->vertexCount = mChainElementList.size() * 2;
100 
101         // Configure chains
102         mChainSegmentList.resize(mChainCount);
103         for (size_t i = 0; i < mChainCount; ++i)
104         {
105             ChainSegment& seg = mChainSegmentList[i];
106             seg.start = i * mMaxElementsPerChain;
107             seg.tail = seg.head = SEGMENT_EMPTY;
108 
109         }
110 
111 
112     }
113     //-----------------------------------------------------------------------
setupVertexDeclaration(void)114     void BillboardChain::setupVertexDeclaration(void)
115     {
116         if (mVertexDeclDirty)
117         {
118             VertexDeclaration* decl = mVertexData->vertexDeclaration;
119             decl->removeAllElements();
120 
121             size_t offset = 0;
122             // Add a description for the buffer of the positions of the vertices
123             decl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
124             offset += VertexElement::getTypeSize(VET_FLOAT3);
125 
126             if (mUseVertexColour)
127             {
128                 decl->addElement(0, offset, VET_COLOUR, VES_DIFFUSE);
129                 offset += VertexElement::getTypeSize(VET_COLOUR);
130             }
131 
132             if (mUseTexCoords)
133             {
134                 decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES);
135             }
136 
137             if (!mUseTexCoords && !mUseVertexColour)
138             {
139                 LogManager::getSingleton().logError(
140                     "BillboardChain '" + mName + "' is using neither "
141                     "texture coordinates nor vertex colours; it will not be "
142                     "visible on some rendering APIs so you should change this "
143                     "so you use one or the other.");
144             }
145             mVertexDeclDirty = false;
146         }
147     }
148     //-----------------------------------------------------------------------
setupBuffers(void)149     void BillboardChain::setupBuffers(void)
150     {
151         setupVertexDeclaration();
152         if (mBuffersNeedRecreating)
153         {
154             // Create the vertex buffer (always dynamic due to the camera adjust)
155             HardwareVertexBufferSharedPtr pBuffer =
156                 HardwareBufferManager::getSingleton().createVertexBuffer(
157                 mVertexData->vertexDeclaration->getVertexSize(0),
158                 mVertexData->vertexCount,
159                 HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
160 
161             // (re)Bind the buffer
162             // Any existing buffer will lose its reference count and be destroyed
163             mVertexData->vertexBufferBinding->setBinding(0, pBuffer);
164 
165             mIndexData->indexBuffer =
166                 HardwareBufferManager::getSingleton().createIndexBuffer(
167                     HardwareIndexBuffer::IT_16BIT,
168                     mChainCount * mMaxElementsPerChain * 6, // max we can use
169                     mDynamic? HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY : HardwareBuffer::HBU_STATIC_WRITE_ONLY);
170             // NB we don't set the indexCount on IndexData here since we will
171             // probably use less than the maximum number of indices
172 
173             mBuffersNeedRecreating = false;
174         }
175     }
176     //-----------------------------------------------------------------------
setMaxChainElements(size_t maxElements)177     void BillboardChain::setMaxChainElements(size_t maxElements)
178     {
179         mMaxElementsPerChain = maxElements;
180         setupChainContainers();
181         mBuffersNeedRecreating = mIndexContentDirty = mVertexContentDirty = true;
182     }
183     //-----------------------------------------------------------------------
setNumberOfChains(size_t numChains)184     void BillboardChain::setNumberOfChains(size_t numChains)
185     {
186         mChainCount = numChains;
187         setupChainContainers();
188         mBuffersNeedRecreating = mIndexContentDirty = mVertexContentDirty = true;
189     }
190     //-----------------------------------------------------------------------
setUseTextureCoords(bool use)191     void BillboardChain::setUseTextureCoords(bool use)
192     {
193         mUseTexCoords = use;
194         mVertexDeclDirty = mBuffersNeedRecreating = true;
195         mIndexContentDirty = mVertexContentDirty = true;
196     }
197     //-----------------------------------------------------------------------
setTextureCoordDirection(BillboardChain::TexCoordDirection dir)198     void BillboardChain::setTextureCoordDirection(BillboardChain::TexCoordDirection dir)
199     {
200         mTexCoordDir = dir;
201         mVertexContentDirty = true;
202     }
203     //-----------------------------------------------------------------------
setOtherTextureCoordRange(Real start,Real end)204     void BillboardChain::setOtherTextureCoordRange(Real start, Real end)
205     {
206         mOtherTexCoordRange[0] = start;
207         mOtherTexCoordRange[1] = end;
208         mVertexContentDirty = true;
209     }
210     //-----------------------------------------------------------------------
setUseVertexColours(bool use)211     void BillboardChain::setUseVertexColours(bool use)
212     {
213         mUseVertexColour = use;
214         mVertexDeclDirty = mBuffersNeedRecreating = true;
215         mIndexContentDirty = mVertexContentDirty = true;
216     }
217     //-----------------------------------------------------------------------
setDynamic(bool dyn)218     void BillboardChain::setDynamic(bool dyn)
219     {
220         mDynamic = dyn;
221         mBuffersNeedRecreating = mIndexContentDirty = mVertexContentDirty = true;
222     }
223     //-----------------------------------------------------------------------
addChainElement(size_t chainIndex,const BillboardChain::Element & dtls)224     void BillboardChain::addChainElement(size_t chainIndex,
225         const BillboardChain::Element& dtls)
226     {
227 
228         if (chainIndex >= mChainCount)
229         {
230             OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
231                 "chainIndex out of bounds",
232                 "BillboardChain::addChainElement");
233         }
234         ChainSegment& seg = mChainSegmentList[chainIndex];
235         if (seg.head == SEGMENT_EMPTY)
236         {
237             // Tail starts at end, head grows backwards
238             seg.tail = mMaxElementsPerChain - 1;
239             seg.head = seg.tail;
240         }
241         else
242         {
243             if (seg.head == 0)
244             {
245                 // Wrap backwards
246                 seg.head = mMaxElementsPerChain - 1;
247             }
248             else
249             {
250                 // Just step backward
251                 --seg.head;
252             }
253             // Run out of elements?
254             if (seg.head == seg.tail)
255             {
256                 // Move tail backwards too, losing the end of the segment and re-using
257                 // it in the head
258                 if (seg.tail == 0)
259                     seg.tail = mMaxElementsPerChain - 1;
260                 else
261                     --seg.tail;
262             }
263         }
264 
265         // Set the details
266         mChainElementList[seg.start + seg.head] = dtls;
267 
268         mVertexContentDirty = true;
269         mIndexContentDirty = true;
270         mBoundsDirty = true;
271         // tell parent node to update bounds
272         if (mParentNode)
273             mParentNode->needUpdate();
274 
275     }
276     //-----------------------------------------------------------------------
removeChainElement(size_t chainIndex)277     void BillboardChain::removeChainElement(size_t chainIndex)
278     {
279         if (chainIndex >= mChainCount)
280         {
281             OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
282                 "chainIndex out of bounds",
283                 "BillboardChain::removeChainElement");
284         }
285         ChainSegment& seg = mChainSegmentList[chainIndex];
286         if (seg.head == SEGMENT_EMPTY)
287             return; // do nothing, nothing to remove
288 
289 
290         if (seg.tail == seg.head)
291         {
292             // last item
293             seg.head = seg.tail = SEGMENT_EMPTY;
294         }
295         else if (seg.tail == 0)
296         {
297             seg.tail = mMaxElementsPerChain - 1;
298         }
299         else
300         {
301             --seg.tail;
302         }
303 
304         // we removed an entry so indexes need updating
305         mVertexContentDirty = true;
306         mIndexContentDirty = true;
307         mBoundsDirty = true;
308         // tell parent node to update bounds
309         if (mParentNode)
310             mParentNode->needUpdate();
311 
312     }
313     //-----------------------------------------------------------------------
clearChain(size_t chainIndex)314     void BillboardChain::clearChain(size_t chainIndex)
315     {
316         if (chainIndex >= mChainCount)
317         {
318             OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
319                 "chainIndex out of bounds",
320                 "BillboardChain::clearChain");
321         }
322         ChainSegment& seg = mChainSegmentList[chainIndex];
323 
324         // Just reset head & tail
325         seg.tail = seg.head = SEGMENT_EMPTY;
326 
327         // we removed an entry so indexes need updating
328         mVertexContentDirty = true;
329         mIndexContentDirty = true;
330         mBoundsDirty = true;
331         // tell parent node to update bounds
332         if (mParentNode)
333             mParentNode->needUpdate();
334 
335     }
336     //-----------------------------------------------------------------------
clearAllChains(void)337     void BillboardChain::clearAllChains(void)
338     {
339         for (size_t i = 0; i < mChainCount; ++i)
340         {
341             clearChain(i);
342         }
343 
344     }
345     //-----------------------------------------------------------------------
setFaceCamera(bool faceCamera,const Vector3 & normalVector)346     void BillboardChain::setFaceCamera( bool faceCamera, const Vector3 &normalVector )
347     {
348         mFaceCamera = faceCamera;
349         mNormalBase = normalVector.normalisedCopy();
350         mVertexContentDirty = true;
351     }
352     //-----------------------------------------------------------------------
updateChainElement(size_t chainIndex,size_t elementIndex,const BillboardChain::Element & dtls)353     void BillboardChain::updateChainElement(size_t chainIndex, size_t elementIndex,
354         const BillboardChain::Element& dtls)
355     {
356         if (chainIndex >= mChainCount)
357         {
358             OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
359                 "chainIndex out of bounds",
360                 "BillboardChain::updateChainElement");
361         }
362         ChainSegment& seg = mChainSegmentList[chainIndex];
363         if (seg.head == SEGMENT_EMPTY)
364         {
365             OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
366                 "Chain segment is empty",
367                 "BillboardChain::updateChainElement");
368         }
369 
370         size_t idx = seg.head + elementIndex;
371         // adjust for the edge and start
372         idx = (idx % mMaxElementsPerChain) + seg.start;
373 
374         mChainElementList[idx] = dtls;
375 
376         mVertexContentDirty = true;
377         mBoundsDirty = true;
378         // tell parent node to update bounds
379         if (mParentNode)
380             mParentNode->needUpdate();
381 
382 
383     }
384     //-----------------------------------------------------------------------
385     const BillboardChain::Element&
getChainElement(size_t chainIndex,size_t elementIndex) const386     BillboardChain::getChainElement(size_t chainIndex, size_t elementIndex) const
387     {
388 
389         if (chainIndex >= mChainCount)
390         {
391             OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
392                 "chainIndex out of bounds",
393                 "BillboardChain::getChainElement");
394         }
395         const ChainSegment& seg = mChainSegmentList[chainIndex];
396         if (seg.head == SEGMENT_EMPTY)
397         {
398             OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
399                 "Chain segment is empty",
400                 "BillboardChain::getChainElement");
401         }
402 
403         size_t idx = seg.head + elementIndex;
404         // adjust for the edge and start
405         idx = (idx % mMaxElementsPerChain) + seg.start;
406 
407         return mChainElementList[idx];
408     }
409     //-----------------------------------------------------------------------
getNumChainElements(size_t chainIndex) const410     size_t BillboardChain::getNumChainElements(size_t chainIndex) const
411     {
412         if (chainIndex >= mChainCount)
413         {
414             OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
415                 "chainIndex out of bounds",
416                 "BillboardChain::getNumChainElements");
417         }
418         const ChainSegment& seg = mChainSegmentList[chainIndex];
419 
420         if (seg.head == SEGMENT_EMPTY)
421         {
422             return 0;
423         }
424         else if (seg.tail < seg.head)
425         {
426             return seg.tail - seg.head + mMaxElementsPerChain + 1;
427         }
428         else
429         {
430             return seg.tail - seg.head + 1;
431         }
432     }
433     //-----------------------------------------------------------------------
updateBoundingBox(void) const434     void BillboardChain::updateBoundingBox(void) const
435     {
436         if (mBoundsDirty)
437         {
438             mAABB.setNull();
439             Vector3 widthVector;
440             for (ChainSegmentList::const_iterator segi = mChainSegmentList.begin();
441                 segi != mChainSegmentList.end(); ++segi)
442             {
443                 const ChainSegment& seg = *segi;
444 
445                 if (seg.head != SEGMENT_EMPTY)
446                 {
447 
448                     for(size_t e = seg.head; ; ++e) // until break
449                     {
450                         // Wrap forwards
451                         if (e == mMaxElementsPerChain)
452                             e = 0;
453 
454                         const Element& elem = mChainElementList[seg.start + e];
455 
456                         widthVector.x = widthVector.y = widthVector.z = elem.width;
457                         mAABB.merge(elem.position - widthVector);
458                         mAABB.merge(elem.position + widthVector);
459 
460                         if (e == seg.tail)
461                             break;
462 
463                     }
464                 }
465 
466             }
467 
468             // Set the current radius
469             if (mAABB.isNull())
470             {
471                 mRadius = 0.0f;
472             }
473             else
474             {
475                 mRadius = Math::Sqrt(
476                     std::max(mAABB.getMinimum().squaredLength(),
477                     mAABB.getMaximum().squaredLength()));
478             }
479 
480             mBoundsDirty = false;
481         }
482     }
483     //-----------------------------------------------------------------------
updateVertexBuffer(Camera * cam)484     void BillboardChain::updateVertexBuffer(Camera* cam)
485     {
486         setupBuffers();
487 
488         // The contents of the vertex buffer are correct if they are not dirty
489         // and the camera used to build the vertex buffer is still the current
490         // camera.
491         if (!mVertexContentDirty && mVertexCameraUsed == cam)
492             return;
493 
494         HardwareVertexBufferSharedPtr pBuffer =
495             mVertexData->vertexBufferBinding->getBuffer(0);
496         HardwareBufferLockGuard vertexLock(pBuffer, HardwareBuffer::HBL_DISCARD);
497 
498         const Vector3& camPos = cam->getDerivedPosition();
499         Vector3 eyePos = mParentNode->convertWorldToLocalPosition(camPos);
500 
501         Vector3 chainTangent;
502         for (ChainSegmentList::iterator segi = mChainSegmentList.begin();
503             segi != mChainSegmentList.end(); ++segi)
504         {
505             ChainSegment& seg = *segi;
506 
507             // Skip 0 or 1 element segment counts
508             if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail)
509             {
510                 size_t laste = seg.head;
511                 for (size_t e = seg.head; ; ++e) // until break
512                 {
513                     // Wrap forwards
514                     if (e == mMaxElementsPerChain)
515                         e = 0;
516 
517                     Element& elem = mChainElementList[e + seg.start];
518                     assert (((e + seg.start) * 2) < 65536 && "Too many elements!");
519                     uint16 baseIdx = static_cast<uint16>((e + seg.start) * 2);
520 
521                     // Determine base pointer to vertex #1
522                     void* pBase = static_cast<void*>(
523                         static_cast<char*>(vertexLock.pData) +
524                             pBuffer->getVertexSize() * baseIdx);
525 
526                     // Get index of next item
527                     size_t nexte = e + 1;
528                     if (nexte == mMaxElementsPerChain)
529                         nexte = 0;
530 
531                     if (e == seg.head)
532                     {
533                         // No laste, use next item
534                         chainTangent = mChainElementList[nexte + seg.start].position - elem.position;
535                     }
536                     else if (e == seg.tail)
537                     {
538                         // No nexte, use only last item
539                         chainTangent = elem.position - mChainElementList[laste + seg.start].position;
540                     }
541                     else
542                     {
543                         // A mid position, use tangent across both prev and next
544                         chainTangent = mChainElementList[nexte + seg.start].position - mChainElementList[laste + seg.start].position;
545 
546                     }
547 
548                     Vector3 vP1ToEye;
549 
550                     if( mFaceCamera )
551                         vP1ToEye = eyePos - elem.position;
552                     else
553                         vP1ToEye = elem.orientation * mNormalBase;
554 
555                     Vector3 vPerpendicular = chainTangent.crossProduct(vP1ToEye);
556                     vPerpendicular.normalise();
557                     vPerpendicular *= (elem.width * 0.5f);
558 
559                     Vector3 pos0 = elem.position - vPerpendicular;
560                     Vector3 pos1 = elem.position + vPerpendicular;
561 
562                     float* pFloat = static_cast<float*>(pBase);
563                     // pos1
564                     *pFloat++ = pos0.x;
565                     *pFloat++ = pos0.y;
566                     *pFloat++ = pos0.z;
567 
568                     pBase = static_cast<void*>(pFloat);
569 
570                     if (mUseVertexColour)
571                     {
572                         RGBA* pCol = static_cast<RGBA*>(pBase);
573                         Root::getSingleton().convertColourValue(elem.colour, pCol);
574                         pCol++;
575                         pBase = static_cast<void*>(pCol);
576                     }
577 
578                     if (mUseTexCoords)
579                     {
580                         pFloat = static_cast<float*>(pBase);
581                         if (mTexCoordDir == TCD_U)
582                         {
583                             *pFloat++ = elem.texCoord;
584                             *pFloat++ = mOtherTexCoordRange[0];
585                         }
586                         else
587                         {
588                             *pFloat++ = mOtherTexCoordRange[0];
589                             *pFloat++ = elem.texCoord;
590                         }
591                         pBase = static_cast<void*>(pFloat);
592                     }
593 
594                     // pos2
595                     pFloat = static_cast<float*>(pBase);
596                     *pFloat++ = pos1.x;
597                     *pFloat++ = pos1.y;
598                     *pFloat++ = pos1.z;
599                     pBase = static_cast<void*>(pFloat);
600 
601                     if (mUseVertexColour)
602                     {
603                         RGBA* pCol = static_cast<RGBA*>(pBase);
604                         Root::getSingleton().convertColourValue(elem.colour, pCol);
605                         pCol++;
606                         pBase = static_cast<void*>(pCol);
607                     }
608 
609                     if (mUseTexCoords)
610                     {
611                         pFloat = static_cast<float*>(pBase);
612                         if (mTexCoordDir == TCD_U)
613                         {
614                             *pFloat++ = elem.texCoord;
615                             *pFloat++ = mOtherTexCoordRange[1];
616                         }
617                         else
618                         {
619                             *pFloat++ = mOtherTexCoordRange[1];
620                             *pFloat++ = elem.texCoord;
621                         }
622                     }
623 
624                     if (e == seg.tail)
625                         break; // last one
626 
627                     laste = e;
628 
629                 } // element
630             } // segment valid?
631 
632         } // each segment
633 
634         mVertexCameraUsed = cam;
635         mVertexContentDirty = false;
636     }
637     //-----------------------------------------------------------------------
updateIndexBuffer(void)638     void BillboardChain::updateIndexBuffer(void)
639     {
640 
641         setupBuffers();
642         if (mIndexContentDirty)
643         {
644             HardwareBufferLockGuard indexLock(mIndexData->indexBuffer, HardwareBuffer::HBL_DISCARD);
645             uint16* pShort = static_cast<uint16*>(indexLock.pData);
646             mIndexData->indexCount = 0;
647             // indexes
648             for (ChainSegmentList::iterator segi = mChainSegmentList.begin();
649                 segi != mChainSegmentList.end(); ++segi)
650             {
651                 ChainSegment& seg = *segi;
652 
653                 // Skip 0 or 1 element segment counts
654                 if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail)
655                 {
656                     // Start from head + 1 since it's only useful in pairs
657                     size_t laste = seg.head;
658                     while(1) // until break
659                     {
660                         size_t e = laste + 1;
661                         // Wrap forwards
662                         if (e == mMaxElementsPerChain)
663                             e = 0;
664                         // indexes of this element are (e * 2) and (e * 2) + 1
665                         // indexes of the last element are the same, -2
666                         assert (((e + seg.start) * 2) < 65536 && "Too many elements!");
667                         uint16 baseIdx = static_cast<uint16>((e + seg.start) * 2);
668                         uint16 lastBaseIdx = static_cast<uint16>((laste + seg.start) * 2);
669                         *pShort++ = lastBaseIdx;
670                         *pShort++ = lastBaseIdx + 1;
671                         *pShort++ = baseIdx;
672                         *pShort++ = lastBaseIdx + 1;
673                         *pShort++ = baseIdx + 1;
674                         *pShort++ = baseIdx;
675 
676                         mIndexData->indexCount += 6;
677 
678 
679                         if (e == seg.tail)
680                             break; // last one
681 
682                         laste = e;
683 
684                     }
685                 }
686 
687             }
688 
689             mIndexContentDirty = false;
690         }
691 
692     }
693     //-----------------------------------------------------------------------
getSquaredViewDepth(const Camera * cam) const694     Real BillboardChain::getSquaredViewDepth(const Camera* cam) const
695     {
696         return (cam->getDerivedPosition() - mAABB.getCenter()).squaredLength();
697     }
698     //-----------------------------------------------------------------------
getBoundingRadius(void) const699     Real BillboardChain::getBoundingRadius(void) const
700     {
701         return mRadius;
702     }
703     //-----------------------------------------------------------------------
getBoundingBox(void) const704     const AxisAlignedBox& BillboardChain::getBoundingBox(void) const
705     {
706         updateBoundingBox();
707         return mAABB;
708     }
709     //-----------------------------------------------------------------------
getMaterial(void) const710     const MaterialPtr& BillboardChain::getMaterial(void) const
711     {
712         return mMaterial;
713     }
714     //-----------------------------------------------------------------------
setMaterialName(const String & name,const String & groupName)715     void BillboardChain::setMaterialName( const String& name, const String& groupName /* = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME */)
716     {
717         mMaterial = MaterialManager::getSingleton().getByName(name, groupName);
718 
719         if (!mMaterial)
720         {
721             LogManager::getSingleton().logMessage("Can't assign material " + name +
722                 " to BillboardChain " + mName + " because this "
723                 "Material does not exist in group "+groupName+". Have you forgotten to define it in a "
724                 ".material script?", LML_CRITICAL);
725             mMaterial = MaterialManager::getSingleton().getDefaultMaterial(false);
726         }
727         // Ensure new material loaded (will not load again if already loaded)
728         mMaterial->load();
729     }
730     //-----------------------------------------------------------------------
getMovableType(void) const731     const String& BillboardChain::getMovableType(void) const
732     {
733         return BillboardChainFactory::FACTORY_TYPE_NAME;
734     }
735     //-----------------------------------------------------------------------
_updateRenderQueue(RenderQueue * queue)736     void BillboardChain::_updateRenderQueue(RenderQueue* queue)
737     {
738         updateIndexBuffer();
739 
740         if (mIndexData->indexCount > 0)
741         {
742             if (mRenderQueuePrioritySet)
743                 queue->addRenderable(this, mRenderQueueID, mRenderQueuePriority);
744             else if (mRenderQueueIDSet)
745                 queue->addRenderable(this, mRenderQueueID);
746             else
747                 queue->addRenderable(this);
748         }
749 
750     }
751     //-----------------------------------------------------------------------
getRenderOperation(RenderOperation & op)752     void BillboardChain::getRenderOperation(RenderOperation& op)
753     {
754         op.indexData = mIndexData.get();
755         op.operationType = RenderOperation::OT_TRIANGLE_LIST;
756         op.srcRenderable = this;
757         op.useIndexes = true;
758         op.vertexData = mVertexData.get();
759     }
760     //-----------------------------------------------------------------------
preRender(SceneManager * sm,RenderSystem * rsys)761     bool BillboardChain::preRender(SceneManager* sm, RenderSystem* rsys)
762     {
763         // Retrieve the current viewport from the scene manager.
764         // The viewport is only valid during a viewport update.
765         Viewport *currentViewport = sm->getCurrentViewport();
766         if( !currentViewport )
767             return false;
768 
769         updateVertexBuffer(currentViewport->getCamera());
770         return true;
771     }
772     //-----------------------------------------------------------------------
getWorldTransforms(Matrix4 * xform) const773     void BillboardChain::getWorldTransforms(Matrix4* xform) const
774     {
775         *xform = _getParentNodeFullTransform();
776     }
777     //-----------------------------------------------------------------------
getLights(void) const778     const LightList& BillboardChain::getLights(void) const
779     {
780         return queryLights();
781     }
782     //---------------------------------------------------------------------
visitRenderables(Renderable::Visitor * visitor,bool debugRenderables)783     void BillboardChain::visitRenderables(Renderable::Visitor* visitor,
784         bool debugRenderables)
785     {
786         // only one renderable
787         visitor->visit(this, 0, false);
788     }
789     //-----------------------------------------------------------------------
790     //-----------------------------------------------------------------------
791     String BillboardChainFactory::FACTORY_TYPE_NAME = "BillboardChain";
792     //-----------------------------------------------------------------------
getType(void) const793     const String& BillboardChainFactory::getType(void) const
794     {
795         return FACTORY_TYPE_NAME;
796     }
797     //-----------------------------------------------------------------------
createInstanceImpl(const String & name,const NameValuePairList * params)798     MovableObject* BillboardChainFactory::createInstanceImpl( const String& name,
799         const NameValuePairList* params)
800     {
801         size_t maxElements = 20;
802         size_t numberOfChains = 1;
803         bool useTex = true;
804         bool useCol = true;
805         bool dynamic = true;
806         // optional params
807         if (params != 0)
808         {
809             NameValuePairList::const_iterator ni = params->find("maxElements");
810             if (ni != params->end())
811             {
812                 maxElements = StringConverter::parseSizeT(ni->second);
813             }
814             ni = params->find("numberOfChains");
815             if (ni != params->end())
816             {
817                 numberOfChains = StringConverter::parseSizeT(ni->second);
818             }
819             ni = params->find("useTextureCoords");
820             if (ni != params->end())
821             {
822                 useTex = StringConverter::parseBool(ni->second);
823             }
824             ni = params->find("useVertexColours");
825             if (ni != params->end())
826             {
827                 useCol = StringConverter::parseBool(ni->second);
828             }
829             ni = params->find("dynamic");
830             if (ni != params->end())
831             {
832                 dynamic = StringConverter::parseBool(ni->second);
833             }
834 
835         }
836 
837         return OGRE_NEW BillboardChain(name, maxElements, numberOfChains, useTex, useCol, dynamic);
838 
839     }
840     //-----------------------------------------------------------------------
destroyInstance(MovableObject * obj)841     void BillboardChainFactory::destroyInstance( MovableObject* obj)
842     {
843         OGRE_DELETE  obj;
844     }
845 
846 }
847 
848 
849