ribbon.cpp
Engine/source/T3D/fx/ribbon.cpp
Public Functions
Detailed Description
Public Functions
IMPLEMENT_CO_DATABLOCK_V1(RibbonData )
IMPLEMENT_CO_NETOBJECT_V1(Ribbon )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2014 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "console/consoleTypes.h" 25#include "console/typeValidators.h" 26#include "core/stream/bitStream.h" 27#include "T3D/shapeBase.h" 28#include "ts/tsShapeInstance.h" 29#include "T3D/fx/ribbon.h" 30#include "math/mathUtils.h" 31#include "math/mathIO.h" 32#include "sim/netConnection.h" 33#include "gfx/primBuilder.h" 34#include "gfx/gfxDrawUtil.h" 35#include "materials/sceneData.h" 36#include "materials/matInstance.h" 37#include "gui/3d/guiTSControl.h" 38#include "materials/materialManager.h" 39#include "materials/processedShaderMaterial.h" 40#include "gfx/gfxTransformSaver.h" 41 42 43IMPLEMENT_CO_DATABLOCK_V1(RibbonData); 44IMPLEMENT_CO_NETOBJECT_V1(Ribbon); 45 46 47//-------------------------------------------------------------------------- 48// 49RibbonData::RibbonData() 50{ 51 for (U8 i = 0; i < NumFields; i++) { 52 mSizes[i] = 0.0f; 53 mColours[i].set(0.0f, 0.0f, 0.0f, 1.0f); 54 mTimes[i] = -1.0f; 55 } 56 57 mRibbonLength = 0; 58 mUseFadeOut = false; 59 mFadeAwayStep = 0.032f; 60 segmentsPerUpdate = 1; 61 mMatName = StringTable->EmptyString(); 62 mTileScale = 1.0f; 63 mFixedTexcoords = false; 64 mSegmentSkipAmount = 0; 65 mTexcoordsRelativeToDistance = false; 66} 67 68//-------------------------------------------------------------------------- 69 70void RibbonData::initPersistFields() 71{ 72 Parent::initPersistFields(); 73 74 addGroup("Ribbon"); 75 76 addField("size", TypeF32, Offset(mSizes, RibbonData), NumFields, 77 "The size of the ribbon at the specified keyframe."); 78 addField("color", TypeColorF, Offset(mColours, RibbonData), NumFields, 79 "The colour of the ribbon at the specified keyframe."); 80 addField("position", TypeF32, Offset(mTimes, RibbonData), NumFields, 81 "The position of the keyframe along the lifetime of the ribbon."); 82 83 addField("ribbonLength", TypeS32, Offset(mRibbonLength, RibbonData), 84 "The amount of segments the Ribbon can maximally have in length."); 85 addField("segmentsPerUpdate", TypeS32, Offset(segmentsPerUpdate, RibbonData), 86 "How many segments to add each update."); 87 addField("skipAmount", TypeS32, Offset(mSegmentSkipAmount, RibbonData), 88 "The amount of segments to skip each update."); 89 90 addField("useFadeOut", TypeBool, Offset(mUseFadeOut, RibbonData), 91 "If true, the ribbon will fade away after deletion."); 92 addField("fadeAwayStep", TypeF32, Offset(mFadeAwayStep, RibbonData), 93 "How much to fade the ribbon with each update, after deletion."); 94 addField("ribbonMaterial", TypeString, Offset(mMatName, RibbonData), 95 "The material the ribbon uses for rendering."); 96 addField("tileScale", TypeF32, Offset(mTileScale, RibbonData), 97 "How much to scale each 'tile' with, where 1 means the material is stretched" 98 "across the whole ribbon. (If TexcoordsRelativeToDistance is true, this is in meters.)"); 99 addField("fixedTexcoords", TypeBool, Offset(mFixedTexcoords, RibbonData), 100 "If true, this prevents 'floating' texture coordinates."); 101 addField("texcoordsRelativeToDistance", TypeBool, Offset(mTexcoordsRelativeToDistance, RibbonData), 102 "If true, texture coordinates are scaled relative to distance, this prevents" 103 "'stretched' textures."); 104 105 endGroup("Ribbon"); 106} 107 108 109//-------------------------------------------------------------------------- 110bool RibbonData::onAdd() 111{ 112 if(!Parent::onAdd()) 113 return false; 114 115 return true; 116} 117 118 119bool RibbonData::preload(bool server, String &errorBuffer) 120{ 121 if (Parent::preload(server, errorBuffer) == false) 122 return false; 123 124 return true; 125} 126 127//-------------------------------------------------------------------------- 128void RibbonData::packData(BitStream* stream) 129{ 130 Parent::packData(stream); 131 132 for (U8 i = 0; i < NumFields; i++) { 133 stream->write(mSizes[i]); 134 stream->write(mColours[i]); 135 stream->write(mTimes[i]); 136 } 137 138 stream->write(mRibbonLength); 139 stream->writeString(mMatName); 140 stream->writeFlag(mUseFadeOut); 141 stream->write(mFadeAwayStep); 142 stream->write(segmentsPerUpdate); 143 stream->write(mTileScale); 144 stream->writeFlag(mFixedTexcoords); 145 stream->writeFlag(mTexcoordsRelativeToDistance); 146} 147 148void RibbonData::unpackData(BitStream* stream) 149{ 150 Parent::unpackData(stream); 151 152 for (U8 i = 0; i < NumFields; i++) { 153 stream->read(&mSizes[i]); 154 stream->read(&mColours[i]); 155 stream->read(&mTimes[i]); 156 } 157 158 stream->read(&mRibbonLength); 159 mMatName = StringTable->insert(stream->readSTString()); 160 mUseFadeOut = stream->readFlag(); 161 stream->read(&mFadeAwayStep); 162 stream->read(&segmentsPerUpdate); 163 stream->read(&mTileScale); 164 mFixedTexcoords = stream->readFlag(); 165 mTexcoordsRelativeToDistance = stream->readFlag(); 166} 167 168 169//-------------------------------------------------------------------------- 170//-------------------------------------- 171// 172Ribbon::Ribbon() 173{ 174 mDataBlock = NULL; 175 mTypeMask |= StaticObjectType; 176 177 VECTOR_SET_ASSOCIATION(mSegmentPoints); 178 mSegmentPoints.clear(); 179 180 mRibbonMat = NULL; 181 182 mUpdateBuffers = true; 183 mDeleteOnEnd = false; 184 mUseFadeOut = false; 185 mFadeAwayStep = 1.0f; 186 mFadeOut = 1.0f; 187 188 mNetFlags.clear(Ghostable); 189 mNetFlags.set(IsGhost); 190 191 mRadiusSC = NULL; 192 mRibbonProjSC = NULL; 193 194 mSegmentOffset = 0; 195 mSegmentIdx = 0; 196 197 mTravelledDistance = 0; 198} 199 200Ribbon::~Ribbon() 201{ 202 //Make sure we cleanup 203 SAFE_DELETE(mRibbonMat); 204} 205 206//-------------------------------------------------------------------------- 207void Ribbon::initPersistFields() 208{ 209 Parent::initPersistFields(); 210} 211 212bool Ribbon::onAdd() 213{ 214 if(!Parent::onAdd()) 215 return false; 216 217 // add to client side mission cleanup 218 SimGroup *cleanup = dynamic_cast<SimGroup *>( Sim::findObject( "ClientMissionCleanup") ); 219 if( cleanup != NULL ) 220 { 221 cleanup->addObject( this ); 222 } 223 else 224 { 225 AssertFatal( false, "Error, could not find ClientMissionCleanup group" ); 226 return false; 227 } 228 229 if (!isServerObject()) { 230 231 if(GFX->getPixelShaderVersion() >= 1.1 && dStrlen(mDataBlock->mMatName) > 0 ) 232 { 233 mRibbonMat = MATMGR->createMatInstance( mDataBlock->mMatName ); 234 GFXStateBlockDesc desc; 235 desc.setZReadWrite( true, false ); 236 desc.cullDefined = true; 237 desc.cullMode = GFXCullNone; 238 desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha); 239 240 desc.samplersDefined = true; 241 242 GFXSamplerStateDesc sDesc(GFXSamplerStateDesc::getClampLinear()); 243 sDesc.addressModeV = GFXAddressWrap; 244 245 desc.samplers[0] = sDesc; 246 247 mRibbonMat->addStateBlockDesc( desc ); 248 mRibbonMat->init(MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPCNTT>()); 249 250 mRadiusSC = mRibbonMat->getMaterialParameterHandle( "$radius" ); 251 mRibbonProjSC = mRibbonMat->getMaterialParameterHandle( "$ribbonProj" ); 252 253 } else { 254 Con::warnf( "Invalid Material name: %s: for Ribbon", mDataBlock->mMatName ); 255#ifdef TORQUE_DEBUG 256 Con::warnf( "- This could be caused by having the shader data datablocks in server-only code." ); 257#endif 258 mRibbonMat = NULL; 259 } 260 } 261 262 mObjBox.minExtents.set( 1.0f, 1.0f, 1.0f ); 263 mObjBox.maxExtents.set( 2.0f, 2.0f, 2.0f ); 264 // Reset the World Box. 265 resetWorldBox(); 266 // Set the Render Transform. 267 setRenderTransform(mObjToWorld); 268 269 addToScene(); 270 271 return true; 272} 273 274 275void Ribbon::onRemove() 276{ 277 278 removeFromScene(); 279 SAFE_DELETE(mRibbonMat); 280 281 Parent::onRemove(); 282} 283 284 285bool Ribbon::onNewDataBlock(GameBaseData* dptr, bool reload) 286{ 287 mDataBlock = dynamic_cast<RibbonData*>(dptr); 288 if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload)) 289 return false; 290 291 return true; 292} 293 294void Ribbon::processTick(const Move* move) 295{ 296 Parent::processTick(move); 297 298 if (mDeleteOnEnd) { 299 300 if (mUseFadeOut) { 301 302 if (mFadeOut <= 0.0f) { 303 mFadeOut = 0.0f; 304 //delete this class 305 mDeleteOnEnd = false; 306 safeDeleteObject(); 307 return; 308 } 309 mFadeOut -= mFadeAwayStep; 310 if (mFadeOut < 0.0f) { 311 mFadeOut = 0.0f; 312 } 313 314 mUpdateBuffers = true; 315 316 } else { 317 //if (mSegmentPoints.size() == 0) { 318 //delete this class 319 mDeleteOnEnd = false; 320 safeDeleteObject(); 321 return; 322 //} 323 //mSegmentPoints.pop_back(); 324 } 325 326 327 } 328} 329 330void Ribbon::advanceTime(F32 dt) 331{ 332 Parent::advanceTime(dt); 333} 334 335void Ribbon::interpolateTick(F32 delta) 336{ 337 Parent::interpolateTick(delta); 338} 339 340void Ribbon::addSegmentPoint(Point3F &point, MatrixF &mat) { 341 342 //update our position 343 setRenderTransform(mat); 344 MatrixF xform(true); 345 xform.setColumn(3, point); 346 setTransform(xform); 347 348 if(mSegmentIdx < mDataBlock->mSegmentSkipAmount) 349 { 350 mSegmentIdx++; 351 return; 352 } 353 354 mSegmentIdx = 0; 355 356 U32 segmentsToDelete = checkRibbonDistance(mDataBlock->segmentsPerUpdate); 357 358 for (U32 i = 0; i < segmentsToDelete; i++) { 359 S32 last = mSegmentPoints.size() - 1; 360 if (last < 0) 361 break; 362 mTravelledDistance += last ? (mSegmentPoints[last] - mSegmentPoints[last-1]).len() : 0; 363 mSegmentPoints.pop_back(); 364 mUpdateBuffers = true; 365 mSegmentOffset++; 366 } 367 368 //If there is no other points, just add a new one. 369 if (mSegmentPoints.size() == 0) { 370 371 mSegmentPoints.push_front(point); 372 mUpdateBuffers = true; 373 return; 374 } 375 376 Point3F startPoint = mSegmentPoints[0]; 377 378 //add X points based on how many segments Per Update from last point to current point 379 for (U32 i = 0; i < mDataBlock->segmentsPerUpdate; i++) { 380 381 F32 interp = (F32(i+1) / (F32)mDataBlock->segmentsPerUpdate); 382 //(end - start) * percentage) + start 383 Point3F derivedPoint = ((point - startPoint) * interp) + startPoint; 384 385 mSegmentPoints.push_front(derivedPoint); 386 mUpdateBuffers = true; 387 } 388 389 if (mSegmentPoints.size() > 1) { 390 391 Point3F pointA = mSegmentPoints[mSegmentPoints.size()-1]; 392 Point3F pointB = mSegmentPoints[0]; 393 394 Point3F diffSize = pointA - pointB; 395 396 if (diffSize.x == 0.0f) 397 diffSize.x = 1.0f; 398 399 if (diffSize.y == 0.0f) 400 diffSize.y = 1.0f; 401 402 if (diffSize.z == 0.0f) 403 diffSize.z = 1.0f; 404 405 Box3F objBox; 406 objBox.minExtents.set( diffSize * -1 ); 407 objBox.maxExtents.set( diffSize ); 408 409 if (objBox.minExtents.x > objBox.maxExtents.x) { 410 F32 tmp = objBox.minExtents.x; 411 objBox.minExtents.x = objBox.maxExtents.x; 412 objBox.maxExtents.x = tmp; 413 } 414 if (objBox.minExtents.y > objBox.maxExtents.y) { 415 F32 tmp = objBox.minExtents.y; 416 objBox.minExtents.y = objBox.maxExtents.y; 417 objBox.maxExtents.y = tmp; 418 } 419 if (objBox.minExtents.z > objBox.maxExtents.z) { 420 F32 tmp = objBox.minExtents.z; 421 objBox.minExtents.z = objBox.maxExtents.z; 422 objBox.maxExtents.z = tmp; 423 } 424 425 426 427 if (objBox.isValidBox()) { 428 mObjBox = objBox; 429 // Reset the World Box. 430 resetWorldBox(); 431 } 432 } 433 434} 435 436void Ribbon::deleteOnEnd() { 437 438 mDeleteOnEnd = true; 439 mUseFadeOut = mDataBlock->mUseFadeOut; 440 mFadeAwayStep = mDataBlock->mFadeAwayStep; 441 442} 443 444U32 Ribbon::checkRibbonDistance(S32 segments) { 445 446 S32 len = mSegmentPoints.size(); 447 S32 difference = (mDataBlock->mRibbonLength/(mDataBlock->mSegmentSkipAmount+1)) - len; 448 449 if (difference < 0) 450 return mAbs(difference); 451 452 return 0; //do not delete any points 453} 454 455void Ribbon::setShaderParams() { 456 457 F32 numSegments = (F32)mSegmentPoints.size(); 458 F32 length = (F32)mDataBlock->mRibbonLength; 459 Point3F radius(numSegments / length, numSegments, length); 460 MaterialParameters* matParams = mRibbonMat->getMaterialParameters(); 461 matParams->setSafe( mRadiusSC, radius ); 462} 463 464//-------------------------------------------------------------------------- 465//U32 Ribbon::packUpdate(NetConnection* con, U32 mask, BitStream* stream) 466//{ 467// U32 retMask = Parent::packUpdate(con, mask, stream); 468// return retMask; 469//} 470// 471//void Ribbon::unpackUpdate(NetConnection* con, BitStream* stream) 472//{ 473// Parent::unpackUpdate(con, stream); 474//} 475 476//-------------------------------------------------------------------------- 477void Ribbon::prepRenderImage(SceneRenderState *state) 478{ 479 if (mFadeOut == 0.0f) 480 return; 481 482 if(!mRibbonMat) 483 return; 484 485 if (mDeleteOnEnd == true && mUseFadeOut == false) { 486 return; 487 } 488 489 // We only render during the normal diffuse render pass. 490 if( !state->isDiffusePass() ) 491 return; 492 493 U32 segments = mSegmentPoints.size(); 494 if (segments < 2) 495 return; 496 497 MeshRenderInst *ri = state->getRenderPass()->allocInst<MeshRenderInst>(); 498 ri->type = RenderPassManager::RIT_Translucent; 499 ri->translucentSort = true; 500 ri->sortDistSq = ( mSegmentPoints[0] - state->getCameraPosition() ).lenSquared(); 501 502 RenderPassManager *renderPass = state->getRenderPass(); 503 MatrixF *proj = renderPass->allocUniqueXform(MatrixF( true )); 504 proj->mul(GFX->getProjectionMatrix()); 505 proj->mul(GFX->getWorldMatrix()); 506 ri->objectToWorld = &MatrixF::Identity; 507 ri->worldToCamera = &MatrixF::Identity; 508 ri->projection = proj; 509 ri->matInst = mRibbonMat; 510 511 // Set up our vertex buffer and primitive buffer 512 if(mUpdateBuffers) 513 createBuffers(state, mVerts, mPrimBuffer, segments); 514 515 ri->vertBuff = &mVerts; 516 ri->primBuff = &mPrimBuffer; 517 ri->visibility = 1.0f; 518 519 ri->prim = renderPass->allocPrim(); 520 ri->prim->type = GFXTriangleList; 521 ri->prim->minIndex = 0; 522 ri->prim->startIndex = 0; 523 ri->prim->numPrimitives = (segments-1) * 2; 524 ri->prim->startVertex = 0; 525 ri->prim->numVertices = segments * 2; 526 527 if (mRibbonMat) { 528 ri->defaultKey = mRibbonMat->getStateHint(); 529 } else { 530 ri->defaultKey = 1; 531 } 532 ri->defaultKey2 = (uintptr_t)ri->vertBuff; // Not 64bit safe! 533 534 state->getRenderPass()->addInst(ri); 535} 536 537void Ribbon::createBuffers(SceneRenderState *state, GFXVertexBufferHandle<GFXVertexPCNTT> &verts, GFXPrimitiveBufferHandle &pb, U32 segments) { 538 PROFILE_SCOPE( Ribbon_createBuffers ); 539 Point3F cameraPos = state->getCameraPosition(); 540 U32 count = 0; 541 U32 indexCount = 0; 542 verts.set(GFX, (segments*2), GFXBufferTypeDynamic); 543 544 // create index buffer based on that size 545 U32 indexListSize = (segments-1) * 6; 546 pb.set( GFX, indexListSize, 0, GFXBufferTypeDynamic ); 547 U16 *indices = NULL; 548 549 verts.lock(); 550 pb.lock( &indices ); 551 F32 totalLength = 0; 552 if(mDataBlock->mTexcoordsRelativeToDistance) 553 { 554 for (U32 i = 0; i < segments; i++) 555 if (i != 0) 556 totalLength += (mSegmentPoints[i] - mSegmentPoints[i-1]).len(); 557 } 558 559 U8 fixedAppend = 0; 560 F32 curLength = 0; 561 for (U32 i = 0; i < segments; i++) { 562 563 F32 interpol = ((F32)i / (F32)(segments-1)); 564 Point3F leftvert = mSegmentPoints[i]; 565 Point3F rightvert = mSegmentPoints[i]; 566 F32 tRadius = mDataBlock->mSizes[0]; 567 LinearColorF tColor = mDataBlock->mColours[0]; 568 569 for (U8 j = 0; j < RibbonData::NumFields-1; j++) { 570 571 F32 curPosition = mDataBlock->mTimes[j]; 572 F32 curRadius = mDataBlock->mSizes[j]; 573 LinearColorF curColor = mDataBlock->mColours[j]; 574 F32 nextPosition = mDataBlock->mTimes[j+1]; 575 F32 nextRadius = mDataBlock->mSizes[j+1]; 576 LinearColorF nextColor = mDataBlock->mColours[j+1]; 577 578 if ( curPosition < 0 579 || curPosition > interpol ) 580 break; 581 F32 positionDiff = (interpol - curPosition) / (nextPosition - curPosition); 582 583 tRadius = curRadius + (nextRadius - curRadius) * positionDiff; 584 tColor.interpolate(curColor, nextColor, positionDiff); 585 } 586 587 Point3F diff; 588 F32 length; 589 if (i == 0) { 590 diff = mSegmentPoints[i+1] - mSegmentPoints[i]; 591 length = 0; 592 } else if (i == segments-1) { 593 diff = mSegmentPoints[i] - mSegmentPoints[i-1]; 594 length = diff.len(); 595 } else { 596 diff = mSegmentPoints[i+1] - mSegmentPoints[i-1]; 597 length = (mSegmentPoints[i] - mSegmentPoints[i-1]).len(); 598 } 599 600 //left point 601 Point3F eyeMinPos = cameraPos - leftvert; 602 Point3F perpendicular = mCross(diff, eyeMinPos); 603 perpendicular.normalize(); 604 perpendicular = perpendicular * tRadius * -1.0f; 605 perpendicular += mSegmentPoints[i]; 606 607 verts[count].point.set(perpendicular); 608 LinearColorF color = tColor; 609 610 if (mDataBlock->mUseFadeOut) 611 color.alpha *= mFadeOut; 612 613 F32 texCoords; 614 if(mDataBlock->mFixedTexcoords && !mDataBlock->mTexcoordsRelativeToDistance) 615 { 616 U32 fixedIdx = (i+mDataBlock->mRibbonLength-mSegmentOffset)%mDataBlock->mRibbonLength; 617 if(fixedIdx == 0 && i > 0) 618 fixedAppend++; 619 F32 fixedInterpol = (F32)fixedIdx / (F32)(mDataBlock->mRibbonLength); 620 fixedInterpol += fixedAppend; 621 texCoords = (1.0f - fixedInterpol)*mDataBlock->mTileScale; 622 } 623 else if(mDataBlock->mTexcoordsRelativeToDistance) 624 texCoords = (mTravelledDistance + (totalLength - (curLength + length)))*mDataBlock->mTileScale; 625 else 626 texCoords = (1.0f - interpol)*mDataBlock->mTileScale; 627 628 verts[count].color = color.toColorI(); 629 verts[count].texCoord[1] = Point2F(interpol, 0); 630 verts[count].texCoord[0] = Point2F(0.0f, texCoords); 631 verts[count].normal.set(diff); 632 633 //Triangle strip style indexing, so grab last 2 634 if (count > 1) { 635 indices[indexCount] = count-2; 636 indexCount++; 637 indices[indexCount] = count; 638 indexCount++; 639 indices[indexCount] = count-1; 640 indexCount++; 641 } 642 count++; 643 644 eyeMinPos = cameraPos - rightvert; 645 perpendicular = mCross(diff, eyeMinPos); 646 perpendicular.normalize(); 647 perpendicular = perpendicular * tRadius; 648 perpendicular += mSegmentPoints[i]; 649 650 verts[count].point.set(perpendicular); 651 color = tColor; 652 653 if (mDataBlock->mUseFadeOut) 654 color.alpha *= mFadeOut; 655 656 verts[count].color = color.toColorI(); 657 verts[count].texCoord[1] = Point2F(interpol, 1); 658 verts[count].texCoord[0] = Point2F(1.0f, texCoords); 659 verts[count].normal.set(diff); 660 661 //Triangle strip style indexing, so grab last 2 662 if (count > 1) { 663 indices[indexCount] = count-2; 664 indexCount++; 665 indices[indexCount] = count-1; 666 indexCount++; 667 indices[indexCount] = count; 668 indexCount++; 669 } 670 count++; 671 curLength += length; 672 } 673 674 Point3F pointA = verts[count-1].point; 675 Point3F pointB = verts[0].point; 676 677 pb.unlock(); 678 verts.unlock(); 679 680 Point3F diffSize = pointA - pointB; 681 682 Box3F objBox; 683 objBox.minExtents.set( diffSize * -1 ); 684 objBox.maxExtents.set( diffSize ); 685 686 if (objBox.minExtents.x > objBox.maxExtents.x) { 687 F32 tmp = objBox.minExtents.x; 688 objBox.minExtents.x = objBox.maxExtents.x; 689 objBox.maxExtents.x = tmp; 690 } 691 if (objBox.minExtents.y > objBox.maxExtents.y) { 692 F32 tmp = objBox.minExtents.y; 693 objBox.minExtents.y = objBox.maxExtents.y; 694 objBox.maxExtents.y = tmp; 695 } 696 if (objBox.minExtents.z > objBox.maxExtents.z) { 697 F32 tmp = objBox.minExtents.z; 698 objBox.minExtents.z = objBox.maxExtents.z; 699 objBox.maxExtents.z = tmp; 700 } 701 702 if (objBox.isValidBox()) { 703 mObjBox = objBox; 704 // Reset the World Box. 705 resetWorldBox(); 706 } 707 708 mUpdateBuffers = false; 709} 710