Torque3D Documentation / _generateds / tsPartInstance.cpp

tsPartInstance.cpp

Engine/source/ts/tsPartInstance.cpp

More...

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 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 "ts/tsPartInstance.h"
 25#include "math/mMath.h"
 26
 27//-------------------------------------------------------------------------------------
 28// Constructors
 29//-------------------------------------------------------------------------------------
 30
 31MRandomR250 TSPartInstance::smRandom;
 32
 33TSPartInstance::TSPartInstance(TSShapeInstance * sourceShape)
 34{
 35   VECTOR_SET_ASSOCIATION(mMeshObjects);
 36
 37   init(sourceShape);
 38}
 39
 40TSPartInstance::TSPartInstance(TSShapeInstance * sourceShape, S32 objectIndex)
 41{
 42   init(sourceShape);
 43   addObject(objectIndex);
 44}
 45
 46void TSPartInstance::init(TSShapeInstance * sourceShape)
 47{
 48   mSourceShape = sourceShape;
 49   mSizeCutoffs = NULL;
 50   mPolyCount = NULL;
 51   mNumDetails = 0;
 52   mCurrentObjectDetail = 0;
 53   mCurrentIntraDL = 1.0f;
 54   mData = 0;
 55   mRadius = 0.125;
 56}
 57
 58TSPartInstance::~TSPartInstance()
 59{
 60   delete [] mPolyCount;
 61}
 62
 63//-------------------------------------------------------------------------------------
 64// Methods for updating PartInstances
 65//-------------------------------------------------------------------------------------
 66
 67void TSPartInstance::addObject(S32 objectIndex)
 68{
 69   if (mSourceShape->mMeshObjects[objectIndex].forceHidden ||
 70      mSourceShape->mMeshObjects[objectIndex].visible < 0.01f)
 71      // not visible, don't bother
 72      return;
 73
 74   mMeshObjects.push_back(&mSourceShape->mMeshObjects[objectIndex]);
 75}
 76
 77void TSPartInstance::updateBounds()
 78{
 79   // run through meshes and brute force it?
 80   Box3F bounds;
 81   mBounds.minExtents.set( 10E30f, 10E30f, 10E30f);
 82   mBounds.maxExtents.set(-10E30f,-10E30f,-10E30f);
 83   for (S32 i=0; i<mMeshObjects.size(); i++)
 84   {
 85      if (mMeshObjects[i]->getMesh(0))
 86         mMeshObjects[i]->getMesh(0)->computeBounds(mMeshObjects[i]->getTransform(),bounds,mMeshObjects[i]->frame);
 87      mBounds.minExtents.setMin(bounds.minExtents);
 88      mBounds.maxExtents.setMax(bounds.maxExtents);
 89   }
 90   mCenter = mBounds.minExtents + mBounds.maxExtents;
 91   mCenter *= 0.5f;
 92   Point3F r = mBounds.maxExtents-mCenter;
 93   mRadius = mSqrt(mDot(r,r));
 94}
 95
 96//-------------------------------------------------------------------------------------
 97// Methods for breaking shapes into pieces
 98//-------------------------------------------------------------------------------------
 99
100void TSPartInstance::breakShape(TSShapeInstance * shape, S32 subShape, Vector<TSPartInstance*> & partList, F32 * probShatter, F32 * probBreak, S32 probDepth)
101{
102   AssertFatal(subShape>=0 && subShape<shape->mShape->subShapeFirstNode.size(),"TSPartInstance::breakShape: subShape out of range.");
103
104   S32 start = shape->mShape->subShapeFirstNode[subShape];
105
106   TSPartInstance::breakShape(shape, NULL, start, partList, probShatter, probBreak, probDepth);
107
108   // update bounds (and get rid of empty parts)
109   for (S32 i=0; i<partList.size(); i++)
110   {
111      if (partList[i]->mMeshObjects.size())
112      {
113         partList[i]->updateBounds();
114         // Remove any parts parts with invalid box
115         Box3F box = partList[i]->getBounds();
116         if (!box.isValidBox())
117         {
118            Con::warnf("TSPartInstance::breakShape - part created with invalid object box. Removing from list.");
119            partList.erase(i);
120            i--;
121         }
122     }
123     else
124     {
125        partList.erase(i);
126        i--;
127     }
128   }
129}
130
131void TSPartInstance::breakShape(TSShapeInstance * shape, TSPartInstance * currentPart, S32 currentNode, Vector<TSPartInstance*> & partList, F32 * probShatter, F32 * probBreak, S32 probDepth)
132{
133   AssertFatal( !probDepth || (probShatter && probBreak),"TSPartInstance::breakShape: probabilities improperly specified.");
134
135   const TSShape::Node * node = &shape->mShape->nodes[currentNode];
136   S32 object = node->firstObject;
137   S32 child  = node->firstChild;
138
139   // copy off probabilities and update probability lists for next level
140   F32 ps = probShatter ? *probShatter : 1.0f;
141   F32 pb = probBreak   ? *probBreak   : 1.0f;
142   if (probDepth>1 && probShatter && probBreak)
143   {
144      probShatter++;
145      probBreak++;
146      probDepth--;
147   }
148
149   // what to do...depending on how the die roll, we can:
150   // a) shatter the shape at this level -- meaning we make a part out of each object on this node and
151   //    we make parts out of all the children (perhaps breaking them up further still)
152   // b) break the shape off at this level -- meaning we make a part out of the intact piece from here
153   //    on down (again, we might break the result further as we iterate through the nodes...what breaking
154   //    the shape really does is separate this piece from the parent piece).
155   // c) add this piece to the parent -- meaning all objects on this node are added to the parent, and children
156   //    are also added (but children will be recursively sent through this routine, so if a parent gets option
157   //    (c) and the child option (a) or (b), then the child will be ripped from the parents grasp.  Cruel
158   //    people us coders are.
159   // Note: (a) is the only way that two objects on the same node can be separated...that is why both
160   //       option a and option b are needed.
161   if (!probShatter || smRandom.randF() < ps)
162   {
163      // option a -- shatter the shape at this level
164
165      // iterate through the objects, make part out of each one
166      while (object>=0)
167      {
168         partList.increment();
169         partList.last() = new TSPartInstance(shape,object);
170         object = shape->mShape->objects[object].nextSibling;
171      }
172
173      // iterate through the child nodes, call ourselves on each one with currentPart = NULL
174      while (child>=0)
175      {
176         TSPartInstance::breakShape(shape,NULL,child,partList,probShatter,probBreak,probDepth);
177         child = shape->mShape->nodes[child].nextSibling;
178      }
179
180      return;
181   }
182
183   if (!probBreak || smRandom.randF() < pb)
184      // option b -- break the shape off at this level
185      currentPart = NULL; // fall through to option C
186
187   // option c -- add this piece to the parent
188
189   if (!currentPart)
190   {
191      currentPart = new TSPartInstance(shape);
192      partList.push_back(currentPart);
193   }
194
195   // iterate through objects, add to currentPart
196   while (object>=0)
197   {
198      currentPart->addObject(object);
199      object = shape->mShape->objects[object].nextSibling;
200   }
201
202   // iterate through child nodes, call ourselves on each one with currentPart as is
203   while (child>=0)
204   {
205      TSPartInstance::breakShape(shape,currentPart,child,partList,probShatter,probBreak,probDepth);
206      child = shape->mShape->nodes[child].nextSibling;
207   }
208}
209
210//-------------------------------------------------------------------------------------
211// render methods -- we use TSShapeInstance code as much as possible
212// issues: setupTexturing expects a detail level, we give it an object detail level
213//-------------------------------------------------------------------------------------
214
215void TSPartInstance::render(S32 od, const TSRenderState &rdata)
216{
217   S32 i;
218
219   // render mesh objects
220   for (i=0; i<mMeshObjects.size(); i++)
221   {
222      TSRenderState objState = rdata;
223      const char *meshName = mSourceShape->mShape->names[mMeshObjects[i]->object->nameIndex];
224      mMeshObjects[i]->render(od,mSourceShape->mShape->mShapeVertexBuffer,mSourceShape->getMaterialList(),objState,1.0, meshName);
225   }
226}
227
228//-------------------------------------------------------------------------------------
229// Detail selection
230// 2 methods:
231// method 1:  use source shapes detail levels...
232// method 2:  pass in our own table...
233// In either case, you can compute the pixel size on your own or let open gl do it.
234// If you want to use method 2, you have to call setDetailData sometime before selecting detail
235//-------------------------------------------------------------------------------------
236
237void TSPartInstance::setDetailData(F32 * sizeCutoffs, S32 numDetails)
238{
239   if (mSizeCutoffs == sizeCutoffs && mNumDetails==numDetails)
240      return;
241
242   mSizeCutoffs = sizeCutoffs;
243   mNumDetails = numDetails;
244   delete [] mPolyCount;
245   mPolyCount = NULL;
246}
247
248/*
249void TSPartInstance::selectCurrentDetail(bool ignoreScale)
250{
251   if (mSizeCutoffs)
252   {
253      selectCurrentDetail(mSizeCutoffs,mNumDetails,ignoreScale);
254      return;
255   }
256
257   mSourceShape->selectCurrentDetail(ignoreScale);
258   mCurrentObjectDetail = mSourceShape->getCurrentDetail();
259   mCurrentIntraDL = mSourceShape->getCurrentIntraDetail();
260}
261
262void TSPartInstance::selectCurrentDetail(F32 pixelSize)
263{
264   if (mSizeCutoffs)
265   {
266      selectCurrentDetail(pixelSize,mSizeCutoffs,mNumDetails);
267      return;
268   }
269
270   mSourceShape->selectCurrentDetail(pixelSize);
271   mCurrentObjectDetail = mSourceShape->getCurrentDetail();
272   mCurrentIntraDL = mSourceShape->getCurrentIntraDetail();
273}
274
275void TSPartInstance::selectCurrentDetail(F32 dist, F32 invScale)
276{
277   if (mSizeCutoffs)
278   {
279      const RectI &viewport = GFX->getViewport();
280      F32 pixelScale = viewport.extent.x * 1.6f / 640.0f;
281      F32 pixelSize = GFX->projectRadius(dist*invScale,mSourceShape->getShape()->radius) * pixelScale * TSShapeInstance::smDetailAdjust;
282      selectCurrentDetail(pixelSize,mSizeCutoffs,mNumDetails);
283      return;
284   }
285
286   mSourceShape->selectCurrentDetail(dist, invScale);
287   mCurrentObjectDetail = mSourceShape->getCurrentDetail();
288   mCurrentIntraDL = mSourceShape->getCurrentIntraDetail();
289}
290
291void TSPartInstance::selectCurrentDetail(F32 * sizeCutoffs, S32 numDetails, bool ignoreScale)
292{
293   // compute pixel size
294   Point3F p;
295   MatrixF toCam = GFX->getWorldMatrix();
296   toCam.mulP(mCenter,&p);
297   F32 dist = mDot(p,p);
298   F32 scale = 1.0f;
299   if (!ignoreScale)
300   {
301      // any scale?
302      Point3F x,y,z;
303      toCam.getRow(0,&x);
304      toCam.getRow(1,&y);
305      toCam.getRow(2,&z);
306      F32 scalex = mDot(x,x);
307      F32 scaley = mDot(y,y);
308      F32 scalez = mDot(z,z);
309      scale = scalex;
310      if (scaley > scale)
311         scale = scaley;
312      if (scalez > scale)
313         scale = scalez;
314   }
315   dist /= scale;
316   dist = mSqrt(dist);
317
318   const RectI &viewport = GFX->getViewport();
319   // JMQMERGE: is this using a hardcoded res/aspect ?  (and the code above)
320   F32 pixelScale = viewport.extent.x * 1.6f / 640.0f;
321   F32 pixelRadius = GFX->projectRadius(dist,mRadius) * pixelScale * TSShapeInstance::smDetailAdjust;
322
323   selectCurrentDetail(pixelRadius,sizeCutoffs,numDetails);
324}
325
326void TSPartInstance::selectCurrentDetail(F32 pixelSize, F32 * sizeCutoffs, S32 numDetails)
327{
328   mCurrentObjectDetail = 0;
329   while (numDetails)
330   {
331      if (pixelSize > *sizeCutoffs)
332         return;
333      mCurrentObjectDetail++;
334      numDetails--;
335      sizeCutoffs++;
336   }
337   mCurrentObjectDetail = -1;
338}
339*/
340
341//-------------------------------------------------------------------------------------
342// Detail query methods...complicated because there are two ways that detail information
343// can be determined...1) using source shape, or 2) using mSizeCutoffs
344//-------------------------------------------------------------------------------------
345
346F32 TSPartInstance::getDetailSize(S32 dl) const
347{
348   if (dl<0)
349      return 0;
350   else if (mSizeCutoffs && dl<mNumDetails)
351      return mSizeCutoffs[dl];
352   else if (!mSizeCutoffs && dl<=mSourceShape->getShape()->mSmallestVisibleDL)
353      return mSourceShape->getShape()->details[dl].size;
354   else return 0;
355}
356
357S32 TSPartInstance::getPolyCount(S32 dl)
358{
359   if (!mPolyCount)
360      computePolyCount();
361
362   if (dl<0 || dl>=mNumDetails)
363      return 0;
364   else
365      return mPolyCount[dl];
366}
367
368void TSPartInstance::computePolyCount()
369{
370   if (!mSizeCutoffs)
371      mNumDetails = mSourceShape->getShape()->mSmallestVisibleDL+1;
372
373   delete [] mPolyCount;
374   mPolyCount = new S32[mNumDetails];
375
376   for (S32 i=0; i<mNumDetails; i++)
377   {
378      mPolyCount[i] = 0;
379      for (S32 j=0; j<mMeshObjects.size(); j++)
380      {
381         if (mMeshObjects[j]->getMesh(i))
382            mPolyCount[i] += mMeshObjects[j]->getMesh(i)->getNumPolys();
383      }
384   }
385}
386
387
388