⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sceneobject.cc

📁 五行MMORPG引擎系统V1.0
💻 CC
📖 第 1 页 / 共 5 页
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------

#include "sim/sceneObject.h"
#include "sceneGraph/sceneGraph.h"
#include "console/consoleTypes.h"
#include "collision/extrudedPolyList.h"
#include "collision/earlyOutPolyList.h"
#include "platform/profiler.h"

#include "platform/profiler.h"
#include "interior/interior.h"
#include "interior/interiorInstance.h"
#include "terrain/terrData.h"
#include "dgl/gBitmap.h"
#include "dgl/dgl.h"

IMPLEMENT_CONOBJECT(SceneObject);

const U32 Container::csmNumBins = 16;
const F32 Container::csmBinSize = 64;
const F32 Container::csmTotalBinSize = Container::csmBinSize * Container::csmNumBins;
U32       Container::smCurrSeqKey = 1;
const U32 Container::csmRefPoolBlockSize = 4096;

// Statics used by buildPolyList methods
AbstractPolyList* sPolyList;
SphereF sBoundingSphere;
Box3F sBoundingBox;

// Statics used by collide methods
ExtrudedPolyList sExtrudedPolyList;
Polyhedron sBoxPolyhedron;

//--------------------------------------------------------------------------
//-------------------------------------- Console callbacks
//

ConsoleMethod( SceneObject, getTransform, const char*, 2, 2, "Get transform of object.")
{
   char *returnBuffer = Con::getReturnBuffer(256);
   const MatrixF& mat = object->getTransform();
   Point3F pos;
   mat.getColumn(3,&pos);
   AngAxisF aa(mat);
   dSprintf(returnBuffer,256,"%g %g %g %g %g %g %g",
            pos.x,pos.y,pos.z,aa.axis.x,aa.axis.y,aa.axis.z,aa.angle);
   return returnBuffer;
}

ConsoleMethod( SceneObject, getPosition, const char*, 2, 2, "Get position of object.")
{
   char *returnBuffer = Con::getReturnBuffer(256);
   const MatrixF& mat = object->getTransform();
   Point3F pos;
   mat.getColumn(3,&pos);
   dSprintf(returnBuffer,256,"%g %g %g",pos.x,pos.y,pos.z);
   return returnBuffer;
}

ConsoleMethod( SceneObject, getForwardVector, const char*, 2, 2, "Returns a vector indicating the direction this object is facing.")
{
   char *returnBuffer = Con::getReturnBuffer(256);
   const MatrixF& mat = object->getTransform();
   Point3F dir;
   mat.getColumn(1,&dir);
   dSprintf(returnBuffer,256,"%g %g %g",dir.x,dir.y,dir.z);
   return returnBuffer;
}

ConsoleMethod( SceneObject, setTransform, void, 3, 3, "(Transform T)")
{
   Point3F pos;
   const MatrixF& tmat = object->getTransform();
   tmat.getColumn(3,&pos);
   AngAxisF aa(tmat);

   dSscanf(argv[2],"%g %g %g %g %g %g %g",
           &pos.x,&pos.y,&pos.z,&aa.axis.x,&aa.axis.y,&aa.axis.z,&aa.angle);

   MatrixF mat;
   aa.setMatrix(&mat);
   mat.setColumn(3,pos);
   object->setTransform(mat);
}

ConsoleMethod( SceneObject, getScale, const char*, 2, 2, "Get scaling as a Point3F.")
{
   char *returnBuffer = Con::getReturnBuffer(256);
   const VectorF & scale = object->getScale();
   dSprintf(returnBuffer, 256, "%g %g %g",
            scale.x, scale.y, scale.z);
   return(returnBuffer);
}

ConsoleMethod( SceneObject, setScale, void, 3, 3, "(Point3F scale)")
{
   VectorF scale(0.f,0.f,0.f);
   dSscanf(argv[2], "%g %g %g", &scale.x, &scale.y, &scale.z);
   object->setScale(scale);
}

ConsoleMethod( SceneObject, getWorldBox, const char*, 2, 2, "Returns six fields, two Point3Fs, containing the min and max points of the worldbox.")
{
   char *returnBuffer = Con::getReturnBuffer(256);
   const Box3F& box = object->getWorldBox();
   dSprintf(returnBuffer,256,"%g %g %g %g %g %g",
            box.min.x, box.min.y, box.min.z,
            box.max.x, box.max.y, box.max.z);
   return returnBuffer;
}

ConsoleMethod( SceneObject, getWorldBoxCenter, const char*, 2, 2, "Returns the center of the world bounding box.")
{
   char *returnBuffer = Con::getReturnBuffer(256);
   const Box3F& box = object->getWorldBox();
   Point3F center;
   box.getCenter(&center);

   dSprintf(returnBuffer,256,"%g %g %g", center.x, center.y, center.z);
   return returnBuffer;
}

ConsoleMethod( SceneObject, getObjectBox, const char *, 2, 2, "Returns the bounding box relative to the object's origin.")
{
   char *returnBuffer = Con::getReturnBuffer(256);
   const Box3F& box = object->getObjBox();
   dSprintf(returnBuffer,256,"%g %g %g %g %g %g",
            box.min.x, box.min.y, box.min.z,
            box.max.x, box.max.y, box.max.z);
   return returnBuffer;
}

ConsoleFunctionGroupBegin( Containers,  "Functions for ray casting and spatial queries.\n\n"
                                        "@note These only work server-side.");

ConsoleFunction(containerBoxEmpty, bool, 4, 6, "(bitset mask, Point3F center, float xRadius, float yRadius, float zRadius)"
               "See if any objects of given types are present in box of given extent.\n\n"
               "@note Extent parameter is last since only one radius is often needed. If one radius is provided, "
               "the yRadius and zRadius are assumed to be the same.\n"
               "@param  mask   Indicates the type of objects we are checking against.\n"
               "@param  center Center of box.\n"
               "@param  xRadius See above.\n"
               "@param  yRadius See above.\n"
               "@param  zRadius See above.")
{
   Point3F  center;
   Point3F  extent;
   U32      mask = dAtoi(argv[1]);
   dSscanf(argv[2], "%g %g %g", &center.x, &center.y, &center.z);
   extent.x = dAtof(argv[3]);
   extent.y = argc > 4 ? dAtof(argv[4]) : extent.x;
   extent.z = argc > 5 ? dAtof(argv[5]) : extent.x;

   Box3F    B(center - extent, center + extent, true);

   EarlyOutPolyList polyList;
   polyList.mPlaneList.clear();
   polyList.mNormal.set(0,0,0);
   polyList.mPlaneList.setSize(6);
   polyList.mPlaneList[0].set(B.min, VectorF(-1,0,0));
   polyList.mPlaneList[1].set(B.max, VectorF(0,1,0));
   polyList.mPlaneList[2].set(B.max, VectorF(1,0,0));
   polyList.mPlaneList[3].set(B.min, VectorF(0,-1,0));
   polyList.mPlaneList[4].set(B.min, VectorF(0,0,-1));
   polyList.mPlaneList[5].set(B.max, VectorF(0,0,1));

   return ! gServerContainer.buildPolyList(B, mask, &polyList);
}

ConsoleFunction( initContainerRadiusSearch, void, 4, 4, "(Point3F pos, float radius, bitset mask)"
                "Start a search for items within radius of pos, filtering by bitset mask.")
{
   F32 x, y, z;
   dSscanf(argv[1], "%g %g %g", &x, &y, &z);
   F32 r = dAtof(argv[2]);
   U32 mask = dAtoi(argv[3]);

   gServerContainer.initRadiusSearch(Point3F(x, y, z), r, mask);
}

ConsoleFunction( containerSearchNext, S32, 1, 1, "Get next item from a search started with initContainerRadiusSearch.")
{
   return gServerContainer.containerSearchNext();
}

ConsoleFunction( containerSearchCurrDist, F32, 1, 1, "Get distance of the center of the current item from the center of the current initContainerRadiusSearch.")
{
   return gServerContainer.containerSearchCurrDist();
}

ConsoleFunction( containerSearchCurrRadiusDist, F32, 1, 1, "Get the distance of the closest point of the current item from the center of the current initContainerRadiusSearch.")
{
   return gServerContainer.containerSearchCurrRadiusDist();
}

ConsoleFunction( containerRayCast, const char*, 4, 5, "( Point3F start, Point3F end, bitset mask, SceneObject exempt=NULL )"
                "Cast a ray from start to end, checking for collision against items matching mask.\n\n"
                "If exempt is specified, then it is temporarily excluded from collision checks (For "
                "instance, you might want to exclude the player if said player was firing a weapon.)\n"
                "@returns A string containing either null, if nothing was struck, or these fields:\n"
                "            - The ID of the object that was struck.\n"
                "            - The x, y, z position that it was struck.\n"
                "            - The x, y, z of the normal of the face that was struck.")
{
   char *returnBuffer = Con::getReturnBuffer(256);
   Point3F start, end;
   dSscanf(argv[1], "%g %g %g", &start.x, &start.y, &start.z);
   dSscanf(argv[2], "%g %g %g", &end.x,   &end.y,   &end.z);
   U32 mask = dAtoi(argv[3]);

   SceneObject* pExempt = NULL;
   if (argc > 4) {
      U32 exemptId = dAtoi(argv[4]);
      Sim::findObject(exemptId, pExempt);
   }
   if (pExempt)
      pExempt->disableCollision();

   RayInfo rinfo;
   S32 ret = 0;
   if (gServerContainer.castRay(start, end, mask, &rinfo) == true)
      ret = rinfo.object->getId();

   if (pExempt)
      pExempt->enableCollision();

   // add the hit position and normal?
   if(ret)
   {
      dSprintf(returnBuffer, 256, "%d %g %g %g %g %g %g",
               ret, rinfo.point.x, rinfo.point.y, rinfo.point.z,
               rinfo.normal.x, rinfo.normal.y, rinfo.normal.z);
   }
   else
   {
      returnBuffer[0] = '0';
      returnBuffer[1] = '\0';
   }

   return(returnBuffer);
}

ConsoleFunctionGroupEnd( Containers );

// Utility method for bin insertion
void getBinRange(const F32 min,
                 const F32 max,
                 U32&      minBin,
                 U32&      maxBin)
{
   AssertFatal(max >= min, "Error, bad range! in getBinRange");

   if ((max - min) > Container::csmTotalBinSize) {
      F32 minCoord = mFmod(min, Container::csmTotalBinSize);
      if (minCoord < 0.0f) {
         minCoord += Container::csmTotalBinSize;

         // This is truly lame, but it can happen.  There must be a better way to
         //  deal with this.
         if (minCoord == Container::csmTotalBinSize)
            minCoord = Container::csmTotalBinSize - 0.01;
      }
      AssertFatal(minCoord >= 0.0 && minCoord < Container::csmTotalBinSize, "Bad minCoord");

      minBin = U32(minCoord / Container::csmBinSize);
      AssertFatal(minBin < Container::csmNumBins, avar("Error, bad clipping! (%g, %d)", minCoord, minBin));

      maxBin = minBin + (Container::csmNumBins - 1);
      return;
   } else {

      F32 minCoord = mFmod(min, Container::csmTotalBinSize);
      if (minCoord < 0.0f) {
         minCoord += Container::csmTotalBinSize;

         // This is truly lame, but it can happen.  There must be a better way to
         //  deal with this.
         if (minCoord == Container::csmTotalBinSize)
            minCoord = Container::csmTotalBinSize - 0.01;
      }
      AssertFatal(minCoord >= 0.0 && minCoord < Container::csmTotalBinSize, "Bad minCoord");

      F32 maxCoord = mFmod(max, Container::csmTotalBinSize);
      if (maxCoord < 0.0f) {
         maxCoord += Container::csmTotalBinSize;

         // This is truly lame, but it can happen.  There must be a better way to
         //  deal with this.
         if (maxCoord == Container::csmTotalBinSize)
            maxCoord = Container::csmTotalBinSize - 0.01;
      }
      AssertFatal(maxCoord >= 0.0 && maxCoord < Container::csmTotalBinSize, "Bad maxCoord");

      minBin = U32(minCoord / Container::csmBinSize);
      maxBin = U32(maxCoord / Container::csmBinSize);
      AssertFatal(minBin < Container::csmNumBins, avar("Error, bad clipping(min)! (%g, %d)", maxCoord, minBin));
      AssertFatal(minBin < Container::csmNumBins, avar("Error, bad clipping(max)! (%g, %d)", maxCoord, maxBin));

      // MSVC6 seems to be generating some bad floating point code around
      // here when full optimizations are on.  The min != max test should
      // not be needed, but it clears up the VC issue.
      if (min != max && minCoord > maxCoord)
         maxBin += Container::csmNumBins;

      AssertFatal(maxBin >= minBin, "Error, min should always be less than max!");
   }
}


//--------------------------------------------------------------------------
//-------------------------------------- SceneObject implementation
//
LightInfo SceneObject::LightingInfo::smAmbientLight;

SceneObject::SceneObject()
{
   mContainer = 0;
   mTypeMask = DefaultObjectType;
   mCollisionCount = 0;
   mGlobalBounds = false;

   mObjScale.set(1,1,1);
   mObjToWorld.identity();
   mWorldToObj.identity();

   mObjBox      = Box3F(Point3F(0, 0, 0), Point3F(0, 0, 0));
   mWorldBox    = Box3F(Point3F(0, 0, 0), Point3F(0, 0, 0));
   mWorldSphere = SphereF(Point3F(0, 0, 0), 0);

   mRenderObjToWorld.identity();
   mRenderWorldToObj.identity();
   mRenderWorldBox = Box3F(Point3F(0, 0, 0), Point3F(0, 0, 0));
   mRenderWorldSphere = SphereF(Point3F(0, 0, 0), 0);

   mContainerSeqKey = 0;

   mBinRefHead  = NULL;

   mSceneManager     = NULL;
   mZoneRangeStart   = 0xFFFFFFFF;

   mNumCurrZones = 0;
   mZoneRefHead = NULL;

   mLastState    = NULL;
   mLastStateKey = 0;

   mBinMinX = 0xFFFFFFFF;
   mBinMaxX = 0xFFFFFFFF;
   mBinMinY = 0xFFFFFFFF;
   mBinMaxY = 0xFFFFFFFF;
}

SceneObject::~SceneObject()
{
   AssertFatal(mZoneRangeStart == 0xFFFFFFFF && mSceneManager == NULL,
               "Error, SceneObject not properly removed from sceneGraph");
   AssertFatal(mZoneRefHead == NULL && mBinRefHead == NULL,
               "Error, still linked in reference lists!");

   unlink();
}

//----------------------------------------------------------------------------
const char* SceneObject::scriptThis()
{
   return Con::getIntArg(getId());
}


//--------------------------------------------------------------------------
void SceneObject::buildConvex(const Box3F&, Convex*)
{
   return;
}

bool SceneObject::buildPolyList(AbstractPolyList*, const Box3F&, const SphereF&)
{
   return false;
}

BSPNode *SceneObject::buildCollisionBSP(BSPTree*, const Box3F&, const SphereF&)
{
   return NULL;
}

bool SceneObject::castRay(const Point3F&, const Point3F&, RayInfo*)
{
   return false;
}

bool SceneObject::collideBox(const Point3F &start, const Point3F &end, RayInfo *info)
{
   const F32 * pStart = (const F32*)start;
   const F32 * pEnd = (const F32*)end;
   const F32 * pMin = (const F32*)mObjBox.min;
   const F32 * pMax = (const F32*)mObjBox.max;

   F32 maxStartTime = -1;
   F32 minEndTime = 1;
   F32 startTime;
   F32 endTime;

   // used for getting normal
   U32 hitIndex;
   U32 side;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -