Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/ogre/OgreMain/src/OgreInstancedGeometry.cpp @ 11

Last change on this file since 11 was 5, checked in by anonymous, 17 years ago

=hoffentlich gehts jetzt

File size: 66.0 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreStableHeaders.h"
30#include "OgreInstancedGeometry.h"
31#include "OgreEntity.h"
32#include "OgreSubEntity.h"
33#include "OgreSceneNode.h"
34#include "OgreException.h"
35#include "OgreMesh.h"
36#include "OgreSubMesh.h"
37#include "OgreLogManager.h"
38#include "OgreSceneManager.h"
39#include "OgreCamera.h"
40#include "OgreMaterialManager.h"
41#include "OgreRoot.h"
42#include "OgreRenderSystem.h"
43#include "OgreEdgeListBuilder.h"
44#include "OgreStringConverter.h"
45
46namespace Ogre {
47
48        #define BatchInstance_RANGE 1024
49        #define BatchInstance_HALF_RANGE 512
50        #define BatchInstance_MAX_INDEX 511
51        #define BatchInstance_MIN_INDEX -512
52
53        //--------------------------------------------------------------------------
54        InstancedGeometry::InstancedGeometry(SceneManager* owner, const String& name):
55                mOwner(owner),
56                mName(name),
57                mBuilt(false),
58                mUpperDistance(0.0f),
59                mSquaredUpperDistance(0.0f),
60                mCastShadows(false),
61                mBatchInstanceDimensions(Vector3(1000,1000,1000)),
62                mHalfBatchInstanceDimensions(Vector3(500,500,500)),
63                mOrigin(Vector3(0,0,0)),
64                mVisible(true),
65        mRenderQueueID(RENDER_QUEUE_MAIN),
66        mRenderQueueIDSet(false),
67                mObjectCount(0),
68                mInstancedGeometryInstance(0),
69                mSkeletonInstance(0)
70        {
71                mBaseSkeleton.setNull();
72        }
73        //--------------------------------------------------------------------------
74        InstancedGeometry::~InstancedGeometry()
75        {
76                reset();
77                if(mSkeletonInstance)
78                        delete mSkeletonInstance;
79
80                       
81        }
82        //--------------------------------------------------------------------------
83        InstancedGeometry::BatchInstance*InstancedGeometry::getInstancedGeometryInstance(void)
84        {
85                if (!mInstancedGeometryInstance)
86                {
87                        uint32 index = 0;
88                        // Make a name
89                        StringUtil::StrStreamType str;
90                        str << mName << ":" << index;
91
92                        mInstancedGeometryInstance = new BatchInstance(this, str.str(), mOwner, index);
93                        mOwner->injectMovableObject(mInstancedGeometryInstance);
94                        mInstancedGeometryInstance->setVisible(mVisible);
95                        mInstancedGeometryInstance->setCastShadows(mCastShadows);
96                        if (mRenderQueueIDSet)
97                        {
98                                mInstancedGeometryInstance->setRenderQueueGroup(mRenderQueueID);
99                        }
100                        mBatchInstanceMap[index] = mInstancedGeometryInstance;
101               
102       
103                }
104                return mInstancedGeometryInstance;
105        }
106        //--------------------------------------------------------------------------
107        InstancedGeometry::BatchInstance* InstancedGeometry::getBatchInstance(const AxisAlignedBox& bounds,
108                bool autoCreate)
109        {
110                if (bounds.isNull())
111                        return 0;
112
113                // Get the BatchInstance which has the largest overlapping volume
114                const Vector3 min = bounds.getMinimum();
115                const Vector3 max = bounds.getMaximum();
116
117                // Get the min and max BatchInstance indexes
118                ushort minx, miny, minz;
119                ushort maxx, maxy, maxz;
120                getBatchInstanceIndexes(min, minx, miny, minz);
121                getBatchInstanceIndexes(max, maxx, maxy, maxz);
122                Real maxVolume = 0.0f;
123                ushort finalx =0 , finaly = 0, finalz = 0;
124                for (ushort x = minx; x <= maxx; ++x)
125                {
126                        for (ushort y = miny; y <= maxy; ++y)
127                        {
128                                for (ushort z = minz; z <= maxz; ++z)
129                                {
130                                        Real vol = getVolumeIntersection(bounds, x, y, z);
131                                        if (vol > maxVolume)
132                                        {
133                                                maxVolume = vol;
134                                                finalx = x;
135                                                finaly = y;
136                                                finalz = z;
137                                        }
138
139                                }
140                        }
141                }
142
143                assert(maxVolume > 0.0f &&
144                        "Static geometry: Problem determining closest volume match!");
145
146                return getBatchInstance(finalx, finaly, finalz, autoCreate);
147
148        }
149        //--------------------------------------------------------------------------
150        Real InstancedGeometry::getVolumeIntersection(const AxisAlignedBox& box,
151                ushort x, ushort y, ushort z)
152        {
153                // Get bounds of indexed BatchInstance
154                AxisAlignedBox BatchInstanceBounds = getBatchInstanceBounds(x, y, z);
155                AxisAlignedBox intersectBox = BatchInstanceBounds.intersection(box);
156                // return a 'volume' which ignores zero dimensions
157                // since we only use this for relative comparisons of the same bounds
158                // this will still be internally consistent
159                Vector3 boxdiff = box.getMaximum() - box.getMinimum();
160                Vector3 intersectDiff = intersectBox.getMaximum() - intersectBox.getMinimum();
161
162                return (boxdiff.x == 0 ? 1 : intersectDiff.x) *
163                        (boxdiff.y == 0 ? 1 : intersectDiff.y) *
164                        (boxdiff.z == 0 ? 1 : intersectDiff.z);
165
166        }
167        //--------------------------------------------------------------------------
168        AxisAlignedBox InstancedGeometry::getBatchInstanceBounds(ushort x, ushort y, ushort z)
169        {
170                Vector3 min(
171                        ((Real)x - BatchInstance_HALF_RANGE) * mBatchInstanceDimensions.x + mOrigin.x,
172                        ((Real)y - BatchInstance_HALF_RANGE) * mBatchInstanceDimensions.y + mOrigin.y,
173                        ((Real)z - BatchInstance_HALF_RANGE) * mBatchInstanceDimensions.z + mOrigin.z
174                        );
175                Vector3 max = min + mBatchInstanceDimensions;
176                return AxisAlignedBox(min, max);
177        }
178        //--------------------------------------------------------------------------
179        Vector3 InstancedGeometry::getBatchInstanceCentre(ushort x, ushort y, ushort z)
180        {
181                return Vector3(
182                        ((Real)x - BatchInstance_HALF_RANGE) * mBatchInstanceDimensions.x + mOrigin.x
183                                + mHalfBatchInstanceDimensions.x,
184                        ((Real)y - BatchInstance_HALF_RANGE) * mBatchInstanceDimensions.y + mOrigin.y
185                                + mHalfBatchInstanceDimensions.y,
186                        ((Real)z - BatchInstance_HALF_RANGE) * mBatchInstanceDimensions.z + mOrigin.z
187                                + mHalfBatchInstanceDimensions.z
188                        );
189        }
190        //--------------------------------------------------------------------------
191        InstancedGeometry::BatchInstance* InstancedGeometry::getBatchInstance(
192                        ushort x, ushort y, ushort z, bool autoCreate)
193        {
194                uint32 index = packIndex(x, y, z);
195                BatchInstance* ret = getBatchInstance(index);
196                if (!ret && autoCreate)
197                {
198                        // Make a name
199                        StringUtil::StrStreamType str;
200                        str << mName << ":" << index;
201                        // Calculate the BatchInstance centre
202                        Vector3 centre(0,0,0);// = getBatchInstanceCentre(x, y, z);
203                        ret = new BatchInstance(this, str.str(), mOwner, index/*, centre*/);
204                        mOwner->injectMovableObject(ret);
205                        ret->setVisible(mVisible);
206                        ret->setCastShadows(mCastShadows);
207                        if (mRenderQueueIDSet)
208                        {
209                                ret->setRenderQueueGroup(mRenderQueueID);
210                        }
211                        mBatchInstanceMap[index] = ret;
212                }
213                return ret;
214        }
215        //--------------------------------------------------------------------------
216        InstancedGeometry::BatchInstance* InstancedGeometry::getBatchInstance(uint32 index)
217        {
218                BatchInstanceMap::iterator i = mBatchInstanceMap.find(index);
219                if (i != mBatchInstanceMap.end())
220                {
221                        return i->second;
222                }
223                else
224                {
225                        return 0;
226                }
227
228        }
229        //--------------------------------------------------------------------------
230        void InstancedGeometry::getBatchInstanceIndexes(const Vector3& point,
231                ushort& x, ushort& y, ushort& z)
232        {
233                // Scale the point into multiples of BatchInstance and adjust for origin
234                Vector3 scaledPoint = (point - mOrigin) / mBatchInstanceDimensions;
235
236                // Round down to 'bottom left' point which represents the cell index
237                int ix = Math::IFloor(scaledPoint.x);
238                int iy = Math::IFloor(scaledPoint.y);
239                int iz = Math::IFloor(scaledPoint.z);
240
241                // Check bounds
242                if (ix < BatchInstance_MIN_INDEX || ix > BatchInstance_MAX_INDEX
243                        || iy < BatchInstance_MIN_INDEX || iy > BatchInstance_MAX_INDEX
244                        || iz < BatchInstance_MIN_INDEX || iz > BatchInstance_MAX_INDEX)
245                {
246                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
247                                "Point out of bounds",
248                                "InstancedGeometry::getBatchInstanceIndexes");
249                }
250                // Adjust for the fact that we use unsigned values for simplicity
251                // (requires less faffing about for negatives give 10-bit packing
252                x = static_cast<ushort>(ix + BatchInstance_HALF_RANGE);
253                y = static_cast<ushort>(iy + BatchInstance_HALF_RANGE);
254                z = static_cast<ushort>(iz + BatchInstance_HALF_RANGE);
255
256
257        }
258        //--------------------------------------------------------------------------
259        uint32 InstancedGeometry::packIndex(ushort x, ushort y, ushort z)
260        {
261                return x + (y << 10) + (z << 20);
262        }
263        //--------------------------------------------------------------------------
264        InstancedGeometry::BatchInstance* InstancedGeometry::getBatchInstance(const Vector3& point,
265                bool autoCreate)
266        {
267                ushort x, y, z;
268                getBatchInstanceIndexes(point, x, y, z);
269                return getBatchInstance(x, y, z, autoCreate);
270        }
271        //--------------------------------------------------------------------------
272        AxisAlignedBox InstancedGeometry::calculateBounds(VertexData* vertexData,
273                const Vector3& position, const Quaternion& orientation,
274                const Vector3& scale)
275        {
276                const VertexElement* posElem =
277                        vertexData->vertexDeclaration->findElementBySemantic(
278                                VES_POSITION);
279                HardwareVertexBufferSharedPtr vbuf =
280                        vertexData->vertexBufferBinding->getBuffer(posElem->getSource());
281                unsigned char* vertex =
282                        static_cast<unsigned char*>(
283                                vbuf->lock(HardwareBuffer::HBL_READ_ONLY));
284                float* pFloat;
285
286                Vector3 min, max;
287                bool first = true;
288
289                for(size_t j = 0; j < vertexData->vertexCount; ++j, vertex += vbuf->getVertexSize())
290                {
291                        posElem->baseVertexPointerToElement(vertex, &pFloat);
292
293                        Vector3 pt;
294
295                        pt.x = (*pFloat++);
296                        pt.y = (*pFloat++);
297                        pt.z = (*pFloat++);
298                        // Transform to world (scale, rotate, translate)
299                        pt = (orientation * (pt * scale)) + position;
300                        if (first)
301                        {
302                                min = max = pt;
303                                first = false;
304                        }
305                        else
306                        {
307                                min.makeFloor(pt);
308                                max.makeCeil(pt);
309                        }
310
311                }
312                vbuf->unlock();
313                return AxisAlignedBox(min, max);
314        }
315        //--------------------------------------------------------------------------
316        void InstancedGeometry::addEntity(Entity* ent, const Vector3& position,
317                const Quaternion& orientation, const Vector3& scale)
318        {
319
320                const MeshPtr& msh = ent->getMesh();
321                // Validate
322                if (msh->isLodManual())
323                {
324                        LogManager::getSingleton().logMessage(
325                                "WARNING (InstancedGeometry): Manual LOD is not supported. "
326                                "Using only highest LOD level for mesh " + msh->getName());
327                }
328
329                //get the skeleton of the entity, if that's not already done
330                if(!ent->getMesh()->getSkeleton().isNull()&&mBaseSkeleton.isNull())
331                {
332                        mBaseSkeleton=ent->getMesh()->getSkeleton();
333                        mSkeletonInstance=new SkeletonInstance(mBaseSkeleton);
334                        mSkeletonInstance->load();
335                        mAnimationState=ent->getAllAnimationStates();
336                }
337                AxisAlignedBox sharedWorldBounds;
338                // queue this entities submeshes and choice of material
339                // also build the lists of geometry to be used for the source of lods
340
341
342                for (uint i = 0; i < ent->getNumSubEntities(); ++i)
343                {
344                        SubEntity* se = ent->getSubEntity(i);
345                        QueuedSubMesh* q = new QueuedSubMesh();
346
347                        // Get the geometry for this SubMesh
348                        q->submesh = se->getSubMesh();
349                        q->geometryLodList = determineGeometry(q->submesh);
350                        q->materialName = se->getMaterialName();
351                        q->orientation = orientation;
352                        q->position = position;
353                        q->scale = scale;
354                        q->ID = mObjectCount;
355                        // Determine the bounds based on the highest LOD
356                        q->worldBounds = calculateBounds(
357                                (*q->geometryLodList)[0].vertexData,
358                                        position, orientation, scale);
359
360                        mQueuedSubMeshes.push_back(q);
361                }
362                mObjectCount++;
363
364        }
365        //--------------------------------------------------------------------------
366        InstancedGeometry::SubMeshLodGeometryLinkList*
367        InstancedGeometry::determineGeometry(SubMesh* sm)
368        {
369                // First, determine if we've already seen this submesh before
370                SubMeshGeometryLookup::iterator i =
371                        mSubMeshGeometryLookup.find(sm);
372                if (i != mSubMeshGeometryLookup.end())
373                {
374                        return i->second;
375                }
376                // Otherwise, we have to create a new one
377                SubMeshLodGeometryLinkList* lodList = new SubMeshLodGeometryLinkList();
378                mSubMeshGeometryLookup[sm] = lodList;
379                ushort numLods = sm->parent->isLodManual() ? 1 :
380                        sm->parent->getNumLodLevels();
381                lodList->resize(numLods);
382                for (ushort lod = 0; lod < numLods; ++lod)
383                {
384                        SubMeshLodGeometryLink& geomLink = (*lodList)[lod];
385                        IndexData *lodIndexData;
386                        if (lod == 0)
387                        {
388                                lodIndexData = sm->indexData;
389                        }
390                        else
391                        {
392                                lodIndexData = sm->mLodFaceList[lod - 1];
393                        }
394                        // Can use the original mesh geometry?
395                        if (sm->useSharedVertices)
396                        {
397                                if (sm->parent->getNumSubMeshes() == 1)
398                                {
399                                        // Ok, this is actually our own anyway
400                                        geomLink.vertexData = sm->parent->sharedVertexData;
401                                        geomLink.indexData = lodIndexData;
402                                }
403                                else
404                                {
405                                        // We have to split it
406                                        splitGeometry(sm->parent->sharedVertexData,
407                                                lodIndexData, &geomLink);
408                                }
409                        }
410                        else
411                        {
412                                if (lod == 0)
413                                {
414                                        // Ok, we can use the existing geometry; should be in full
415                                        // use by just this SubMesh
416                                        geomLink.vertexData = sm->vertexData;
417                                        geomLink.indexData = sm->indexData;
418                                }
419                                else
420                                {
421                                        // We have to split it
422                                        splitGeometry(sm->vertexData,
423                                                lodIndexData, &geomLink);
424                                }
425                        }
426                        assert (geomLink.vertexData->vertexStart == 0 &&
427                                "Cannot use vertexStart > 0 on indexed geometry due to "
428                                "rendersystem incompatibilities - see the docs!");
429                }
430
431
432                return lodList;
433        }
434        //--------------------------------------------------------------------------
435        void InstancedGeometry::splitGeometry(VertexData* vd, IndexData* id,
436                        InstancedGeometry::SubMeshLodGeometryLink* targetGeomLink)
437        {
438                // Firstly we need to scan to see how many vertices are being used
439                // and while we're at it, build the remap we can use later
440                bool use32bitIndexes =
441                        id->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT;
442                uint16 *p16;
443                uint32 *p32;
444                IndexRemap indexRemap;
445                if (use32bitIndexes)
446                {
447                        p32 = static_cast<uint32*>(id->indexBuffer->lock(
448                                id->indexStart, 
449                                id->indexCount * id->indexBuffer->getIndexSize(), 
450                                HardwareBuffer::HBL_READ_ONLY));
451                        buildIndexRemap(p32, id->indexCount, indexRemap);
452                        id->indexBuffer->unlock();
453                }
454                else
455                {
456                        p16 = static_cast<uint16*>(id->indexBuffer->lock(
457                                id->indexStart, 
458                                id->indexCount * id->indexBuffer->getIndexSize(), 
459                                HardwareBuffer::HBL_READ_ONLY));
460                        buildIndexRemap(p16, id->indexCount, indexRemap);
461                        id->indexBuffer->unlock();
462                }
463                if (indexRemap.size() == vd->vertexCount)
464                {
465                        // ha, complete usage after all
466                        targetGeomLink->vertexData = vd;
467                        targetGeomLink->indexData = id;
468                        return;
469                }
470
471
472                // Create the new vertex data records
473                targetGeomLink->vertexData = vd->clone(false);
474                // Convenience
475                VertexData* newvd = targetGeomLink->vertexData;
476                //IndexData* newid = targetGeomLink->indexData;
477                // Update the vertex count
478                newvd->vertexCount = indexRemap.size();
479
480                size_t numvbufs = vd->vertexBufferBinding->getBufferCount();
481                // Copy buffers from old to new
482                for (unsigned short b = 0; b < numvbufs; ++b)
483                {
484                        // Lock old buffer
485                        HardwareVertexBufferSharedPtr oldBuf =
486                                vd->vertexBufferBinding->getBuffer(b);
487                        // Create new buffer
488                        HardwareVertexBufferSharedPtr newBuf =
489                                HardwareBufferManager::getSingleton().createVertexBuffer(
490                                        oldBuf->getVertexSize(),
491                                        indexRemap.size(),
492                                        HardwareBuffer::HBU_STATIC);
493                        // rebind
494                        newvd->vertexBufferBinding->setBinding(b, newBuf);
495
496                        // Copy all the elements of the buffer across, by iterating over
497                        // the IndexRemap which describes how to move the old vertices
498                        // to the new ones. By nature of the map the remap is in order of
499                        // indexes in the old buffer, but note that we're not guaranteed to
500                        // address every vertex (which is kinda why we're here)
501                        uchar* pSrcBase = static_cast<uchar*>(
502                                oldBuf->lock(HardwareBuffer::HBL_READ_ONLY));
503                        uchar* pDstBase = static_cast<uchar*>(
504                                newBuf->lock(HardwareBuffer::HBL_DISCARD));
505                        size_t vertexSize = oldBuf->getVertexSize();
506                        // Buffers should be the same size
507                        assert (vertexSize == newBuf->getVertexSize());
508
509                        for (IndexRemap::iterator r = indexRemap.begin();
510                                r != indexRemap.end(); ++r)
511                        {
512                                assert (r->first < oldBuf->getNumVertices());
513                                assert (r->second < newBuf->getNumVertices());
514
515                                uchar* pSrc = pSrcBase + r->first * vertexSize;
516                                uchar* pDst = pDstBase + r->second * vertexSize;
517                                memcpy(pDst, pSrc, vertexSize);
518                        }
519                        // unlock
520                        oldBuf->unlock();
521                        newBuf->unlock();
522
523                }
524
525                // Now create a new index buffer
526                HardwareIndexBufferSharedPtr ibuf =
527                        HardwareBufferManager::getSingleton().createIndexBuffer(
528                                id->indexBuffer->getType(), id->indexCount,
529                                HardwareBuffer::HBU_STATIC);
530
531                if (use32bitIndexes)
532                {
533                        uint32 *pSrc32, *pDst32;
534                        pSrc32 = static_cast<uint32*>(id->indexBuffer->lock(
535                                id->indexStart, id->indexCount * id->indexBuffer->getIndexSize(), 
536                                HardwareBuffer::HBL_READ_ONLY));
537                        pDst32 = static_cast<uint32*>(ibuf->lock(
538                                HardwareBuffer::HBL_DISCARD));
539                        remapIndexes(pSrc32, pDst32, indexRemap, id->indexCount);
540                        id->indexBuffer->unlock();
541                        ibuf->unlock();
542                }
543                else
544                {
545                        uint16 *pSrc16, *pDst16;
546                        pSrc16 = static_cast<uint16*>(id->indexBuffer->lock(
547                                id->indexStart, id->indexCount * id->indexBuffer->getIndexSize(), 
548                                HardwareBuffer::HBL_READ_ONLY));
549                        pDst16 = static_cast<uint16*>(ibuf->lock(
550                                HardwareBuffer::HBL_DISCARD));
551                        remapIndexes(pSrc16, pDst16, indexRemap, id->indexCount);
552                        id->indexBuffer->unlock();
553                        ibuf->unlock();
554                }
555
556                targetGeomLink->indexData = new IndexData();
557                targetGeomLink->indexData->indexStart = 0;
558                targetGeomLink->indexData->indexCount = id->indexCount;
559                targetGeomLink->indexData->indexBuffer = ibuf;
560
561                // Store optimised geometry for deallocation later
562                OptimisedSubMeshGeometry *optGeom = new OptimisedSubMeshGeometry();
563                optGeom->indexData = targetGeomLink->indexData;
564                optGeom->vertexData = targetGeomLink->vertexData;
565                mOptimisedSubMeshGeometryList.push_back(optGeom);
566        }
567        //--------------------------------------------------------------------------
568        void InstancedGeometry::addSceneNode(const SceneNode* node)
569        {
570                SceneNode::ConstObjectIterator obji = node->getAttachedObjectIterator();
571                while (obji.hasMoreElements())
572                {
573                        MovableObject* mobj = obji.getNext();
574                        if (mobj->getMovableType() == "Entity")
575                        {
576                                addEntity(static_cast<Entity*>(mobj),
577                                        node->_getDerivedPosition(),
578                                        node->_getDerivedOrientation(),
579                                        node->_getDerivedScale());
580                        }
581                }
582                // Iterate through all the child-nodes
583                SceneNode::ConstChildNodeIterator nodei = node->getChildIterator();
584
585                while (nodei.hasMoreElements())
586                {
587                        const SceneNode* newNode = static_cast<const SceneNode*>(nodei.getNext());
588                        // Add this subnode and its children...
589                        addSceneNode( newNode );
590                }
591        }
592        //--------------------------------------------------------------------------
593        void InstancedGeometry::build(void)
594        {
595                // Make sure there's nothing from previous builds
596                destroy();
597
598                // Firstly allocate meshes to BatchInstances
599                for (QueuedSubMeshList::iterator qi = mQueuedSubMeshes.begin();
600                        qi != mQueuedSubMeshes.end(); ++qi)
601                {
602                        QueuedSubMesh* qsm = *qi;
603                        //BatchInstance* BatchInstance = getBatchInstance(qsm->worldBounds, true);
604                        BatchInstance* batchInstance = getInstancedGeometryInstance();
605                        batchInstance->assign(qsm);
606                }
607
608                // Now tell each BatchInstance to build itself
609                for (BatchInstanceMap::iterator ri = mBatchInstanceMap.begin();
610                        ri != mBatchInstanceMap.end(); ++ri)
611                {
612                        ri->second->build();
613                }
614
615
616        }
617        //--------------------------------------------------------------------------
618        void InstancedGeometry::addBatchInstance(void)
619        {
620               
621
622                BatchInstanceIterator regIt = getBatchInstanceIterator();
623                BatchInstance*lastBatchInstance=0 ;
624                while(regIt.hasMoreElements())
625                {
626                        lastBatchInstance= regIt.getNext();
627                }
628                uint32 index=(lastBatchInstance)?lastBatchInstance->getID()+1:0;
629                //create a new BatchInstance
630
631                BatchInstance*ret = new BatchInstance(this, mName+":"+StringConverter::toString(index),
632                        mOwner, index);
633
634                ret->attachToScene();
635
636                mOwner->injectMovableObject(ret);
637                ret->setVisible(mVisible);
638                ret->setCastShadows(mCastShadows);
639                mBatchInstanceMap[index] = ret;
640
641                if (mRenderQueueIDSet)
642                {
643                                ret->setRenderQueueGroup(mRenderQueueID);
644                }
645       
646                const size_t numLod = lastBatchInstance->mLodSquaredDistances.size();
647                ret->mLodSquaredDistances.resize(numLod);
648                for (ushort lod = 0; lod < numLod; lod++)
649                {
650                        ret->mLodSquaredDistances[lod] =
651                        lastBatchInstance->mLodSquaredDistances[lod];
652                }
653
654
655       
656                // update bounds
657                AxisAlignedBox box(lastBatchInstance->mAABB.getMinimum(),lastBatchInstance->mAABB.getMaximum());
658                ret->mAABB.merge(box);
659
660                ret->mBoundingRadius = lastBatchInstance->mBoundingRadius ;
661                //now create  news instanced objects
662                BatchInstance::ObjectsMap::iterator objIt;
663                for(objIt=lastBatchInstance->getInstancesMap().begin();objIt!=lastBatchInstance->getInstancesMap().end();objIt++)
664                {
665                        InstancedObject* instancedObject = ret->isInstancedObjectPresent(objIt->first);
666                        if(instancedObject == NULL)
667                        {
668                                if(mBaseSkeleton.isNull())
669                                {
670                                        instancedObject=new InstancedObject(objIt->first);
671                                }
672                                else
673                                {
674                                        instancedObject=new InstancedObject(objIt->first,mSkeletonInstance,mAnimationState);
675                                }
676                                ret->addInstancedObject(objIt->first,instancedObject);
677                        }
678
679                }
680
681
682
683                BatchInstance::LODIterator lodIterator = lastBatchInstance->getLODIterator();
684                //parse all the lod buckets of the BatchInstance
685                while (lodIterator.hasMoreElements())
686                {
687               
688                        LODBucket* lod = lodIterator.getNext();
689                        //create a new lod bucket for the new BatchInstance
690                        LODBucket* lodBucket= new LODBucket(ret,lod->getLod(),lod->getSquaredDistance());
691
692                        //add the lod bucket to the BatchInstance list
693                        ret->updateContainers(lodBucket);
694                       
695                        LODBucket::MaterialIterator matIt = lod->getMaterialIterator();
696                        //parse all the material buckets of the lod bucket
697                        while (matIt.hasMoreElements())
698                        {
699                               
700                                MaterialBucket*mat = matIt.getNext();
701                                //create a new material bucket
702                                String materialName=mat->getMaterialName();
703                                MaterialBucket* matBucket = new MaterialBucket(lodBucket,materialName);
704
705                                //add the material bucket to the lod buckets list and map
706                                lodBucket->updateContainers(matBucket, materialName);
707
708                                MaterialBucket::GeometryIterator geomIt = mat->getGeometryIterator();
709                                //parse all the geometry buckets of the material bucket
710                                while(geomIt.hasMoreElements())
711                                {
712                                        //get the source geometry bucket
713                                        GeometryBucket *geom = geomIt.getNext();
714                                        //create a new geometry bucket
715                                        GeometryBucket *geomBucket = new GeometryBucket(matBucket,geom->getFormatString(),geom);
716                       
717                                        //update the material bucket map of the material bucket
718                                        matBucket->updateContainers(geomBucket, geomBucket->getFormatString() );
719
720                                        //copy bounding informations
721                                        geomBucket->getAABB()=geom->getAABB();
722                                        geomBucket->setBoundingBox(     geom->getBoundingBox());
723                                        //now setups the news InstancedObjects.
724                                        for(objIt=ret->getInstancesMap().begin();objIt!=ret->getInstancesMap().end();objIt++)
725                                        {
726                                                //get the destination IntanciedObject
727                                                InstancedObject*obj=objIt->second;
728                                                InstancedObject::GeometryBucketList::iterator findIt;
729                                                //check if the bucket is not already in the list
730                                                findIt=std::find(obj->getGeometryBucketList().begin(),obj->getGeometryBucketList().end(),geomBucket);
731                                                if(findIt==obj->getGeometryBucketList().end())
732                                                                obj->addBucketToList(geomBucket);
733                                        }
734                       
735
736                                }       
737                        }
738                }
739        }
740        //--------------------------------------------------------------------------
741        void InstancedGeometry::BatchInstance::updateContainers(LODBucket* bucket )
742        {
743                mLodBucketList.push_back(bucket);
744        }
745        //--------------------------------------------------------------------------
746        void InstancedGeometry::LODBucket::updateContainers(MaterialBucket* bucket, String& name )
747        {
748                mMaterialBucketMap[name] = bucket;
749        }
750
751        //--------------------------------------------------------------------------
752        String InstancedGeometry::GeometryBucket::getFormatString(void) const
753        {
754                return mFormatString;
755        }
756        //--------------------------------------------------------------------------
757        void InstancedGeometry::BatchInstance::attachToScene()
758        {
759
760                        mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(mName/*,mCentre*/);
761                        mNode->attachObject(this);
762        }
763        //--------------------------------------------------------------------------
764        void InstancedGeometry::MaterialBucket::updateContainers(InstancedGeometry::GeometryBucket* bucket, const String & format)
765        {
766                mCurrentGeometryMap[format]=bucket;
767                mGeometryBucketList.push_back(bucket);
768        }
769        void InstancedGeometry::MaterialBucket:: setMaterial(const String & name)
770        {
771                mMaterial=MaterialManager::getSingleton().getByName(name);
772        };
773        //--------------------------------------------------------------------------
774        void InstancedGeometry::destroy(void)
775        {
776                RenderOperationVector::iterator it;
777                for(it=mRenderOps.begin();it!=mRenderOps.end();++it)
778                {
779                        delete (*it)->vertexData;
780                        delete (*it)->indexData;
781       
782                }
783                // delete the BatchInstances
784                for (BatchInstanceMap::iterator i = mBatchInstanceMap.begin();
785                        i != mBatchInstanceMap.end(); ++i)
786                {
787                        mOwner->extractMovableObject(i->second);
788                        delete i->second;
789
790                }
791                mBatchInstanceMap.clear();
792        }
793        //--------------------------------------------------------------------------
794        void InstancedGeometry::reset(void)
795        {
796                destroy();
797
798                for (QueuedSubMeshList::iterator i = mQueuedSubMeshes.begin();
799                        i != mQueuedSubMeshes.end(); ++i)
800                {
801                        delete *i;
802                       
803                }
804                mQueuedSubMeshes.clear();
805                // Delete precached geoemtry lists
806                for (SubMeshGeometryLookup::iterator l = mSubMeshGeometryLookup.begin();
807                        l != mSubMeshGeometryLookup.end(); ++l)
808                {
809                        delete l->second;
810               
811                }
812                mSubMeshGeometryLookup.clear();
813                // Delete optimised geometry
814                for (OptimisedSubMeshGeometryList::iterator o = mOptimisedSubMeshGeometryList.begin();
815                        o != mOptimisedSubMeshGeometryList.end(); ++o)
816                {
817                        delete *o;
818                       
819                }
820                mOptimisedSubMeshGeometryList.clear();
821
822        }
823        //--------------------------------------------------------------------------
824        void InstancedGeometry::setVisible(bool visible)
825        {
826                       
827                mVisible = visible;
828                // tell any existing BatchInstances
829                for (BatchInstanceMap::iterator ri = mBatchInstanceMap.begin();
830                        ri != mBatchInstanceMap.end(); ++ri)
831                {
832
833                       
834                        ri->second->setVisible(visible);
835                }
836        }
837        //--------------------------------------------------------------------------
838        void InstancedGeometry::setCastShadows(bool castShadows)
839        {
840                mCastShadows = castShadows;
841                // tell any existing BatchInstances
842                for (BatchInstanceMap::iterator ri = mBatchInstanceMap.begin();
843                        ri != mBatchInstanceMap.end(); ++ri)
844                {
845                        ri->second->setCastShadows(castShadows);
846                }
847
848        }
849        //--------------------------------------------------------------------------
850    void InstancedGeometry::setRenderQueueGroup(uint8 queueID)
851        {
852                assert(queueID <= RENDER_QUEUE_MAX && "Render queue out of range!");
853                mRenderQueueIDSet = true;
854                mRenderQueueID = queueID;
855                // tell any existing BatchInstances
856                for (BatchInstanceMap::iterator ri = mBatchInstanceMap.begin();
857                        ri != mBatchInstanceMap.end(); ++ri)
858                {
859                        ri->second->setRenderQueueGroup(queueID);
860                }
861        }
862        //--------------------------------------------------------------------------
863        uint8 InstancedGeometry::getRenderQueueGroup(void) const
864        {
865                return mRenderQueueID;
866        }
867        //--------------------------------------------------------------------------
868        void InstancedGeometry::dump(const String& filename) const
869        {
870                std::ofstream of(filename.c_str());
871                of << "Static Geometry Report for " << mName << std::endl;
872                of << "-------------------------------------------------" << std::endl;
873                of << "Number of queued submeshes: " << mQueuedSubMeshes.size() << std::endl;
874                of << "Number of BatchInstances: " << mBatchInstanceMap.size() << std::endl;
875                of << "BatchInstance dimensions: " << mBatchInstanceDimensions << std::endl;
876                of << "Origin: " << mOrigin << std::endl;
877                of << "Max distance: " << mUpperDistance << std::endl;
878                of << "Casts shadows?: " << mCastShadows << std::endl;
879                of << std::endl;
880                for (BatchInstanceMap::const_iterator ri = mBatchInstanceMap.begin();
881                        ri != mBatchInstanceMap.end(); ++ri)
882                {
883                        ri->second->dump(of);
884                }
885                of << "-------------------------------------------------" << std::endl;
886        }
887        //--------------------------------------------------------------------------
888        InstancedGeometry::InstancedObject::InstancedObject(int index,SkeletonInstance *skeleton, AnimationStateSet*animations):mIndex(index),
889                mTransformation(Matrix4::ZERO),
890                mOrientation(Quaternion::IDENTITY),
891                mScale(Vector3::UNIT_SCALE),
892                mPosition(Vector3::ZERO),
893                mSkeletonInstance(skeleton),
894                mBoneWorldMatrices(NULL),
895        mBoneMatrices(NULL),
896        mNumBoneMatrices(0),
897                mFrameAnimationLastUpdated(std::numeric_limits<unsigned long>::max())
898
899        {
900                       
901                        mSkeletonInstance->load();
902               
903                        mAnimationState = new AnimationStateSet();
904                        mNumBoneMatrices = mSkeletonInstance->getNumBones();
905                        mBoneMatrices = new Matrix4[mNumBoneMatrices];
906                        AnimationStateIterator it=animations->getAnimationStateIterator();
907                        while (it.hasMoreElements())
908                        {
909                                AnimationState*anim= it.getNext();
910                                mAnimationState->createAnimationState(anim->getAnimationName(),anim->getTimePosition(),anim->getLength(),
911                                anim->getWeight());
912
913                        }
914                       
915        }
916        //--------------------------------------------------------------------------
917        InstancedGeometry::InstancedObject::InstancedObject(int index):mIndex(index),
918                mTransformation(Matrix4::ZERO),
919                mOrientation(Quaternion::IDENTITY),
920                mScale(Vector3::UNIT_SCALE),
921                mPosition(Vector3::ZERO),
922                mSkeletonInstance(0),
923                mBoneWorldMatrices(0),
924        mBoneMatrices(0),
925                mAnimationState(0),
926        mNumBoneMatrices(0),
927                mFrameAnimationLastUpdated(std::numeric_limits<unsigned long>::max())
928        {
929        }
930        //--------------------------------------------------------------------------
931        InstancedGeometry::InstancedObject::~InstancedObject()
932        {
933                mGeometryBucketList.clear();
934                delete mAnimationState;
935                delete[] mBoneMatrices;
936                delete[] mBoneWorldMatrices;
937        }
938        //--------------------------------------------------------------------------
939        void InstancedGeometry::InstancedObject::addBucketToList(GeometryBucket*bucket)
940        {
941                mGeometryBucketList.push_back(bucket);
942        }
943        //--------------------------------------------------------------------------
944        void InstancedGeometry::InstancedObject::setPosition( Vector3  position)
945        {
946
947                mPosition=position;
948                needUpdate();
949                BatchInstance*parentBatchInstance=(*(mGeometryBucketList.begin()))->getParent()->getParent()->getParent();
950                parentBatchInstance->updateBoundingBox();
951
952        }
953        //--------------------------------------------------------------------------
954        void InstancedGeometry::InstancedObject::translate(const Vector3 &d)
955        {
956                mPosition += d;
957                needUpdate();
958        }
959        //--------------------------------------------------------------------------
960        void InstancedGeometry::InstancedObject::translate(const Matrix3 & axes,const Vector3 &move)
961        {
962                Vector3 derived = axes * move;
963        translate(derived);
964        }
965        //--------------------------------------------------------------------------
966        Matrix3 InstancedGeometry::InstancedObject::getLocalAxes() const
967        {
968                Vector3 axisX = Vector3::UNIT_X;
969        Vector3 axisY = Vector3::UNIT_Y;
970        Vector3 axisZ = Vector3::UNIT_Z;
971
972        axisX = mOrientation * axisX;
973        axisY = mOrientation * axisY;
974        axisZ = mOrientation * axisZ;
975
976        return Matrix3(axisX.x, axisY.x, axisZ.x,
977                       axisX.y, axisY.y, axisZ.y,
978                       axisX.z, axisY.z, axisZ.z);
979        }
980        //--------------------------------------------------------------------------
981        Vector3 & InstancedGeometry::InstancedObject::getPosition(void)
982        {
983                return mPosition;
984        }
985        //--------------------------------------------------------------------------
986        void InstancedGeometry::InstancedObject::yaw(const Radian&angle)
987        {
988                Quaternion q;
989        q.FromAngleAxis(angle,Vector3::UNIT_Y);
990        rotate(q);
991        }
992        //--------------------------------------------------------------------------
993        void InstancedGeometry::InstancedObject::pitch(const Radian&angle)
994        {
995                Quaternion q;
996        q.FromAngleAxis(angle,Vector3::UNIT_X);
997        rotate(q);
998        }
999        //--------------------------------------------------------------------------
1000        void InstancedGeometry::InstancedObject::roll(const Radian&angle)
1001        {
1002                Quaternion q;
1003        q.FromAngleAxis(angle,Vector3::UNIT_Z);
1004        rotate(q);
1005
1006        }
1007        //--------------------------------------------------------------------------
1008        void InstancedGeometry::InstancedObject::setScale(const Vector3&scale)
1009        {
1010                mScale=scale;
1011                needUpdate();
1012        }
1013        //--------------------------------------------------------------------------
1014        void InstancedGeometry::InstancedObject::rotate(const Quaternion& q)
1015        {
1016       
1017            mOrientation = mOrientation * q;
1018                         needUpdate();
1019        }
1020        //--------------------------------------------------------------------------
1021        void InstancedGeometry::InstancedObject::needUpdate()
1022        {
1023                 mTransformation.makeTransform(
1024                mPosition,
1025                mScale,
1026                mOrientation);
1027                       
1028                       
1029        }
1030        //--------------------------------------------------------------------------
1031        void InstancedGeometry::InstancedObject::updateAnimation(void)
1032        {
1033
1034                if(mSkeletonInstance)
1035                {
1036                        GeometryBucketList::iterator it;
1037                    mSkeletonInstance->setAnimationState(*mAnimationState);
1038            mSkeletonInstance->_getBoneMatrices(mBoneMatrices);
1039
1040                         // Allocate bone world matrices on demand, for better memory footprint
1041            // when using software animation.
1042            if (!mBoneWorldMatrices)
1043            {
1044                mBoneWorldMatrices = new Matrix4[mNumBoneMatrices];
1045            }
1046
1047            for (unsigned short i = 0; i < mNumBoneMatrices; ++i)
1048            {
1049                mBoneWorldMatrices[i] =  mTransformation * mBoneMatrices[i];
1050                       
1051            }
1052                       
1053
1054
1055                }
1056
1057        }
1058        //--------------------------------------------------------------------------
1059        AnimationState* InstancedGeometry::InstancedObject::getAnimationState(const String& name) const
1060    {
1061        if (!mAnimationState)
1062        {
1063            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Object is not animated",
1064                "InstancedGeometry::InstancedObject::getAnimationState");
1065        }
1066//              AnimationStateIterator it=mAnimationState->getAnimationStateIterator();
1067//              while (it.hasMoreElements())
1068//              {
1069//                      AnimationState*anim= it.getNext();
1070//
1071//                     
1072//              }
1073                return mAnimationState->getAnimationState(name);
1074    }
1075        //--------------------------------------------------------------------------
1076        InstancedGeometry::BatchInstanceIterator InstancedGeometry::getBatchInstanceIterator(void)
1077        {
1078                return BatchInstanceIterator(mBatchInstanceMap.begin(), mBatchInstanceMap.end());
1079        }
1080        //--------------------------------------------------------------------------
1081        InstancedGeometry::BatchInstance::BatchInstance(InstancedGeometry* parent, const String& name,
1082                SceneManager* mgr, uint32 BatchInstanceID)
1083                : MovableObject(name), mParent(parent), mSceneMgr(mgr), mNode(0),
1084                mBatchInstanceID(BatchInstanceID), mBoundingRadius(0.0f),
1085                mCurrentLod(0)
1086        {
1087                // First LOD mandatory, and always from 0
1088                mLodSquaredDistances.push_back(0.0f);
1089        }
1090        //--------------------------------------------------------------------------
1091        InstancedGeometry::BatchInstance::~BatchInstance()
1092        {
1093                if (mNode)
1094                {
1095                        mNode->getParentSceneNode()->removeChild(mNode);
1096                        mSceneMgr->destroySceneNode(mNode->getName());
1097                        mNode = 0;
1098                }
1099                // delete
1100                for (LODBucketList::iterator i = mLodBucketList.begin();
1101                        i != mLodBucketList.end(); ++i)
1102                {
1103                        delete *i;
1104                }
1105                mLodBucketList.clear();
1106                ObjectsMap::iterator o;
1107
1108                for(o=mInstancesMap.begin();o!=mInstancesMap.end();o++)
1109                {
1110                        delete o->second;
1111                }
1112                mInstancesMap.clear();
1113                // no need to delete queued meshes, these are managed in InstancedGeometry
1114        }
1115        //--------------------------------------------------------------------------
1116        void InstancedGeometry::BatchInstance::assign(QueuedSubMesh* qmesh)
1117        {
1118                mQueuedSubMeshes.push_back(qmesh);
1119                // update lod distances
1120                ushort lodLevels = qmesh->submesh->parent->getNumLodLevels();
1121                assert(qmesh->geometryLodList->size() == lodLevels);
1122
1123                while(mLodSquaredDistances.size() < lodLevels)
1124                {
1125                        mLodSquaredDistances.push_back(0.0f);
1126                }
1127                // Make sure LOD levels are max of all at the requested level
1128                for (ushort lod = 1; lod < lodLevels; ++lod)
1129                {
1130                        const MeshLodUsage& meshLod =
1131                                qmesh->submesh->parent->getLodLevel(lod);
1132                        mLodSquaredDistances[lod] = std::max(mLodSquaredDistances[lod],
1133                                meshLod.fromDepthSquared);
1134                }
1135
1136                // update bounds
1137                // Transform world bounds relative to our centre
1138                AxisAlignedBox localBounds(
1139                        qmesh->worldBounds.getMinimum() ,
1140                        qmesh->worldBounds.getMaximum());
1141                mAABB.merge(localBounds);
1142                mBoundingRadius = std::max(mBoundingRadius, localBounds.getMinimum().length());
1143                mBoundingRadius = std::max(mBoundingRadius, localBounds.getMaximum().length());
1144
1145        }
1146        //--------------------------------------------------------------------------
1147        void InstancedGeometry::BatchInstance::build()
1148        {
1149                // Create a node
1150                mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(mName);
1151                mNode->attachObject(this);
1152                // We need to create enough LOD buckets to deal with the highest LOD
1153                // we encountered in all the meshes queued
1154                for (ushort lod = 0; lod < mLodSquaredDistances.size(); ++lod)
1155                {
1156                        LODBucket* lodBucket =
1157                                new LODBucket(this, lod, mLodSquaredDistances[lod]);
1158                        mLodBucketList.push_back(lodBucket);
1159                        // Now iterate over the meshes and assign to LODs
1160                        // LOD bucket will pick the right LOD to use
1161                        QueuedSubMeshList::iterator qi, qiend;
1162                        qiend = mQueuedSubMeshes.end();
1163                        for (qi = mQueuedSubMeshes.begin(); qi != qiend; ++qi)
1164                        {
1165                                lodBucket->assign(*qi, lod);
1166                        }
1167                        // now build
1168                        lodBucket->build();
1169                }
1170
1171
1172        }
1173       
1174        //--------------------------------------------------------------------------
1175        void InstancedGeometry::BatchInstance::updateBoundingBox()
1176        {
1177
1178                        Vector3 *Positions = new Vector3[mInstancesMap.size()];
1179
1180                        ObjectsMap::iterator objIt;
1181                        size_t k = 0;
1182                        for(objIt=mInstancesMap.begin();objIt!=mInstancesMap.end();objIt++)
1183                        {
1184                                Positions[k++] = objIt->second->getPosition();
1185                        }
1186
1187                        LODIterator lodIterator = getLODIterator();
1188                        while (lodIterator.hasMoreElements())
1189                        {                       
1190                                LODBucket* lod = lodIterator.getNext();
1191                                LODBucket::MaterialIterator matIt = lod->getMaterialIterator();
1192                                while (matIt.hasMoreElements())
1193                                {                                       
1194                                        MaterialBucket*mat = matIt.getNext();
1195                                        MaterialBucket::GeometryIterator geomIt = mat->getGeometryIterator();
1196                                        while(geomIt.hasMoreElements())
1197                                        {
1198                                                // to generate the boundingBox
1199                                                Real Xmin= Positions[0].x;
1200                                                Real Ymin= Positions[0].y;
1201                                                Real Zmin= Positions[0].z;
1202
1203                                                Real Xmax= Positions[0].x;
1204                                                Real Ymax= Positions[0].y;
1205                                                Real Zmax= Positions[0].z;
1206
1207                                                GeometryBucket*geom=geomIt.getNext();
1208                                                for (size_t i = 0; i < mInstancesMap.size (); i++)
1209                                                {
1210                                                        if(Positions[i].x<Xmin)
1211                                                                Xmin = Positions[i].x;
1212                                                        if(Positions[i].y<Ymin)
1213                                                                Ymin = Positions[i].y;
1214                                                        if(Positions[i].z<Zmin)
1215                                                                Zmin = Positions[i].z;
1216                                                        if(Positions[i].x>Xmax)
1217                                                                Xmax = Positions[i].x;
1218                                                        if(Positions[i].y>Ymax)
1219                                                                Ymax = Positions[i].y;
1220                                                        if(Positions[i].z>Zmax)
1221                                                                Zmax = Positions[i].z;
1222                                                }
1223                                                geom->setBoundingBox(AxisAlignedBox(Xmin,Ymin,Zmin,Xmax,Ymax,Zmax));                                           
1224                                                mAABB=AxisAlignedBox(
1225                                                        Vector3(Xmin,Ymin,Zmin) + geom->getAABB().getMinimum(),
1226                                                        Vector3(Xmax,Ymax,Zmax) + geom->getAABB().getMaximum());
1227                                       
1228                                        }
1229                                }
1230                        }
1231
1232                        delete [] Positions;           
1233        }
1234       
1235       
1236       
1237       
1238       
1239       
1240       
1241       
1242        //--------------------------------------------------------------------------
1243        void InstancedGeometry::BatchInstance::addInstancedObject(int index,InstancedObject* object)
1244        {
1245                mInstancesMap[index]=object;
1246        }
1247        //--------------------------------------------------------------------------
1248         InstancedGeometry::InstancedObject* InstancedGeometry::BatchInstance::isInstancedObjectPresent(int index)
1249        {
1250                if (mInstancesMap.find(index)!=mInstancesMap.end())
1251                        return mInstancesMap[index];
1252                else return NULL;
1253        }
1254        //--------------------------------------------------------------------------
1255        InstancedGeometry::InstancedObject** InstancedGeometry::BatchInstance::getObjectsAsArray(unsigned short & size)
1256        {
1257                size = static_cast <unsigned short> (mInstancesMap.size());
1258                ObjectsMap::iterator it;
1259                InstancedObject** array=new InstancedObject*[size];
1260                int i=0;
1261                for(it=mInstancesMap.begin();it!=mInstancesMap.end();it++)
1262                {
1263                        array[i]=it->second;
1264                        i++;
1265                }
1266                return array;
1267        }
1268        //--------------------------------------------------------------------------
1269
1270        const String& InstancedGeometry::BatchInstance::getMovableType(void) const
1271        {
1272                static String sType = "InstancedGeometry";
1273                return sType;
1274        }
1275        //--------------------------------------------------------------------------
1276        void InstancedGeometry::BatchInstance::_notifyCurrentCamera(Camera* cam)
1277        {
1278                // Calculate squared view depth
1279                Vector3 diff = cam->getDerivedPosition() ;
1280                Real squaredDepth = diff.squaredLength();
1281
1282                // Determine whether to still render
1283                Real renderingDist = mParent->getRenderingDistance();
1284                if (renderingDist > 0)
1285                {
1286                        // Max distance to still render
1287                        Real maxDist = renderingDist + mBoundingRadius;
1288                        if (squaredDepth > Math::Sqr(maxDist))
1289                        {
1290                                mBeyondFarDistance = true;
1291                                return;
1292                        }
1293                }
1294
1295                mBeyondFarDistance = false;
1296
1297                // Distance from the edge of the bounding sphere
1298                mCamDistanceSquared = squaredDepth - mBoundingRadius * mBoundingRadius;
1299                // Clamp to 0
1300                mCamDistanceSquared = std::max(static_cast<Real>(0.0), mCamDistanceSquared);
1301
1302                // Determine active lod
1303                mCurrentLod = static_cast<ushort>(mLodSquaredDistances.size() - 1);
1304                assert (!mLodSquaredDistances.empty());
1305                mCurrentLod = static_cast <unsigned short> (mLodSquaredDistances.size() - 1);
1306       
1307                for (ushort i = 0; i < mLodSquaredDistances.size(); ++i)
1308                {
1309                        if (mLodSquaredDistances[i] > mCamDistanceSquared)
1310                        {
1311                                mCurrentLod = i - 1;
1312                                break;
1313                        }
1314                }
1315
1316        }
1317        //--------------------------------------------------------------------------
1318        const AxisAlignedBox& InstancedGeometry::BatchInstance::getBoundingBox(void) const
1319        {
1320                return mAABB;
1321        }
1322        //--------------------------------------------------------------------------
1323        void InstancedGeometry::BatchInstance::setBoundingBox(AxisAlignedBox & box)
1324        {
1325                mAABB=box;
1326        }
1327        //--------------------------------------------------------------------------
1328        Real InstancedGeometry::BatchInstance::getBoundingRadius(void) const
1329        {
1330                return mBoundingRadius;
1331        }
1332        //--------------------------------------------------------------------------
1333        void InstancedGeometry::BatchInstance::_updateRenderQueue(RenderQueue* queue)
1334        {
1335                ObjectsMap::iterator it;
1336                //we parse the Instanced Object map to update the animations.
1337
1338                for (it=mInstancesMap.begin();it!=mInstancesMap.end();++it)
1339                {
1340                        it->second->updateAnimation();
1341                       
1342                }
1343       
1344                mLodBucketList[mCurrentLod]->addRenderables(queue, mRenderQueueID,
1345                        mCamDistanceSquared);
1346        }
1347        //--------------------------------------------------------------------------
1348        bool InstancedGeometry::BatchInstance::isVisible(void) const
1349        {
1350                return mVisible && !mBeyondFarDistance;
1351        }
1352        //--------------------------------------------------------------------------
1353        InstancedGeometry::BatchInstance::LODIterator
1354        InstancedGeometry::BatchInstance::getLODIterator(void)
1355        {
1356                return LODIterator(mLodBucketList.begin(), mLodBucketList.end());
1357        }
1358        //--------------------------------------------------------------------------
1359        const LightList& InstancedGeometry::BatchInstance::getLights(void) const
1360        {
1361                return queryLights();
1362        }
1363        //--------------------------------------------------------------------------
1364        void InstancedGeometry::BatchInstance::dump(std::ofstream& of) const
1365        {
1366                of << "BatchInstance " << mBatchInstanceID << std::endl;
1367                of << "--------------------------" << std::endl;
1368                of << "Local AABB: " << mAABB << std::endl;
1369                of << "Bounding radius: " << mBoundingRadius << std::endl;
1370                of << "Number of LODs: " << mLodBucketList.size() << std::endl;
1371
1372                for (LODBucketList::const_iterator i = mLodBucketList.begin();
1373                        i != mLodBucketList.end(); ++i)
1374                {
1375                        (*i)->dump(of);
1376                }
1377                of << "--------------------------" << std::endl;
1378        }
1379        //--------------------------------------------------------------------------
1380        //--------------------------------------------------------------------------
1381        InstancedGeometry::LODBucket::LODBucket(BatchInstance* parent, unsigned short lod,
1382                Real lodDist)
1383                : mParent(parent), mLod(lod), mSquaredDistance(lodDist)
1384        {
1385        }
1386        //--------------------------------------------------------------------------
1387        InstancedGeometry::LODBucket::~LODBucket()
1388        {
1389                // delete
1390                for (MaterialBucketMap::iterator i = mMaterialBucketMap.begin();
1391                        i != mMaterialBucketMap.end(); ++i)
1392                {
1393                        delete i->second;
1394                }
1395                mMaterialBucketMap.clear();
1396                for(QueuedGeometryList::iterator qi = mQueuedGeometryList.begin();
1397                        qi != mQueuedGeometryList.end(); ++qi)
1398                {
1399                        delete *qi;
1400                }
1401                mQueuedGeometryList.clear();
1402                // no need to delete queued meshes, these are managed in InstancedGeometry
1403        }
1404        //--------------------------------------------------------------------------
1405        void InstancedGeometry::LODBucket::assign(QueuedSubMesh* qmesh, ushort atLod)
1406        {
1407                QueuedGeometry* q = new QueuedGeometry();
1408                mQueuedGeometryList.push_back(q);
1409                q->position = qmesh->position;
1410                q->orientation = qmesh->orientation;
1411                q->scale = qmesh->scale;
1412                q->ID = qmesh->ID;
1413                if (qmesh->geometryLodList->size() > atLod)
1414                {
1415                        // This submesh has enough lods, use the right one
1416                        q->geometry = &(*qmesh->geometryLodList)[atLod];
1417                }
1418                else
1419                {
1420                        // Not enough lods, use the lowest one we have
1421                        q->geometry =
1422                                &(*qmesh->geometryLodList)[qmesh->geometryLodList->size() - 1];
1423                }
1424                // Locate a material bucket
1425                MaterialBucket* mbucket = 0;
1426                MaterialBucketMap::iterator m =
1427                        mMaterialBucketMap.find(qmesh->materialName);
1428                if (m != mMaterialBucketMap.end())
1429                {
1430                        mbucket = m->second;
1431                }
1432                else
1433                {
1434                        mbucket = new MaterialBucket(this, qmesh->materialName);
1435                        mMaterialBucketMap[qmesh->materialName] = mbucket;
1436                }
1437                mbucket->assign(q);
1438        }
1439        //--------------------------------------------------------------------------
1440        void InstancedGeometry::LODBucket::build()
1441        {
1442                // Just pass this on to child buckets
1443               
1444                for (MaterialBucketMap::iterator i = mMaterialBucketMap.begin();
1445                        i != mMaterialBucketMap.end(); ++i)
1446                {
1447                        i->second->build();
1448                }
1449        }
1450        //--------------------------------------------------------------------------
1451        void InstancedGeometry::LODBucket::addRenderables(RenderQueue* queue,
1452                uint8 group, Real camDistanceSquared)
1453        {
1454                // Just pass this on to child buckets
1455                MaterialBucketMap::iterator i, iend;
1456                iend =  mMaterialBucketMap.end();
1457                int j=0;
1458                for (i = mMaterialBucketMap.begin(); i != iend; ++i)
1459                {
1460                        i->second->addRenderables(queue, group, camDistanceSquared);
1461                        j++;
1462                }
1463        }
1464        //--------------------------------------------------------------------------
1465        InstancedGeometry::LODBucket::MaterialIterator
1466        InstancedGeometry::LODBucket::getMaterialIterator(void)
1467        {
1468                return MaterialIterator(
1469                        mMaterialBucketMap.begin(), mMaterialBucketMap.end());
1470        }
1471        //--------------------------------------------------------------------------
1472        void InstancedGeometry::LODBucket::dump(std::ofstream& of) const
1473        {
1474                of << "LOD Bucket " << mLod << std::endl;
1475                of << "------------------" << std::endl;
1476                of << "Distance: " << Math::Sqrt(mSquaredDistance) << std::endl;
1477                of << "Number of Materials: " << mMaterialBucketMap.size() << std::endl;
1478                for (MaterialBucketMap::const_iterator i = mMaterialBucketMap.begin();
1479                        i != mMaterialBucketMap.end(); ++i)
1480                {
1481                        i->second->dump(of);
1482                }
1483                of << "------------------" << std::endl;
1484
1485        }
1486        //--------------------------------------------------------------------------
1487        //--------------------------------------------------------------------------
1488        InstancedGeometry::MaterialBucket::MaterialBucket(LODBucket* parent,
1489                const String& materialName)
1490                : mParent(parent), mMaterialName(materialName),mLastIndex(0)
1491        {
1492                                                mMaterial = MaterialManager::getSingleton().getByName(mMaterialName);
1493        }
1494        //--------------------------------------------------------------------------
1495        InstancedGeometry::MaterialBucket::~MaterialBucket()
1496        {
1497                // delete
1498                for (GeometryBucketList::iterator i = mGeometryBucketList.begin();
1499                        i != mGeometryBucketList.end(); ++i)
1500                {
1501                        delete *i;
1502                }
1503                mGeometryBucketList.clear();
1504                // no need to delete queued meshes, these are managed in InstancedGeometry
1505
1506        }
1507        //--------------------------------------------------------------------------
1508
1509        void InstancedGeometry::MaterialBucket::assign(QueuedGeometry* qgeom)
1510        {
1511                // Look up any current geometry
1512                String formatString = getGeometryFormatString(qgeom->geometry);
1513                CurrentGeometryMap::iterator gi = mCurrentGeometryMap.find(formatString);
1514                bool newBucket = true;
1515                if (gi != mCurrentGeometryMap.end())
1516                {
1517                        // Found existing geometry, try to assign
1518                        newBucket = !gi->second->assign(qgeom);
1519                        // Note that this bucket will be replaced as the 'current'
1520                        // for this format string below since it's out of space
1521                }
1522                // Do we need to create a new one?
1523                if (newBucket)
1524                {
1525                        GeometryBucket* gbucket = new GeometryBucket(this, formatString,
1526                                qgeom->geometry->vertexData, qgeom->geometry->indexData);
1527                        // Add to main list
1528                        mGeometryBucketList.push_back(gbucket);
1529                        // Also index in 'current' list
1530                        mCurrentGeometryMap[formatString] = gbucket;
1531                        if (!gbucket->assign(qgeom))
1532                        {
1533                                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
1534                                        "Somehow we couldn't fit the requested geometry even in a "
1535                                        "brand new GeometryBucket!! Must be a bug, please report.",
1536                                        "InstancedGeometry::MaterialBucket::assign");
1537                        }
1538                }
1539        }
1540        //--------------------------------------------------------------------------
1541        void InstancedGeometry::MaterialBucket::build()
1542        {
1543                mMaterial = MaterialManager::getSingleton().getByName(mMaterialName);
1544                if (mMaterial.isNull())
1545                {
1546                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
1547                                "Material '" + mMaterialName + "' not found.",
1548                                "InstancedGeometry::MaterialBucket::build");
1549                }
1550                mMaterial->load();
1551                // tell the geometry buckets to build
1552               
1553                for (GeometryBucketList::iterator i = mGeometryBucketList.begin();
1554                        i != mGeometryBucketList.end(); ++i)
1555                {
1556                        (*i)->build();
1557                }
1558        }
1559        //--------------------------------------------------------------------------
1560        void InstancedGeometry::MaterialBucket::addRenderables(RenderQueue* queue,
1561                uint8 group, Real camDistanceSquared)
1562        {
1563
1564                // Determine the current material technique
1565                mTechnique = mMaterial->getTechnique(
1566                        mMaterial->getLodIndexSquaredDepth(camDistanceSquared));       
1567                GeometryBucketList::iterator i, iend;
1568                iend =  mGeometryBucketList.end();
1569                int j=0;
1570                       
1571                for (i = mGeometryBucketList.begin(); i != iend; ++i)
1572                {
1573                        queue->addRenderable(*i, group);
1574                        j++;
1575                }
1576
1577        }
1578        //--------------------------------------------------------------------------
1579        String InstancedGeometry::MaterialBucket::getGeometryFormatString(
1580                SubMeshLodGeometryLink* geom)
1581        {
1582                // Formulate an identifying string for the geometry format
1583                // Must take into account the vertex declaration and the index type
1584                // Format is (all lines separated by '|'):
1585                // Index type
1586                // Vertex element (repeating)
1587                //   source
1588                //   semantic
1589                //   type
1590                StringUtil::StrStreamType str;
1591
1592                str << geom->indexData->indexBuffer->getType() << "|";
1593                const VertexDeclaration::VertexElementList& elemList =
1594                        geom->vertexData->vertexDeclaration->getElements();
1595                VertexDeclaration::VertexElementList::const_iterator ei, eiend;
1596                eiend = elemList.end();
1597                for (ei = elemList.begin(); ei != eiend; ++ei)
1598                {
1599                        const VertexElement& elem = *ei;
1600                        str << elem.getSource() << "|";
1601                        str << elem.getSource() << "|";
1602                        str << elem.getSemantic() << "|";
1603                        str << elem.getType() << "|";
1604                }
1605
1606                return str.str();
1607
1608        }
1609        //--------------------------------------------------------------------------
1610        InstancedGeometry::MaterialBucket::GeometryIterator
1611        InstancedGeometry::MaterialBucket::getGeometryIterator(void)
1612        {
1613                return GeometryIterator(
1614                        mGeometryBucketList.begin(), mGeometryBucketList.end());
1615        }
1616        //--------------------------------------------------------------------------
1617        void InstancedGeometry::MaterialBucket::dump(std::ofstream& of) const
1618        {
1619                of << "Material Bucket " << mMaterialName << std::endl;
1620                of << "--------------------------------------------------" << std::endl;
1621                of << "Geometry buckets: " << mGeometryBucketList.size() << std::endl;
1622                for (GeometryBucketList::const_iterator i = mGeometryBucketList.begin();
1623                        i != mGeometryBucketList.end(); ++i)
1624                {
1625                        (*i)->dump(of);
1626                }
1627                of << "--------------------------------------------------" << std::endl;
1628
1629        }
1630        //--------------------------------------------------------------------------
1631        //--------------------------------------------------------------------------
1632        InstancedGeometry::GeometryBucket::GeometryBucket(MaterialBucket* parent,
1633                const String& formatString, const VertexData* vData,
1634                const IndexData* iData)
1635                : SimpleRenderable(),
1636                 mParent(parent), 
1637                 mFormatString(formatString),
1638                 mVertexData(0),
1639                 mIndexData(0)
1640        {
1641                mBatch=mParent->getParent()->getParent()->getParent();
1642                if(!mBatch->getBaseSkeleton().isNull())
1643                        setCustomParameter(0,Vector4(mBatch->getBaseSkeleton()->getNumBones(),0,0,0));
1644                //mRenderOperation=new RenderOperation();
1645                // Clone the structure from the example
1646                mVertexData = vData->clone(false);
1647
1648                mRenderOp.useIndexes = true;
1649                mRenderOp.indexData = new IndexData();
1650
1651                mRenderOp.indexData->indexCount = 0;
1652                mRenderOp.indexData->indexStart = 0;
1653                mRenderOp.vertexData = new VertexData();
1654                mRenderOp.vertexData->vertexCount = 0;
1655
1656                mRenderOp.vertexData->vertexDeclaration = vData->vertexDeclaration->clone();
1657                mIndexType = iData->indexBuffer->getType();
1658                // Derive the max vertices
1659                if (mIndexType == HardwareIndexBuffer::IT_32BIT)
1660                {
1661                        mMaxVertexIndex = 0xFFFFFFFF;
1662                }
1663                else
1664                {
1665                        mMaxVertexIndex = 0xFFFF;
1666                }
1667
1668
1669                size_t offset=0, tcOffset=0;
1670                unsigned short texCoordOffset=0;
1671                unsigned short texCoordSource=0;
1672                for(ushort i=0;i<mRenderOp.vertexData->vertexDeclaration->getElementCount();i++)
1673                {
1674               
1675                        if(mRenderOp.vertexData->vertexDeclaration->getElement(i)->getSemantic() == VES_TEXTURE_COORDINATES)
1676                        {
1677                                texCoordOffset++;
1678                                texCoordSource=mRenderOp.vertexData->vertexDeclaration->getElement(i)->getSource();
1679                                tcOffset=mRenderOp.vertexData->vertexDeclaration->getElement(i)->getOffset()+VertexElement::getTypeSize(
1680                                                mRenderOp.vertexData->vertexDeclaration->getElement(i)->getType());
1681                        }
1682                        offset+= VertexElement::getTypeSize(
1683                        mRenderOp.vertexData->vertexDeclaration->getElement(i)->getType());
1684                }
1685
1686                mRenderOp.vertexData->vertexDeclaration->addElement(texCoordSource,tcOffset, VET_FLOAT1, VES_TEXTURE_COORDINATES,texCoordOffset);
1687
1688                mTexCoordIndex=texCoordOffset;
1689               
1690               
1691
1692        }
1693        //--------------------------------------------------------------------------
1694        InstancedGeometry::GeometryBucket::GeometryBucket(MaterialBucket* parent,
1695                const String& formatString,GeometryBucket* bucket)
1696                : SimpleRenderable(),
1697                 mParent(parent),
1698                  mFormatString(formatString),
1699                  mVertexData(0),
1700                  mIndexData(0)
1701        {
1702
1703                mBatch=mParent->getParent()->getParent()->getParent();
1704                if(!mBatch->getBaseSkeleton().isNull())
1705                        setCustomParameter(0,Vector4(mBatch->getBaseSkeleton()->getNumBones(),0,0,0));
1706                bucket->getRenderOperation(mRenderOp);
1707                mVertexData=mRenderOp.vertexData;
1708                mIndexData=mRenderOp.indexData;
1709                setBoundingBox(AxisAlignedBox(-10000,-10000,-10000,
1710                10000,10000,10000));
1711
1712        }
1713        //--------------------------------------------------------------------------
1714        InstancedGeometry::GeometryBucket::~GeometryBucket()
1715        {       
1716        }
1717
1718        //--------------------------------------------------------------------------
1719        Real InstancedGeometry::GeometryBucket::getBoundingRadius(void) const
1720        {
1721                return 1;
1722        }
1723        //--------------------------------------------------------------------------
1724        const MaterialPtr& InstancedGeometry::GeometryBucket::getMaterial(void) const
1725        {
1726                return mParent->getMaterial();
1727        }
1728        //--------------------------------------------------------------------------
1729        Technique* InstancedGeometry::GeometryBucket::getTechnique(void) const
1730        {
1731                return mParent->getCurrentTechnique();
1732        }
1733        //--------------------------------------------------------------------------
1734        void InstancedGeometry::GeometryBucket::getWorldTransforms(Matrix4* xform) const
1735        {
1736                        // Should be the identity transform, but lets allow transformation of the
1737                // nodes the BatchInstances are attached to for kicks
1738                if(mBatch->getBaseSkeleton().isNull())
1739                {
1740                        BatchInstance::ObjectsMap::iterator it,itbegin,itend,newit;
1741                        itbegin=mParent->getParent()->getParent()->getInstancesMap().begin();
1742                        itend=mParent->getParent()->getParent()->getInstancesMap().end();
1743
1744                        for (it=itbegin;
1745                                it!=itend;
1746                                ++it,++xform)
1747                        {
1748                               
1749                                        *xform = it->second->mTransformation;
1750                        }
1751                }
1752                else
1753                {
1754                        BatchInstance::ObjectsMap::iterator it,itbegin,itend,newit;
1755                        itbegin=mParent->getParent()->getParent()->getInstancesMap().begin();
1756                        itend=mParent->getParent()->getParent()->getInstancesMap().end();
1757
1758                        for (it=itbegin;
1759                                it!=itend;
1760                                ++it)
1761                        {
1762                               
1763                                for(int i=0;i<it->second->mNumBoneMatrices;++i,++xform)
1764                                {
1765                                        *xform = it->second->mBoneWorldMatrices[i];
1766                                }
1767                        }
1768                               
1769                }
1770
1771        }
1772        //--------------------------------------------------------------------------
1773        unsigned short InstancedGeometry::GeometryBucket::getNumWorldTransforms(void) const 
1774        {
1775                if(mBatch->getBaseSkeleton().isNull())
1776                {
1777                        BatchInstance* batch=mParent->getParent()->getParent();
1778                        return static_cast<ushort>(batch->getInstancesMap().size());
1779                }
1780                else
1781                {
1782                        BatchInstance* batch=mParent->getParent()->getParent();
1783                        return static_cast<ushort>(
1784                                mBatch->getBaseSkeleton()->getNumBones()*batch->getInstancesMap().size());
1785                }
1786        }
1787        //--------------------------------------------------------------------------
1788        const Quaternion& InstancedGeometry::GeometryBucket::getWorldOrientation(void) const
1789        {
1790                return Quaternion::IDENTITY;
1791        }
1792        //--------------------------------------------------------------------------
1793        const Vector3& InstancedGeometry::GeometryBucket::getWorldPosition(void) const
1794        {
1795                return Vector3::ZERO;
1796        }
1797        //--------------------------------------------------------------------------
1798        Real InstancedGeometry::GeometryBucket::getSquaredViewDepth(const Camera* cam) const
1799        {
1800                return mParent->getParent()->getSquaredDistance();
1801        }
1802        //--------------------------------------------------------------------------
1803        const LightList& InstancedGeometry::GeometryBucket::getLights(void) const
1804        {
1805                return mParent->getParent()->getParent()->getLights();
1806        }
1807        //--------------------------------------------------------------------------
1808        bool InstancedGeometry::GeometryBucket::getCastsShadows(void) const
1809        {
1810                return mParent->getParent()->getParent()->getCastShadows();
1811        }
1812        //--------------------------------------------------------------------------
1813        bool InstancedGeometry::GeometryBucket::assign(QueuedGeometry* qgeom)
1814        {
1815                // Do we have enough space?
1816                if (mRenderOp.vertexData->vertexCount + qgeom->geometry->vertexData->vertexCount
1817                        > mMaxVertexIndex)
1818                {
1819                        return false;
1820                }
1821
1822                mQueuedGeometry.push_back(qgeom);
1823                mRenderOp.vertexData->vertexCount += qgeom->geometry->vertexData->vertexCount;
1824                mRenderOp.indexData->indexCount += qgeom->geometry->indexData->indexCount;
1825
1826                return true;
1827        }
1828
1829        //--------------------------------------------------------------------------
1830        void InstancedGeometry::GeometryBucket::build()
1831        {
1832
1833
1834       
1835                // Ok, here's where we transfer the vertices and indexes to the shared
1836                // buffers
1837                // Shortcuts
1838                VertexDeclaration* dcl = mRenderOp.vertexData->vertexDeclaration;
1839                VertexBufferBinding* binds =mVertexData->vertexBufferBinding;
1840
1841                // create index buffer, and lock
1842                mRenderOp.indexData->indexBuffer = HardwareBufferManager::getSingleton()
1843                        .createIndexBuffer(mIndexType, mRenderOp.indexData->indexCount,
1844                                HardwareBuffer::HBU_STATIC_WRITE_ONLY);
1845                uint32* p32Dest = 0;
1846                uint16* p16Dest = 0;
1847
1848                if (mIndexType == HardwareIndexBuffer::IT_32BIT)
1849                {
1850                        p32Dest = static_cast<uint32*>(
1851                                mRenderOp.indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
1852                }
1853                else
1854                {
1855                        p16Dest = static_cast<uint16*>(
1856                                mRenderOp.indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
1857                }
1858
1859                // create all vertex buffers, and lock
1860                ushort b;
1861                //ushort posBufferIdx = dcl->findElementBySemantic(VES_POSITION)->getSource();
1862       
1863                std::vector<uchar*> destBufferLocks;
1864                std::vector<VertexDeclaration::VertexElementList> bufferElements;
1865
1866                for (b = 0; b < binds->getBufferCount(); ++b)
1867                {
1868
1869                        size_t vertexCount = mRenderOp.vertexData->vertexCount;
1870
1871                        HardwareVertexBufferSharedPtr vbuf =
1872                                HardwareBufferManager::getSingleton().createVertexBuffer(
1873                                        dcl->getVertexSize(b),
1874                                        vertexCount,
1875                                        HardwareBuffer::HBU_STATIC_WRITE_ONLY);
1876                        binds->setBinding(b, vbuf);
1877                        uchar* pLock = static_cast<uchar*>(
1878                                vbuf->lock(HardwareBuffer::HBL_DISCARD));
1879                        destBufferLocks.push_back(pLock);
1880                        // Pre-cache vertex elements per buffer
1881                        bufferElements.push_back(dcl->findElementsBySource(b));
1882                        mRenderOp.vertexData->vertexBufferBinding->setBinding(b,vbuf);
1883                }
1884
1885
1886                // Iterate over the geometry items
1887                size_t indexOffset = 0;
1888
1889                QueuedGeometryList::iterator gi, giend;
1890                giend = mQueuedGeometry.end();
1891
1892                // to generate the boundingBox
1893                Real Xmin,Ymin,Zmin,Xmax,Ymax,Zmax; 
1894                Xmin=0;
1895                Ymin=0;
1896                Zmin=0;
1897                Xmax=0;
1898                Ymax=0;
1899                Zmax=0;
1900                QueuedGeometry* precGeom = *(mQueuedGeometry.begin());
1901                int index=0;
1902                if( mParent->getLastIndex()!=0)
1903                        index=mParent->getLastIndex()+1;
1904
1905                for (gi = mQueuedGeometry.begin(); gi != giend; ++gi)
1906                {
1907
1908                        QueuedGeometry* geom = *gi;
1909                        if(precGeom->ID!=geom->ID)
1910                                        index++;
1911
1912                        //create  a new instanced object
1913                        InstancedObject* instancedObject = mParent->getParent()->getParent()->isInstancedObjectPresent(index);
1914                        if(instancedObject == NULL)
1915                        {
1916                                if(mBatch->getBaseSkeleton().isNull())
1917                                {
1918                                        instancedObject=new InstancedObject(index);
1919                                }
1920                                else
1921                                {
1922                                        instancedObject=new InstancedObject(index,mBatch->getBaseSkeletonInstance(),
1923                                                mBatch->getBaseAnimationState());
1924                                }
1925                                mParent->getParent()->getParent()->addInstancedObject(index,instancedObject);
1926
1927                        }
1928                        instancedObject->addBucketToList(this);
1929
1930
1931                       
1932                        // Copy indexes across with offset
1933                        IndexData* srcIdxData = geom->geometry->indexData;
1934                        if (mIndexType == HardwareIndexBuffer::IT_32BIT)
1935                        {
1936                                // Lock source indexes
1937                                uint32* pSrc = static_cast<uint32*>(
1938                                        srcIdxData->indexBuffer->lock(
1939                                                srcIdxData->indexStart, 
1940                                                srcIdxData->indexCount * srcIdxData->indexBuffer->getIndexSize(),
1941                                                HardwareBuffer::HBL_READ_ONLY));
1942
1943                                copyIndexes(pSrc, p32Dest, srcIdxData->indexCount, indexOffset);
1944                                p32Dest += srcIdxData->indexCount;
1945                                srcIdxData->indexBuffer->unlock();
1946                        }
1947                        else
1948                        {
1949                               
1950                                // Lock source indexes
1951                                uint16* pSrc = static_cast<uint16*>(
1952                                        srcIdxData->indexBuffer->lock(
1953                                        srcIdxData->indexStart, 
1954                                        srcIdxData->indexCount * srcIdxData->indexBuffer->getIndexSize(),
1955                                        HardwareBuffer::HBL_READ_ONLY));
1956
1957                                copyIndexes(pSrc, p16Dest, srcIdxData->indexCount, indexOffset);
1958                                p16Dest += srcIdxData->indexCount;
1959                                srcIdxData->indexBuffer->unlock();
1960                        }
1961
1962                        // Now deal with vertex buffers
1963                        // we can rely on buffer counts / formats being the same
1964                        VertexData* srcVData = geom->geometry->vertexData;
1965                        VertexBufferBinding* srcBinds = srcVData->vertexBufferBinding;
1966               
1967                        for (b = 0; b < binds->getBufferCount(); ++b)
1968                        {
1969
1970                                // lock source
1971                                HardwareVertexBufferSharedPtr srcBuf =
1972                                        srcBinds->getBuffer(b);
1973                                uchar* pSrcBase = static_cast<uchar*>(
1974                                        srcBuf->lock(HardwareBuffer::HBL_READ_ONLY));
1975                                // Get buffer lock pointer, we'll update this later
1976                                uchar* pDstBase = destBufferLocks[b];
1977                                size_t bufInc = srcBuf->getVertexSize();
1978                       
1979                                // Iterate over vertices
1980                                float *pSrcReal, *pDstReal;
1981                                Vector3 tmp;
1982
1983                       
1984                       
1985                                for (size_t v = 0; v < srcVData->vertexCount; ++v)
1986                                {
1987                                        //to know if the current buffer is the one with the buffer or not
1988                                        bool isTheBufferWithIndex=false;
1989                                        // Iterate over vertex elements
1990                                        VertexDeclaration::VertexElementList& elems =
1991                                                bufferElements[b];
1992                                        VertexDeclaration::VertexElementList::iterator ei;
1993                               
1994                                        for (ei = elems.begin(); ei != elems.end(); ++ei)
1995                                        {
1996                                                VertexElement& elem = *ei;
1997                                                elem.baseVertexPointerToElement(pSrcBase, &pSrcReal);
1998                                                elem.baseVertexPointerToElement(pDstBase, &pDstReal);
1999                                                if(elem.getSemantic()==VES_TEXTURE_COORDINATES && elem.getIndex()==mTexCoordIndex)
2000                                                {
2001                                                        isTheBufferWithIndex=true;
2002                                                        *pDstReal++=index;
2003                                                }
2004                                                else
2005                                                {
2006                                                        switch (elem.getSemantic())
2007                                                        {
2008                                                                case VES_POSITION:
2009                                                                        tmp.x = *pSrcReal++;
2010                                                                        tmp.y = *pSrcReal++;
2011                                                                        tmp.z = *pSrcReal++;
2012                                                                        *pDstReal++ = tmp.x;
2013                                                                        *pDstReal++ = tmp.y;
2014                                                                        *pDstReal++ = tmp.z;
2015                                                                        if(tmp.x<Xmin)
2016                                                                                Xmin = tmp.x;
2017                                                                        if(tmp.y<Ymin)
2018                                                                                Ymin = tmp.y;
2019                                                                        if(tmp.z<Zmin)
2020                                                                                Zmin = tmp.z;
2021                                                                        if(tmp.x>Xmax)
2022                                                                                Xmax = tmp.x;
2023                                                                        if(tmp.y>Ymax)
2024                                                                                Ymax = tmp.y;
2025                                                                        if(tmp.z>Zmax)
2026                                                                                Zmax = tmp.z;
2027                                                                default:
2028                                                                // just raw copy
2029                                                                memcpy(pDstReal, pSrcReal,
2030                                                                        VertexElement::getTypeSize(elem.getType()));
2031                                                                break;
2032                                                        };
2033
2034                                                }
2035                                       
2036
2037                                        }
2038                                        if (isTheBufferWithIndex)
2039                                        pDstBase += bufInc+4;
2040                                        else
2041                                        pDstBase += bufInc;
2042                                        pSrcBase += bufInc;
2043
2044                                }
2045       
2046                                // Update pointer
2047                                destBufferLocks[b] = pDstBase;
2048                                srcBuf->unlock();
2049
2050                       
2051                        }
2052                        indexOffset += geom->geometry->vertexData->vertexCount;
2053
2054
2055                precGeom=geom;
2056
2057                }
2058                mParent->setLastIndex(index);
2059                // Unlock everything
2060                mRenderOp.indexData->indexBuffer->unlock();
2061                for (b = 0; b < binds->getBufferCount(); ++b)
2062                {
2063                        binds->getBuffer(b)->unlock();
2064                }
2065       
2066        delete mVertexData;
2067        delete mIndexData;
2068       
2069        mVertexData=mRenderOp.vertexData;
2070        mIndexData=mRenderOp.indexData;
2071        mBatch->getRenderOperationVector().push_back(&mRenderOp);
2072        setBoundingBox(AxisAlignedBox(Xmin,Ymin,Zmin,Xmax,Ymax,Zmax));
2073        mAABB=AxisAlignedBox(Xmin,Ymin,Zmin,Xmax,Ymax,Zmax);
2074
2075        }
2076        //--------------------------------------------------------------------------
2077        void InstancedGeometry::GeometryBucket::dump(std::ofstream& of) const
2078        {
2079                of << "Geometry Bucket" << std::endl;
2080                of << "---------------" << std::endl;
2081                of << "Format string: " << mFormatString << std::endl;
2082                of << "Geometry items: " << mQueuedGeometry.size() << std::endl;
2083                of << "---------------" << std::endl;
2084
2085        }
2086        //--------------------------------------------------------------------------
2087
2088}
2089
Note: See TracBrowser for help on using the repository browser.