| 1 | /* | 
|---|
| 2 | ----------------------------------------------------------------------------- | 
|---|
| 3 | This source file is part of OGRE | 
|---|
| 4 | (Object-oriented Graphics Rendering Engine) | 
|---|
| 5 | For the latest info, see http://www.ogre3d.org/ | 
|---|
| 6 |  | 
|---|
| 7 | Copyright (c) 2000-2006 Torus Knot Software Ltd | 
|---|
| 8 | Also see acknowledgements in Readme.html | 
|---|
| 9 |  | 
|---|
| 10 | This program is free software; you can redistribute it and/or modify it under | 
|---|
| 11 | the terms of the GNU Lesser General Public License as published by the Free Software | 
|---|
| 12 | Foundation; either version 2 of the License, or (at your option) any later | 
|---|
| 13 | version. | 
|---|
| 14 |  | 
|---|
| 15 | This program is distributed in the hope that it will be useful, but WITHOUT | 
|---|
| 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 
|---|
| 17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. | 
|---|
| 18 |  | 
|---|
| 19 | You should have received a copy of the GNU Lesser General Public License along with | 
|---|
| 20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 
|---|
| 21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to | 
|---|
| 22 | http://www.gnu.org/copyleft/lesser.txt. | 
|---|
| 23 |  | 
|---|
| 24 | You may alternatively use this source under the terms of a specific version of | 
|---|
| 25 | the OGRE Unrestricted License provided you have obtained such a license from | 
|---|
| 26 | Torus Knot Software Ltd. | 
|---|
| 27 | ----------------------------------------------------------------------------- | 
|---|
| 28 | */ | 
|---|
| 29 | #include "OgreStableHeaders.h" | 
|---|
| 30 | #include "OgreStaticGeometry.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 |  | 
|---|
| 45 | namespace Ogre { | 
|---|
| 46 |  | 
|---|
| 47 |         #define REGION_RANGE 1024 | 
|---|
| 48 |         #define REGION_HALF_RANGE 512 | 
|---|
| 49 |         #define REGION_MAX_INDEX 511 | 
|---|
| 50 |         #define REGION_MIN_INDEX -512 | 
|---|
| 51 |  | 
|---|
| 52 |         //-------------------------------------------------------------------------- | 
|---|
| 53 |         StaticGeometry::StaticGeometry(SceneManager* owner, const String& name): | 
|---|
| 54 |                 mOwner(owner), | 
|---|
| 55 |                 mName(name), | 
|---|
| 56 |                 mBuilt(false), | 
|---|
| 57 |                 mUpperDistance(0.0f), | 
|---|
| 58 |                 mSquaredUpperDistance(0.0f), | 
|---|
| 59 |                 mCastShadows(false), | 
|---|
| 60 |                 mRegionDimensions(Vector3(1000,1000,1000)), | 
|---|
| 61 |                 mHalfRegionDimensions(Vector3(500,500,500)), | 
|---|
| 62 |                 mOrigin(Vector3(0,0,0)), | 
|---|
| 63 |                 mVisible(true), | 
|---|
| 64 |         mRenderQueueID(RENDER_QUEUE_MAIN), | 
|---|
| 65 |         mRenderQueueIDSet(false) | 
|---|
| 66 |         { | 
|---|
| 67 |         } | 
|---|
| 68 |         //-------------------------------------------------------------------------- | 
|---|
| 69 |         StaticGeometry::~StaticGeometry() | 
|---|
| 70 |         { | 
|---|
| 71 |                 reset(); | 
|---|
| 72 |         } | 
|---|
| 73 |         //-------------------------------------------------------------------------- | 
|---|
| 74 |         StaticGeometry::Region* StaticGeometry::getRegion(const AxisAlignedBox& bounds, | 
|---|
| 75 |                 bool autoCreate) | 
|---|
| 76 |         { | 
|---|
| 77 |                 if (bounds.isNull()) | 
|---|
| 78 |                         return 0; | 
|---|
| 79 |  | 
|---|
| 80 |                 // Get the region which has the largest overlapping volume | 
|---|
| 81 |                 const Vector3 min = bounds.getMinimum(); | 
|---|
| 82 |                 const Vector3 max = bounds.getMaximum(); | 
|---|
| 83 |  | 
|---|
| 84 |                 // Get the min and max region indexes | 
|---|
| 85 |                 ushort minx, miny, minz; | 
|---|
| 86 |                 ushort maxx, maxy, maxz; | 
|---|
| 87 |                 getRegionIndexes(min, minx, miny, minz); | 
|---|
| 88 |                 getRegionIndexes(max, maxx, maxy, maxz); | 
|---|
| 89 |                 Real maxVolume = 0.0f; | 
|---|
| 90 |                 ushort finalx, finaly, finalz; | 
|---|
| 91 |                 for (ushort x = minx; x <= maxx; ++x) | 
|---|
| 92 |                 { | 
|---|
| 93 |                         for (ushort y = miny; y <= maxy; ++y) | 
|---|
| 94 |                         { | 
|---|
| 95 |                                 for (ushort z = minz; z <= maxz; ++z) | 
|---|
| 96 |                                 { | 
|---|
| 97 |                                         Real vol = getVolumeIntersection(bounds, x, y, z); | 
|---|
| 98 |                                         if (vol > maxVolume) | 
|---|
| 99 |                                         { | 
|---|
| 100 |                                                 maxVolume = vol; | 
|---|
| 101 |                                                 finalx = x; | 
|---|
| 102 |                                                 finaly = y; | 
|---|
| 103 |                                                 finalz = z; | 
|---|
| 104 |                                         } | 
|---|
| 105 |  | 
|---|
| 106 |                                 } | 
|---|
| 107 |                         } | 
|---|
| 108 |                 } | 
|---|
| 109 |  | 
|---|
| 110 |                 assert(maxVolume > 0.0f && | 
|---|
| 111 |                         "Static geometry: Problem determining closest volume match!"); | 
|---|
| 112 |  | 
|---|
| 113 |                 return getRegion(finalx, finaly, finalz, autoCreate); | 
|---|
| 114 |  | 
|---|
| 115 |         } | 
|---|
| 116 |         //-------------------------------------------------------------------------- | 
|---|
| 117 |         Real StaticGeometry::getVolumeIntersection(const AxisAlignedBox& box, | 
|---|
| 118 |                 ushort x, ushort y, ushort z) | 
|---|
| 119 |         { | 
|---|
| 120 |                 // Get bounds of indexed region | 
|---|
| 121 |                 AxisAlignedBox regionBounds = getRegionBounds(x, y, z); | 
|---|
| 122 |                 AxisAlignedBox intersectBox = regionBounds.intersection(box); | 
|---|
| 123 |                 // return a 'volume' which ignores zero dimensions | 
|---|
| 124 |                 // since we only use this for relative comparisons of the same bounds | 
|---|
| 125 |                 // this will still be internally consistent | 
|---|
| 126 |                 Vector3 boxdiff = box.getMaximum() - box.getMinimum(); | 
|---|
| 127 |                 Vector3 intersectDiff = intersectBox.getMaximum() - intersectBox.getMinimum(); | 
|---|
| 128 |  | 
|---|
| 129 |                 return (boxdiff.x == 0 ? 1 : intersectDiff.x) * | 
|---|
| 130 |                         (boxdiff.y == 0 ? 1 : intersectDiff.y) * | 
|---|
| 131 |                         (boxdiff.z == 0 ? 1 : intersectDiff.z); | 
|---|
| 132 |  | 
|---|
| 133 |         } | 
|---|
| 134 |         //-------------------------------------------------------------------------- | 
|---|
| 135 |         AxisAlignedBox StaticGeometry::getRegionBounds(ushort x, ushort y, ushort z) | 
|---|
| 136 |         { | 
|---|
| 137 |                 Vector3 min( | 
|---|
| 138 |                         ((Real)x - REGION_HALF_RANGE) * mRegionDimensions.x + mOrigin.x, | 
|---|
| 139 |                         ((Real)y - REGION_HALF_RANGE) * mRegionDimensions.y + mOrigin.y, | 
|---|
| 140 |                         ((Real)z - REGION_HALF_RANGE) * mRegionDimensions.z + mOrigin.z | 
|---|
| 141 |                         ); | 
|---|
| 142 |                 Vector3 max = min + mRegionDimensions; | 
|---|
| 143 |                 return AxisAlignedBox(min, max); | 
|---|
| 144 |         } | 
|---|
| 145 |         //-------------------------------------------------------------------------- | 
|---|
| 146 |         Vector3 StaticGeometry::getRegionCentre(ushort x, ushort y, ushort z) | 
|---|
| 147 |         { | 
|---|
| 148 |                 return Vector3( | 
|---|
| 149 |                         ((Real)x - REGION_HALF_RANGE) * mRegionDimensions.x + mOrigin.x | 
|---|
| 150 |                                 + mHalfRegionDimensions.x, | 
|---|
| 151 |                         ((Real)y - REGION_HALF_RANGE) * mRegionDimensions.y + mOrigin.y | 
|---|
| 152 |                                 + mHalfRegionDimensions.y, | 
|---|
| 153 |                         ((Real)z - REGION_HALF_RANGE) * mRegionDimensions.z + mOrigin.z | 
|---|
| 154 |                                 + mHalfRegionDimensions.z | 
|---|
| 155 |                         ); | 
|---|
| 156 |         } | 
|---|
| 157 |         //-------------------------------------------------------------------------- | 
|---|
| 158 |         StaticGeometry::Region* StaticGeometry::getRegion( | 
|---|
| 159 |                         ushort x, ushort y, ushort z, bool autoCreate) | 
|---|
| 160 |         { | 
|---|
| 161 |                 uint32 index = packIndex(x, y, z); | 
|---|
| 162 |                 Region* ret = getRegion(index); | 
|---|
| 163 |                 if (!ret && autoCreate) | 
|---|
| 164 |                 { | 
|---|
| 165 |                         // Make a name | 
|---|
| 166 |                         StringUtil::StrStreamType str; | 
|---|
| 167 |                         str << mName << ":" << index; | 
|---|
| 168 |                         // Calculate the region centre | 
|---|
| 169 |                         Vector3 centre = getRegionCentre(x, y, z); | 
|---|
| 170 |                         ret = new Region(this, str.str(), mOwner, index, centre); | 
|---|
| 171 |                         mOwner->injectMovableObject(ret); | 
|---|
| 172 |                         ret->setVisible(mVisible); | 
|---|
| 173 |                         ret->setCastShadows(mCastShadows); | 
|---|
| 174 |                         if (mRenderQueueIDSet) | 
|---|
| 175 |                         { | 
|---|
| 176 |                                 ret->setRenderQueueGroup(mRenderQueueID); | 
|---|
| 177 |                         } | 
|---|
| 178 |                         mRegionMap[index] = ret; | 
|---|
| 179 |                 } | 
|---|
| 180 |                 return ret; | 
|---|
| 181 |         } | 
|---|
| 182 |         //-------------------------------------------------------------------------- | 
|---|
| 183 |         StaticGeometry::Region* StaticGeometry::getRegion(uint32 index) | 
|---|
| 184 |         { | 
|---|
| 185 |                 RegionMap::iterator i = mRegionMap.find(index); | 
|---|
| 186 |                 if (i != mRegionMap.end()) | 
|---|
| 187 |                 { | 
|---|
| 188 |                         return i->second; | 
|---|
| 189 |                 } | 
|---|
| 190 |                 else | 
|---|
| 191 |                 { | 
|---|
| 192 |                         return 0; | 
|---|
| 193 |                 } | 
|---|
| 194 |  | 
|---|
| 195 |         } | 
|---|
| 196 |         //-------------------------------------------------------------------------- | 
|---|
| 197 |         void StaticGeometry::getRegionIndexes(const Vector3& point, | 
|---|
| 198 |                 ushort& x, ushort& y, ushort& z) | 
|---|
| 199 |         { | 
|---|
| 200 |                 // Scale the point into multiples of region and adjust for origin | 
|---|
| 201 |                 Vector3 scaledPoint = (point - mOrigin) / mRegionDimensions; | 
|---|
| 202 |  | 
|---|
| 203 |                 // Round down to 'bottom left' point which represents the cell index | 
|---|
| 204 |                 int ix = Math::IFloor(scaledPoint.x); | 
|---|
| 205 |                 int iy = Math::IFloor(scaledPoint.y); | 
|---|
| 206 |                 int iz = Math::IFloor(scaledPoint.z); | 
|---|
| 207 |  | 
|---|
| 208 |                 // Check bounds | 
|---|
| 209 |                 if (ix < REGION_MIN_INDEX || ix > REGION_MAX_INDEX | 
|---|
| 210 |                         || iy < REGION_MIN_INDEX || iy > REGION_MAX_INDEX | 
|---|
| 211 |                         || iz < REGION_MIN_INDEX || iz > REGION_MAX_INDEX) | 
|---|
| 212 |                 { | 
|---|
| 213 |                         OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, | 
|---|
| 214 |                                 "Point out of bounds", | 
|---|
| 215 |                                 "StaticGeometry::getRegionIndexes"); | 
|---|
| 216 |                 } | 
|---|
| 217 |                 // Adjust for the fact that we use unsigned values for simplicity | 
|---|
| 218 |                 // (requires less faffing about for negatives give 10-bit packing | 
|---|
| 219 |                 x = static_cast<ushort>(ix + REGION_HALF_RANGE); | 
|---|
| 220 |                 y = static_cast<ushort>(iy + REGION_HALF_RANGE); | 
|---|
| 221 |                 z = static_cast<ushort>(iz + REGION_HALF_RANGE); | 
|---|
| 222 |  | 
|---|
| 223 |  | 
|---|
| 224 |         } | 
|---|
| 225 |         //-------------------------------------------------------------------------- | 
|---|
| 226 |         uint32 StaticGeometry::packIndex(ushort x, ushort y, ushort z) | 
|---|
| 227 |         { | 
|---|
| 228 |                 return x + (y << 10) + (z << 20); | 
|---|
| 229 |         } | 
|---|
| 230 |         //-------------------------------------------------------------------------- | 
|---|
| 231 |         StaticGeometry::Region* StaticGeometry::getRegion(const Vector3& point, | 
|---|
| 232 |                 bool autoCreate) | 
|---|
| 233 |         { | 
|---|
| 234 |                 ushort x, y, z; | 
|---|
| 235 |                 getRegionIndexes(point, x, y, z); | 
|---|
| 236 |                 return getRegion(x, y, z, autoCreate); | 
|---|
| 237 |         } | 
|---|
| 238 |         //-------------------------------------------------------------------------- | 
|---|
| 239 |         AxisAlignedBox StaticGeometry::calculateBounds(VertexData* vertexData, | 
|---|
| 240 |                 const Vector3& position, const Quaternion& orientation, | 
|---|
| 241 |                 const Vector3& scale) | 
|---|
| 242 |         { | 
|---|
| 243 |                 const VertexElement* posElem = | 
|---|
| 244 |                         vertexData->vertexDeclaration->findElementBySemantic( | 
|---|
| 245 |                                 VES_POSITION); | 
|---|
| 246 |                 HardwareVertexBufferSharedPtr vbuf = | 
|---|
| 247 |                         vertexData->vertexBufferBinding->getBuffer(posElem->getSource()); | 
|---|
| 248 |                 unsigned char* vertex = | 
|---|
| 249 |                         static_cast<unsigned char*>( | 
|---|
| 250 |                                 vbuf->lock(HardwareBuffer::HBL_READ_ONLY)); | 
|---|
| 251 |                 float* pFloat; | 
|---|
| 252 |  | 
|---|
| 253 |                 Vector3 min, max; | 
|---|
| 254 |                 bool first = true; | 
|---|
| 255 |  | 
|---|
| 256 |                 for(size_t j = 0; j < vertexData->vertexCount; ++j, vertex += vbuf->getVertexSize()) | 
|---|
| 257 |                 { | 
|---|
| 258 |                         posElem->baseVertexPointerToElement(vertex, &pFloat); | 
|---|
| 259 |  | 
|---|
| 260 |                         Vector3 pt; | 
|---|
| 261 |  | 
|---|
| 262 |                         pt.x = (*pFloat++); | 
|---|
| 263 |                         pt.y = (*pFloat++); | 
|---|
| 264 |                         pt.z = (*pFloat++); | 
|---|
| 265 |                         // Transform to world (scale, rotate, translate) | 
|---|
| 266 |                         pt = (orientation * (pt * scale)) + position; | 
|---|
| 267 |                         if (first) | 
|---|
| 268 |                         { | 
|---|
| 269 |                                 min = max = pt; | 
|---|
| 270 |                                 first = false; | 
|---|
| 271 |                         } | 
|---|
| 272 |                         else | 
|---|
| 273 |                         { | 
|---|
| 274 |                                 min.makeFloor(pt); | 
|---|
| 275 |                                 max.makeCeil(pt); | 
|---|
| 276 |                         } | 
|---|
| 277 |  | 
|---|
| 278 |                 } | 
|---|
| 279 |                 vbuf->unlock(); | 
|---|
| 280 |                 return AxisAlignedBox(min, max); | 
|---|
| 281 |         } | 
|---|
| 282 |         //-------------------------------------------------------------------------- | 
|---|
| 283 |         void StaticGeometry::addEntity(Entity* ent, const Vector3& position, | 
|---|
| 284 |                 const Quaternion& orientation, const Vector3& scale) | 
|---|
| 285 |         { | 
|---|
| 286 |                 const MeshPtr& msh = ent->getMesh(); | 
|---|
| 287 |                 // Validate | 
|---|
| 288 |                 if (msh->isLodManual()) | 
|---|
| 289 |                 { | 
|---|
| 290 |                         LogManager::getSingleton().logMessage( | 
|---|
| 291 |                                 "WARNING (StaticGeometry): Manual LOD is not supported. " | 
|---|
| 292 |                                 "Using only highest LOD level for mesh " + msh->getName()); | 
|---|
| 293 |                 } | 
|---|
| 294 |  | 
|---|
| 295 |                 AxisAlignedBox sharedWorldBounds; | 
|---|
| 296 |                 // queue this entities submeshes and choice of material | 
|---|
| 297 |                 // also build the lists of geometry to be used for the source of lods | 
|---|
| 298 |                 for (uint i = 0; i < ent->getNumSubEntities(); ++i) | 
|---|
| 299 |                 { | 
|---|
| 300 |                         SubEntity* se = ent->getSubEntity(i); | 
|---|
| 301 |                         QueuedSubMesh* q = new QueuedSubMesh(); | 
|---|
| 302 |  | 
|---|
| 303 |                         // Get the geometry for this SubMesh | 
|---|
| 304 |                         q->submesh = se->getSubMesh(); | 
|---|
| 305 |                         q->geometryLodList = determineGeometry(q->submesh); | 
|---|
| 306 |                         q->materialName = se->getMaterialName(); | 
|---|
| 307 |                         q->orientation = orientation; | 
|---|
| 308 |                         q->position = position; | 
|---|
| 309 |                         q->scale = scale; | 
|---|
| 310 |                         // Determine the bounds based on the highest LOD | 
|---|
| 311 |                         q->worldBounds = calculateBounds( | 
|---|
| 312 |                                 (*q->geometryLodList)[0].vertexData, | 
|---|
| 313 |                                         position, orientation, scale); | 
|---|
| 314 |  | 
|---|
| 315 |                         mQueuedSubMeshes.push_back(q); | 
|---|
| 316 |                 } | 
|---|
| 317 |         } | 
|---|
| 318 |         //-------------------------------------------------------------------------- | 
|---|
| 319 |         StaticGeometry::SubMeshLodGeometryLinkList* | 
|---|
| 320 |         StaticGeometry::determineGeometry(SubMesh* sm) | 
|---|
| 321 |         { | 
|---|
| 322 |                 // First, determine if we've already seen this submesh before | 
|---|
| 323 |                 SubMeshGeometryLookup::iterator i = | 
|---|
| 324 |                         mSubMeshGeometryLookup.find(sm); | 
|---|
| 325 |                 if (i != mSubMeshGeometryLookup.end()) | 
|---|
| 326 |                 { | 
|---|
| 327 |                         return i->second; | 
|---|
| 328 |                 } | 
|---|
| 329 |                 // Otherwise, we have to create a new one | 
|---|
| 330 |                 SubMeshLodGeometryLinkList* lodList = new SubMeshLodGeometryLinkList(); | 
|---|
| 331 |                 mSubMeshGeometryLookup[sm] = lodList; | 
|---|
| 332 |                 ushort numLods = sm->parent->isLodManual() ? 1 : | 
|---|
| 333 |                         sm->parent->getNumLodLevels(); | 
|---|
| 334 |                 lodList->resize(numLods); | 
|---|
| 335 |                 for (ushort lod = 0; lod < numLods; ++lod) | 
|---|
| 336 |                 { | 
|---|
| 337 |                         SubMeshLodGeometryLink& geomLink = (*lodList)[lod]; | 
|---|
| 338 |                         IndexData *lodIndexData; | 
|---|
| 339 |                         if (lod == 0) | 
|---|
| 340 |                         { | 
|---|
| 341 |                                 lodIndexData = sm->indexData; | 
|---|
| 342 |                         } | 
|---|
| 343 |                         else | 
|---|
| 344 |                         { | 
|---|
| 345 |                                 lodIndexData = sm->mLodFaceList[lod - 1]; | 
|---|
| 346 |                         } | 
|---|
| 347 |                         // Can use the original mesh geometry? | 
|---|
| 348 |                         if (sm->useSharedVertices) | 
|---|
| 349 |                         { | 
|---|
| 350 |                                 if (sm->parent->getNumSubMeshes() == 1) | 
|---|
| 351 |                                 { | 
|---|
| 352 |                                         // Ok, this is actually our own anyway | 
|---|
| 353 |                                         geomLink.vertexData = sm->parent->sharedVertexData; | 
|---|
| 354 |                                         geomLink.indexData = lodIndexData; | 
|---|
| 355 |                                 } | 
|---|
| 356 |                                 else | 
|---|
| 357 |                                 { | 
|---|
| 358 |                                         // We have to split it | 
|---|
| 359 |                                         splitGeometry(sm->parent->sharedVertexData, | 
|---|
| 360 |                                                 lodIndexData, &geomLink); | 
|---|
| 361 |                                 } | 
|---|
| 362 |                         } | 
|---|
| 363 |                         else | 
|---|
| 364 |                         { | 
|---|
| 365 |                                 if (lod == 0) | 
|---|
| 366 |                                 { | 
|---|
| 367 |                                         // Ok, we can use the existing geometry; should be in full | 
|---|
| 368 |                                         // use by just this SubMesh | 
|---|
| 369 |                                         geomLink.vertexData = sm->vertexData; | 
|---|
| 370 |                                         geomLink.indexData = sm->indexData; | 
|---|
| 371 |                                 } | 
|---|
| 372 |                                 else | 
|---|
| 373 |                                 { | 
|---|
| 374 |                                         // We have to split it | 
|---|
| 375 |                                         splitGeometry(sm->vertexData, | 
|---|
| 376 |                                                 lodIndexData, &geomLink); | 
|---|
| 377 |                                 } | 
|---|
| 378 |                         } | 
|---|
| 379 |                         assert (geomLink.vertexData->vertexStart == 0 && | 
|---|
| 380 |                                 "Cannot use vertexStart > 0 on indexed geometry due to " | 
|---|
| 381 |                                 "rendersystem incompatibilities - see the docs!"); | 
|---|
| 382 |                 } | 
|---|
| 383 |  | 
|---|
| 384 |  | 
|---|
| 385 |                 return lodList; | 
|---|
| 386 |         } | 
|---|
| 387 |         //-------------------------------------------------------------------------- | 
|---|
| 388 |         void StaticGeometry::splitGeometry(VertexData* vd, IndexData* id, | 
|---|
| 389 |                         StaticGeometry::SubMeshLodGeometryLink* targetGeomLink) | 
|---|
| 390 |         { | 
|---|
| 391 |                 // Firstly we need to scan to see how many vertices are being used | 
|---|
| 392 |                 // and while we're at it, build the remap we can use later | 
|---|
| 393 |                 bool use32bitIndexes = | 
|---|
| 394 |                         id->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT; | 
|---|
| 395 |                 uint16 *p16; | 
|---|
| 396 |                 uint32 *p32; | 
|---|
| 397 |                 IndexRemap indexRemap; | 
|---|
| 398 |                 if (use32bitIndexes) | 
|---|
| 399 |                 { | 
|---|
| 400 |                         p32 = static_cast<uint32*>(id->indexBuffer->lock( | 
|---|
| 401 |                                 id->indexStart,  | 
|---|
| 402 |                                 id->indexCount * id->indexBuffer->getIndexSize(),  | 
|---|
| 403 |                                 HardwareBuffer::HBL_READ_ONLY)); | 
|---|
| 404 |                         buildIndexRemap(p32, id->indexCount, indexRemap); | 
|---|
| 405 |                         id->indexBuffer->unlock(); | 
|---|
| 406 |                 } | 
|---|
| 407 |                 else | 
|---|
| 408 |                 { | 
|---|
| 409 |                         p16 = static_cast<uint16*>(id->indexBuffer->lock( | 
|---|
| 410 |                                 id->indexStart,  | 
|---|
| 411 |                                 id->indexCount * id->indexBuffer->getIndexSize(),  | 
|---|
| 412 |                                 HardwareBuffer::HBL_READ_ONLY)); | 
|---|
| 413 |                         buildIndexRemap(p16, id->indexCount, indexRemap); | 
|---|
| 414 |                         id->indexBuffer->unlock(); | 
|---|
| 415 |                 } | 
|---|
| 416 |                 if (indexRemap.size() == vd->vertexCount) | 
|---|
| 417 |                 { | 
|---|
| 418 |                         // ha, complete usage after all | 
|---|
| 419 |                         targetGeomLink->vertexData = vd; | 
|---|
| 420 |                         targetGeomLink->indexData = id; | 
|---|
| 421 |                         return; | 
|---|
| 422 |                 } | 
|---|
| 423 |  | 
|---|
| 424 |  | 
|---|
| 425 |                 // Create the new vertex data records | 
|---|
| 426 |                 targetGeomLink->vertexData = vd->clone(false); | 
|---|
| 427 |                 // Convenience | 
|---|
| 428 |                 VertexData* newvd = targetGeomLink->vertexData; | 
|---|
| 429 |                 //IndexData* newid = targetGeomLink->indexData; | 
|---|
| 430 |                 // Update the vertex count | 
|---|
| 431 |                 newvd->vertexCount = indexRemap.size(); | 
|---|
| 432 |  | 
|---|
| 433 |                 size_t numvbufs = vd->vertexBufferBinding->getBufferCount(); | 
|---|
| 434 |                 // Copy buffers from old to new | 
|---|
| 435 |                 for (unsigned short b = 0; b < numvbufs; ++b) | 
|---|
| 436 |                 { | 
|---|
| 437 |                         // Lock old buffer | 
|---|
| 438 |                         HardwareVertexBufferSharedPtr oldBuf = | 
|---|
| 439 |                                 vd->vertexBufferBinding->getBuffer(b); | 
|---|
| 440 |                         // Create new buffer | 
|---|
| 441 |                         HardwareVertexBufferSharedPtr newBuf = | 
|---|
| 442 |                                 HardwareBufferManager::getSingleton().createVertexBuffer( | 
|---|
| 443 |                                         oldBuf->getVertexSize(), | 
|---|
| 444 |                                         indexRemap.size(), | 
|---|
| 445 |                                         HardwareBuffer::HBU_STATIC); | 
|---|
| 446 |                         // rebind | 
|---|
| 447 |                         newvd->vertexBufferBinding->setBinding(b, newBuf); | 
|---|
| 448 |  | 
|---|
| 449 |                         // Copy all the elements of the buffer across, by iterating over | 
|---|
| 450 |                         // the IndexRemap which describes how to move the old vertices | 
|---|
| 451 |                         // to the new ones. By nature of the map the remap is in order of | 
|---|
| 452 |                         // indexes in the old buffer, but note that we're not guaranteed to | 
|---|
| 453 |                         // address every vertex (which is kinda why we're here) | 
|---|
| 454 |                         uchar* pSrcBase = static_cast<uchar*>( | 
|---|
| 455 |                                 oldBuf->lock(HardwareBuffer::HBL_READ_ONLY)); | 
|---|
| 456 |                         uchar* pDstBase = static_cast<uchar*>( | 
|---|
| 457 |                                 newBuf->lock(HardwareBuffer::HBL_DISCARD)); | 
|---|
| 458 |                         size_t vertexSize = oldBuf->getVertexSize(); | 
|---|
| 459 |                         // Buffers should be the same size | 
|---|
| 460 |                         assert (vertexSize == newBuf->getVertexSize()); | 
|---|
| 461 |  | 
|---|
| 462 |                         for (IndexRemap::iterator r = indexRemap.begin(); | 
|---|
| 463 |                                 r != indexRemap.end(); ++r) | 
|---|
| 464 |                         { | 
|---|
| 465 |                                 assert (r->first < oldBuf->getNumVertices()); | 
|---|
| 466 |                                 assert (r->second < newBuf->getNumVertices()); | 
|---|
| 467 |  | 
|---|
| 468 |                                 uchar* pSrc = pSrcBase + r->first * vertexSize; | 
|---|
| 469 |                                 uchar* pDst = pDstBase + r->second * vertexSize; | 
|---|
| 470 |                                 memcpy(pDst, pSrc, vertexSize); | 
|---|
| 471 |                         } | 
|---|
| 472 |                         // unlock | 
|---|
| 473 |                         oldBuf->unlock(); | 
|---|
| 474 |                         newBuf->unlock(); | 
|---|
| 475 |  | 
|---|
| 476 |                 } | 
|---|
| 477 |  | 
|---|
| 478 |                 // Now create a new index buffer | 
|---|
| 479 |                 HardwareIndexBufferSharedPtr ibuf = | 
|---|
| 480 |                         HardwareBufferManager::getSingleton().createIndexBuffer( | 
|---|
| 481 |                                 id->indexBuffer->getType(), id->indexCount, | 
|---|
| 482 |                                 HardwareBuffer::HBU_STATIC); | 
|---|
| 483 |  | 
|---|
| 484 |                 if (use32bitIndexes) | 
|---|
| 485 |                 { | 
|---|
| 486 |                         uint32 *pSrc32, *pDst32; | 
|---|
| 487 |                         pSrc32 = static_cast<uint32*>(id->indexBuffer->lock( | 
|---|
| 488 |                                 id->indexStart,  | 
|---|
| 489 |                                 id->indexCount * id->indexBuffer->getIndexSize(),  | 
|---|
| 490 |                                 HardwareBuffer::HBL_READ_ONLY)); | 
|---|
| 491 |                         pDst32 = static_cast<uint32*>(ibuf->lock( | 
|---|
| 492 |                                 HardwareBuffer::HBL_DISCARD)); | 
|---|
| 493 |                         remapIndexes(pSrc32, pDst32, indexRemap, id->indexCount); | 
|---|
| 494 |                         id->indexBuffer->unlock(); | 
|---|
| 495 |                         ibuf->unlock(); | 
|---|
| 496 |                 } | 
|---|
| 497 |                 else | 
|---|
| 498 |                 { | 
|---|
| 499 |                         uint16 *pSrc16, *pDst16; | 
|---|
| 500 |                         pSrc16 = static_cast<uint16*>(id->indexBuffer->lock( | 
|---|
| 501 |                                 id->indexStart,  | 
|---|
| 502 |                                 id->indexCount * id->indexBuffer->getIndexSize(),  | 
|---|
| 503 |                                 HardwareBuffer::HBL_READ_ONLY)); | 
|---|
| 504 |                         pDst16 = static_cast<uint16*>(ibuf->lock( | 
|---|
| 505 |                                 HardwareBuffer::HBL_DISCARD)); | 
|---|
| 506 |                         remapIndexes(pSrc16, pDst16, indexRemap, id->indexCount); | 
|---|
| 507 |                         id->indexBuffer->unlock(); | 
|---|
| 508 |                         ibuf->unlock(); | 
|---|
| 509 |                 } | 
|---|
| 510 |  | 
|---|
| 511 |                 targetGeomLink->indexData = new IndexData(); | 
|---|
| 512 |                 targetGeomLink->indexData->indexStart = 0; | 
|---|
| 513 |                 targetGeomLink->indexData->indexCount = id->indexCount; | 
|---|
| 514 |                 targetGeomLink->indexData->indexBuffer = ibuf; | 
|---|
| 515 |  | 
|---|
| 516 |                 // Store optimised geometry for deallocation later | 
|---|
| 517 |                 OptimisedSubMeshGeometry *optGeom = new OptimisedSubMeshGeometry(); | 
|---|
| 518 |                 optGeom->indexData = targetGeomLink->indexData; | 
|---|
| 519 |                 optGeom->vertexData = targetGeomLink->vertexData; | 
|---|
| 520 |                 mOptimisedSubMeshGeometryList.push_back(optGeom); | 
|---|
| 521 |         } | 
|---|
| 522 |         //-------------------------------------------------------------------------- | 
|---|
| 523 |         void StaticGeometry::addSceneNode(const SceneNode* node) | 
|---|
| 524 |         { | 
|---|
| 525 |                 SceneNode::ConstObjectIterator obji = node->getAttachedObjectIterator(); | 
|---|
| 526 |                 while (obji.hasMoreElements()) | 
|---|
| 527 |                 { | 
|---|
| 528 |                         MovableObject* mobj = obji.getNext(); | 
|---|
| 529 |                         if (mobj->getMovableType() == "Entity") | 
|---|
| 530 |                         { | 
|---|
| 531 |                                 addEntity(static_cast<Entity*>(mobj), | 
|---|
| 532 |                                         node->_getDerivedPosition(), | 
|---|
| 533 |                                         node->_getDerivedOrientation(), | 
|---|
| 534 |                                         node->_getDerivedScale()); | 
|---|
| 535 |                         } | 
|---|
| 536 |                 } | 
|---|
| 537 |                 // Iterate through all the child-nodes | 
|---|
| 538 |                 SceneNode::ConstChildNodeIterator nodei = node->getChildIterator(); | 
|---|
| 539 |  | 
|---|
| 540 |                 while (nodei.hasMoreElements()) | 
|---|
| 541 |                 { | 
|---|
| 542 |                         const SceneNode* node = static_cast<const SceneNode*>(nodei.getNext()); | 
|---|
| 543 |                         // Add this subnode and its children... | 
|---|
| 544 |                         addSceneNode( node ); | 
|---|
| 545 |                 } | 
|---|
| 546 |         } | 
|---|
| 547 |         //-------------------------------------------------------------------------- | 
|---|
| 548 |         void StaticGeometry::build(void) | 
|---|
| 549 |         { | 
|---|
| 550 |                 // Make sure there's nothing from previous builds | 
|---|
| 551 |                 destroy(); | 
|---|
| 552 |  | 
|---|
| 553 |                 // Firstly allocate meshes to regions | 
|---|
| 554 |                 for (QueuedSubMeshList::iterator qi = mQueuedSubMeshes.begin(); | 
|---|
| 555 |                         qi != mQueuedSubMeshes.end(); ++qi) | 
|---|
| 556 |                 { | 
|---|
| 557 |                         QueuedSubMesh* qsm = *qi; | 
|---|
| 558 |                         Region* region = getRegion(qsm->worldBounds, true); | 
|---|
| 559 |                         region->assign(qsm); | 
|---|
| 560 |                 } | 
|---|
| 561 |                 bool stencilShadows = false; | 
|---|
| 562 |                 if (mCastShadows && mOwner->isShadowTechniqueStencilBased()) | 
|---|
| 563 |                 { | 
|---|
| 564 |                         stencilShadows = true; | 
|---|
| 565 |                 } | 
|---|
| 566 |  | 
|---|
| 567 |                 // Now tell each region to build itself | 
|---|
| 568 |                 for (RegionMap::iterator ri = mRegionMap.begin(); | 
|---|
| 569 |                         ri != mRegionMap.end(); ++ri) | 
|---|
| 570 |                 { | 
|---|
| 571 |                         ri->second->build(stencilShadows); | 
|---|
| 572 |                 } | 
|---|
| 573 |  | 
|---|
| 574 |         } | 
|---|
| 575 |         //-------------------------------------------------------------------------- | 
|---|
| 576 |         void StaticGeometry::destroy(void) | 
|---|
| 577 |         { | 
|---|
| 578 |                 // delete the regions | 
|---|
| 579 |                 for (RegionMap::iterator i = mRegionMap.begin(); | 
|---|
| 580 |                         i != mRegionMap.end(); ++i) | 
|---|
| 581 |                 { | 
|---|
| 582 |                         mOwner->extractMovableObject(i->second); | 
|---|
| 583 |                         delete i->second; | 
|---|
| 584 |                 } | 
|---|
| 585 |                 mRegionMap.clear(); | 
|---|
| 586 |         } | 
|---|
| 587 |         //-------------------------------------------------------------------------- | 
|---|
| 588 |         void StaticGeometry::reset(void) | 
|---|
| 589 |         { | 
|---|
| 590 |                 destroy(); | 
|---|
| 591 |                 for (QueuedSubMeshList::iterator i = mQueuedSubMeshes.begin(); | 
|---|
| 592 |                         i != mQueuedSubMeshes.end(); ++i) | 
|---|
| 593 |                 { | 
|---|
| 594 |                         delete *i; | 
|---|
| 595 |                 } | 
|---|
| 596 |                 mQueuedSubMeshes.clear(); | 
|---|
| 597 |                 // Delete precached geoemtry lists | 
|---|
| 598 |                 for (SubMeshGeometryLookup::iterator l = mSubMeshGeometryLookup.begin(); | 
|---|
| 599 |                         l != mSubMeshGeometryLookup.end(); ++l) | 
|---|
| 600 |                 { | 
|---|
| 601 |                         delete l->second; | 
|---|
| 602 |                 } | 
|---|
| 603 |                 mSubMeshGeometryLookup.clear(); | 
|---|
| 604 |                 // Delete optimised geometry | 
|---|
| 605 |                 for (OptimisedSubMeshGeometryList::iterator o = mOptimisedSubMeshGeometryList.begin(); | 
|---|
| 606 |                         o != mOptimisedSubMeshGeometryList.end(); ++o) | 
|---|
| 607 |                 { | 
|---|
| 608 |                         delete *o; | 
|---|
| 609 |                 } | 
|---|
| 610 |                 mOptimisedSubMeshGeometryList.clear(); | 
|---|
| 611 |  | 
|---|
| 612 |         } | 
|---|
| 613 |         //-------------------------------------------------------------------------- | 
|---|
| 614 |         void StaticGeometry::setVisible(bool visible) | 
|---|
| 615 |         { | 
|---|
| 616 |                 mVisible = visible; | 
|---|
| 617 |                 // tell any existing regions | 
|---|
| 618 |                 for (RegionMap::iterator ri = mRegionMap.begin(); | 
|---|
| 619 |                         ri != mRegionMap.end(); ++ri) | 
|---|
| 620 |                 { | 
|---|
| 621 |                         ri->second->setVisible(visible); | 
|---|
| 622 |                 } | 
|---|
| 623 |         } | 
|---|
| 624 |         //-------------------------------------------------------------------------- | 
|---|
| 625 |         void StaticGeometry::setCastShadows(bool castShadows) | 
|---|
| 626 |         { | 
|---|
| 627 |                 mCastShadows = castShadows; | 
|---|
| 628 |                 // tell any existing regions | 
|---|
| 629 |                 for (RegionMap::iterator ri = mRegionMap.begin(); | 
|---|
| 630 |                         ri != mRegionMap.end(); ++ri) | 
|---|
| 631 |                 { | 
|---|
| 632 |                         ri->second->setCastShadows(castShadows); | 
|---|
| 633 |                 } | 
|---|
| 634 |  | 
|---|
| 635 |         } | 
|---|
| 636 |         //-------------------------------------------------------------------------- | 
|---|
| 637 |     void StaticGeometry::setRenderQueueGroup(uint8 queueID) | 
|---|
| 638 |         { | 
|---|
| 639 |                 assert(queueID <= RENDER_QUEUE_MAX && "Render queue out of range!"); | 
|---|
| 640 |                 mRenderQueueIDSet = true; | 
|---|
| 641 |                 mRenderQueueID = queueID; | 
|---|
| 642 |                 // tell any existing regions | 
|---|
| 643 |                 for (RegionMap::iterator ri = mRegionMap.begin(); | 
|---|
| 644 |                         ri != mRegionMap.end(); ++ri) | 
|---|
| 645 |                 { | 
|---|
| 646 |                         ri->second->setRenderQueueGroup(queueID); | 
|---|
| 647 |                 } | 
|---|
| 648 |         } | 
|---|
| 649 |         //-------------------------------------------------------------------------- | 
|---|
| 650 |         uint8 StaticGeometry::getRenderQueueGroup(void) const | 
|---|
| 651 |         { | 
|---|
| 652 |                 return mRenderQueueID; | 
|---|
| 653 |         } | 
|---|
| 654 |         //-------------------------------------------------------------------------- | 
|---|
| 655 |         void StaticGeometry::dump(const String& filename) const | 
|---|
| 656 |         { | 
|---|
| 657 |                 std::ofstream of(filename.c_str()); | 
|---|
| 658 |                 of << "Static Geometry Report for " << mName << std::endl; | 
|---|
| 659 |                 of << "-------------------------------------------------" << std::endl; | 
|---|
| 660 |                 of << "Number of queued submeshes: " << mQueuedSubMeshes.size() << std::endl; | 
|---|
| 661 |                 of << "Number of regions: " << mRegionMap.size() << std::endl; | 
|---|
| 662 |                 of << "Region dimensions: " << mRegionDimensions << std::endl; | 
|---|
| 663 |                 of << "Origin: " << mOrigin << std::endl; | 
|---|
| 664 |                 of << "Max distance: " << mUpperDistance << std::endl; | 
|---|
| 665 |                 of << "Casts shadows?: " << mCastShadows << std::endl; | 
|---|
| 666 |                 of << std::endl; | 
|---|
| 667 |                 for (RegionMap::const_iterator ri = mRegionMap.begin(); | 
|---|
| 668 |                         ri != mRegionMap.end(); ++ri) | 
|---|
| 669 |                 { | 
|---|
| 670 |                         ri->second->dump(of); | 
|---|
| 671 |                 } | 
|---|
| 672 |                 of << "-------------------------------------------------" << std::endl; | 
|---|
| 673 |         } | 
|---|
| 674 |         //-------------------------------------------------------------------------- | 
|---|
| 675 |         StaticGeometry::RegionIterator StaticGeometry::getRegionIterator(void) | 
|---|
| 676 |         { | 
|---|
| 677 |                 return RegionIterator(mRegionMap.begin(), mRegionMap.end()); | 
|---|
| 678 |         } | 
|---|
| 679 |         //-------------------------------------------------------------------------- | 
|---|
| 680 |         //-------------------------------------------------------------------------- | 
|---|
| 681 |         StaticGeometry::Region::Region(StaticGeometry* parent, const String& name, | 
|---|
| 682 |                 SceneManager* mgr, uint32 regionID, const Vector3& centre) | 
|---|
| 683 |                 : MovableObject(name), mParent(parent), mSceneMgr(mgr), mNode(0), | 
|---|
| 684 |                 mRegionID(regionID), mCentre(centre), mBoundingRadius(0.0f), | 
|---|
| 685 |                 mCurrentLod(0), mEdgeList(0), mVertexProgramInUse(false) | 
|---|
| 686 |         { | 
|---|
| 687 |                 // First LOD mandatory, and always from 0 | 
|---|
| 688 |                 mLodSquaredDistances.push_back(0.0f); | 
|---|
| 689 |         } | 
|---|
| 690 |         //-------------------------------------------------------------------------- | 
|---|
| 691 |         StaticGeometry::Region::~Region() | 
|---|
| 692 |         { | 
|---|
| 693 |                 if (mNode) | 
|---|
| 694 |                 { | 
|---|
| 695 |                         mNode->getParentSceneNode()->removeChild(mNode); | 
|---|
| 696 |                         mSceneMgr->destroySceneNode(mNode->getName()); | 
|---|
| 697 |                         mNode = 0; | 
|---|
| 698 |                 } | 
|---|
| 699 |                 // delete | 
|---|
| 700 |                 for (LODBucketList::iterator i = mLodBucketList.begin(); | 
|---|
| 701 |                         i != mLodBucketList.end(); ++i) | 
|---|
| 702 |                 { | 
|---|
| 703 |                         delete *i; | 
|---|
| 704 |                 } | 
|---|
| 705 |                 mLodBucketList.clear(); | 
|---|
| 706 |  | 
|---|
| 707 |                 for (ShadowRenderableList::iterator s = mShadowRenderables.begin(); | 
|---|
| 708 |                         s != mShadowRenderables.end(); ++s) | 
|---|
| 709 |                 { | 
|---|
| 710 |                         delete *s; | 
|---|
| 711 |                 } | 
|---|
| 712 |                 mShadowRenderables.clear(); | 
|---|
| 713 |                 delete mEdgeList; | 
|---|
| 714 |  | 
|---|
| 715 |                 // no need to delete queued meshes, these are managed in StaticGeometry | 
|---|
| 716 |  | 
|---|
| 717 |         } | 
|---|
| 718 |         //-------------------------------------------------------------------------- | 
|---|
| 719 |         uint32 StaticGeometry::Region::getTypeFlags(void) const | 
|---|
| 720 |         { | 
|---|
| 721 |                 return SceneManager::STATICGEOMETRY_TYPE_MASK; | 
|---|
| 722 |         } | 
|---|
| 723 |         //-------------------------------------------------------------------------- | 
|---|
| 724 |         void StaticGeometry::Region::assign(QueuedSubMesh* qmesh) | 
|---|
| 725 |         { | 
|---|
| 726 |                 mQueuedSubMeshes.push_back(qmesh); | 
|---|
| 727 |                 // update lod distances | 
|---|
| 728 |                 ushort lodLevels = qmesh->submesh->parent->getNumLodLevels(); | 
|---|
| 729 |                 assert(qmesh->geometryLodList->size() == lodLevels); | 
|---|
| 730 |  | 
|---|
| 731 |                 while(mLodSquaredDistances.size() < lodLevels) | 
|---|
| 732 |                 { | 
|---|
| 733 |                         mLodSquaredDistances.push_back(0.0f); | 
|---|
| 734 |                 } | 
|---|
| 735 |                 // Make sure LOD levels are max of all at the requested level | 
|---|
| 736 |                 for (ushort lod = 1; lod < lodLevels; ++lod) | 
|---|
| 737 |                 { | 
|---|
| 738 |                         const MeshLodUsage& meshLod = | 
|---|
| 739 |                                 qmesh->submesh->parent->getLodLevel(lod); | 
|---|
| 740 |                         mLodSquaredDistances[lod] = std::max(mLodSquaredDistances[lod], | 
|---|
| 741 |                                 meshLod.fromDepthSquared); | 
|---|
| 742 |                 } | 
|---|
| 743 |  | 
|---|
| 744 |                 // update bounds | 
|---|
| 745 |                 // Transform world bounds relative to our centre | 
|---|
| 746 |                 AxisAlignedBox localBounds( | 
|---|
| 747 |                         qmesh->worldBounds.getMinimum() - mCentre, | 
|---|
| 748 |                         qmesh->worldBounds.getMaximum() - mCentre); | 
|---|
| 749 |                 mAABB.merge(localBounds); | 
|---|
| 750 |                 mBoundingRadius = std::max(mBoundingRadius, localBounds.getMinimum().length()); | 
|---|
| 751 |                 mBoundingRadius = std::max(mBoundingRadius, localBounds.getMaximum().length()); | 
|---|
| 752 |  | 
|---|
| 753 |         } | 
|---|
| 754 |         //-------------------------------------------------------------------------- | 
|---|
| 755 |         void StaticGeometry::Region::build(bool stencilShadows) | 
|---|
| 756 |         { | 
|---|
| 757 |                 // Create a node | 
|---|
| 758 |                 mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(mName, | 
|---|
| 759 |                         mCentre); | 
|---|
| 760 |                 mNode->attachObject(this); | 
|---|
| 761 |                 // We need to create enough LOD buckets to deal with the highest LOD | 
|---|
| 762 |                 // we encountered in all the meshes queued | 
|---|
| 763 |                 for (ushort lod = 0; lod < mLodSquaredDistances.size(); ++lod) | 
|---|
| 764 |                 { | 
|---|
| 765 |                         LODBucket* lodBucket = | 
|---|
| 766 |                                 new LODBucket(this, lod, mLodSquaredDistances[lod]); | 
|---|
| 767 |                         mLodBucketList.push_back(lodBucket); | 
|---|
| 768 |                         // Now iterate over the meshes and assign to LODs | 
|---|
| 769 |                         // LOD bucket will pick the right LOD to use | 
|---|
| 770 |                         QueuedSubMeshList::iterator qi, qiend; | 
|---|
| 771 |                         qiend = mQueuedSubMeshes.end(); | 
|---|
| 772 |                         for (qi = mQueuedSubMeshes.begin(); qi != qiend; ++qi) | 
|---|
| 773 |                         { | 
|---|
| 774 |                                 lodBucket->assign(*qi, lod); | 
|---|
| 775 |                         } | 
|---|
| 776 |                         // now build | 
|---|
| 777 |                         lodBucket->build(stencilShadows); | 
|---|
| 778 |                 } | 
|---|
| 779 |  | 
|---|
| 780 |                 // Do we need to build an edge list? | 
|---|
| 781 |                 if (stencilShadows) | 
|---|
| 782 |                 { | 
|---|
| 783 |                         EdgeListBuilder eb; | 
|---|
| 784 |                         size_t vertexSet = 0; | 
|---|
| 785 |                         LODIterator lodIterator = getLODIterator(); | 
|---|
| 786 |                         while (lodIterator.hasMoreElements()) | 
|---|
| 787 |                         { | 
|---|
| 788 |                                 LODBucket* lod = lodIterator.getNext(); | 
|---|
| 789 |                                 LODBucket::MaterialIterator matIt = lod->getMaterialIterator(); | 
|---|
| 790 |                                 while (matIt.hasMoreElements()) | 
|---|
| 791 |                                 { | 
|---|
| 792 |                                         MaterialBucket* mat = matIt.getNext(); | 
|---|
| 793 |                                         MaterialBucket::GeometryIterator geomIt = | 
|---|
| 794 |                                                 mat->getGeometryIterator(); | 
|---|
| 795 |                                         // Check if we have vertex programs here | 
|---|
| 796 |                                         Technique* t = mat->getMaterial()->getBestTechnique(); | 
|---|
| 797 |                                         if (t) | 
|---|
| 798 |                                         { | 
|---|
| 799 |                                                 Pass* p = t->getPass(0); | 
|---|
| 800 |                                                 if (p) | 
|---|
| 801 |                                                 { | 
|---|
| 802 |                                                         if (p->hasVertexProgram()) | 
|---|
| 803 |                                                         { | 
|---|
| 804 |                                                                 mVertexProgramInUse = true; | 
|---|
| 805 |                                                         } | 
|---|
| 806 |                                                 } | 
|---|
| 807 |                                         } | 
|---|
| 808 |  | 
|---|
| 809 |                                         while (geomIt.hasMoreElements()) | 
|---|
| 810 |                                         { | 
|---|
| 811 |                                                 GeometryBucket* geom = geomIt.getNext(); | 
|---|
| 812 |  | 
|---|
| 813 |                                                 // Check we're dealing with 16-bit indexes here | 
|---|
| 814 |                                                 // Since stencil shadows can only deal with 16-bit | 
|---|
| 815 |                                                 // More than that and stencil is probably too CPU-heavy | 
|---|
| 816 |                                                 // in any case | 
|---|
| 817 |                                                 assert(geom->getIndexData()->indexBuffer->getType() | 
|---|
| 818 |                                                         == HardwareIndexBuffer::IT_16BIT && | 
|---|
| 819 |                                                         "Only 16-bit indexes allowed when using stencil shadows"); | 
|---|
| 820 |                                                 eb.addVertexData(geom->getVertexData()); | 
|---|
| 821 |                                                 eb.addIndexData(geom->getIndexData(), vertexSet++); | 
|---|
| 822 |                                         } | 
|---|
| 823 |                                 } | 
|---|
| 824 |                         } | 
|---|
| 825 |                         mEdgeList = eb.build(); | 
|---|
| 826 |  | 
|---|
| 827 |                 } | 
|---|
| 828 |  | 
|---|
| 829 |  | 
|---|
| 830 |         } | 
|---|
| 831 |         //-------------------------------------------------------------------------- | 
|---|
| 832 |         const String& StaticGeometry::Region::getMovableType(void) const | 
|---|
| 833 |         { | 
|---|
| 834 |                 static String sType = "StaticGeometry"; | 
|---|
| 835 |                 return sType; | 
|---|
| 836 |         } | 
|---|
| 837 |         //-------------------------------------------------------------------------- | 
|---|
| 838 |         void StaticGeometry::Region::_notifyCurrentCamera(Camera* cam) | 
|---|
| 839 |         { | 
|---|
| 840 |                 // Calculate squared view depth | 
|---|
| 841 |                 Vector3 diff = cam->getDerivedPosition() - mCentre; | 
|---|
| 842 |                 Real squaredDepth = diff.squaredLength(); | 
|---|
| 843 |  | 
|---|
| 844 |                 // Determine whether to still render | 
|---|
| 845 |                 Real renderingDist = mParent->getRenderingDistance(); | 
|---|
| 846 |                 if (renderingDist > 0) | 
|---|
| 847 |                 { | 
|---|
| 848 |                         // Max distance to still render | 
|---|
| 849 |                         Real maxDist = renderingDist + mBoundingRadius; | 
|---|
| 850 |                         if (squaredDepth > Math::Sqr(maxDist)) | 
|---|
| 851 |                         { | 
|---|
| 852 |                                 mBeyondFarDistance = true; | 
|---|
| 853 |                                 return; | 
|---|
| 854 |                         } | 
|---|
| 855 |                 } | 
|---|
| 856 |  | 
|---|
| 857 |                 mBeyondFarDistance = false; | 
|---|
| 858 |  | 
|---|
| 859 |                 // Distance from the edge of the bounding sphere | 
|---|
| 860 |                 mCamDistanceSquared = squaredDepth - mBoundingRadius * mBoundingRadius; | 
|---|
| 861 |                 // Clamp to 0 | 
|---|
| 862 |                 mCamDistanceSquared = std::max(static_cast<Real>(0.0), mCamDistanceSquared); | 
|---|
| 863 |  | 
|---|
| 864 |                 // Determine active lod | 
|---|
| 865 |                 mCurrentLod = static_cast<ushort>(mLodSquaredDistances.size() - 1); | 
|---|
| 866 |                 for (ushort i = 0; i < mLodSquaredDistances.size(); ++i) | 
|---|
| 867 |                 { | 
|---|
| 868 |                         if (mLodSquaredDistances[i] > mCamDistanceSquared) | 
|---|
| 869 |                         { | 
|---|
| 870 |                                 mCurrentLod = i - 1; | 
|---|
| 871 |                                 break; | 
|---|
| 872 |                         } | 
|---|
| 873 |                 } | 
|---|
| 874 |  | 
|---|
| 875 |         } | 
|---|
| 876 |         //-------------------------------------------------------------------------- | 
|---|
| 877 |         const AxisAlignedBox& StaticGeometry::Region::getBoundingBox(void) const | 
|---|
| 878 |         { | 
|---|
| 879 |                 return mAABB; | 
|---|
| 880 |         } | 
|---|
| 881 |         //-------------------------------------------------------------------------- | 
|---|
| 882 |         Real StaticGeometry::Region::getBoundingRadius(void) const | 
|---|
| 883 |         { | 
|---|
| 884 |                 return mBoundingRadius; | 
|---|
| 885 |         } | 
|---|
| 886 |         //-------------------------------------------------------------------------- | 
|---|
| 887 |         void StaticGeometry::Region::_updateRenderQueue(RenderQueue* queue) | 
|---|
| 888 |         { | 
|---|
| 889 |                 mLodBucketList[mCurrentLod]->addRenderables(queue, mRenderQueueID, | 
|---|
| 890 |                         mCamDistanceSquared); | 
|---|
| 891 |         } | 
|---|
| 892 |         //-------------------------------------------------------------------------- | 
|---|
| 893 |         bool StaticGeometry::Region::isVisible(void) const | 
|---|
| 894 |         { | 
|---|
| 895 |                 return mVisible && !mBeyondFarDistance; | 
|---|
| 896 |         } | 
|---|
| 897 |         //-------------------------------------------------------------------------- | 
|---|
| 898 |         StaticGeometry::Region::LODIterator | 
|---|
| 899 |         StaticGeometry::Region::getLODIterator(void) | 
|---|
| 900 |         { | 
|---|
| 901 |                 return LODIterator(mLodBucketList.begin(), mLodBucketList.end()); | 
|---|
| 902 |         } | 
|---|
| 903 |         //-------------------------------------------------------------------------- | 
|---|
| 904 |         ShadowCaster::ShadowRenderableListIterator | 
|---|
| 905 |         StaticGeometry::Region::getShadowVolumeRenderableIterator( | 
|---|
| 906 |                 ShadowTechnique shadowTechnique, const Light* light, | 
|---|
| 907 |                 HardwareIndexBufferSharedPtr* indexBuffer, | 
|---|
| 908 |                 bool extrude, Real extrusionDistance, unsigned long flags) | 
|---|
| 909 |         { | 
|---|
| 910 |  | 
|---|
| 911 |                 assert(indexBuffer && "Only external index buffers are supported right now"); | 
|---|
| 912 |                 assert((*indexBuffer)->getType() == HardwareIndexBuffer::IT_16BIT && | 
|---|
| 913 |                         "Only 16-bit indexes supported for now"); | 
|---|
| 914 |  | 
|---|
| 915 |                 // Calculate the object space light details | 
|---|
| 916 |                 Vector4 lightPos = light->getAs4DVector(); | 
|---|
| 917 |                 Matrix4 world2Obj = mParentNode->_getFullTransform().inverseAffine(); | 
|---|
| 918 |                 lightPos = world2Obj.transformAffine(lightPos); | 
|---|
| 919 |  | 
|---|
| 920 |                 // We need to search the edge list for silhouette edges | 
|---|
| 921 |                 if (!mEdgeList) | 
|---|
| 922 |                 { | 
|---|
| 923 |                         OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, | 
|---|
| 924 |                                 "You enabled stencil shadows after the buid process!", | 
|---|
| 925 |                                 "StaticGeometry::Region::getShadowVolumeRenderableIterator"); | 
|---|
| 926 |                 } | 
|---|
| 927 |  | 
|---|
| 928 |                 // Init shadow renderable list if required | 
|---|
| 929 |                 bool init = mShadowRenderables.empty(); | 
|---|
| 930 |  | 
|---|
| 931 |                 EdgeData::EdgeGroupList::iterator egi; | 
|---|
| 932 |                 ShadowRenderableList::iterator si, siend; | 
|---|
| 933 |                 RegionShadowRenderable* esr = 0; | 
|---|
| 934 |                 if (init) | 
|---|
| 935 |                         mShadowRenderables.resize(mEdgeList->edgeGroups.size()); | 
|---|
| 936 |  | 
|---|
| 937 |                 //bool updatedSharedGeomNormals = false; | 
|---|
| 938 |                 siend = mShadowRenderables.end(); | 
|---|
| 939 |                 egi = mEdgeList->edgeGroups.begin(); | 
|---|
| 940 |                 for (si = mShadowRenderables.begin(); si != siend; ++si, ++egi) | 
|---|
| 941 |                 { | 
|---|
| 942 |                         if (init) | 
|---|
| 943 |                         { | 
|---|
| 944 |                                 // Create a new renderable, create a separate light cap if | 
|---|
| 945 |                                 // we're using a vertex program (either for this model, or | 
|---|
| 946 |                                 // for extruding the shadow volume) since otherwise we can | 
|---|
| 947 |                                 // get depth-fighting on the light cap | 
|---|
| 948 |  | 
|---|
| 949 |                                 *si = new RegionShadowRenderable(this, indexBuffer, | 
|---|
| 950 |                                         egi->vertexData, mVertexProgramInUse || !extrude); | 
|---|
| 951 |                         } | 
|---|
| 952 |                         // Get shadow renderable | 
|---|
| 953 |                         esr = static_cast<RegionShadowRenderable*>(*si); | 
|---|
| 954 |                         HardwareVertexBufferSharedPtr esrPositionBuffer = esr->getPositionBuffer(); | 
|---|
| 955 |                         // Extrude vertices in software if required | 
|---|
| 956 |                         if (extrude) | 
|---|
| 957 |                         { | 
|---|
| 958 |                                 extrudeVertices(esrPositionBuffer, | 
|---|
| 959 |                                         egi->vertexData->vertexCount, | 
|---|
| 960 |                                         lightPos, extrusionDistance); | 
|---|
| 961 |  | 
|---|
| 962 |                         } | 
|---|
| 963 |  | 
|---|
| 964 |                 } | 
|---|
| 965 |                 // Calc triangle light facing | 
|---|
| 966 |                 updateEdgeListLightFacing(mEdgeList, lightPos); | 
|---|
| 967 |  | 
|---|
| 968 |                 // Generate indexes and update renderables | 
|---|
| 969 |                 generateShadowVolume(mEdgeList, *indexBuffer, light, | 
|---|
| 970 |                         mShadowRenderables, flags); | 
|---|
| 971 |  | 
|---|
| 972 |  | 
|---|
| 973 |                 return ShadowRenderableListIterator(mShadowRenderables.begin(), mShadowRenderables.end()); | 
|---|
| 974 |  | 
|---|
| 975 |  | 
|---|
| 976 |         } | 
|---|
| 977 |         //-------------------------------------------------------------------------- | 
|---|
| 978 |         EdgeData* StaticGeometry::Region::getEdgeList(void) | 
|---|
| 979 |         { | 
|---|
| 980 |                 return mEdgeList; | 
|---|
| 981 |         } | 
|---|
| 982 |         //-------------------------------------------------------------------------- | 
|---|
| 983 |         bool StaticGeometry::Region::hasEdgeList(void) | 
|---|
| 984 |         { | 
|---|
| 985 |                 return mEdgeList != 0; | 
|---|
| 986 |         } | 
|---|
| 987 |         //-------------------------------------------------------------------------- | 
|---|
| 988 |         void StaticGeometry::Region::dump(std::ofstream& of) const | 
|---|
| 989 |         { | 
|---|
| 990 |                 of << "Region " << mRegionID << std::endl; | 
|---|
| 991 |                 of << "--------------------------" << std::endl; | 
|---|
| 992 |                 of << "Centre: " << mCentre << std::endl; | 
|---|
| 993 |                 of << "Local AABB: " << mAABB << std::endl; | 
|---|
| 994 |                 of << "Bounding radius: " << mBoundingRadius << std::endl; | 
|---|
| 995 |                 of << "Number of LODs: " << mLodBucketList.size() << std::endl; | 
|---|
| 996 |  | 
|---|
| 997 |                 for (LODBucketList::const_iterator i = mLodBucketList.begin(); | 
|---|
| 998 |                         i != mLodBucketList.end(); ++i) | 
|---|
| 999 |                 { | 
|---|
| 1000 |                         (*i)->dump(of); | 
|---|
| 1001 |                 } | 
|---|
| 1002 |                 of << "--------------------------" << std::endl; | 
|---|
| 1003 |         } | 
|---|
| 1004 |         //-------------------------------------------------------------------------- | 
|---|
| 1005 |         //-------------------------------------------------------------------------- | 
|---|
| 1006 |         StaticGeometry::Region::RegionShadowRenderable::RegionShadowRenderable( | 
|---|
| 1007 |                 Region* parent, HardwareIndexBufferSharedPtr* indexBuffer, | 
|---|
| 1008 |                 const VertexData* vertexData, bool createSeparateLightCap, | 
|---|
| 1009 |                 bool isLightCap) | 
|---|
| 1010 |                 : mParent(parent) | 
|---|
| 1011 |         { | 
|---|
| 1012 |                 // Initialise render op | 
|---|
| 1013 |                 mRenderOp.indexData = new IndexData(); | 
|---|
| 1014 |                 mRenderOp.indexData->indexBuffer = *indexBuffer; | 
|---|
| 1015 |                 mRenderOp.indexData->indexStart = 0; | 
|---|
| 1016 |                 // index start and count are sorted out later | 
|---|
| 1017 |  | 
|---|
| 1018 |                 // Create vertex data which just references position component (and 2 component) | 
|---|
| 1019 |                 mRenderOp.vertexData = new VertexData(); | 
|---|
| 1020 |                 // Map in position data | 
|---|
| 1021 |                 mRenderOp.vertexData->vertexDeclaration->addElement(0,0,VET_FLOAT3, VES_POSITION); | 
|---|
| 1022 |                 ushort origPosBind = | 
|---|
| 1023 |                         vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION)->getSource(); | 
|---|
| 1024 |                 mPositionBuffer = vertexData->vertexBufferBinding->getBuffer(origPosBind); | 
|---|
| 1025 |                 mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer); | 
|---|
| 1026 |                 // Map in w-coord buffer (if present) | 
|---|
| 1027 |                 if(!vertexData->hardwareShadowVolWBuffer.isNull()) | 
|---|
| 1028 |                 { | 
|---|
| 1029 |                         mRenderOp.vertexData->vertexDeclaration->addElement(1,0,VET_FLOAT1, VES_TEXTURE_COORDINATES, 0); | 
|---|
| 1030 |                         mWBuffer = vertexData->hardwareShadowVolWBuffer; | 
|---|
| 1031 |                         mRenderOp.vertexData->vertexBufferBinding->setBinding(1, mWBuffer); | 
|---|
| 1032 |                 } | 
|---|
| 1033 |                 // Use same vertex start as input | 
|---|
| 1034 |                 mRenderOp.vertexData->vertexStart = vertexData->vertexStart; | 
|---|
| 1035 |  | 
|---|
| 1036 |                 if (isLightCap) | 
|---|
| 1037 |                 { | 
|---|
| 1038 |                         // Use original vertex count, no extrusion | 
|---|
| 1039 |                         mRenderOp.vertexData->vertexCount = vertexData->vertexCount; | 
|---|
| 1040 |                 } | 
|---|
| 1041 |                 else | 
|---|
| 1042 |                 { | 
|---|
| 1043 |                         // Vertex count must take into account the doubling of the buffer, | 
|---|
| 1044 |                         // because second half of the buffer is the extruded copy | 
|---|
| 1045 |                         mRenderOp.vertexData->vertexCount = | 
|---|
| 1046 |                                 vertexData->vertexCount * 2; | 
|---|
| 1047 |                         if (createSeparateLightCap) | 
|---|
| 1048 |                         { | 
|---|
| 1049 |                                 // Create child light cap | 
|---|
| 1050 |                                 mLightCap = new RegionShadowRenderable(parent, | 
|---|
| 1051 |                                         indexBuffer, vertexData, false, true); | 
|---|
| 1052 |                         } | 
|---|
| 1053 |                 } | 
|---|
| 1054 |         } | 
|---|
| 1055 |         //-------------------------------------------------------------------------- | 
|---|
| 1056 |         StaticGeometry::Region::RegionShadowRenderable::~RegionShadowRenderable() | 
|---|
| 1057 |         { | 
|---|
| 1058 |                 delete mRenderOp.indexData; | 
|---|
| 1059 |                 delete mRenderOp.vertexData; | 
|---|
| 1060 |         } | 
|---|
| 1061 |         //-------------------------------------------------------------------------- | 
|---|
| 1062 |         void StaticGeometry::Region::RegionShadowRenderable::getWorldTransforms( | 
|---|
| 1063 |                 Matrix4* xform) const | 
|---|
| 1064 |         { | 
|---|
| 1065 |                 // pretransformed | 
|---|
| 1066 |                 *xform = mParent->_getParentNodeFullTransform(); | 
|---|
| 1067 |         } | 
|---|
| 1068 |         //-------------------------------------------------------------------------- | 
|---|
| 1069 |         const Quaternion& | 
|---|
| 1070 |         StaticGeometry::Region::RegionShadowRenderable::getWorldOrientation(void) const | 
|---|
| 1071 |         { | 
|---|
| 1072 |                 return mParent->getParentNode()->_getDerivedOrientation(); | 
|---|
| 1073 |         } | 
|---|
| 1074 |         //-------------------------------------------------------------------------- | 
|---|
| 1075 |         const Vector3& | 
|---|
| 1076 |         StaticGeometry::Region::RegionShadowRenderable::getWorldPosition(void) const | 
|---|
| 1077 |         { | 
|---|
| 1078 |                 return mParent->getCentre(); | 
|---|
| 1079 |         } | 
|---|
| 1080 |         //-------------------------------------------------------------------------- | 
|---|
| 1081 |         //-------------------------------------------------------------------------- | 
|---|
| 1082 |         StaticGeometry::LODBucket::LODBucket(Region* parent, unsigned short lod, | 
|---|
| 1083 |                 Real lodDist) | 
|---|
| 1084 |                 : mParent(parent), mLod(lod), mSquaredDistance(lodDist) | 
|---|
| 1085 |         { | 
|---|
| 1086 |         } | 
|---|
| 1087 |         //-------------------------------------------------------------------------- | 
|---|
| 1088 |         StaticGeometry::LODBucket::~LODBucket() | 
|---|
| 1089 |         { | 
|---|
| 1090 |                 // delete | 
|---|
| 1091 |                 for (MaterialBucketMap::iterator i = mMaterialBucketMap.begin(); | 
|---|
| 1092 |                         i != mMaterialBucketMap.end(); ++i) | 
|---|
| 1093 |                 { | 
|---|
| 1094 |                         delete i->second; | 
|---|
| 1095 |                 } | 
|---|
| 1096 |                 mMaterialBucketMap.clear(); | 
|---|
| 1097 |                 for(QueuedGeometryList::iterator qi = mQueuedGeometryList.begin(); | 
|---|
| 1098 |                         qi != mQueuedGeometryList.end(); ++qi) | 
|---|
| 1099 |                 { | 
|---|
| 1100 |                         delete *qi; | 
|---|
| 1101 |                 } | 
|---|
| 1102 |                 mQueuedGeometryList.clear(); | 
|---|
| 1103 |  | 
|---|
| 1104 |                 // no need to delete queued meshes, these are managed in StaticGeometry | 
|---|
| 1105 |         } | 
|---|
| 1106 |         //-------------------------------------------------------------------------- | 
|---|
| 1107 |         void StaticGeometry::LODBucket::assign(QueuedSubMesh* qmesh, ushort atLod) | 
|---|
| 1108 |         { | 
|---|
| 1109 |                 QueuedGeometry* q = new QueuedGeometry(); | 
|---|
| 1110 |                 mQueuedGeometryList.push_back(q); | 
|---|
| 1111 |                 q->position = qmesh->position; | 
|---|
| 1112 |                 q->orientation = qmesh->orientation; | 
|---|
| 1113 |                 q->scale = qmesh->scale; | 
|---|
| 1114 |                 if (qmesh->geometryLodList->size() > atLod) | 
|---|
| 1115 |                 { | 
|---|
| 1116 |                         // This submesh has enough lods, use the right one | 
|---|
| 1117 |                         q->geometry = &(*qmesh->geometryLodList)[atLod]; | 
|---|
| 1118 |                 } | 
|---|
| 1119 |                 else | 
|---|
| 1120 |                 { | 
|---|
| 1121 |                         // Not enough lods, use the lowest one we have | 
|---|
| 1122 |                         q->geometry = | 
|---|
| 1123 |                                 &(*qmesh->geometryLodList)[qmesh->geometryLodList->size() - 1]; | 
|---|
| 1124 |                 } | 
|---|
| 1125 |                 // Locate a material bucket | 
|---|
| 1126 |                 MaterialBucket* mbucket = 0; | 
|---|
| 1127 |                 MaterialBucketMap::iterator m = | 
|---|
| 1128 |                         mMaterialBucketMap.find(qmesh->materialName); | 
|---|
| 1129 |                 if (m != mMaterialBucketMap.end()) | 
|---|
| 1130 |                 { | 
|---|
| 1131 |                         mbucket = m->second; | 
|---|
| 1132 |                 } | 
|---|
| 1133 |                 else | 
|---|
| 1134 |                 { | 
|---|
| 1135 |                         mbucket = new MaterialBucket(this, qmesh->materialName); | 
|---|
| 1136 |                         mMaterialBucketMap[qmesh->materialName] = mbucket; | 
|---|
| 1137 |                 } | 
|---|
| 1138 |                 mbucket->assign(q); | 
|---|
| 1139 |         } | 
|---|
| 1140 |         //-------------------------------------------------------------------------- | 
|---|
| 1141 |         void StaticGeometry::LODBucket::build(bool stencilShadows) | 
|---|
| 1142 |         { | 
|---|
| 1143 |                 // Just pass this on to child buckets | 
|---|
| 1144 |                 for (MaterialBucketMap::iterator i = mMaterialBucketMap.begin(); | 
|---|
| 1145 |                         i != mMaterialBucketMap.end(); ++i) | 
|---|
| 1146 |                 { | 
|---|
| 1147 |                         i->second->build(stencilShadows); | 
|---|
| 1148 |                 } | 
|---|
| 1149 |         } | 
|---|
| 1150 |         //-------------------------------------------------------------------------- | 
|---|
| 1151 |         void StaticGeometry::LODBucket::addRenderables(RenderQueue* queue, | 
|---|
| 1152 |                 uint8 group, Real camDistanceSquared) | 
|---|
| 1153 |         { | 
|---|
| 1154 |                 // Just pass this on to child buckets | 
|---|
| 1155 |                 MaterialBucketMap::iterator i, iend; | 
|---|
| 1156 |                 iend =  mMaterialBucketMap.end(); | 
|---|
| 1157 |                 for (i = mMaterialBucketMap.begin(); i != iend; ++i) | 
|---|
| 1158 |                 { | 
|---|
| 1159 |                         i->second->addRenderables(queue, group, camDistanceSquared); | 
|---|
| 1160 |                 } | 
|---|
| 1161 |         } | 
|---|
| 1162 |         //-------------------------------------------------------------------------- | 
|---|
| 1163 |         StaticGeometry::LODBucket::MaterialIterator | 
|---|
| 1164 |         StaticGeometry::LODBucket::getMaterialIterator(void) | 
|---|
| 1165 |         { | 
|---|
| 1166 |                 return MaterialIterator( | 
|---|
| 1167 |                         mMaterialBucketMap.begin(), mMaterialBucketMap.end()); | 
|---|
| 1168 |         } | 
|---|
| 1169 |         //-------------------------------------------------------------------------- | 
|---|
| 1170 |         void StaticGeometry::LODBucket::dump(std::ofstream& of) const | 
|---|
| 1171 |         { | 
|---|
| 1172 |                 of << "LOD Bucket " << mLod << std::endl; | 
|---|
| 1173 |                 of << "------------------" << std::endl; | 
|---|
| 1174 |                 of << "Distance: " << Math::Sqrt(mSquaredDistance) << std::endl; | 
|---|
| 1175 |                 of << "Number of Materials: " << mMaterialBucketMap.size() << std::endl; | 
|---|
| 1176 |                 for (MaterialBucketMap::const_iterator i = mMaterialBucketMap.begin(); | 
|---|
| 1177 |                         i != mMaterialBucketMap.end(); ++i) | 
|---|
| 1178 |                 { | 
|---|
| 1179 |                         i->second->dump(of); | 
|---|
| 1180 |                 } | 
|---|
| 1181 |                 of << "------------------" << std::endl; | 
|---|
| 1182 |  | 
|---|
| 1183 |         } | 
|---|
| 1184 |         //-------------------------------------------------------------------------- | 
|---|
| 1185 |         //-------------------------------------------------------------------------- | 
|---|
| 1186 |         StaticGeometry::MaterialBucket::MaterialBucket(LODBucket* parent, | 
|---|
| 1187 |                 const String& materialName) | 
|---|
| 1188 |                 : mParent(parent), mMaterialName(materialName) | 
|---|
| 1189 |         { | 
|---|
| 1190 |         } | 
|---|
| 1191 |         //-------------------------------------------------------------------------- | 
|---|
| 1192 |         StaticGeometry::MaterialBucket::~MaterialBucket() | 
|---|
| 1193 |         { | 
|---|
| 1194 |                 // delete | 
|---|
| 1195 |                 for (GeometryBucketList::iterator i = mGeometryBucketList.begin(); | 
|---|
| 1196 |                         i != mGeometryBucketList.end(); ++i) | 
|---|
| 1197 |                 { | 
|---|
| 1198 |                         delete *i; | 
|---|
| 1199 |                 } | 
|---|
| 1200 |                 mGeometryBucketList.clear(); | 
|---|
| 1201 |  | 
|---|
| 1202 |                 // no need to delete queued meshes, these are managed in StaticGeometry | 
|---|
| 1203 |         } | 
|---|
| 1204 |         //-------------------------------------------------------------------------- | 
|---|
| 1205 |         void StaticGeometry::MaterialBucket::assign(QueuedGeometry* qgeom) | 
|---|
| 1206 |         { | 
|---|
| 1207 |                 // Look up any current geometry | 
|---|
| 1208 |                 String formatString = getGeometryFormatString(qgeom->geometry); | 
|---|
| 1209 |                 CurrentGeometryMap::iterator gi = mCurrentGeometryMap.find(formatString); | 
|---|
| 1210 |                 bool newBucket = true; | 
|---|
| 1211 |                 if (gi != mCurrentGeometryMap.end()) | 
|---|
| 1212 |                 { | 
|---|
| 1213 |                         // Found existing geometry, try to assign | 
|---|
| 1214 |                         newBucket = !gi->second->assign(qgeom); | 
|---|
| 1215 |                         // Note that this bucket will be replaced as the 'current' | 
|---|
| 1216 |                         // for this format string below since it's out of space | 
|---|
| 1217 |                 } | 
|---|
| 1218 |                 // Do we need to create a new one? | 
|---|
| 1219 |                 if (newBucket) | 
|---|
| 1220 |                 { | 
|---|
| 1221 |                         GeometryBucket* gbucket = new GeometryBucket(this, formatString, | 
|---|
| 1222 |                                 qgeom->geometry->vertexData, qgeom->geometry->indexData); | 
|---|
| 1223 |                         // Add to main list | 
|---|
| 1224 |                         mGeometryBucketList.push_back(gbucket); | 
|---|
| 1225 |                         // Also index in 'current' list | 
|---|
| 1226 |                         mCurrentGeometryMap[formatString] = gbucket; | 
|---|
| 1227 |                         if (!gbucket->assign(qgeom)) | 
|---|
| 1228 |                         { | 
|---|
| 1229 |                                 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, | 
|---|
| 1230 |                                         "Somehow we couldn't fit the requested geometry even in a " | 
|---|
| 1231 |                                         "brand new GeometryBucket!! Must be a bug, please report.", | 
|---|
| 1232 |                                         "StaticGeometry::MaterialBucket::assign"); | 
|---|
| 1233 |                         } | 
|---|
| 1234 |                 } | 
|---|
| 1235 |         } | 
|---|
| 1236 |         //-------------------------------------------------------------------------- | 
|---|
| 1237 |         void StaticGeometry::MaterialBucket::build(bool stencilShadows) | 
|---|
| 1238 |         { | 
|---|
| 1239 |                 mMaterial = MaterialManager::getSingleton().getByName(mMaterialName); | 
|---|
| 1240 |                 if (mMaterial.isNull()) | 
|---|
| 1241 |                 { | 
|---|
| 1242 |                         OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, | 
|---|
| 1243 |                                 "Material '" + mMaterialName + "' not found.", | 
|---|
| 1244 |                                 "StaticGeometry::MaterialBucket::build"); | 
|---|
| 1245 |                 } | 
|---|
| 1246 |                 mMaterial->load(); | 
|---|
| 1247 |                 // tell the geometry buckets to build | 
|---|
| 1248 |                 for (GeometryBucketList::iterator i = mGeometryBucketList.begin(); | 
|---|
| 1249 |                         i != mGeometryBucketList.end(); ++i) | 
|---|
| 1250 |                 { | 
|---|
| 1251 |                         (*i)->build(stencilShadows); | 
|---|
| 1252 |                 } | 
|---|
| 1253 |         } | 
|---|
| 1254 |         //-------------------------------------------------------------------------- | 
|---|
| 1255 |         void StaticGeometry::MaterialBucket::addRenderables(RenderQueue* queue, | 
|---|
| 1256 |                 uint8 group, Real camDistanceSquared) | 
|---|
| 1257 |         { | 
|---|
| 1258 |                 // Determine the current material technique | 
|---|
| 1259 |                 mTechnique = mMaterial->getBestTechnique( | 
|---|
| 1260 |                         mMaterial->getLodIndexSquaredDepth(camDistanceSquared)); | 
|---|
| 1261 |  | 
|---|
| 1262 |                 GeometryBucketList::iterator i, iend; | 
|---|
| 1263 |                 iend =  mGeometryBucketList.end(); | 
|---|
| 1264 |                 for (i = mGeometryBucketList.begin(); i != iend; ++i) | 
|---|
| 1265 |                 { | 
|---|
| 1266 |                         queue->addRenderable(*i, group); | 
|---|
| 1267 |                 } | 
|---|
| 1268 |  | 
|---|
| 1269 |         } | 
|---|
| 1270 |         //-------------------------------------------------------------------------- | 
|---|
| 1271 |         String StaticGeometry::MaterialBucket::getGeometryFormatString( | 
|---|
| 1272 |                 SubMeshLodGeometryLink* geom) | 
|---|
| 1273 |         { | 
|---|
| 1274 |                 // Formulate an identifying string for the geometry format | 
|---|
| 1275 |                 // Must take into account the vertex declaration and the index type | 
|---|
| 1276 |                 // Format is (all lines separated by '|'): | 
|---|
| 1277 |                 // Index type | 
|---|
| 1278 |                 // Vertex element (repeating) | 
|---|
| 1279 |                 //   source | 
|---|
| 1280 |                 //   semantic | 
|---|
| 1281 |                 //   type | 
|---|
| 1282 |                 StringUtil::StrStreamType str; | 
|---|
| 1283 |  | 
|---|
| 1284 |                 str << geom->indexData->indexBuffer->getType() << "|"; | 
|---|
| 1285 |                 const VertexDeclaration::VertexElementList& elemList = | 
|---|
| 1286 |                         geom->vertexData->vertexDeclaration->getElements(); | 
|---|
| 1287 |                 VertexDeclaration::VertexElementList::const_iterator ei, eiend; | 
|---|
| 1288 |                 eiend = elemList.end(); | 
|---|
| 1289 |                 for (ei = elemList.begin(); ei != eiend; ++ei) | 
|---|
| 1290 |                 { | 
|---|
| 1291 |                         const VertexElement& elem = *ei; | 
|---|
| 1292 |                         str << elem.getSource() << "|"; | 
|---|
| 1293 |                         str << elem.getSource() << "|"; | 
|---|
| 1294 |                         str << elem.getSemantic() << "|"; | 
|---|
| 1295 |                         str << elem.getType() << "|"; | 
|---|
| 1296 |                 } | 
|---|
| 1297 |  | 
|---|
| 1298 |                 return str.str(); | 
|---|
| 1299 |  | 
|---|
| 1300 |         } | 
|---|
| 1301 |         //-------------------------------------------------------------------------- | 
|---|
| 1302 |         StaticGeometry::MaterialBucket::GeometryIterator | 
|---|
| 1303 |         StaticGeometry::MaterialBucket::getGeometryIterator(void) | 
|---|
| 1304 |         { | 
|---|
| 1305 |                 return GeometryIterator( | 
|---|
| 1306 |                         mGeometryBucketList.begin(), mGeometryBucketList.end()); | 
|---|
| 1307 |         } | 
|---|
| 1308 |         //-------------------------------------------------------------------------- | 
|---|
| 1309 |         void StaticGeometry::MaterialBucket::dump(std::ofstream& of) const | 
|---|
| 1310 |         { | 
|---|
| 1311 |                 of << "Material Bucket " << mMaterialName << std::endl; | 
|---|
| 1312 |                 of << "--------------------------------------------------" << std::endl; | 
|---|
| 1313 |                 of << "Geometry buckets: " << mGeometryBucketList.size() << std::endl; | 
|---|
| 1314 |                 for (GeometryBucketList::const_iterator i = mGeometryBucketList.begin(); | 
|---|
| 1315 |                         i != mGeometryBucketList.end(); ++i) | 
|---|
| 1316 |                 { | 
|---|
| 1317 |                         (*i)->dump(of); | 
|---|
| 1318 |                 } | 
|---|
| 1319 |                 of << "--------------------------------------------------" << std::endl; | 
|---|
| 1320 |  | 
|---|
| 1321 |         } | 
|---|
| 1322 |         //-------------------------------------------------------------------------- | 
|---|
| 1323 |         //-------------------------------------------------------------------------- | 
|---|
| 1324 |         StaticGeometry::GeometryBucket::GeometryBucket(MaterialBucket* parent, | 
|---|
| 1325 |                 const String& formatString, const VertexData* vData, | 
|---|
| 1326 |                 const IndexData* iData) | 
|---|
| 1327 |                 : Renderable(), mParent(parent), mFormatString(formatString) | 
|---|
| 1328 |         { | 
|---|
| 1329 |                 // Clone the structure from the example | 
|---|
| 1330 |                 mVertexData = vData->clone(false); | 
|---|
| 1331 |                 mIndexData = iData->clone(false); | 
|---|
| 1332 |                 mVertexData->vertexCount = 0; | 
|---|
| 1333 |                 mVertexData->vertexStart = 0; | 
|---|
| 1334 |                 mIndexData->indexCount = 0; | 
|---|
| 1335 |                 mIndexData->indexStart = 0; | 
|---|
| 1336 |                 mIndexType = iData->indexBuffer->getType(); | 
|---|
| 1337 |                 // Derive the max vertices | 
|---|
| 1338 |                 if (mIndexType == HardwareIndexBuffer::IT_32BIT) | 
|---|
| 1339 |                 { | 
|---|
| 1340 |                         mMaxVertexIndex = 0xFFFFFFFF; | 
|---|
| 1341 |                 } | 
|---|
| 1342 |                 else | 
|---|
| 1343 |                 { | 
|---|
| 1344 |                         mMaxVertexIndex = 0xFFFF; | 
|---|
| 1345 |                 } | 
|---|
| 1346 |  | 
|---|
| 1347 |                 // Check to see if we have blend indices / blend weights | 
|---|
| 1348 |                 // remove them if so, they can try to blend non-existent bones! | 
|---|
| 1349 |                 const VertexElement* blendIndices = | 
|---|
| 1350 |                         mVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_INDICES); | 
|---|
| 1351 |                 const VertexElement* blendWeights = | 
|---|
| 1352 |                         mVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_WEIGHTS); | 
|---|
| 1353 |                 if (blendIndices && blendWeights) | 
|---|
| 1354 |                 { | 
|---|
| 1355 |                         assert(blendIndices->getSource() == blendWeights->getSource() | 
|---|
| 1356 |                                 && "Blend indices and weights should be in the same buffer"); | 
|---|
| 1357 |                         // Get the source | 
|---|
| 1358 |                         ushort source = blendIndices->getSource(); | 
|---|
| 1359 |                         assert(blendIndices->getSize() + blendWeights->getSize() == | 
|---|
| 1360 |                                 mVertexData->vertexBufferBinding->getBuffer(source)->getVertexSize() | 
|---|
| 1361 |                                 && "Blend indices and blend buffers should have buffer to themselves!"); | 
|---|
| 1362 |                         // Unset the buffer | 
|---|
| 1363 |                         mVertexData->vertexBufferBinding->unsetBinding(source); | 
|---|
| 1364 |                         // Remove the elements | 
|---|
| 1365 |                         mVertexData->vertexDeclaration->removeElement(VES_BLEND_INDICES); | 
|---|
| 1366 |                         mVertexData->vertexDeclaration->removeElement(VES_BLEND_WEIGHTS); | 
|---|
| 1367 |             // Close gaps in bindings for effective and safely | 
|---|
| 1368 |             mVertexData->closeGapsInBindings(); | 
|---|
| 1369 |                 } | 
|---|
| 1370 |  | 
|---|
| 1371 |  | 
|---|
| 1372 |         } | 
|---|
| 1373 |         //-------------------------------------------------------------------------- | 
|---|
| 1374 |         StaticGeometry::GeometryBucket::~GeometryBucket() | 
|---|
| 1375 |         { | 
|---|
| 1376 |                 delete mVertexData; | 
|---|
| 1377 |                 delete mIndexData; | 
|---|
| 1378 |         } | 
|---|
| 1379 |         //-------------------------------------------------------------------------- | 
|---|
| 1380 |         const MaterialPtr& StaticGeometry::GeometryBucket::getMaterial(void) const | 
|---|
| 1381 |         { | 
|---|
| 1382 |                 return mParent->getMaterial(); | 
|---|
| 1383 |         } | 
|---|
| 1384 |         //-------------------------------------------------------------------------- | 
|---|
| 1385 |         Technique* StaticGeometry::GeometryBucket::getTechnique(void) const | 
|---|
| 1386 |         { | 
|---|
| 1387 |                 return mParent->getCurrentTechnique(); | 
|---|
| 1388 |         } | 
|---|
| 1389 |         //-------------------------------------------------------------------------- | 
|---|
| 1390 |         void StaticGeometry::GeometryBucket::getRenderOperation(RenderOperation& op) | 
|---|
| 1391 |         { | 
|---|
| 1392 |                 op.indexData = mIndexData; | 
|---|
| 1393 |                 op.operationType = RenderOperation::OT_TRIANGLE_LIST; | 
|---|
| 1394 |                 op.srcRenderable = this; | 
|---|
| 1395 |                 op.useIndexes = true; | 
|---|
| 1396 |                 op.vertexData = mVertexData; | 
|---|
| 1397 |         } | 
|---|
| 1398 |         //-------------------------------------------------------------------------- | 
|---|
| 1399 |         void StaticGeometry::GeometryBucket::getWorldTransforms(Matrix4* xform) const | 
|---|
| 1400 |         { | 
|---|
| 1401 |                 // Should be the identity transform, but lets allow transformation of the | 
|---|
| 1402 |                 // nodes the regions are attached to for kicks | 
|---|
| 1403 |                 *xform = mParent->getParent()->getParent()->_getParentNodeFullTransform(); | 
|---|
| 1404 |         } | 
|---|
| 1405 |         //-------------------------------------------------------------------------- | 
|---|
| 1406 |         const Quaternion& StaticGeometry::GeometryBucket::getWorldOrientation(void) const | 
|---|
| 1407 |         { | 
|---|
| 1408 |                 return Quaternion::IDENTITY; | 
|---|
| 1409 |         } | 
|---|
| 1410 |         //-------------------------------------------------------------------------- | 
|---|
| 1411 |         const Vector3& StaticGeometry::GeometryBucket::getWorldPosition(void) const | 
|---|
| 1412 |         { | 
|---|
| 1413 |                 return mParent->getParent()->getParent()->getCentre(); | 
|---|
| 1414 |         } | 
|---|
| 1415 |         //-------------------------------------------------------------------------- | 
|---|
| 1416 |         Real StaticGeometry::GeometryBucket::getSquaredViewDepth(const Camera* cam) const | 
|---|
| 1417 |         { | 
|---|
| 1418 |                 return mParent->getParent()->getSquaredDistance(); | 
|---|
| 1419 |         } | 
|---|
| 1420 |         //-------------------------------------------------------------------------- | 
|---|
| 1421 |         const LightList& StaticGeometry::GeometryBucket::getLights(void) const | 
|---|
| 1422 |         { | 
|---|
| 1423 |                 return mParent->getParent()->getParent()->queryLights(); | 
|---|
| 1424 |         } | 
|---|
| 1425 |         //-------------------------------------------------------------------------- | 
|---|
| 1426 |         bool StaticGeometry::GeometryBucket::getCastsShadows(void) const | 
|---|
| 1427 |         { | 
|---|
| 1428 |                 return mParent->getParent()->getParent()->getCastShadows(); | 
|---|
| 1429 |         } | 
|---|
| 1430 |         //-------------------------------------------------------------------------- | 
|---|
| 1431 |         bool StaticGeometry::GeometryBucket::assign(QueuedGeometry* qgeom) | 
|---|
| 1432 |         { | 
|---|
| 1433 |                 // Do we have enough space? | 
|---|
| 1434 |                 if (mVertexData->vertexCount + qgeom->geometry->vertexData->vertexCount | 
|---|
| 1435 |                         > mMaxVertexIndex) | 
|---|
| 1436 |                 { | 
|---|
| 1437 |                         return false; | 
|---|
| 1438 |                 } | 
|---|
| 1439 |  | 
|---|
| 1440 |                 mQueuedGeometry.push_back(qgeom); | 
|---|
| 1441 |                 mVertexData->vertexCount += qgeom->geometry->vertexData->vertexCount; | 
|---|
| 1442 |                 mIndexData->indexCount += qgeom->geometry->indexData->indexCount; | 
|---|
| 1443 |  | 
|---|
| 1444 |                 return true; | 
|---|
| 1445 |         } | 
|---|
| 1446 |         //-------------------------------------------------------------------------- | 
|---|
| 1447 |         void StaticGeometry::GeometryBucket::build(bool stencilShadows) | 
|---|
| 1448 |         { | 
|---|
| 1449 |                 // Ok, here's where we transfer the vertices and indexes to the shared | 
|---|
| 1450 |                 // buffers | 
|---|
| 1451 |                 // Shortcuts | 
|---|
| 1452 |                 VertexDeclaration* dcl = mVertexData->vertexDeclaration; | 
|---|
| 1453 |                 VertexBufferBinding* binds = mVertexData->vertexBufferBinding; | 
|---|
| 1454 |  | 
|---|
| 1455 |                 // create index buffer, and lock | 
|---|
| 1456 |                 mIndexData->indexBuffer = HardwareBufferManager::getSingleton() | 
|---|
| 1457 |                         .createIndexBuffer(mIndexType, mIndexData->indexCount, | 
|---|
| 1458 |                                 HardwareBuffer::HBU_STATIC_WRITE_ONLY); | 
|---|
| 1459 |                 uint32* p32Dest = 0; | 
|---|
| 1460 |                 uint16* p16Dest = 0; | 
|---|
| 1461 |                 if (mIndexType == HardwareIndexBuffer::IT_32BIT) | 
|---|
| 1462 |                 { | 
|---|
| 1463 |                         p32Dest = static_cast<uint32*>( | 
|---|
| 1464 |                                 mIndexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD)); | 
|---|
| 1465 |                 } | 
|---|
| 1466 |                 else | 
|---|
| 1467 |                 { | 
|---|
| 1468 |                         p16Dest = static_cast<uint16*>( | 
|---|
| 1469 |                                 mIndexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD)); | 
|---|
| 1470 |                 } | 
|---|
| 1471 |                 // create all vertex buffers, and lock | 
|---|
| 1472 |                 ushort b; | 
|---|
| 1473 |                 ushort posBufferIdx = dcl->findElementBySemantic(VES_POSITION)->getSource(); | 
|---|
| 1474 |  | 
|---|
| 1475 |                 std::vector<uchar*> destBufferLocks; | 
|---|
| 1476 |                 std::vector<VertexDeclaration::VertexElementList> bufferElements; | 
|---|
| 1477 |                 for (b = 0; b < binds->getBufferCount(); ++b) | 
|---|
| 1478 |                 { | 
|---|
| 1479 |                         size_t vertexCount = mVertexData->vertexCount; | 
|---|
| 1480 |                         // Need to double the vertex count for the position buffer | 
|---|
| 1481 |                         // if we're doing stencil shadows | 
|---|
| 1482 |                         if (stencilShadows && b == posBufferIdx) | 
|---|
| 1483 |                         { | 
|---|
| 1484 |                                 vertexCount = vertexCount * 2; | 
|---|
| 1485 |                                 assert(vertexCount <= mMaxVertexIndex && | 
|---|
| 1486 |                                         "Index range exceeded when using stencil shadows, consider " | 
|---|
| 1487 |                                         "reducing your region size or reducing poly count"); | 
|---|
| 1488 |                         } | 
|---|
| 1489 |                         HardwareVertexBufferSharedPtr vbuf = | 
|---|
| 1490 |                                 HardwareBufferManager::getSingleton().createVertexBuffer( | 
|---|
| 1491 |                                         dcl->getVertexSize(b), | 
|---|
| 1492 |                                         vertexCount, | 
|---|
| 1493 |                                         HardwareBuffer::HBU_STATIC_WRITE_ONLY); | 
|---|
| 1494 |                         binds->setBinding(b, vbuf); | 
|---|
| 1495 |                         uchar* pLock = static_cast<uchar*>( | 
|---|
| 1496 |                                 vbuf->lock(HardwareBuffer::HBL_DISCARD)); | 
|---|
| 1497 |                         destBufferLocks.push_back(pLock); | 
|---|
| 1498 |                         // Pre-cache vertex elements per buffer | 
|---|
| 1499 |                         bufferElements.push_back(dcl->findElementsBySource(b)); | 
|---|
| 1500 |                 } | 
|---|
| 1501 |  | 
|---|
| 1502 |  | 
|---|
| 1503 |                 // Iterate over the geometry items | 
|---|
| 1504 |                 size_t indexOffset = 0; | 
|---|
| 1505 |                 QueuedGeometryList::iterator gi, giend; | 
|---|
| 1506 |                 giend = mQueuedGeometry.end(); | 
|---|
| 1507 |                 Vector3 regionCentre = mParent->getParent()->getParent()->getCentre(); | 
|---|
| 1508 |                 for (gi = mQueuedGeometry.begin(); gi != giend; ++gi) | 
|---|
| 1509 |                 { | 
|---|
| 1510 |                         QueuedGeometry* geom = *gi; | 
|---|
| 1511 |                         // Copy indexes across with offset | 
|---|
| 1512 |                         IndexData* srcIdxData = geom->geometry->indexData; | 
|---|
| 1513 |                         if (mIndexType == HardwareIndexBuffer::IT_32BIT) | 
|---|
| 1514 |                         { | 
|---|
| 1515 |                                 // Lock source indexes | 
|---|
| 1516 |                                 uint32* pSrc = static_cast<uint32*>( | 
|---|
| 1517 |                                         srcIdxData->indexBuffer->lock( | 
|---|
| 1518 |                                                 srcIdxData->indexStart,  | 
|---|
| 1519 |                                                 srcIdxData->indexCount * srcIdxData->indexBuffer->getIndexSize(), | 
|---|
| 1520 |                                                 HardwareBuffer::HBL_READ_ONLY)); | 
|---|
| 1521 |  | 
|---|
| 1522 |                                 copyIndexes(pSrc, p32Dest, srcIdxData->indexCount, indexOffset); | 
|---|
| 1523 |                                 p32Dest += srcIdxData->indexCount; | 
|---|
| 1524 |                                 srcIdxData->indexBuffer->unlock(); | 
|---|
| 1525 |                         } | 
|---|
| 1526 |                         else | 
|---|
| 1527 |                         { | 
|---|
| 1528 |                                 // Lock source indexes | 
|---|
| 1529 |                                 uint16* pSrc = static_cast<uint16*>( | 
|---|
| 1530 |                                         srcIdxData->indexBuffer->lock( | 
|---|
| 1531 |                                         srcIdxData->indexStart,  | 
|---|
| 1532 |                                         srcIdxData->indexCount * srcIdxData->indexBuffer->getIndexSize(), | 
|---|
| 1533 |                                         HardwareBuffer::HBL_READ_ONLY)); | 
|---|
| 1534 |  | 
|---|
| 1535 |                                 copyIndexes(pSrc, p16Dest, srcIdxData->indexCount, indexOffset); | 
|---|
| 1536 |                                 p16Dest += srcIdxData->indexCount; | 
|---|
| 1537 |                                 srcIdxData->indexBuffer->unlock(); | 
|---|
| 1538 |                         } | 
|---|
| 1539 |  | 
|---|
| 1540 |                         // Now deal with vertex buffers | 
|---|
| 1541 |                         // we can rely on buffer counts / formats being the same | 
|---|
| 1542 |                         VertexData* srcVData = geom->geometry->vertexData; | 
|---|
| 1543 |                         VertexBufferBinding* srcBinds = srcVData->vertexBufferBinding; | 
|---|
| 1544 |                         for (b = 0; b < binds->getBufferCount(); ++b) | 
|---|
| 1545 |                         { | 
|---|
| 1546 |                                 // lock source | 
|---|
| 1547 |                                 HardwareVertexBufferSharedPtr srcBuf = | 
|---|
| 1548 |                                         srcBinds->getBuffer(b); | 
|---|
| 1549 |                                 uchar* pSrcBase = static_cast<uchar*>( | 
|---|
| 1550 |                                         srcBuf->lock(HardwareBuffer::HBL_READ_ONLY)); | 
|---|
| 1551 |                                 // Get buffer lock pointer, we'll update this later | 
|---|
| 1552 |                                 uchar* pDstBase = destBufferLocks[b]; | 
|---|
| 1553 |                                 size_t bufInc = srcBuf->getVertexSize(); | 
|---|
| 1554 |  | 
|---|
| 1555 |                                 // Iterate over vertices | 
|---|
| 1556 |                                 float *pSrcReal, *pDstReal; | 
|---|
| 1557 |                                 Vector3 tmp; | 
|---|
| 1558 |                                 for (size_t v = 0; v < srcVData->vertexCount; ++v) | 
|---|
| 1559 |                                 { | 
|---|
| 1560 |                                         // Iterate over vertex elements | 
|---|
| 1561 |                                         VertexDeclaration::VertexElementList& elems = | 
|---|
| 1562 |                                                 bufferElements[b]; | 
|---|
| 1563 |                                         VertexDeclaration::VertexElementList::iterator ei; | 
|---|
| 1564 |                                         for (ei = elems.begin(); ei != elems.end(); ++ei) | 
|---|
| 1565 |                                         { | 
|---|
| 1566 |                                                 VertexElement& elem = *ei; | 
|---|
| 1567 |                                                 elem.baseVertexPointerToElement(pSrcBase, &pSrcReal); | 
|---|
| 1568 |                                                 elem.baseVertexPointerToElement(pDstBase, &pDstReal); | 
|---|
| 1569 |                                                 switch (elem.getSemantic()) | 
|---|
| 1570 |                                                 { | 
|---|
| 1571 |                                                 case VES_POSITION: | 
|---|
| 1572 |                                                         tmp.x = *pSrcReal++; | 
|---|
| 1573 |                                                         tmp.y = *pSrcReal++; | 
|---|
| 1574 |                                                         tmp.z = *pSrcReal++; | 
|---|
| 1575 |                                                         // transform | 
|---|
| 1576 |                                                         tmp = (geom->orientation * (tmp * geom->scale)) + | 
|---|
| 1577 |                                                                 geom->position; | 
|---|
| 1578 |                                                         // Adjust for region centre | 
|---|
| 1579 |                                                         tmp -= regionCentre; | 
|---|
| 1580 |                                                         *pDstReal++ = tmp.x; | 
|---|
| 1581 |                                                         *pDstReal++ = tmp.y; | 
|---|
| 1582 |                                                         *pDstReal++ = tmp.z; | 
|---|
| 1583 |                                                         break; | 
|---|
| 1584 |                                                 case VES_NORMAL: | 
|---|
| 1585 |                                                 case VES_TANGENT: | 
|---|
| 1586 |                                                 case VES_BINORMAL: | 
|---|
| 1587 |                                                         tmp.x = *pSrcReal++; | 
|---|
| 1588 |                                                         tmp.y = *pSrcReal++; | 
|---|
| 1589 |                                                         tmp.z = *pSrcReal++; | 
|---|
| 1590 |                                                         // scale (invert) | 
|---|
| 1591 |                                                         tmp = tmp / geom->scale; | 
|---|
| 1592 |                                                         tmp.normalise(); | 
|---|
| 1593 |                                                         // rotation | 
|---|
| 1594 |                                                         tmp = geom->orientation * tmp; | 
|---|
| 1595 |                                                         *pDstReal++ = tmp.x; | 
|---|
| 1596 |                                                         *pDstReal++ = tmp.y; | 
|---|
| 1597 |                                                         *pDstReal++ = tmp.z; | 
|---|
| 1598 |                                                         break; | 
|---|
| 1599 |                                                 default: | 
|---|
| 1600 |                                                         // just raw copy | 
|---|
| 1601 |                                                         memcpy(pDstReal, pSrcReal, | 
|---|
| 1602 |                                                                         VertexElement::getTypeSize(elem.getType())); | 
|---|
| 1603 |                                                         break; | 
|---|
| 1604 |                                                 }; | 
|---|
| 1605 |  | 
|---|
| 1606 |                                         } | 
|---|
| 1607 |  | 
|---|
| 1608 |                                         // Increment both pointers | 
|---|
| 1609 |                                         pDstBase += bufInc; | 
|---|
| 1610 |                                         pSrcBase += bufInc; | 
|---|
| 1611 |  | 
|---|
| 1612 |                                 } | 
|---|
| 1613 |  | 
|---|
| 1614 |                                 // Update pointer | 
|---|
| 1615 |                                 destBufferLocks[b] = pDstBase; | 
|---|
| 1616 |                                 srcBuf->unlock(); | 
|---|
| 1617 |                         } | 
|---|
| 1618 |  | 
|---|
| 1619 |                         indexOffset += geom->geometry->vertexData->vertexCount; | 
|---|
| 1620 |                 } | 
|---|
| 1621 |  | 
|---|
| 1622 |                 // Unlock everything | 
|---|
| 1623 |                 mIndexData->indexBuffer->unlock(); | 
|---|
| 1624 |                 for (b = 0; b < binds->getBufferCount(); ++b) | 
|---|
| 1625 |                 { | 
|---|
| 1626 |                         binds->getBuffer(b)->unlock(); | 
|---|
| 1627 |                 } | 
|---|
| 1628 |  | 
|---|
| 1629 |                 // If we're dealing with stencil shadows, copy the position data from | 
|---|
| 1630 |                 // the early half of the buffer to the latter part | 
|---|
| 1631 |                 if (stencilShadows) | 
|---|
| 1632 |                 { | 
|---|
| 1633 |                         HardwareVertexBufferSharedPtr buf = binds->getBuffer(posBufferIdx); | 
|---|
| 1634 |                         void* pSrc = buf->lock(HardwareBuffer::HBL_NORMAL); | 
|---|
| 1635 |                         // Point dest at second half (remember vertexcount is original count) | 
|---|
| 1636 |                         void* pDest = static_cast<uchar*>(pSrc) + | 
|---|
| 1637 |                                 buf->getVertexSize() * mVertexData->vertexCount; | 
|---|
| 1638 |                         memcpy(pDest, pSrc, buf->getVertexSize() * mVertexData->vertexCount); | 
|---|
| 1639 |                         buf->unlock(); | 
|---|
| 1640 |  | 
|---|
| 1641 |                         // Also set up hardware W buffer if appropriate | 
|---|
| 1642 |                         RenderSystem* rend = Root::getSingleton().getRenderSystem(); | 
|---|
| 1643 |                         if (rend && rend->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM)) | 
|---|
| 1644 |                         { | 
|---|
| 1645 |                                 buf = HardwareBufferManager::getSingleton().createVertexBuffer( | 
|---|
| 1646 |                                         sizeof(float), mVertexData->vertexCount * 2, | 
|---|
| 1647 |                                         HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); | 
|---|
| 1648 |                                 // Fill the first half with 1.0, second half with 0.0 | 
|---|
| 1649 |                                 float *pW = static_cast<float*>( | 
|---|
| 1650 |                                         buf->lock(HardwareBuffer::HBL_DISCARD)); | 
|---|
| 1651 |                                 size_t v; | 
|---|
| 1652 |                                 for (v = 0; v < mVertexData->vertexCount; ++v) | 
|---|
| 1653 |                                 { | 
|---|
| 1654 |                                         *pW++ = 1.0f; | 
|---|
| 1655 |                                 } | 
|---|
| 1656 |                                 for (v = 0; v < mVertexData->vertexCount; ++v) | 
|---|
| 1657 |                                 { | 
|---|
| 1658 |                                         *pW++ = 0.0f; | 
|---|
| 1659 |                                 } | 
|---|
| 1660 |                                 buf->unlock(); | 
|---|
| 1661 |                                 mVertexData->hardwareShadowVolWBuffer = buf; | 
|---|
| 1662 |                         } | 
|---|
| 1663 |                 } | 
|---|
| 1664 |  | 
|---|
| 1665 |         } | 
|---|
| 1666 |         //-------------------------------------------------------------------------- | 
|---|
| 1667 |         void StaticGeometry::GeometryBucket::dump(std::ofstream& of) const | 
|---|
| 1668 |         { | 
|---|
| 1669 |                 of << "Geometry Bucket" << std::endl; | 
|---|
| 1670 |                 of << "---------------" << std::endl; | 
|---|
| 1671 |                 of << "Format string: " << mFormatString << std::endl; | 
|---|
| 1672 |                 of << "Geometry items: " << mQueuedGeometry.size() << std::endl; | 
|---|
| 1673 |                 of << "Vertex count: " << mVertexData->vertexCount << std::endl; | 
|---|
| 1674 |                 of << "Index count: " << mIndexData->indexCount << std::endl; | 
|---|
| 1675 |                 of << "---------------" << std::endl; | 
|---|
| 1676 |  | 
|---|
| 1677 |         } | 
|---|
| 1678 |         //-------------------------------------------------------------------------- | 
|---|
| 1679 |  | 
|---|
| 1680 | } | 
|---|
| 1681 |  | 
|---|