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

📄 terrdata.cc

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

#include "terrain/terrData.h"
#include "dgl/dgl.h"
#include "dgl/gBitmap.h"
#include "dgl/gTexManager.h"
#include "dgl/materialList.h"
#include "dgl/materialPropertyMap.h"
#include "math/mMath.h"			
#include "math/mathIO.h"
#include "core/fileStream.h"
#include "core/bitStream.h"
#include "console/consoleTypes.h"
#include "sceneGraph/sceneGraph.h"
#include "sceneGraph/sceneState.h"
#include "sim/netConnection.h"
#include "terrain/terrRender.h"
#include "terrain/blender.h"




#ifdef TGE_RPG  /// TGE_Collision 地形的全局指针,通常,RPG只有一个地形便可
	TerrainBlock* g_pTerrainBlock = 0;
#endif

extern bool gDGLRender;

IMPLEMENT_CO_NETOBJECT_V1(TerrainBlock);

namespace 
{

void terrainTextureEventCB(const U32 eventCode, void *userData)
{
   TerrainBlock* pTerr = reinterpret_cast<TerrainBlock*>(userData);
   pTerr->processTextureEvent(eventCode);
}

Point3F sgTexGenS;
Point3F sgTexGenT;
Point3F sgLMGenS;
Point3F sgLMGenT;

} // namespace {}




//--------------------------------------
TerrainBlock::TerrainBlock()
{
   squareSize = 8;

   mBlender = NULL;
   lightMap = 0;

   for(S32 i = BlockShift; i >= 0; i--)
      gridMap[i] = NULL;

	mTerrFileName	= NULL; /// TGE_Map
#ifdef TGE_RPG /// TGE_TerrainScene
	mSceneFileName	= NULL;
#endif

   heightMap = NULL;
   materialMap = NULL;
   mBaseMaterialMap = NULL;
   mMaterialFileName = NULL;
   mTypeMask = TerrainObjectType | StaticObjectType | StaticRenderedObjectType;
   mNetFlags.set(Ghostable | ScopeAlways);
   mCollideEmpty = false;
   mDetailTextureName = NULL;

   mBumpTextureName = NULL;
	mBumpScale = 1.0;
	mBumpOffset = 0.01;
	mZeroBumpScale = 8;

#ifdef TGE_RPGCLIENT2//TGE_RPGClient2
   mCRC = 1;
#else
   mCRC = 0;
#endif
   flagMap = 0;
	mVertexBuffer = -1;
   mTile = true;
}


//--------------------------------------
TerrainBlock::~TerrainBlock()
{
   delete lightMap;
}


//--------------------------------------
void TerrainBlock::setFile(Resource<TerrainFile> terr)
{
   mFile = terr;
   for(U32 i = 0; i <= BlockShift; i++)
      gridMap[i] = mFile->mGridMap[i];

   mBaseMaterialMap = mFile->mBaseMaterialMap;
   mMaterialFileName= mFile->mMaterialFileName;
   mChunkMap = mFile->mChunkMap;
   materialMap = mFile->mMaterialMap;
   heightMap   = mFile->mHeightMap;
   flagMap = mFile->mFlagMap;
}

#ifdef TGE_RPG /// TGE_TerrainScene
void TerrainBlock::setScene(Resource<TerrainScene> scene)
{
	mTerrainScene = scene;
}
#endif

//--------------------------------------------------------------------------
bool TerrainBlock::save(const char *filename)
{
#ifdef TGE_RPG /// TGE_TerrainScene

	char *fn = dStrdup(filename);
   char* ext = dStrrchr(fn, '.');
   if (!ext || dStricmp(ext, ".sce") != 0)
	{  
		*ext = 0;
		dStrcat(fn, ".sce");
	}
	mTerrainScene->save(fn);
#endif

   return mFile->save(filename);
}


//--------------------------------------
static U16 calcDev(PlaneF &pl, Point3F &pt)
{
   F32 z = (pl.d + pl.x * pt.x + pl.y * pt.y) / -pl.z;
   F32 diff = z - pt.z;
   if(diff < 0)
      diff = -diff;

   if(diff > 0xFFFF)
      return 0xFFFF;
   else
      return U16(diff);
}

static U16 Umax(U16 u1, U16 u2)
{
   return u1 > u2 ? u1 : u2;
}

//------------------------------------------------------------------------------

bool TerrainBlock::unpackEmptySquares()
{
   U32 size = BlockSquareWidth * BlockSquareWidth;

   U32 i;
   for(i = 0; i < size; i++)
      materialMap[i].flags &= ~Material::Empty;

   // walk the pairs
   for(i = 0; i < mEmptySquareRuns.size(); i++)
   {
		/// TGE_Map
      U32 offset	= mEmptySquareRuns[i] & BlockSizeSquareMask;
      U32 run		= BlockMask&(U32(mEmptySquareRuns[i]) >> 16);
      //U32 offset = mEmptySquareRuns[i] & 0xffff;
      //U32 run		= U32(mEmptySquareRuns[i]) >> 16;

      //
      for(U32 j = 0; j < run; j++)
      {
         if((offset+j) >= size)
         {
            Con::errorf(ConsoleLogEntry::General, "TerrainBlock::unpackEmpties: invalid entry.");
            return(false);
         }
         materialMap[offset+j].flags |= Material::Empty;
      }
   }

   rebuildEmptyFlags();
   return(true);
}

void TerrainBlock::packEmptySquares()
{
   AssertFatal(isServerObject(), "TerrainBlock::packEmptySquares: client!");
   mEmptySquareRuns.clear();

   // walk the map
   U32 run = 0;
   U32 offset;

   U32 size = BlockSquareWidth * BlockSquareWidth;
   for(U32 i = 0; i < size; i++)
   {
      if(materialMap[i].flags & Material::Empty)
      {
         if(!run)
            offset = i;
         run++;
      }
      else if(run)
      {
         mEmptySquareRuns.push_back((run << 16) | offset);
         run = 0;

         // cap it
         if(mEmptySquareRuns.size() == MaxEmptyRunPairs)
            break;
      }
   }

   //
   if(run && mEmptySquareRuns.size() != MaxEmptyRunPairs)
      mEmptySquareRuns.push_back((run << 16) | offset);

   if(mEmptySquareRuns.size() == MaxEmptyRunPairs)
      Con::warnf(ConsoleLogEntry::General, "TerrainBlock::packEmptySquares: More than %d run pairs encountered.  Extras will not persist.", MaxEmptyRunPairs);

   //
   mNetFlags |= EmptyMask;
}

//------------------------------------------------------------------------------

void TerrainBlock::rebuildEmptyFlags()
{
   // rebuild entire maps empty flags!
   for(U32 y = 0; y < TerrainBlock::ChunkSquareWidth; y++)
   {
      for(U32 x = 0; x < TerrainBlock::ChunkSquareWidth; x++)
      {
         GridChunk &gc = *(mChunkMap + x + (y << TerrainBlock::ChunkShift));
         gc.emptyFlags = 0;
         U32 sx = x << TerrainBlock::ChunkDownShift;
         U32 sy = y << TerrainBlock::ChunkDownShift;
         for(U32 j = 0; j < 4; j++)
         {
            for(U32 i = 0; i < 4; i++)
            {
               TerrainBlock::Material *mat = getMaterial(sx + i, sy + j);
               if(mat->flags & TerrainBlock::Material::Empty)
                  gc.emptyFlags |= (1 << (j * 4 + i));
            }
         }
      }
   }

   for(S32 i = BlockShift; i >= 0; i--)
   {
      S32 squareCount = 1 << (BlockShift - i);
      S32 squareSize = (TerrainBlock::BlockSize) / squareCount;

      for(S32 squareX = 0; squareX < squareCount; squareX++)
      {
         for(S32 squareY = 0; squareY < squareCount; squareY++)
         {
            GridSquare *parent = NULL;
            if(i < BlockShift)
               parent = findSquare(i+1, Point2I(squareX * squareSize, squareY * squareSize));
            bool empty = true;

            for(S32 sizeX = 0; empty && sizeX <= squareSize; sizeX++)
            {
               for(S32 sizeY = 0; empty && sizeY <= squareSize; sizeY++)
               {
                  S32 x = squareX * squareSize + sizeX;
                  S32 y = squareY * squareSize + sizeY;

                  if(sizeX != squareSize && sizeY != squareSize)
                  {
                     TerrainBlock::Material *mat = getMaterial(x, y);
                     if(!(mat->flags & TerrainBlock::Material::Empty))
                        empty = false;
                  }
               }
            }
            GridSquare *sq = findSquare(i, Point2I(squareX * squareSize, squareY * squareSize));
            if(empty)
               sq->flags |= GridSquare::Empty;
            else
               sq->flags &= ~GridSquare::Empty;
         }
      }
   }
}

//------------------------------------------------------------------------------

void TerrainBlock::setHeight(const Point2I & pos, float height)
{
   // set the height
   U16 ht = floatToFixed(height);
   *((U16*)getHeightAddress(pos.x, pos.y)) = ht;
}


inline void getMinMax(U16 &min, U16 &max, U16 height)
{
   if(height < min)
      min = height;
   if(height > max)
      max = height;
}

inline void checkSquareMinMax(GridSquare *parent, GridSquare *child)
{
   if(parent->minHeight > child->minHeight)
      parent->minHeight = child->minHeight;
   if(parent->maxHeight < child->maxHeight)
      parent->maxHeight = child->maxHeight;
}

void TerrainBlock::updateGridMaterials(Point2I min, Point2I max)
{
   // ok:
   // build the chunk materials flags for all the chunks in the bounding rect
   // ((min - 1) >> ChunkDownShift) up to ((max + ChunkWidth) >> ChunkDownShift)

   // we have to make sure to cover boundary conditions as as stated above
   // since, for example, x = 0 affects 2 chunks

   for (S32 y = min.y - 1; y < max.y + 1; y++)
   {
      for (S32 x=min.x - 1; x < max.x + 1; x++)
      {
         GridSquare *sq = findSquare(0, Point2I(x, y));
         sq->flags &= (GridSquare::MaterialStart -1);
         S32 xpl = (x + 1) & TerrainBlock::BlockMask;
         S32 ypl = (y + 1) & TerrainBlock::BlockMask;
         for(U32 i = 0; i < TerrainBlock::MaterialGroups; i++)
         {
            if (mFile->mMaterialAlphaMap[i] != NULL) {
               U32 mapVal = (mFile->mMaterialAlphaMap[i][(y << TerrainBlock::BlockShift) + x]     |
                             mFile->mMaterialAlphaMap[i][(ypl << TerrainBlock::BlockShift) + x]   |
                             mFile->mMaterialAlphaMap[i][(ypl << TerrainBlock::BlockShift) + xpl] |
                             mFile->mMaterialAlphaMap[i][(y << TerrainBlock::BlockShift) + xpl]);
               if(mapVal)
                  sq->flags |= (GridSquare::MaterialStart << i);
            }
         }
      }
   }
   for (S32 y = min.y - 2; y < max.y + 2; y += 2)
   {
      for (S32 x= min.x - 2; x < max.x + 2; x += 2)
      {
         GridSquare *sq = findSquare(1, Point2I(x, y));
         GridSquare *s1 = findSquare(0, Point2I(x, y));
         GridSquare *s2 = findSquare(0, Point2I(x+1, y));
         GridSquare *s3 = findSquare(0, Point2I(x, y+1));
         GridSquare *s4 = findSquare(0, Point2I(x+1, y+1));
         sq->flags |= (s1->flags | s2->flags | s3->flags | s4->flags) & ~(GridSquare::MaterialStart -1);
      }
   }
   TerrainRender::flushCacheRect(RectI(min, max - min));
}

void TerrainBlock::updateGrid(Point2I min, Point2I max)
{
   // ok:
   // build the chunk deviance for all the chunks in the bounding rect,
   // ((min - 1) >> ChunkDownShift) up to ((max + ChunkWidth) >> ChunkDownShift)

   // update the chunk deviances for the affected chunks
   // we have to make sure to cover boundary conditions as as stated above
   // since, for example, x = 0 affects 2 chunks

   for(S32 x = (min.x - 1) >> ChunkDownShift;x < (max.x + ChunkSize) >> ChunkDownShift; x++)
   {
      for(S32 y = (min.y - 1) >> ChunkDownShift;y < (max.y + ChunkSize) >> ChunkDownShift; y++)
      {
         S32 px = x;
         S32 py = y;
         if(px < 0)
            px += BlockSize >> ChunkDownShift;
         if(py < 0)
            py += BlockSize >> ChunkDownShift;

         buildChunkDeviance(px, py);
      }
   }

   // ok the chunk deviances are rebuilt... now rebuild the affected area
   // of the grid map:

   // here's how it works:
   // for the current terrain renderer we only care about
   // the minHeight and maxHeight on the GridSquare
   // so we do one pass through, updating minHeight and maxHeight
   // on the level 0 squares, then we loop up the grid map from 1 to
   // the top, expanding the bounding boxes as necessary.
   // this should end up being way, way, way, way faster for the terrain
   // editor

   for(S32 y = min.y - 1; y < max.y + 1; y++)
   {
      for(S32 x = min.x - 1; x < max.x + 1; x++)
      {
         S32 px = x;
         S32 py = y;
         if(px < 0)
            px += BlockSize;

⌨️ 快捷键说明

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