Coverage Report

Created: 2026-01-09 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreBillboardChain.cpp
Line
Count
Source
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
#include <memory>
38
39
namespace Ogre {
40
    const size_t BillboardChain::SEGMENT_EMPTY = std::numeric_limits<size_t>::max();
41
    //-----------------------------------------------------------------------
42
    BillboardChain::Element::Element(const Vector3 &_position,
43
        float _width,
44
        float _texCoord,
45
        const ColourValue &_colour,
46
        const Quaternion &_orientation) :
47
0
    position(_position),
48
0
        width(_width),
49
0
        texCoord(_texCoord),
50
0
        colour(_colour),
51
0
        orientation(_orientation)
52
0
    {
53
0
    }
54
    //-----------------------------------------------------------------------
55
    BillboardChain::BillboardChain(const String& name, size_t maxElements,
56
        size_t numberOfChains, bool useTextureCoords, bool useColours, bool dynamic)
57
0
        :MovableObject(name),
58
0
        mMaxElementsPerChain(maxElements),
59
0
        mChainCount(numberOfChains),
60
0
        mUseTexCoords(useTextureCoords),
61
0
        mUseVertexColour(useColours),
62
0
        mVertexDeclDirty(true),
63
0
        mBuffersNeedRecreating(true),
64
0
        mBoundsDirty(true),
65
0
        mIndexContentDirty(true),
66
0
        mVertexContentDirty(true),
67
0
        mRadius(0.0f),
68
0
        mTexCoordDir(TCD_U),
69
0
        mFaceCamera(true),
70
0
        mNormalBase(Vector3::UNIT_X),
71
0
        mVertexCameraUsed(0)
72
0
    {
73
0
        mVertexData = std::make_unique<VertexData>();
74
0
        mIndexData = std::make_unique<IndexData>();
75
76
0
        mOtherTexCoordRange[0] = 0.0f;
77
0
        mOtherTexCoordRange[1] = 1.0f;
78
79
0
        setupChainContainers();
80
81
0
        mVertexData->vertexStart = 0;
82
        // index data set up later
83
        // set basic white material
84
0
        mMaterial = MaterialManager::getSingleton().getDefaultMaterial(false);
85
0
        mMaterial->load();
86
0
    }
87
88
0
    BillboardChain::~BillboardChain() = default; // ensure unique_ptr destructors are in cpp
89
90
    //-----------------------------------------------------------------------
91
    void BillboardChain::setupChainContainers(void)
92
0
    {
93
        // Allocate enough space for everything
94
0
        mChainElementList.resize(mChainCount * mMaxElementsPerChain);
95
0
        mVertexData->vertexCount = mChainElementList.size() * 2;
96
97
        // Configure chains
98
0
        mChainSegmentList.resize(mChainCount);
99
0
        for (size_t i = 0; i < mChainCount; ++i)
100
0
        {
101
0
            ChainSegment& seg = mChainSegmentList[i];
102
0
            seg.start = i * mMaxElementsPerChain;
103
0
            seg.tail = seg.head = SEGMENT_EMPTY;
104
105
0
        }
106
107
108
0
    }
109
    //-----------------------------------------------------------------------
110
    void BillboardChain::setupVertexDeclaration(void)
111
0
    {
112
0
        if (mVertexDeclDirty)
113
0
        {
114
0
            VertexDeclaration* decl = mVertexData->vertexDeclaration;
115
0
            decl->removeAllElements();
116
117
0
            size_t offset = 0;
118
            // Add a description for the buffer of the positions of the vertices
119
0
            offset += decl->addElement(0, offset, VET_FLOAT3, VES_POSITION).getSize();
120
121
0
            if (mUseVertexColour)
122
0
            {
123
0
                offset += decl->addElement(0, offset, VET_UBYTE4_NORM, VES_DIFFUSE).getSize();
124
0
            }
125
126
0
            if (mUseTexCoords)
127
0
            {
128
0
                decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES);
129
0
            }
130
131
0
            if (!mUseTexCoords && !mUseVertexColour)
132
0
            {
133
0
                LogManager::getSingleton().logError(
134
0
                    "BillboardChain '" + mName + "' is using neither "
135
0
                    "texture coordinates nor vertex colours; it will not be "
136
0
                    "visible on some rendering APIs so you should change this "
137
0
                    "so you use one or the other.");
138
0
            }
139
0
            mVertexDeclDirty = false;
140
0
        }
141
0
    }
142
    //-----------------------------------------------------------------------
143
    void BillboardChain::setupBuffers(void)
144
0
    {
145
0
        setupVertexDeclaration();
146
0
        if (mBuffersNeedRecreating)
147
0
        {
148
            // Create the vertex buffer (always dynamic due to the camera adjust)
149
0
            HardwareVertexBufferSharedPtr pBuffer =
150
0
                HardwareBufferManager::getSingleton().createVertexBuffer(
151
0
                mVertexData->vertexDeclaration->getVertexSize(0),
152
0
                mVertexData->vertexCount,
153
0
                HBU_CPU_TO_GPU);
154
155
            // (re)Bind the buffer
156
            // Any existing buffer will lose its reference count and be destroyed
157
0
            mVertexData->vertexBufferBinding->setBinding(0, pBuffer);
158
159
0
            mIndexData->indexBuffer =
160
0
                HardwareBufferManager::getSingleton().createIndexBuffer(
161
0
                    HardwareIndexBuffer::IT_16BIT,
162
0
                    mChainCount * mMaxElementsPerChain * 6, // max we can use
163
0
                    HBU_GPU_ONLY);
164
            // NB we don't set the indexCount on IndexData here since we will
165
            // probably use less than the maximum number of indices
166
167
0
            mBuffersNeedRecreating = false;
168
0
        }
169
0
    }
170
    //-----------------------------------------------------------------------
171
    void BillboardChain::setMaxChainElements(size_t maxElements)
172
0
    {
173
0
        mMaxElementsPerChain = maxElements;
174
0
        setupChainContainers();
175
0
        mBuffersNeedRecreating = mIndexContentDirty = mVertexContentDirty = true;
176
0
    }
177
    //-----------------------------------------------------------------------
178
    void BillboardChain::setNumberOfChains(size_t numChains)
179
0
    {
180
0
        mChainCount = numChains;
181
0
        setupChainContainers();
182
0
        mBuffersNeedRecreating = mIndexContentDirty = mVertexContentDirty = true;
183
0
    }
184
    //-----------------------------------------------------------------------
185
    void BillboardChain::setUseTextureCoords(bool use)
186
0
    {
187
0
        mUseTexCoords = use;
188
0
        mVertexDeclDirty = mBuffersNeedRecreating = true;
189
0
        mIndexContentDirty = mVertexContentDirty = true;
190
0
    }
191
    //-----------------------------------------------------------------------
192
    void BillboardChain::setTextureCoordDirection(BillboardChain::TexCoordDirection dir)
193
0
    {
194
0
        mTexCoordDir = dir;
195
0
        mVertexContentDirty = true;
196
0
    }
197
    //-----------------------------------------------------------------------
198
    void BillboardChain::setOtherTextureCoordRange(Real start, Real end)
199
0
    {
200
0
        mOtherTexCoordRange[0] = start;
201
0
        mOtherTexCoordRange[1] = end;
202
0
        mVertexContentDirty = true;
203
0
    }
204
    //-----------------------------------------------------------------------
205
    void BillboardChain::setUseVertexColours(bool use)
206
0
    {
207
0
        mUseVertexColour = use;
208
0
        mVertexDeclDirty = mBuffersNeedRecreating = true;
209
0
        mIndexContentDirty = mVertexContentDirty = true;
210
0
    }
211
    void BillboardChain::setAutoUpdate(bool autoUpdate)
212
0
    {
213
0
        mAutoUpdate = autoUpdate;
214
0
    }
215
    //-----------------------------------------------------------------------
216
    void BillboardChain::addChainElement(size_t chainIndex,
217
        const BillboardChain::Element& dtls)
218
0
    {
219
0
        ChainSegment& seg = mChainSegmentList.at(chainIndex);
220
0
        if (seg.head == SEGMENT_EMPTY)
221
0
        {
222
            // Tail starts at end, head grows backwards
223
0
            seg.tail = mMaxElementsPerChain - 1;
224
0
            seg.head = seg.tail;
225
0
        }
226
0
        else
227
0
        {
228
0
            if (seg.head == 0)
229
0
            {
230
                // Wrap backwards
231
0
                seg.head = mMaxElementsPerChain - 1;
232
0
            }
233
0
            else
234
0
            {
235
                // Just step backward
236
0
                --seg.head;
237
0
            }
238
            // Run out of elements?
239
0
            if (seg.head == seg.tail)
240
0
            {
241
                // Move tail backwards too, losing the end of the segment and re-using
242
                // it in the head
243
0
                if (seg.tail == 0)
244
0
                    seg.tail = mMaxElementsPerChain - 1;
245
0
                else
246
0
                    --seg.tail;
247
0
            }
248
0
        }
249
250
        // Set the details
251
0
        mChainElementList[seg.start + seg.head] = dtls;
252
253
0
        mVertexContentDirty = true;
254
0
        mIndexContentDirty = true;
255
0
        mBoundsDirty = true;
256
        // tell parent node to update bounds
257
0
        if (mParentNode)
258
0
            mParentNode->needUpdate();
259
260
0
    }
261
    //-----------------------------------------------------------------------
262
    void BillboardChain::removeChainElement(size_t chainIndex)
263
0
    {
264
0
        ChainSegment& seg = mChainSegmentList.at(chainIndex);
265
0
        if (seg.head == SEGMENT_EMPTY)
266
0
            return; // do nothing, nothing to remove
267
268
269
0
        if (seg.tail == seg.head)
270
0
        {
271
            // last item
272
0
            seg.head = seg.tail = SEGMENT_EMPTY;
273
0
        }
274
0
        else if (seg.tail == 0)
275
0
        {
276
0
            seg.tail = mMaxElementsPerChain - 1;
277
0
        }
278
0
        else
279
0
        {
280
0
            --seg.tail;
281
0
        }
282
283
        // we removed an entry so indexes need updating
284
0
        mVertexContentDirty = true;
285
0
        mIndexContentDirty = true;
286
0
        mBoundsDirty = true;
287
        // tell parent node to update bounds
288
0
        if (mParentNode)
289
0
            mParentNode->needUpdate();
290
291
0
    }
292
    //-----------------------------------------------------------------------
293
    void BillboardChain::clearChain(size_t chainIndex)
294
0
    {
295
0
        ChainSegment& seg = mChainSegmentList.at(chainIndex);
296
297
        // Just reset head & tail
298
0
        seg.tail = seg.head = SEGMENT_EMPTY;
299
300
        // we removed an entry so indexes need updating
301
0
        mVertexContentDirty = true;
302
0
        mIndexContentDirty = true;
303
0
        mBoundsDirty = true;
304
        // tell parent node to update bounds
305
0
        if (mParentNode)
306
0
            mParentNode->needUpdate();
307
308
0
    }
309
    //-----------------------------------------------------------------------
310
    void BillboardChain::clearAllChains(void)
311
0
    {
312
0
        for (size_t i = 0; i < mChainCount; ++i)
313
0
        {
314
0
            clearChain(i);
315
0
        }
316
317
0
    }
318
    //-----------------------------------------------------------------------
319
    void BillboardChain::setFaceCamera( bool faceCamera, const Vector3 &normalVector )
320
0
    {
321
0
        mFaceCamera = faceCamera;
322
0
        mNormalBase = normalVector.normalisedCopy();
323
0
        mVertexContentDirty = true;
324
0
    }
325
    //-----------------------------------------------------------------------
326
    void BillboardChain::updateChainElement(size_t chainIndex, size_t elementIndex,
327
        const BillboardChain::Element& dtls)
328
0
    {
329
0
        ChainSegment& seg = mChainSegmentList.at(chainIndex);
330
0
        OgreAssert(seg.head != SEGMENT_EMPTY, "Chain segment is empty");
331
332
0
        size_t idx = seg.head + elementIndex;
333
        // adjust for the edge and start
334
0
        idx = (idx % mMaxElementsPerChain) + seg.start;
335
336
0
        mChainElementList[idx] = dtls;
337
338
0
        mVertexContentDirty = true;
339
0
        mBoundsDirty = true;
340
        // tell parent node to update bounds
341
0
        if (mParentNode)
342
0
            mParentNode->needUpdate();
343
344
345
0
    }
346
    //-----------------------------------------------------------------------
347
    const BillboardChain::Element&
348
    BillboardChain::getChainElement(size_t chainIndex, size_t elementIndex) const
349
0
    {
350
0
        const ChainSegment& seg = mChainSegmentList.at(chainIndex);
351
0
        OgreAssert(seg.head != SEGMENT_EMPTY, "Chain segment is empty");
352
353
0
        size_t idx = seg.head + elementIndex;
354
        // adjust for the edge and start
355
0
        idx = (idx % mMaxElementsPerChain) + seg.start;
356
357
0
        return mChainElementList[idx];
358
0
    }
359
    //-----------------------------------------------------------------------
360
    size_t BillboardChain::getNumChainElements(size_t chainIndex) const
361
0
    {
362
0
        const ChainSegment& seg = mChainSegmentList.at(chainIndex);
363
        
364
0
        if (seg.head == SEGMENT_EMPTY)
365
0
        {
366
0
            return 0;
367
0
        }
368
0
        else if (seg.tail < seg.head)
369
0
        {
370
0
            return seg.tail - seg.head + mMaxElementsPerChain + 1;
371
0
        }
372
0
        else
373
0
        {
374
0
            return seg.tail - seg.head + 1;
375
0
        }
376
0
    }
377
    //-----------------------------------------------------------------------
378
    void BillboardChain::updateBoundingBox(void) const
379
0
    {
380
0
        if (mBoundsDirty)
381
0
        {
382
0
            mAABB.setNull();
383
0
            Vector3 widthVector;
384
0
            for (const auto& seg : mChainSegmentList)
385
0
            {
386
0
                if (seg.head != SEGMENT_EMPTY)
387
0
                {
388
389
0
                    for(size_t e = seg.head; ; ++e) // until break
390
0
                    {
391
                        // Wrap forwards
392
0
                        if (e == mMaxElementsPerChain)
393
0
                            e = 0;
394
395
0
                        const Element& elem = mChainElementList[seg.start + e];
396
397
0
                        widthVector.x = widthVector.y = widthVector.z = elem.width;
398
0
                        mAABB.merge(elem.position - widthVector);
399
0
                        mAABB.merge(elem.position + widthVector);
400
401
0
                        if (e == seg.tail)
402
0
                            break;
403
404
0
                    }
405
0
                }
406
407
0
            }
408
409
            // Set the current radius
410
0
            if (mAABB.isNull())
411
0
            {
412
0
                mRadius = 0.0f;
413
0
            }
414
0
            else
415
0
            {
416
0
                mRadius = Math::Sqrt(
417
0
                    std::max(mAABB.getMinimum().squaredLength(),
418
0
                    mAABB.getMaximum().squaredLength()));
419
0
            }
420
421
0
            mBoundsDirty = false;
422
0
        }
423
0
    }
424
    //-----------------------------------------------------------------------
425
    void BillboardChain::updateVertexBuffer(Camera* cam)
426
0
    {
427
0
        setupBuffers();
428
429
0
        if (!mVertexContentDirty && !mAutoUpdate)
430
0
            return;
431
432
0
        HardwareVertexBufferSharedPtr pBuffer =
433
0
            mVertexData->vertexBufferBinding->getBuffer(0);
434
0
        HardwareBufferLockGuard vertexLock(pBuffer, HardwareBuffer::HBL_DISCARD);
435
436
0
        const Vector3& camPos = cam->getDerivedPosition();
437
0
        Vector3 eyePos = mParentNode->convertWorldToLocalPosition(camPos);
438
439
0
        Vector3 chainTangent;
440
0
        for (auto& seg : mChainSegmentList)
441
0
        {
442
            // Skip 0 or 1 element segment counts
443
0
            if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail)
444
0
            {
445
0
                size_t laste = seg.head;
446
0
                for (size_t e = seg.head; ; ++e) // until break
447
0
                {
448
                    // Wrap forwards
449
0
                    if (e == mMaxElementsPerChain)
450
0
                        e = 0;
451
452
0
                    Element& elem = mChainElementList[e + seg.start];
453
0
                    assert (((e + seg.start) * 2) < 65536 && "Too many elements!");
454
0
                    uint16 baseIdx = static_cast<uint16>((e + seg.start) * 2);
455
456
                    // Determine base pointer to vertex #1
457
0
                    float* pFloat = reinterpret_cast<float*>(
458
0
                        static_cast<char*>(vertexLock.pData) +
459
0
                            pBuffer->getVertexSize() * baseIdx);
460
461
                    // Get index of next item
462
0
                    size_t nexte = e + 1;
463
0
                    if (nexte == mMaxElementsPerChain)
464
0
                        nexte = 0;
465
466
0
                    if (e == seg.head)
467
0
                    {
468
                        // No laste, use next item
469
0
                        chainTangent = mChainElementList[nexte + seg.start].position - elem.position;
470
0
                    }
471
0
                    else if (e == seg.tail)
472
0
                    {
473
                        // No nexte, use only last item
474
0
                        chainTangent = elem.position - mChainElementList[laste + seg.start].position;
475
0
                    }
476
0
                    else
477
0
                    {
478
                        // A mid position, use tangent across both prev and next
479
0
                        chainTangent = mChainElementList[nexte + seg.start].position - mChainElementList[laste + seg.start].position;
480
481
0
                    }
482
483
0
                    Vector3 vP1ToEye;
484
485
0
                    if( mFaceCamera )
486
0
                        vP1ToEye = eyePos - elem.position;
487
0
                    else
488
0
                        vP1ToEye = elem.orientation * mNormalBase;
489
490
0
                    Vector3 vPerpendicular = chainTangent.crossProduct(vP1ToEye);
491
0
                    vPerpendicular.normalise();
492
0
                    vPerpendicular *= (elem.width * 0.5f);
493
494
0
                    Vector3 pos0 = elem.position - vPerpendicular;
495
0
                    Vector3 pos1 = elem.position + vPerpendicular;
496
497
                    // pos1
498
0
                    *pFloat++ = pos0.x;
499
0
                    *pFloat++ = pos0.y;
500
0
                    *pFloat++ = pos0.z;
501
502
0
                    if (mUseVertexColour)
503
0
                    {
504
0
                        RGBA col = elem.colour.getAsBYTE();
505
0
                        memcpy(pFloat++, &col, sizeof(RGBA));
506
0
                    }
507
508
0
                    if (mUseTexCoords)
509
0
                    {
510
0
                        if (mTexCoordDir == TCD_U)
511
0
                        {
512
0
                            *pFloat++ = elem.texCoord;
513
0
                            *pFloat++ = mOtherTexCoordRange[0];
514
0
                        }
515
0
                        else
516
0
                        {
517
0
                            *pFloat++ = mOtherTexCoordRange[0];
518
0
                            *pFloat++ = elem.texCoord;
519
0
                        }
520
0
                    }
521
522
                    // pos2
523
0
                    *pFloat++ = pos1.x;
524
0
                    *pFloat++ = pos1.y;
525
0
                    *pFloat++ = pos1.z;
526
527
0
                    if (mUseVertexColour)
528
0
                    {
529
0
                        RGBA col = elem.colour.getAsBYTE();
530
0
                        memcpy(pFloat++, &col, sizeof(RGBA));
531
0
                    }
532
533
0
                    if (mUseTexCoords)
534
0
                    {
535
0
                        if (mTexCoordDir == TCD_U)
536
0
                        {
537
0
                            *pFloat++ = elem.texCoord;
538
0
                            *pFloat++ = mOtherTexCoordRange[1];
539
0
                        }
540
0
                        else
541
0
                        {
542
0
                            *pFloat++ = mOtherTexCoordRange[1];
543
0
                            *pFloat++ = elem.texCoord;
544
0
                        }
545
0
                    }
546
547
0
                    if (e == seg.tail)
548
0
                        break; // last one
549
550
0
                    laste = e;
551
552
0
                } // element
553
0
            } // segment valid?
554
555
0
        } // each segment
556
557
0
        mVertexCameraUsed = cam;
558
0
        mVertexContentDirty = false;
559
0
    }
560
    //-----------------------------------------------------------------------
561
    void BillboardChain::updateIndexBuffer(void)
562
0
    {
563
564
0
        setupBuffers();
565
0
        if (mIndexContentDirty)
566
0
        {
567
0
            HardwareBufferLockGuard indexLock(mIndexData->indexBuffer, HardwareBuffer::HBL_DISCARD);
568
0
            uint16* pShort = static_cast<uint16*>(indexLock.pData);
569
0
            mIndexData->indexCount = 0;
570
            // indexes
571
0
            for (auto& seg : mChainSegmentList)
572
0
            {
573
                // Skip 0 or 1 element segment counts
574
0
                if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail)
575
0
                {
576
                    // Start from head + 1 since it's only useful in pairs
577
0
                    size_t laste = seg.head;
578
0
                    while(1) // until break
579
0
                    {
580
0
                        size_t e = laste + 1;
581
                        // Wrap forwards
582
0
                        if (e == mMaxElementsPerChain)
583
0
                            e = 0;
584
                        // indexes of this element are (e * 2) and (e * 2) + 1
585
                        // indexes of the last element are the same, -2
586
0
                        assert (((e + seg.start) * 2) < 65536 && "Too many elements!");
587
0
                        uint16 baseIdx = static_cast<uint16>((e + seg.start) * 2);
588
0
                        uint16 lastBaseIdx = static_cast<uint16>((laste + seg.start) * 2);
589
0
                        *pShort++ = lastBaseIdx;
590
0
                        *pShort++ = lastBaseIdx + 1;
591
0
                        *pShort++ = baseIdx;
592
0
                        *pShort++ = lastBaseIdx + 1;
593
0
                        *pShort++ = baseIdx + 1;
594
0
                        *pShort++ = baseIdx;
595
596
0
                        mIndexData->indexCount += 6;
597
598
599
0
                        if (e == seg.tail)
600
0
                            break; // last one
601
602
0
                        laste = e;
603
604
0
                    }
605
0
                }
606
607
0
            }
608
609
0
            mIndexContentDirty = false;
610
0
        }
611
612
0
    }
613
    //-----------------------------------------------------------------------
614
    Real BillboardChain::getSquaredViewDepth(const Camera* cam) const
615
0
    {
616
0
        return (cam->getDerivedPosition() - mAABB.getCenter()).squaredLength();
617
0
    }
618
    //-----------------------------------------------------------------------
619
    Real BillboardChain::getBoundingRadius(void) const
620
0
    {
621
0
        return mRadius;
622
0
    }
623
    //-----------------------------------------------------------------------
624
    const AxisAlignedBox& BillboardChain::getBoundingBox(void) const
625
0
    {
626
0
        updateBoundingBox();
627
0
        return mAABB;
628
0
    }
629
    //-----------------------------------------------------------------------
630
    const MaterialPtr& BillboardChain::getMaterial(void) const
631
0
    {
632
0
        return mMaterial;
633
0
    }
634
    //-----------------------------------------------------------------------
635
    void BillboardChain::setMaterialName( const String& name, const String& groupName /* = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME */)
636
0
    {
637
0
        mMaterial = MaterialManager::getSingleton().getByName(name, groupName);
638
639
0
        if (!mMaterial)
640
0
        {
641
0
            logMaterialNotFound(name, groupName, "BillboardChain", mName);
642
0
            mMaterial = MaterialManager::getSingleton().getDefaultMaterial(false);
643
0
        }
644
        // Ensure new material loaded (will not load again if already loaded)
645
0
        mMaterial->load();
646
0
    }
647
    //-----------------------------------------------------------------------
648
    const String& BillboardChain::getMovableType(void) const
649
0
    {
650
0
        return MOT_BILLBOARD_CHAIN;
651
0
    }
652
    //-----------------------------------------------------------------------
653
    void BillboardChain::_updateRenderQueue(RenderQueue* queue)
654
0
    {
655
0
        updateIndexBuffer();
656
657
0
        if (mIndexData->indexCount > 0)
658
0
        {
659
0
            if (mRenderQueuePrioritySet)
660
0
                queue->addRenderable(this, mRenderQueueID, mRenderQueuePriority);
661
0
            else if (mRenderQueueIDSet)
662
0
                queue->addRenderable(this, mRenderQueueID);
663
0
            else
664
0
                queue->addRenderable(this);
665
0
        }
666
0
    }
667
    //-----------------------------------------------------------------------
668
    void BillboardChain::getRenderOperation(RenderOperation& op)
669
0
    {
670
0
        op.indexData = mIndexData.get();
671
0
        op.operationType = RenderOperation::OT_TRIANGLE_LIST;
672
0
        op.srcRenderable = this;
673
0
        op.useIndexes = true;
674
0
        op.vertexData = mVertexData.get();
675
0
    }
676
    //-----------------------------------------------------------------------
677
    bool BillboardChain::preRender(SceneManager* sm, RenderSystem* rsys)
678
0
    {
679
        // Retrieve the current viewport from the scene manager.
680
        // The viewport is only valid during a viewport update.
681
0
        Viewport *currentViewport = sm->getCurrentViewport();
682
0
        if( !currentViewport )
683
0
            return false;
684
685
0
        updateVertexBuffer(currentViewport->getCamera());
686
0
        return true;
687
0
    }
688
    //-----------------------------------------------------------------------
689
    void BillboardChain::getWorldTransforms(Matrix4* xform) const
690
0
    {
691
0
        *xform = _getParentNodeFullTransform();
692
0
    }
693
    //-----------------------------------------------------------------------
694
    const LightList& BillboardChain::getLights(void) const
695
0
    {
696
0
        return queryLights();
697
0
    }
698
    //---------------------------------------------------------------------
699
    void BillboardChain::visitRenderables(Renderable::Visitor* visitor, 
700
        bool debugRenderables)
701
0
    {
702
        // only one renderable
703
0
        visitor->visit(this, 0, false);
704
0
    }
705
    //-----------------------------------------------------------------------
706
    //-----------------------------------------------------------------------
707
    const String MOT_BILLBOARD_CHAIN = "BillboardChain";
708
    //-----------------------------------------------------------------------
709
    const String& BillboardChainFactory::getType(void) const
710
0
    {
711
0
        return MOT_BILLBOARD_CHAIN;
712
0
    }
713
    //-----------------------------------------------------------------------
714
    MovableObject* BillboardChainFactory::createInstanceImpl( const String& name,
715
        const NameValuePairList* params)
716
0
    {
717
0
        size_t maxElements = 20;
718
0
        size_t numberOfChains = 1;
719
0
        bool useTex = true;
720
0
        bool useCol = true;
721
0
        bool dynamic = true;
722
        // optional params
723
0
        if (params != 0)
724
0
        {
725
0
            NameValuePairList::const_iterator ni = params->find("maxElements");
726
0
            if (ni != params->end())
727
0
            {
728
0
                maxElements = StringConverter::parseSizeT(ni->second);
729
0
            }
730
0
            ni = params->find("numberOfChains");
731
0
            if (ni != params->end())
732
0
            {
733
0
                numberOfChains = StringConverter::parseSizeT(ni->second);
734
0
            }
735
0
            ni = params->find("useTextureCoords");
736
0
            if (ni != params->end())
737
0
            {
738
0
                useTex = StringConverter::parseBool(ni->second);
739
0
            }
740
0
            ni = params->find("useVertexColours");
741
0
            if (ni != params->end())
742
0
            {
743
0
                useCol = StringConverter::parseBool(ni->second);
744
0
            }
745
0
            ni = params->find("dynamic");
746
0
            if (ni != params->end())
747
0
            {
748
0
                dynamic = StringConverter::parseBool(ni->second);
749
0
            }
750
0
        }
751
752
0
        return OGRE_NEW BillboardChain(name, maxElements, numberOfChains, useTex, useCol, dynamic);
753
754
0
    }
755
}