636 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			636 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| //-----------------------------------------------------------------------------
 | |
| // Torque Game Engine
 | |
| // Copyright (C) GarageGames.com, Inc.
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| #include "game/tsStatic.h"
 | |
| #include "core/bitStream.h"
 | |
| #include "dgl/dgl.h"
 | |
| #include "sceneGraph/sceneState.h"
 | |
| #include "sceneGraph/sceneGraph.h"
 | |
| #include "math/mathIO.h"
 | |
| #include "ts/tsShapeInstance.h"
 | |
| #include "console/consoleTypes.h"
 | |
| #include "game/shapeBase.h"
 | |
| #include "game/shadow.h"
 | |
| #include "sceneGraph/detailManager.h"
 | |
| #include "sim/netConnection.h"
 | |
| 
 | |
| IMPLEMENT_CO_NETOBJECT_V1(TSStatic);
 | |
| 
 | |
| 
 | |
| //--------------------------------------------------------------------------
 | |
| //--------------------------------------------------------------------------
 | |
| TSStatic::TSStatic()
 | |
| {
 | |
|    mNetFlags.set(Ghostable | ScopeAlways);
 | |
| 
 | |
|    mTypeMask |= StaticObjectType | StaticTSObjectType | StaticRenderedObjectType;
 | |
| 
 | |
|    mShapeName        = "";
 | |
|    mShapeInstance    = NULL;
 | |
|    mShadow           = NULL;
 | |
| 
 | |
|    mConvexList = new Convex;
 | |
| }
 | |
| 
 | |
| TSStatic::~TSStatic()
 | |
| {
 | |
|    delete mConvexList;
 | |
|    mConvexList = NULL;
 | |
|    delete mShadow;
 | |
| }
 | |
| 
 | |
| //--------------------------------------------------------------------------
 | |
| void TSStatic::initPersistFields()
 | |
| {
 | |
|    Parent::initPersistFields();
 | |
| 
 | |
|    addGroup("Media");
 | |
|    addField("shapeName", TypeFilename, Offset(mShapeName, TSStatic));
 | |
|    endGroup("Media");
 | |
| }
 | |
| 
 | |
| //--------------------------------------------------------------------------
 | |
| bool TSStatic::onAdd()
 | |
| {
 | |
|    if(!Parent::onAdd())
 | |
|       return false;
 | |
| 
 | |
|    if (!mShapeName || mShapeName[0] == '\0') {
 | |
|       Con::errorf("TSStatic::onAdd: no shape name!");
 | |
|       return false;
 | |
|    }
 | |
|    mShapeHash = _StringTable::hashString(mShapeName);
 | |
| 
 | |
|    mShape = ResourceManager->load(mShapeName);
 | |
| 
 | |
|    if (bool(mShape) == false)
 | |
|    {
 | |
|       Con::errorf("TSStatic::onAdd: unable to load shape: %s", mShapeName);
 | |
|       return false;
 | |
|    }
 | |
| 
 | |
|    if(isClientObject() && !mShape->preloadMaterialList() && NetConnection::filesWereDownloaded())
 | |
|       return false;
 | |
| 
 | |
|    mObjBox = mShape->bounds;
 | |
|    resetWorldBox();
 | |
|    setRenderTransform(mObjToWorld);
 | |
| 
 | |
|    mShapeInstance = new TSShapeInstance(mShape, isClientObject());
 | |
| 
 | |
|    // Scan out the collision hulls...
 | |
|    U32 i;
 | |
|    for (i = 0; i < mShape->details.size(); i++)
 | |
|    {
 | |
|       char* name = (char*)mShape->names[mShape->details[i].nameIndex];
 | |
| 
 | |
|       if (dStrstr((const char*)dStrlwr(name), "collision-"))
 | |
|       {
 | |
|          mCollisionDetails.push_back(i);
 | |
| 
 | |
|          // The way LOS works is that it will check to see if there is a LOS detail that matches
 | |
|          // the the collision detail + 1 + MaxCollisionShapes (this variable name should change in
 | |
|          // the future). If it can't find a matching LOS it will simply use the collision instead.
 | |
|          // We check for any "unmatched" LOS's further down
 | |
|          mLOSDetails.increment();
 | |
| 
 | |
|       char buff[128];
 | |
|          dSprintf(buff, sizeof(buff), "LOS-%d", i + 1 + MaxCollisionShapes);
 | |
|          U32 los = mShape->findDetail(buff);
 | |
|          if (los == -1)
 | |
|             mLOSDetails.last() = i;
 | |
|          else
 | |
|             mLOSDetails.last() = los;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // Snag any "unmatched" LOS details
 | |
|    for (i = 0; i < mShape->details.size(); i++)
 | |
|    {
 | |
|       char* name = (char*)mShape->names[mShape->details[i].nameIndex];
 | |
| 
 | |
|       if (dStrstr((const char*)dStrlwr(name), "los-"))
 | |
|       {
 | |
|          // See if we already have this LOS
 | |
|          bool found = false;
 | |
|          for (U32 j = 0; j < mLOSDetails.size(); j++)
 | |
|          {
 | |
|             if (mLOSDetails[j] == i)
 | |
|             {
 | |
|                found = true;
 | |
|                break;
 | |
|             }
 | |
|          }
 | |
| 
 | |
|          if (!found)
 | |
|             mLOSDetails.push_back(i);
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // Compute the hull accelerators (actually, just force the shape to compute them)
 | |
|    for (i = 0; i < mCollisionDetails.size(); i++)
 | |
|          mShapeInstance->getShape()->getAccelerator(mCollisionDetails[i]);
 | |
| 
 | |
|    addToScene();
 | |
| 
 | |
|    return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| void TSStatic::onRemove()
 | |
| {
 | |
|    mConvexList->nukeList();
 | |
| 
 | |
|    removeFromScene();
 | |
| 
 | |
|    delete mShapeInstance;
 | |
|    mShapeInstance = NULL;
 | |
|    delete mShadow;
 | |
|    mShadow = NULL;
 | |
| 
 | |
|    Parent::onRemove();
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| //--------------------------------------------------------------------------
 | |
| bool TSStatic::prepRenderImage(SceneState* state, const U32 stateKey,
 | |
|                                        const U32 /*startZone*/, const bool /*modifyBaseState*/)
 | |
| {
 | |
|    if (isLastState(state, stateKey))
 | |
|       return false;
 | |
|    setLastState(state, stateKey);
 | |
| 
 | |
|    // This should be sufficient for most objects that don't manage zones, and
 | |
|    //  don't need to return a specialized RenderImage...
 | |
|    if (mShapeInstance && state->isObjectRendered(this)) {
 | |
|       Point3F cameraOffset;
 | |
|       getRenderTransform().getColumn(3,&cameraOffset);
 | |
|       cameraOffset -= state->getCameraPosition();
 | |
|       F32 dist = cameraOffset.len();
 | |
|       if (dist < 0.01)
 | |
|          dist = 0.01;
 | |
|       F32 fogAmount = state->getHazeAndFog(dist,cameraOffset.z);
 | |
|       if (fogAmount>0.99f)
 | |
|          return false;
 | |
| 
 | |
|       F32 invScale = (1.0f/getMax(getMax(mObjScale.x,mObjScale.y),mObjScale.z));
 | |
|       DetailManager::selectPotentialDetails(mShapeInstance,dist,invScale);
 | |
|       if (mShapeInstance->getCurrentDetail()<0)
 | |
|          return false;
 | |
| 
 | |
|       if (mShapeInstance->hasSolid())
 | |
|       {
 | |
|          SceneRenderImage* image = new SceneRenderImage;
 | |
|          image->obj = this;
 | |
|          image->isTranslucent = false;
 | |
|          image->textureSortKey = mShapeHash;
 | |
|          state->insertRenderImage(image);
 | |
|       }
 | |
| 
 | |
|       if (mShapeInstance->hasTranslucency())
 | |
|       {
 | |
|          SceneRenderImage* image = new SceneRenderImage;
 | |
|          image->obj = this;
 | |
|          image->isTranslucent = true;
 | |
|          image->sortType = SceneRenderImage::Point;
 | |
|          image->textureSortKey = mShapeHash;
 | |
|          state->setImageRefPoint(this, image);
 | |
| 
 | |
|          state->insertRenderImage(image);
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| void TSStatic::setTransform(const MatrixF & mat)
 | |
| {
 | |
|    Parent::setTransform(mat);
 | |
| 
 | |
|    // Since the interior is a static object, it's render transform changes 1 to 1
 | |
|    //  with it's collision transform
 | |
|    setRenderTransform(mat);
 | |
| }
 | |
| 
 | |
| 
 | |
| void TSStatic::renderObject(SceneState* state, SceneRenderImage* image)
 | |
| {
 | |
|    AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
 | |
| 
 | |
|    if (!DetailManager::selectCurrentDetail(mShapeInstance))
 | |
|       // we were detailed out
 | |
|       return;
 | |
| 
 | |
|    RectI viewport;
 | |
|    glMatrixMode(GL_PROJECTION);
 | |
|    glPushMatrix();
 | |
|    dglGetViewport(&viewport);
 | |
| 
 | |
|    installLights();
 | |
| 
 | |
|    // Uncomment this if this is a "simple" (non-zone managing) object
 | |
|    state->setupObjectProjection(this);
 | |
| 
 | |
|    // This is something of a hack, but since the 3space objects don't have a
 | |
|    //  clear conception of texels/meter like the interiors do, we're sorta
 | |
|    //  stuck.  I can't even claim this is anything more scientific than eyeball
 | |
|    //  work.  DMM
 | |
|    F32 axis = (getObjBox().len_x() + getObjBox().len_y() + getObjBox().len_z()) / 3.0;
 | |
|    F32 dist = (getRenderWorldBox().getClosestPoint(state->getCameraPosition()) - state->getCameraPosition()).len();
 | |
|    if (dist != 0)
 | |
|    {
 | |
|       F32 projected = dglProjectRadius(dist, axis) / 25;
 | |
|       if (projected < (1.0 / 16.0))
 | |
|       {
 | |
|          TextureManager::setSmallTexturesActive(true);
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    glMatrixMode(GL_MODELVIEW);
 | |
|    glPushMatrix();
 | |
|    dglMultMatrix(&mObjToWorld);
 | |
|    glScalef(mObjScale.x, mObjScale.y, mObjScale.z);
 | |
| 
 | |
|    // RENDER CODE HERE
 | |
|    mShapeInstance->setEnvironmentMap(state->getEnvironmentMap());
 | |
|    mShapeInstance->setEnvironmentMapOn(true,1);
 | |
|    mShapeInstance->setAlphaAlways(1.0);
 | |
| 
 | |
|    Point3F cameraOffset;
 | |
|    mObjToWorld.getColumn(3,&cameraOffset);
 | |
|    cameraOffset -= state->getCameraPosition();
 | |
|    dist = cameraOffset.len();
 | |
|    F32 fogAmount = state->getHazeAndFog(dist,cameraOffset.z);
 | |
| 
 | |
|    if (image->isTranslucent == true)
 | |
|    {
 | |
|       TSShapeInstance::smNoRenderNonTranslucent = true;
 | |
|       TSShapeInstance::smNoRenderTranslucent    = false;
 | |
|    }
 | |
|    else
 | |
|    {
 | |
|       TSShapeInstance::smNoRenderNonTranslucent = false;
 | |
|       TSShapeInstance::smNoRenderTranslucent    = true;
 | |
|    }
 | |
| 
 | |
|    mShapeInstance->setupFog(fogAmount,state->getFogColor());
 | |
|    mShapeInstance->animate();
 | |
|    mShapeInstance->render();
 | |
| 
 | |
|    renderShadow(dist,fogAmount);
 | |
| 
 | |
|    TSShapeInstance::smNoRenderNonTranslucent = false;
 | |
|    TSShapeInstance::smNoRenderTranslucent    = false;
 | |
|    TextureManager::setSmallTexturesActive(false);
 | |
| 
 | |
|    glMatrixMode(GL_MODELVIEW);
 | |
|    glPopMatrix();
 | |
| 
 | |
|    uninstallLights();
 | |
|    dglSetCanonicalState();
 | |
| 
 | |
|    if (GameBase::gShowBoundingBox) {
 | |
|       glDisable(GL_DEPTH_TEST);
 | |
|       Point3F box;
 | |
|       glPushMatrix();
 | |
|       dglMultMatrix(&getTransform());
 | |
|       box = (mObjBox.min + mObjBox.max) * 0.5;
 | |
|       glTranslatef(box.x,box.y,box.z);
 | |
|       box = (mObjBox.max - mObjBox.min) * 0.5;
 | |
|       glScalef(box.x,box.y,box.z);
 | |
|       glColor3f(1, 0, 1);
 | |
|       ShapeBase::wireCube(Point3F(1,1,1),Point3F(0,0,0));
 | |
|       glPopMatrix();
 | |
| 
 | |
|       glPushMatrix();
 | |
|       box = (mWorldBox.min + mWorldBox.max) * 0.5;
 | |
|       glTranslatef(box.x,box.y,box.z);
 | |
|       box = (mWorldBox.max - mWorldBox.min) * 0.5;
 | |
|       glScalef(box.x,box.y,box.z);
 | |
|       glColor3f(0, 1, 1);
 | |
|       ShapeBase::wireCube(Point3F(1,1,1),Point3F(0,0,0));
 | |
|       glPopMatrix();
 | |
|       glEnable(GL_DEPTH_TEST);
 | |
|    }
 | |
| 
 | |
|    glMatrixMode(GL_PROJECTION);
 | |
|    glPopMatrix();
 | |
|    glMatrixMode(GL_MODELVIEW);
 | |
|    dglSetViewport(viewport);
 | |
| 
 | |
|    AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
 | |
| }
 | |
| 
 | |
| void TSStatic::renderShadow(F32 dist, F32 fogAmount)
 | |
| {
 | |
|    if (Shadow::getGlobalShadowDetailLevel()<StaticShape_NoShadowLevel)
 | |
|       return;
 | |
|    if (mShapeInstance->getShape()->subShapeFirstTranslucentObject.empty() || mShapeInstance->getShape()->subShapeFirstTranslucentObject[0]==0)
 | |
|       return;
 | |
| 
 | |
|    if (!mShadow)
 | |
|       mShadow = new Shadow();
 | |
|    mShadow->setGeneric(Shadow::getGlobalShadowDetailLevel() < StaticShape_GenericShadowLevel);
 | |
|    mShadow->setMoving(false);
 | |
|    mShadow->setAnimating(false);
 | |
| 
 | |
|    Point3F lightDir = gClientSceneGraph->getLightManager()->getShadowLightDirection();
 | |
| 
 | |
|    F32 shadowLen = 10.0f * mShapeInstance->getShape()->radius;
 | |
|    Point3F pos = mShapeInstance->getShape()->center;
 | |
| 
 | |
|    // this is a bit of a hack...move generic shadows towards feet/base of shape
 | |
|    if (Shadow::getGlobalShadowDetailLevel() < StaticShape_GenericShadowLevel)
 | |
|       pos *= 0.5f;
 | |
|    pos.convolve(mObjScale);
 | |
|    mObjToWorld.mulP(pos);
 | |
| 
 | |
|    // pos is where shadow will be centered (in world space)
 | |
|    mShadow->setRadius(mShapeInstance,mObjScale);
 | |
|    if (!mShadow->prepare(pos,lightDir,shadowLen,mObjScale,dist,fogAmount,mShapeInstance))
 | |
|       return;
 | |
| 
 | |
|    F32 maxScale = getMax(mObjScale.x,getMax(mObjScale.y,mObjScale.z));
 | |
| 
 | |
|    if (mShadow->needBitmap())
 | |
|    {
 | |
|       mShadow->beginRenderToBitmap();
 | |
|       mShadow->selectShapeDetail(mShapeInstance,dist,maxScale);
 | |
|       mShadow->renderToBitmap(mShapeInstance,mObjToWorld,pos,mObjScale);
 | |
|       mShadow->endRenderToBitmap();
 | |
|    }
 | |
| 
 | |
|    mShadow->render();
 | |
| }
 | |
| 
 | |
| U32 TSStatic::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
 | |
| {
 | |
|    U32 retMask = Parent::packUpdate(con, mask, stream);
 | |
| 
 | |
|    mathWrite(*stream, getTransform());
 | |
|    mathWrite(*stream, getScale());
 | |
|    stream->writeString(mShapeName);
 | |
| 
 | |
|    return retMask;
 | |
| }
 | |
| 
 | |
| 
 | |
| void TSStatic::unpackUpdate(NetConnection *con, BitStream *stream)
 | |
| {
 | |
|    Parent::unpackUpdate(con, stream);
 | |
| 
 | |
|    MatrixF mat;
 | |
|    Point3F scale;
 | |
|    mathRead(*stream, &mat);
 | |
|    mathRead(*stream, &scale);
 | |
|    setScale(scale);
 | |
|    setTransform(mat);
 | |
| 
 | |
|    mShapeName = stream->readSTString();
 | |
| }
 | |
| 
 | |
| 
 | |
| //--------------------------------------------------------------------------
 | |
| //----------------------------------------------------------------------------
 | |
| bool TSStatic::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
 | |
| {
 | |
|    if (mShapeInstance)
 | |
|    {
 | |
|       RayInfo shortest;
 | |
|       shortest.t = 1e8;
 | |
| 
 | |
|       info->object = NULL;
 | |
|       for (U32 i = 0; i < mLOSDetails.size(); i++)
 | |
|       {
 | |
|             mShapeInstance->animate(mLOSDetails[i]);
 | |
|          if (mShapeInstance->castRay(start, end, info, mLOSDetails[i]))
 | |
|          {
 | |
|                info->object = this;
 | |
|                if (info->t < shortest.t)
 | |
|                   shortest = *info;
 | |
|             }
 | |
|          }
 | |
| 
 | |
|       if (info->object == this) {
 | |
|          // Copy out the shortest time...
 | |
|          *info = shortest;
 | |
|          return true;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| //----------------------------------------------------------------------------
 | |
| bool TSStatic::buildPolyList(AbstractPolyList* polyList, const Box3F &, const SphereF &)
 | |
| {
 | |
|    if (mShapeInstance) {
 | |
|       bool ret = false;
 | |
| 
 | |
|       polyList->setTransform(&mObjToWorld, mObjScale);
 | |
|       polyList->setObject(this);
 | |
| 
 | |
|       for (U32 i = 0; i < mCollisionDetails.size(); i++)
 | |
|       {
 | |
|             mShapeInstance->buildPolyList(polyList, mCollisionDetails[i]);
 | |
|             ret = true;
 | |
|          }
 | |
| 
 | |
|       return ret;
 | |
|    }
 | |
| 
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| void TSStatic::buildConvex(const Box3F& box, Convex* convex)
 | |
| {
 | |
|    if (mShapeInstance == NULL)
 | |
|       return;
 | |
| 
 | |
|    // These should really come out of a pool
 | |
|    mConvexList->collectGarbage();
 | |
| 
 | |
|    Box3F realBox = box;
 | |
|    mWorldToObj.mul(realBox);
 | |
|    realBox.min.convolveInverse(mObjScale);
 | |
|    realBox.max.convolveInverse(mObjScale);
 | |
| 
 | |
|    if (realBox.isOverlapped(getObjBox()) == false)
 | |
|       return;
 | |
| 
 | |
|    for (U32 i = 0; i < mCollisionDetails.size(); i++)
 | |
|    {
 | |
|          // If there is no convex "accelerator" for this detail,
 | |
|          // there's nothing to collide with.
 | |
|          TSShape::ConvexHullAccelerator* pAccel =
 | |
|          mShapeInstance->getShape()->getAccelerator(mCollisionDetails[i]);
 | |
|          if (!pAccel || !pAccel->numVerts)
 | |
|             continue;
 | |
| 
 | |
|          // See if this hull exists in the working set already...
 | |
|          Convex* cc = 0;
 | |
|          CollisionWorkingList& wl = convex->getWorkingList();
 | |
|          for (CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext) {
 | |
|             if (itr->mConvex->getType() == TSStaticConvexType &&
 | |
|                 (static_cast<TSStaticConvex*>(itr->mConvex)->pStatic == this &&
 | |
|                  static_cast<TSStaticConvex*>(itr->mConvex)->hullId  == i)) {
 | |
|                cc = itr->mConvex;
 | |
|                break;
 | |
|             }
 | |
|          }
 | |
|          if (cc)
 | |
|             continue;
 | |
| 
 | |
|          // Create a new convex.
 | |
|          TSStaticConvex* cp = new TSStaticConvex;
 | |
|          mConvexList->registerObject(cp);
 | |
|          convex->addToWorkingList(cp);
 | |
|          cp->mObject    = this;
 | |
|          cp->pStatic    = this;
 | |
|          cp->hullId     = i;
 | |
|          cp->box        = mObjBox;
 | |
|          cp->findNodeTransform();
 | |
|    }
 | |
| }
 | |
| 
 | |
| 
 | |
| //--------------------------------------------------------------------------
 | |
| //--------------------------------------------------------------------------
 | |
| void TSStaticConvex::findNodeTransform()
 | |
| {
 | |
|    S32 dl = pStatic->mCollisionDetails[hullId];
 | |
| 
 | |
|    TSShapeInstance* si = pStatic->mShapeInstance;
 | |
|    TSShape* shape = si->getShape();
 | |
| 
 | |
|    const TSShape::Detail* detail = &shape->details[dl];
 | |
|    S32 subs = detail->subShapeNum;
 | |
|    S32 start = shape->subShapeFirstObject[subs];
 | |
|    S32 end = start + shape->subShapeNumObjects[subs];
 | |
| 
 | |
|    // Find the first object that contains a mesh for this
 | |
|    // detail level. There should only be one mesh per
 | |
|    // collision detail level.
 | |
|    for (S32 i = start; i < end; i++) {
 | |
|       const TSShape::Object* obj = &shape->objects[i];
 | |
|       if (obj->numMeshes && detail->objectDetailNum < obj->numMeshes) {
 | |
|          nodeTransform = &si->mNodeTransforms[obj->nodeIndex];
 | |
|          return;
 | |
|       }
 | |
|    }
 | |
|    return;
 | |
| }
 | |
| 
 | |
| const MatrixF& TSStaticConvex::getTransform() const
 | |
| {
 | |
|    // Multiply on the mesh shape offset
 | |
|    // tg: Returning this static here is not really a good idea, but
 | |
|    // all this Convex code needs to be re-organized.
 | |
|    if (nodeTransform) {
 | |
|       static MatrixF mat;
 | |
|       mat.mul(mObject->getTransform(),*nodeTransform);
 | |
|       return mat;
 | |
|    }
 | |
|    return mObject->getTransform();
 | |
| }
 | |
| 
 | |
| Box3F TSStaticConvex::getBoundingBox() const
 | |
| {
 | |
|    return getBoundingBox(mObject->getTransform(), mObject->getScale());
 | |
| }
 | |
| 
 | |
| Box3F TSStaticConvex::getBoundingBox(const MatrixF& mat, const Point3F& scale) const
 | |
| {
 | |
|    Box3F newBox = box;
 | |
|    newBox.min.convolve(scale);
 | |
|    newBox.max.convolve(scale);
 | |
|    mat.mul(newBox);
 | |
|    return newBox;
 | |
| }
 | |
| 
 | |
| Point3F TSStaticConvex::support(const VectorF& v) const
 | |
| {
 | |
|    TSShape::ConvexHullAccelerator* pAccel =
 | |
|       pStatic->mShapeInstance->getShape()->getAccelerator(pStatic->mCollisionDetails[hullId]);
 | |
|    AssertFatal(pAccel != NULL, "Error, no accel!");
 | |
| 
 | |
|    F32 currMaxDP = mDot(pAccel->vertexList[0], v);
 | |
|    U32 index = 0;
 | |
|    for (U32 i = 1; i < pAccel->numVerts; i++) {
 | |
|       F32 dp = mDot(pAccel->vertexList[i], v);
 | |
|       if (dp > currMaxDP) {
 | |
|          currMaxDP = dp;
 | |
|          index = i;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    return pAccel->vertexList[index];
 | |
| }
 | |
| 
 | |
| 
 | |
| void TSStaticConvex::getFeatures(const MatrixF& mat, const VectorF& n, ConvexFeature* cf)
 | |
| {
 | |
|    cf->material = 0;
 | |
|    cf->object = mObject;
 | |
| 
 | |
|    TSShape::ConvexHullAccelerator* pAccel =
 | |
|       pStatic->mShapeInstance->getShape()->getAccelerator(pStatic->mCollisionDetails[hullId]);
 | |
|    AssertFatal(pAccel != NULL, "Error, no accel!");
 | |
| 
 | |
|    F32 currMaxDP = mDot(pAccel->vertexList[0], n);
 | |
|    U32 index = 0;
 | |
|    U32 i;
 | |
|    for (i = 1; i < pAccel->numVerts; i++) {
 | |
|       F32 dp = mDot(pAccel->vertexList[i], n);
 | |
|       if (dp > currMaxDP) {
 | |
|          currMaxDP = dp;
 | |
|          index = i;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    const U8* emitString = pAccel->emitStrings[index];
 | |
|    U32 currPos = 0;
 | |
|    U32 numVerts = emitString[currPos++];
 | |
|    for (i = 0; i < numVerts; i++) {
 | |
|       cf->mVertexList.increment();
 | |
|       U32 index = emitString[currPos++];
 | |
|       mat.mulP(pAccel->vertexList[index], &cf->mVertexList.last());
 | |
|    }
 | |
| 
 | |
|    U32 numEdges = emitString[currPos++];
 | |
|    for (i = 0; i < numEdges; i++) {
 | |
|       U32 ev0 = emitString[currPos++];
 | |
|       U32 ev1 = emitString[currPos++];
 | |
|       cf->mEdgeList.increment();
 | |
|       cf->mEdgeList.last().vertex[0] = ev0;
 | |
|       cf->mEdgeList.last().vertex[1] = ev1;
 | |
|    }
 | |
| 
 | |
|    U32 numFaces = emitString[currPos++];
 | |
|    for (i = 0; i < numFaces; i++) {
 | |
|       cf->mFaceList.increment();
 | |
|       U32 plane = emitString[currPos++];
 | |
|       mat.mulV(pAccel->normalList[plane], &cf->mFaceList.last().normal);
 | |
|       for (U32 j = 0; j < 3; j++)
 | |
|          cf->mFaceList.last().vertex[j] = emitString[currPos++];
 | |
|    }
 | |
| }
 | |
| 
 | |
| 
 | |
| void TSStaticConvex::getPolyList(AbstractPolyList* list)
 | |
| {
 | |
|    list->setTransform(&pStatic->getTransform(), pStatic->getScale());
 | |
|    list->setObject(pStatic);
 | |
| 
 | |
|    pStatic->mShapeInstance->animate(pStatic->mCollisionDetails[hullId]);
 | |
|    pStatic->mShapeInstance->buildPolyList(list, pStatic->mCollisionDetails[hullId]);
 | |
| }
 | |
| 
 | |
| 
 | 
