ribbon.cpp

Engine/source/T3D/fx/ribbon.cpp

More...

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