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-2013 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 #include "OgreStableHeaders.h" 29 30 #include "OgreMeshManager.h" 31 32 #include "OgreMesh.h" 33 #include "OgreSubMesh.h" 34 #include "OgreMatrix4.h" 35 #include "OgreMatrix3.h" 36 #include "OgreVector3.h" 37 #include "OgrePlane.h" 38 #include "OgreHardwareBufferManager.h" 39 #include "OgrePatchSurface.h" 40 #include "OgreException.h" 41 42 #include "OgrePrefabFactory.h" 43 44 namespace Ogre 45 { 46 //----------------------------------------------------------------------- 47 template<> MeshManager* Singleton<MeshManager>::msSingleton = 0; getSingletonPtr(void)48 MeshManager* MeshManager::getSingletonPtr(void) 49 { 50 return msSingleton; 51 } getSingleton(void)52 MeshManager& MeshManager::getSingleton(void) 53 { 54 assert( msSingleton ); return ( *msSingleton ); 55 } 56 //----------------------------------------------------------------------- MeshManager()57 MeshManager::MeshManager(): 58 mBoundsPaddingFactor(0.01), mListener(0) 59 { 60 mPrepAllMeshesForShadowVolumes = false; 61 62 mLoadOrder = 350.0f; 63 mResourceType = "Mesh"; 64 65 ResourceGroupManager::getSingleton()._registerResourceManager(mResourceType, this); 66 67 } 68 //----------------------------------------------------------------------- ~MeshManager()69 MeshManager::~MeshManager() 70 { 71 ResourceGroupManager::getSingleton()._unregisterResourceManager(mResourceType); 72 } 73 //----------------------------------------------------------------------- getByName(const String & name,const String & groupName)74 MeshPtr MeshManager::getByName(const String& name, const String& groupName) 75 { 76 return getResourceByName(name, groupName).staticCast<Mesh>(); 77 } 78 //----------------------------------------------------------------------- _initialise(void)79 void MeshManager::_initialise(void) 80 { 81 // Create prefab objects 82 createPrefabPlane(); 83 createPrefabCube(); 84 createPrefabSphere(); 85 } 86 //----------------------------------------------------------------------- createOrRetrieve(const String & name,const String & group,bool isManual,ManualResourceLoader * loader,const NameValuePairList * params,HardwareBuffer::Usage vertexBufferUsage,HardwareBuffer::Usage indexBufferUsage,bool vertexBufferShadowed,bool indexBufferShadowed)87 MeshManager::ResourceCreateOrRetrieveResult MeshManager::createOrRetrieve( 88 const String& name, const String& group, 89 bool isManual, ManualResourceLoader* loader, 90 const NameValuePairList* params, 91 HardwareBuffer::Usage vertexBufferUsage, 92 HardwareBuffer::Usage indexBufferUsage, 93 bool vertexBufferShadowed, bool indexBufferShadowed) 94 { 95 ResourceCreateOrRetrieveResult res = 96 ResourceManager::createOrRetrieve(name,group,isManual,loader,params); 97 MeshPtr pMesh = res.first.staticCast<Mesh>(); 98 // Was it created? 99 if (res.second) 100 { 101 pMesh->setVertexBufferPolicy(vertexBufferUsage, vertexBufferShadowed); 102 pMesh->setIndexBufferPolicy(indexBufferUsage, indexBufferShadowed); 103 } 104 return res; 105 106 } 107 //----------------------------------------------------------------------- prepare(const String & filename,const String & groupName,HardwareBuffer::Usage vertexBufferUsage,HardwareBuffer::Usage indexBufferUsage,bool vertexBufferShadowed,bool indexBufferShadowed)108 MeshPtr MeshManager::prepare( const String& filename, const String& groupName, 109 HardwareBuffer::Usage vertexBufferUsage, 110 HardwareBuffer::Usage indexBufferUsage, 111 bool vertexBufferShadowed, bool indexBufferShadowed) 112 { 113 MeshPtr pMesh = createOrRetrieve(filename,groupName,false,0,0, 114 vertexBufferUsage,indexBufferUsage, 115 vertexBufferShadowed,indexBufferShadowed).first.staticCast<Mesh>(); 116 pMesh->prepare(); 117 return pMesh; 118 } 119 //----------------------------------------------------------------------- load(const String & filename,const String & groupName,HardwareBuffer::Usage vertexBufferUsage,HardwareBuffer::Usage indexBufferUsage,bool vertexBufferShadowed,bool indexBufferShadowed)120 MeshPtr MeshManager::load( const String& filename, const String& groupName, 121 HardwareBuffer::Usage vertexBufferUsage, 122 HardwareBuffer::Usage indexBufferUsage, 123 bool vertexBufferShadowed, bool indexBufferShadowed) 124 { 125 MeshPtr pMesh = createOrRetrieve(filename,groupName,false,0,0, 126 vertexBufferUsage,indexBufferUsage, 127 vertexBufferShadowed,indexBufferShadowed).first.staticCast<Mesh>(); 128 pMesh->load(); 129 return pMesh; 130 } 131 //----------------------------------------------------------------------- create(const String & name,const String & group,bool isManual,ManualResourceLoader * loader,const NameValuePairList * createParams)132 MeshPtr MeshManager::create (const String& name, const String& group, 133 bool isManual, ManualResourceLoader* loader, 134 const NameValuePairList* createParams) 135 { 136 return createResource(name,group,isManual,loader,createParams).staticCast<Mesh>(); 137 } 138 //----------------------------------------------------------------------- createManual(const String & name,const String & groupName,ManualResourceLoader * loader)139 MeshPtr MeshManager::createManual( const String& name, const String& groupName, 140 ManualResourceLoader* loader) 141 { 142 // Don't try to get existing, create should fail if already exists 143 return create(name, groupName, true, loader); 144 } 145 //----------------------------------------------------------------------- createPlane(const String & name,const String & groupName,const Plane & plane,Real width,Real height,int xsegments,int ysegments,bool normals,unsigned short numTexCoordSets,Real xTile,Real yTile,const Vector3 & upVector,HardwareBuffer::Usage vertexBufferUsage,HardwareBuffer::Usage indexBufferUsage,bool vertexShadowBuffer,bool indexShadowBuffer)146 MeshPtr MeshManager::createPlane( const String& name, const String& groupName, 147 const Plane& plane, Real width, Real height, int xsegments, int ysegments, 148 bool normals, unsigned short numTexCoordSets, Real xTile, Real yTile, const Vector3& upVector, 149 HardwareBuffer::Usage vertexBufferUsage, HardwareBuffer::Usage indexBufferUsage, 150 bool vertexShadowBuffer, bool indexShadowBuffer) 151 { 152 // Create manual mesh which calls back self to load 153 MeshPtr pMesh = createManual(name, groupName, this); 154 // Planes can never be manifold 155 pMesh->setAutoBuildEdgeLists(false); 156 // store parameters 157 MeshBuildParams params; 158 params.type = MBT_PLANE; 159 params.plane = plane; 160 params.width = width; 161 params.height = height; 162 params.xsegments = xsegments; 163 params.ysegments = ysegments; 164 params.normals = normals; 165 params.numTexCoordSets = numTexCoordSets; 166 params.xTile = xTile; 167 params.yTile = yTile; 168 params.upVector = upVector; 169 params.vertexBufferUsage = vertexBufferUsage; 170 params.indexBufferUsage = indexBufferUsage; 171 params.vertexShadowBuffer = vertexShadowBuffer; 172 params.indexShadowBuffer = indexShadowBuffer; 173 mMeshBuildParams[pMesh.getPointer()] = params; 174 175 // to preserve previous behaviour, load immediately 176 pMesh->load(); 177 178 return pMesh; 179 } 180 181 //----------------------------------------------------------------------- createCurvedPlane(const String & name,const String & groupName,const Plane & plane,Real width,Real height,Real bow,int xsegments,int ysegments,bool normals,unsigned short numTexCoordSets,Real xTile,Real yTile,const Vector3 & upVector,HardwareBuffer::Usage vertexBufferUsage,HardwareBuffer::Usage indexBufferUsage,bool vertexShadowBuffer,bool indexShadowBuffer)182 MeshPtr MeshManager::createCurvedPlane( const String& name, const String& groupName, 183 const Plane& plane, Real width, Real height, Real bow, int xsegments, int ysegments, 184 bool normals, unsigned short numTexCoordSets, Real xTile, Real yTile, const Vector3& upVector, 185 HardwareBuffer::Usage vertexBufferUsage, HardwareBuffer::Usage indexBufferUsage, 186 bool vertexShadowBuffer, bool indexShadowBuffer) 187 { 188 // Create manual mesh which calls back self to load 189 MeshPtr pMesh = createManual(name, groupName, this); 190 // Planes can never be manifold 191 pMesh->setAutoBuildEdgeLists(false); 192 // store parameters 193 MeshBuildParams params; 194 params.type = MBT_CURVED_PLANE; 195 params.plane = plane; 196 params.width = width; 197 params.height = height; 198 params.curvature = bow; 199 params.xsegments = xsegments; 200 params.ysegments = ysegments; 201 params.normals = normals; 202 params.numTexCoordSets = numTexCoordSets; 203 params.xTile = xTile; 204 params.yTile = yTile; 205 params.upVector = upVector; 206 params.vertexBufferUsage = vertexBufferUsage; 207 params.indexBufferUsage = indexBufferUsage; 208 params.vertexShadowBuffer = vertexShadowBuffer; 209 params.indexShadowBuffer = indexShadowBuffer; 210 mMeshBuildParams[pMesh.getPointer()] = params; 211 212 // to preserve previous behaviour, load immediately 213 pMesh->load(); 214 215 return pMesh; 216 217 } 218 //----------------------------------------------------------------------- createCurvedIllusionPlane(const String & name,const String & groupName,const Plane & plane,Real width,Real height,Real curvature,int xsegments,int ysegments,bool normals,unsigned short numTexCoordSets,Real uTile,Real vTile,const Vector3 & upVector,const Quaternion & orientation,HardwareBuffer::Usage vertexBufferUsage,HardwareBuffer::Usage indexBufferUsage,bool vertexShadowBuffer,bool indexShadowBuffer,int ySegmentsToKeep)219 MeshPtr MeshManager::createCurvedIllusionPlane( 220 const String& name, const String& groupName, const Plane& plane, 221 Real width, Real height, Real curvature, 222 int xsegments, int ysegments, 223 bool normals, unsigned short numTexCoordSets, 224 Real uTile, Real vTile, const Vector3& upVector, 225 const Quaternion& orientation, 226 HardwareBuffer::Usage vertexBufferUsage, 227 HardwareBuffer::Usage indexBufferUsage, 228 bool vertexShadowBuffer, bool indexShadowBuffer, 229 int ySegmentsToKeep) 230 { 231 // Create manual mesh which calls back self to load 232 MeshPtr pMesh = createManual(name, groupName, this); 233 // Planes can never be manifold 234 pMesh->setAutoBuildEdgeLists(false); 235 // store parameters 236 MeshBuildParams params; 237 params.type = MBT_CURVED_ILLUSION_PLANE; 238 params.plane = plane; 239 params.width = width; 240 params.height = height; 241 params.curvature = curvature; 242 params.xsegments = xsegments; 243 params.ysegments = ysegments; 244 params.normals = normals; 245 params.numTexCoordSets = numTexCoordSets; 246 params.xTile = uTile; 247 params.yTile = vTile; 248 params.upVector = upVector; 249 params.orientation = orientation; 250 params.vertexBufferUsage = vertexBufferUsage; 251 params.indexBufferUsage = indexBufferUsage; 252 params.vertexShadowBuffer = vertexShadowBuffer; 253 params.indexShadowBuffer = indexShadowBuffer; 254 params.ySegmentsToKeep = ySegmentsToKeep; 255 mMeshBuildParams[pMesh.getPointer()] = params; 256 257 // to preserve previous behaviour, load immediately 258 pMesh->load(); 259 260 return pMesh; 261 } 262 263 //----------------------------------------------------------------------- tesselate2DMesh(SubMesh * sm,unsigned short meshWidth,unsigned short meshHeight,bool doubleSided,HardwareBuffer::Usage indexBufferUsage,bool indexShadowBuffer)264 void MeshManager::tesselate2DMesh(SubMesh* sm, unsigned short meshWidth, unsigned short meshHeight, 265 bool doubleSided, HardwareBuffer::Usage indexBufferUsage, bool indexShadowBuffer) 266 { 267 // The mesh is built, just make a list of indexes to spit out the triangles 268 unsigned short vInc, v, iterations; 269 270 if (doubleSided) 271 { 272 iterations = 2; 273 vInc = 1; 274 v = 0; // Start with front 275 } 276 else 277 { 278 iterations = 1; 279 vInc = 1; 280 v = 0; 281 } 282 283 // Allocate memory for faces 284 // Num faces, width*height*2 (2 tris per square), index count is * 3 on top 285 sm->indexData->indexCount = (meshWidth-1) * (meshHeight-1) * 2 * iterations * 3; 286 sm->indexData->indexBuffer = HardwareBufferManager::getSingleton(). 287 createIndexBuffer(HardwareIndexBuffer::IT_16BIT, 288 sm->indexData->indexCount, indexBufferUsage, indexShadowBuffer); 289 290 unsigned short v1, v2, v3; 291 //bool firstTri = true; 292 HardwareIndexBufferSharedPtr ibuf = sm->indexData->indexBuffer; 293 // Lock the whole buffer 294 unsigned short* pIndexes = static_cast<unsigned short*>( 295 ibuf->lock(HardwareBuffer::HBL_DISCARD) ); 296 297 while (iterations--) 298 { 299 // Make tris in a zigzag pattern (compatible with strips) 300 unsigned short u = 0; 301 unsigned short uInc = 1; // Start with moving +u 302 unsigned short vCount = meshHeight - 1; 303 304 while (vCount--) 305 { 306 unsigned short uCount = meshWidth - 1; 307 while (uCount--) 308 { 309 // First Tri in cell 310 // ----------------- 311 v1 = ((v + vInc) * meshWidth) + u; 312 v2 = (v * meshWidth) + u; 313 v3 = ((v + vInc) * meshWidth) + (u + uInc); 314 // Output indexes 315 *pIndexes++ = v1; 316 *pIndexes++ = v2; 317 *pIndexes++ = v3; 318 // Second Tri in cell 319 // ------------------ 320 v1 = ((v + vInc) * meshWidth) + (u + uInc); 321 v2 = (v * meshWidth) + u; 322 v3 = (v * meshWidth) + (u + uInc); 323 // Output indexes 324 *pIndexes++ = v1; 325 *pIndexes++ = v2; 326 *pIndexes++ = v3; 327 328 // Next column 329 u += uInc; 330 } 331 // Next row 332 v += vInc; 333 u = 0; 334 335 336 } 337 338 // Reverse vInc for double sided 339 v = meshHeight - 1; 340 vInc = -vInc; 341 342 } 343 // Unlock 344 ibuf->unlock(); 345 346 } 347 348 //----------------------------------------------------------------------- createPrefabPlane(void)349 void MeshManager::createPrefabPlane(void) 350 { 351 MeshPtr msh = create( 352 "Prefab_Plane", 353 ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME, 354 true, // manually loaded 355 this); 356 // Planes can never be manifold 357 msh->setAutoBuildEdgeLists(false); 358 // to preserve previous behaviour, load immediately 359 msh->load(); 360 } 361 //----------------------------------------------------------------------- createPrefabCube(void)362 void MeshManager::createPrefabCube(void) 363 { 364 MeshPtr msh = create( 365 "Prefab_Cube", 366 ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME, 367 true, // manually loaded 368 this); 369 370 // to preserve previous behaviour, load immediately 371 msh->load(); 372 } 373 //------------------------------------------------------------------------- createPrefabSphere(void)374 void MeshManager::createPrefabSphere(void) 375 { 376 MeshPtr msh = create( 377 "Prefab_Sphere", 378 ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME, 379 true, // manually loaded 380 this); 381 382 // to preserve previous behaviour, load immediately 383 msh->load(); 384 } 385 //------------------------------------------------------------------------- setListener(Ogre::MeshSerializerListener * listener)386 void MeshManager::setListener(Ogre::MeshSerializerListener *listener) 387 { 388 mListener = listener; 389 } 390 //------------------------------------------------------------------------- getListener()391 MeshSerializerListener *MeshManager::getListener() 392 { 393 return mListener; 394 } 395 //----------------------------------------------------------------------- loadResource(Resource * res)396 void MeshManager::loadResource(Resource* res) 397 { 398 Mesh* msh = static_cast<Mesh*>(res); 399 400 // attempt to create a prefab mesh 401 bool createdPrefab = PrefabFactory::createPrefab(msh); 402 403 // the mesh was not a prefab.. 404 if(!createdPrefab) 405 { 406 // Find build parameters 407 MeshBuildParamsMap::iterator ibld = mMeshBuildParams.find(res); 408 if (ibld == mMeshBuildParams.end()) 409 { 410 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 411 "Cannot find build parameters for " + res->getName(), 412 "MeshManager::loadResource"); 413 } 414 MeshBuildParams& params = ibld->second; 415 416 switch(params.type) 417 { 418 case MBT_PLANE: 419 loadManualPlane(msh, params); 420 break; 421 case MBT_CURVED_ILLUSION_PLANE: 422 loadManualCurvedIllusionPlane(msh, params); 423 break; 424 case MBT_CURVED_PLANE: 425 loadManualCurvedPlane(msh, params); 426 break; 427 default: 428 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 429 "Unknown build parameters for " + res->getName(), 430 "MeshManager::loadResource"); 431 } 432 } 433 } 434 435 //----------------------------------------------------------------------- loadManualPlane(Mesh * pMesh,MeshBuildParams & params)436 void MeshManager::loadManualPlane(Mesh* pMesh, MeshBuildParams& params) 437 { 438 if ((params.xsegments + 1) * (params.ysegments + 1) > 65536) 439 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 440 "Plane tesselation is too high, must generate max 65536 vertices", 441 __FUNCTION__); 442 SubMesh *pSub = pMesh->createSubMesh(); 443 444 // Set up vertex data 445 // Use a single shared buffer 446 pMesh->sharedVertexData = OGRE_NEW VertexData(); 447 VertexData* vertexData = pMesh->sharedVertexData; 448 // Set up Vertex Declaration 449 VertexDeclaration* vertexDecl = vertexData->vertexDeclaration; 450 size_t currOffset = 0; 451 // We always need positions 452 vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION); 453 currOffset += VertexElement::getTypeSize(VET_FLOAT3); 454 // Optional normals 455 if(params.normals) 456 { 457 vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_NORMAL); 458 currOffset += VertexElement::getTypeSize(VET_FLOAT3); 459 } 460 461 for (unsigned short i = 0; i < params.numTexCoordSets; ++i) 462 { 463 // Assumes 2D texture coords 464 vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, i); 465 currOffset += VertexElement::getTypeSize(VET_FLOAT2); 466 } 467 468 vertexData->vertexCount = (params.xsegments + 1) * (params.ysegments + 1); 469 470 // Allocate vertex buffer 471 HardwareVertexBufferSharedPtr vbuf = 472 HardwareBufferManager::getSingleton(). 473 createVertexBuffer(vertexDecl->getVertexSize(0), vertexData->vertexCount, 474 params.vertexBufferUsage, params.vertexShadowBuffer); 475 476 // Set up the binding (one source only) 477 VertexBufferBinding* binding = vertexData->vertexBufferBinding; 478 binding->setBinding(0, vbuf); 479 480 // Work out the transform required 481 // Default orientation of plane is normal along +z, distance 0 482 Matrix4 xlate, xform, rot; 483 Matrix3 rot3; 484 xlate = rot = Matrix4::IDENTITY; 485 // Determine axes 486 Vector3 zAxis, yAxis, xAxis; 487 zAxis = params.plane.normal; 488 zAxis.normalise(); 489 yAxis = params.upVector; 490 yAxis.normalise(); 491 xAxis = yAxis.crossProduct(zAxis); 492 if (xAxis.length() == 0) 493 { 494 //upVector must be wrong 495 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "The upVector you supplied is parallel to the plane normal, so is not valid.", 496 "MeshManager::createPlane"); 497 } 498 499 rot3.FromAxes(xAxis, yAxis, zAxis); 500 rot = rot3; 501 502 // Set up standard transform from origin 503 xlate.setTrans(params.plane.normal * -params.plane.d); 504 505 // concatenate 506 xform = xlate * rot; 507 508 // Generate vertex data 509 // Lock the whole buffer 510 float* pReal = static_cast<float*>( 511 vbuf->lock(HardwareBuffer::HBL_DISCARD) ); 512 Real xSpace = params.width / params.xsegments; 513 Real ySpace = params.height / params.ysegments; 514 Real halfWidth = params.width / 2; 515 Real halfHeight = params.height / 2; 516 Real xTex = (1.0f * params.xTile) / params.xsegments; 517 Real yTex = (1.0f * params.yTile) / params.ysegments; 518 Vector3 vec; 519 Vector3 min = Vector3::ZERO, max = Vector3::UNIT_SCALE; 520 Real maxSquaredLength = 0; 521 bool firstTime = true; 522 523 for (int y = 0; y < params.ysegments + 1; ++y) 524 { 525 for (int x = 0; x < params.xsegments + 1; ++x) 526 { 527 // Work out centered on origin 528 vec.x = (x * xSpace) - halfWidth; 529 vec.y = (y * ySpace) - halfHeight; 530 vec.z = 0.0f; 531 // Transform by orientation and distance 532 vec = xform.transformAffine(vec); 533 // Assign to geometry 534 *pReal++ = vec.x; 535 *pReal++ = vec.y; 536 *pReal++ = vec.z; 537 538 // Build bounds as we go 539 if (firstTime) 540 { 541 min = vec; 542 max = vec; 543 maxSquaredLength = vec.squaredLength(); 544 firstTime = false; 545 } 546 else 547 { 548 min.makeFloor(vec); 549 max.makeCeil(vec); 550 maxSquaredLength = std::max(maxSquaredLength, vec.squaredLength()); 551 } 552 553 if (params.normals) 554 { 555 // Default normal is along unit Z 556 vec = Vector3::UNIT_Z; 557 // Rotate 558 vec = rot.transformAffine(vec); 559 560 *pReal++ = vec.x; 561 *pReal++ = vec.y; 562 *pReal++ = vec.z; 563 } 564 565 for (unsigned short i = 0; i < params.numTexCoordSets; ++i) 566 { 567 *pReal++ = x * xTex; 568 *pReal++ = 1 - (y * yTex); 569 } 570 571 572 } // x 573 } // y 574 575 // Unlock 576 vbuf->unlock(); 577 // Generate face list 578 pSub->useSharedVertices = true; 579 tesselate2DMesh(pSub, params.xsegments + 1, params.ysegments + 1, false, 580 params.indexBufferUsage, params.indexShadowBuffer); 581 582 pMesh->_setBounds(AxisAlignedBox(min, max), true); 583 pMesh->_setBoundingSphereRadius(Math::Sqrt(maxSquaredLength)); 584 } 585 //----------------------------------------------------------------------- loadManualCurvedPlane(Mesh * pMesh,MeshBuildParams & params)586 void MeshManager::loadManualCurvedPlane(Mesh* pMesh, MeshBuildParams& params) 587 { 588 if ((params.xsegments + 1) * (params.ysegments + 1) > 65536) 589 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 590 "Plane tesselation is too high, must generate max 65536 vertices", 591 __FUNCTION__); 592 SubMesh *pSub = pMesh->createSubMesh(); 593 594 // Set options 595 pMesh->sharedVertexData = OGRE_NEW VertexData(); 596 pMesh->sharedVertexData->vertexStart = 0; 597 VertexBufferBinding* bind = pMesh->sharedVertexData->vertexBufferBinding; 598 VertexDeclaration* decl = pMesh->sharedVertexData->vertexDeclaration; 599 600 pMesh->sharedVertexData->vertexCount = (params.xsegments + 1) * (params.ysegments + 1); 601 602 size_t offset = 0; 603 decl->addElement(0, offset, VET_FLOAT3, VES_POSITION); 604 offset += VertexElement::getTypeSize(VET_FLOAT3); 605 if (params.normals) 606 { 607 decl->addElement(0, 0, VET_FLOAT3, VES_NORMAL); 608 offset += VertexElement::getTypeSize(VET_FLOAT3); 609 } 610 611 for (unsigned short i = 0; i < params.numTexCoordSets; ++i) 612 { 613 decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, i); 614 offset += VertexElement::getTypeSize(VET_FLOAT2); 615 } 616 617 618 // Allocate memory 619 HardwareVertexBufferSharedPtr vbuf = 620 HardwareBufferManager::getSingleton().createVertexBuffer( 621 offset, 622 pMesh->sharedVertexData->vertexCount, 623 params.vertexBufferUsage, 624 params.vertexShadowBuffer); 625 bind->setBinding(0, vbuf); 626 627 // Work out the transform required 628 // Default orientation of plane is normal along +z, distance 0 629 Matrix4 xlate, xform, rot; 630 Matrix3 rot3; 631 xlate = rot = Matrix4::IDENTITY; 632 // Determine axes 633 Vector3 zAxis, yAxis, xAxis; 634 zAxis = params.plane.normal; 635 zAxis.normalise(); 636 yAxis = params.upVector; 637 yAxis.normalise(); 638 xAxis = yAxis.crossProduct(zAxis); 639 if (xAxis.length() == 0) 640 { 641 //upVector must be wrong 642 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "The upVector you supplied is parallel to the plane normal, so is not valid.", 643 "MeshManager::createPlane"); 644 } 645 646 rot3.FromAxes(xAxis, yAxis, zAxis); 647 rot = rot3; 648 649 // Set up standard transform from origin 650 xlate.setTrans(params.plane.normal * -params.plane.d); 651 652 // concatenate 653 xform = xlate * rot; 654 655 // Generate vertex data 656 float* pFloat = static_cast<float*>( 657 vbuf->lock(HardwareBuffer::HBL_DISCARD)); 658 Real xSpace = params.width / params.xsegments; 659 Real ySpace = params.height / params.ysegments; 660 Real halfWidth = params.width / 2; 661 Real halfHeight = params.height / 2; 662 Real xTex = (1.0f * params.xTile) / params.xsegments; 663 Real yTex = (1.0f * params.yTile) / params.ysegments; 664 Vector3 vec; 665 666 Vector3 min = Vector3::ZERO, max = Vector3::UNIT_SCALE; 667 Real maxSqLen = 0; 668 bool first = true; 669 670 Real diff_x, diff_y, dist; 671 672 for (int y = 0; y < params.ysegments + 1; ++y) 673 { 674 for (int x = 0; x < params.xsegments + 1; ++x) 675 { 676 // Work out centered on origin 677 vec.x = (x * xSpace) - halfWidth; 678 vec.y = (y * ySpace) - halfHeight; 679 680 // Here's where curved plane is different from standard plane. Amazing, I know. 681 diff_x = (x - ((params.xsegments) / 2)) / static_cast<Real>((params.xsegments)); 682 diff_y = (y - ((params.ysegments) / 2)) / static_cast<Real>((params.ysegments)); 683 dist = sqrt(diff_x*diff_x + diff_y * diff_y ); 684 vec.z = (-sin((1-dist) * (Math::PI/2)) * params.curvature) + params.curvature; 685 686 // Transform by orientation and distance 687 Vector3 pos = xform.transformAffine(vec); 688 // Assign to geometry 689 *pFloat++ = pos.x; 690 *pFloat++ = pos.y; 691 *pFloat++ = pos.z; 692 693 // Record bounds 694 if (first) 695 { 696 min = max = vec; 697 maxSqLen = vec.squaredLength(); 698 first = false; 699 } 700 else 701 { 702 min.makeFloor(vec); 703 max.makeCeil(vec); 704 maxSqLen = std::max(maxSqLen, vec.squaredLength()); 705 } 706 707 if (params.normals) 708 { 709 // This part is kinda 'wrong' for curved planes... but curved planes are 710 // very valuable outside sky planes, which don't typically need normals 711 // so I'm not going to mess with it for now. 712 713 // Default normal is along unit Z 714 //vec = Vector3::UNIT_Z; 715 // Rotate 716 vec = rot.transformAffine(vec); 717 vec.normalise(); 718 719 *pFloat++ = vec.x; 720 *pFloat++ = vec.y; 721 *pFloat++ = vec.z; 722 } 723 724 for (unsigned short i = 0; i < params.numTexCoordSets; ++i) 725 { 726 *pFloat++ = x * xTex; 727 *pFloat++ = 1 - (y * yTex); 728 } 729 730 } // x 731 } // y 732 vbuf->unlock(); 733 734 // Generate face list 735 tesselate2DMesh(pSub, params.xsegments + 1, params.ysegments + 1, 736 false, params.indexBufferUsage, params.indexShadowBuffer); 737 738 pMesh->_setBounds(AxisAlignedBox(min, max), true); 739 pMesh->_setBoundingSphereRadius(Math::Sqrt(maxSqLen)); 740 741 } 742 //----------------------------------------------------------------------- loadManualCurvedIllusionPlane(Mesh * pMesh,MeshBuildParams & params)743 void MeshManager::loadManualCurvedIllusionPlane(Mesh* pMesh, MeshBuildParams& params) 744 { 745 if (params.ySegmentsToKeep == -1) params.ySegmentsToKeep = params.ysegments; 746 747 if ((params.xsegments + 1) * (params.ySegmentsToKeep + 1) > 65536) 748 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 749 "Plane tesselation is too high, must generate max 65536 vertices", 750 __FUNCTION__); 751 SubMesh *pSub = pMesh->createSubMesh(); 752 753 754 // Set up vertex data 755 // Use a single shared buffer 756 pMesh->sharedVertexData = OGRE_NEW VertexData(); 757 VertexData* vertexData = pMesh->sharedVertexData; 758 // Set up Vertex Declaration 759 VertexDeclaration* vertexDecl = vertexData->vertexDeclaration; 760 size_t currOffset = 0; 761 // We always need positions 762 vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION); 763 currOffset += VertexElement::getTypeSize(VET_FLOAT3); 764 // Optional normals 765 if(params.normals) 766 { 767 vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_NORMAL); 768 currOffset += VertexElement::getTypeSize(VET_FLOAT3); 769 } 770 771 for (unsigned short i = 0; i < params.numTexCoordSets; ++i) 772 { 773 // Assumes 2D texture coords 774 vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, i); 775 currOffset += VertexElement::getTypeSize(VET_FLOAT2); 776 } 777 778 vertexData->vertexCount = (params.xsegments + 1) * (params.ySegmentsToKeep + 1); 779 780 // Allocate vertex buffer 781 HardwareVertexBufferSharedPtr vbuf = 782 HardwareBufferManager::getSingleton(). 783 createVertexBuffer(vertexDecl->getVertexSize(0), vertexData->vertexCount, 784 params.vertexBufferUsage, params.vertexShadowBuffer); 785 786 // Set up the binding (one source only) 787 VertexBufferBinding* binding = vertexData->vertexBufferBinding; 788 binding->setBinding(0, vbuf); 789 790 // Work out the transform required 791 // Default orientation of plane is normal along +z, distance 0 792 Matrix4 xlate, xform, rot; 793 Matrix3 rot3; 794 xlate = rot = Matrix4::IDENTITY; 795 // Determine axes 796 Vector3 zAxis, yAxis, xAxis; 797 zAxis = params.plane.normal; 798 zAxis.normalise(); 799 yAxis = params.upVector; 800 yAxis.normalise(); 801 xAxis = yAxis.crossProduct(zAxis); 802 if (xAxis.length() == 0) 803 { 804 //upVector must be wrong 805 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "The upVector you supplied is parallel to the plane normal, so is not valid.", 806 "MeshManager::createPlane"); 807 } 808 809 rot3.FromAxes(xAxis, yAxis, zAxis); 810 rot = rot3; 811 812 // Set up standard transform from origin 813 xlate.setTrans(params.plane.normal * -params.plane.d); 814 815 // concatenate 816 xform = xlate * rot; 817 818 // Generate vertex data 819 // Imagine a large sphere with the camera located near the top 820 // The lower the curvature, the larger the sphere 821 // Use the angle from viewer to the points on the plane 822 // Credit to Aftershock for the general approach 823 Real camPos; // Camera position relative to sphere center 824 825 // Derive sphere radius 826 Vector3 vertPos; // position relative to camera 827 Real sphDist; // Distance from camera to sphere along box vertex vector 828 // Vector3 camToSph; // camera position to sphere 829 Real sphereRadius;// Sphere radius 830 // Actual values irrelevant, it's the relation between sphere radius and camera position that's important 831 const Real SPHERE_RAD = 100.0; 832 const Real CAM_DIST = 5.0; 833 834 sphereRadius = SPHERE_RAD - params.curvature; 835 camPos = sphereRadius - CAM_DIST; 836 837 // Lock the whole buffer 838 float* pFloat = static_cast<float*>( 839 vbuf->lock(HardwareBuffer::HBL_DISCARD) ); 840 Real xSpace = params.width / params.xsegments; 841 Real ySpace = params.height / params.ysegments; 842 Real halfWidth = params.width / 2; 843 Real halfHeight = params.height / 2; 844 Vector3 vec, norm; 845 Vector3 min = Vector3::ZERO, max = Vector3::UNIT_SCALE; 846 Real maxSquaredLength = 0; 847 bool firstTime = true; 848 849 for (int y = params.ysegments - params.ySegmentsToKeep; y < params.ysegments + 1; ++y) 850 { 851 for (int x = 0; x < params.xsegments + 1; ++x) 852 { 853 // Work out centered on origin 854 vec.x = (x * xSpace) - halfWidth; 855 vec.y = (y * ySpace) - halfHeight; 856 vec.z = 0.0f; 857 // Transform by orientation and distance 858 vec = xform.transformAffine(vec); 859 // Assign to geometry 860 *pFloat++ = vec.x; 861 *pFloat++ = vec.y; 862 *pFloat++ = vec.z; 863 864 // Build bounds as we go 865 if (firstTime) 866 { 867 min = vec; 868 max = vec; 869 maxSquaredLength = vec.squaredLength(); 870 firstTime = false; 871 } 872 else 873 { 874 min.makeFloor(vec); 875 max.makeCeil(vec); 876 maxSquaredLength = std::max(maxSquaredLength, vec.squaredLength()); 877 } 878 879 if (params.normals) 880 { 881 // Default normal is along unit Z 882 norm = Vector3::UNIT_Z; 883 // Rotate 884 norm = params.orientation * norm; 885 886 *pFloat++ = norm.x; 887 *pFloat++ = norm.y; 888 *pFloat++ = norm.z; 889 } 890 891 // Generate texture coords 892 // Normalise position 893 // modify by orientation to return +y up 894 vec = params.orientation.Inverse() * vec; 895 vec.normalise(); 896 // Find distance to sphere 897 sphDist = Math::Sqrt(camPos*camPos * (vec.y*vec.y-1.0f) + sphereRadius*sphereRadius) - camPos*vec.y; 898 899 vec.x *= sphDist; 900 vec.z *= sphDist; 901 902 // Use x and y on sphere as texture coordinates, tiled 903 Real s = vec.x * (0.01f * params.xTile); 904 Real t = 1.0f - (vec.z * (0.01f * params.yTile)); 905 for (unsigned short i = 0; i < params.numTexCoordSets; ++i) 906 { 907 *pFloat++ = s; 908 *pFloat++ = t; 909 } 910 911 912 } // x 913 } // y 914 915 // Unlock 916 vbuf->unlock(); 917 // Generate face list 918 pSub->useSharedVertices = true; 919 tesselate2DMesh(pSub, params.xsegments + 1, params.ySegmentsToKeep + 1, false, 920 params.indexBufferUsage, params.indexShadowBuffer); 921 922 pMesh->_setBounds(AxisAlignedBox(min, max), true); 923 pMesh->_setBoundingSphereRadius(Math::Sqrt(maxSquaredLength)); 924 } 925 //----------------------------------------------------------------------- createBezierPatch(const String & name,const String & groupName,void * controlPointBuffer,VertexDeclaration * declaration,size_t width,size_t height,size_t uMaxSubdivisionLevel,size_t vMaxSubdivisionLevel,PatchSurface::VisibleSide visibleSide,HardwareBuffer::Usage vbUsage,HardwareBuffer::Usage ibUsage,bool vbUseShadow,bool ibUseShadow)926 PatchMeshPtr MeshManager::createBezierPatch(const String& name, const String& groupName, 927 void* controlPointBuffer, VertexDeclaration *declaration, 928 size_t width, size_t height, 929 size_t uMaxSubdivisionLevel, size_t vMaxSubdivisionLevel, 930 PatchSurface::VisibleSide visibleSide, 931 HardwareBuffer::Usage vbUsage, HardwareBuffer::Usage ibUsage, 932 bool vbUseShadow, bool ibUseShadow) 933 { 934 if (width < 3 || height < 3) 935 { 936 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 937 "Bezier patch require at least 3x3 control points", 938 "MeshManager::createBezierPatch"); 939 } 940 941 MeshPtr pMesh = getByName(name); 942 if (!pMesh.isNull()) 943 { 944 OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "A mesh called " + name + 945 " already exists!", "MeshManager::createBezierPatch"); 946 } 947 PatchMesh* pm = OGRE_NEW PatchMesh(this, name, getNextHandle(), groupName); 948 pm->define(controlPointBuffer, declaration, width, height, 949 uMaxSubdivisionLevel, vMaxSubdivisionLevel, visibleSide, vbUsage, ibUsage, 950 vbUseShadow, ibUseShadow); 951 pm->load(); 952 ResourcePtr res(pm); 953 addImpl(res); 954 955 return res.staticCast<PatchMesh>(); 956 } 957 //----------------------------------------------------------------------- setPrepareAllMeshesForShadowVolumes(bool enable)958 void MeshManager::setPrepareAllMeshesForShadowVolumes(bool enable) 959 { 960 mPrepAllMeshesForShadowVolumes = enable; 961 } 962 //----------------------------------------------------------------------- getPrepareAllMeshesForShadowVolumes(void)963 bool MeshManager::getPrepareAllMeshesForShadowVolumes(void) 964 { 965 return mPrepAllMeshesForShadowVolumes; 966 } 967 //----------------------------------------------------------------------- getBoundsPaddingFactor(void)968 Real MeshManager::getBoundsPaddingFactor(void) 969 { 970 return mBoundsPaddingFactor; 971 } 972 //----------------------------------------------------------------------- setBoundsPaddingFactor(Real paddingFactor)973 void MeshManager::setBoundsPaddingFactor(Real paddingFactor) 974 { 975 mBoundsPaddingFactor = paddingFactor; 976 } 977 //----------------------------------------------------------------------- createImpl(const String & name,ResourceHandle handle,const String & group,bool isManual,ManualResourceLoader * loader,const NameValuePairList * createParams)978 Resource* MeshManager::createImpl(const String& name, ResourceHandle handle, 979 const String& group, bool isManual, ManualResourceLoader* loader, 980 const NameValuePairList* createParams) 981 { 982 // no use for createParams here 983 return OGRE_NEW Mesh(this, name, handle, group, isManual, loader); 984 } 985 //----------------------------------------------------------------------- 986 987 } 988