📄 vmapmanager.cpp
字号:
}
}
return(height);
}
float VMapManager::getHeight(unsigned int mapid, LocationVector & vec)
{
float height = VMAP_INVALID_HEIGHT; //no height
if( m_maps[mapid] != NULL )
{
Vector3 pos = convertPositionToInternalRepMod(vec);
height = m_maps[mapid]->getHeight(pos);
if(!(height < inf()))
{
return VMAP_INVALID_HEIGHT;
}
}
return(height);
}
//=========================================================
//=========================================================
//=========================================================
MapTree::MapTree(const char* pBaseDir)
{
iBasePath = std::string(pBaseDir);
if(iBasePath.length() > 0 && (iBasePath[iBasePath.length()-1] != '/' || iBasePath[iBasePath.length()-1] != '\\'))
{
iBasePath.append("/");
}
iTree = new AABSPTree<ModelContainer *>();
}
//=========================================================
MapTree::~MapTree()
{
Array<ModelContainer *> mcArray;
iTree->getMembers(mcArray);
int no = mcArray.size();
while(no >0)
{
--no;
delete mcArray[no];
}
delete iTree;
}
//=========================================================
// just for visual debugging with an external debug class
#ifdef _DEBUG_VMAPS
#ifndef gBoxArray
extern Vector3 p1,p2,p3,p4,p5,p6,p7;
extern Array<AABox>gBoxArray;
extern int gCount1, gCount2, gCount3, gCount4;
extern bool myfound;
#endif
#endif
typedef AABSPTree<ModelContainer*>::RayIntersectionIterator IT;
//=========================================================
/**
return dist to hit or inf() if no hit
*/
float MapTree::getIntersectionTime(const Ray& pRay, float pMaxDist, bool pStopAtFirstHit)
{
double firstDistance = inf();
const IT end = iTree->endRayIntersection();
IT obj = iTree->beginRayIntersection(pRay, pMaxDist);
for ( ;obj != end; ++obj) // (preincrement is *much* faster than postincrement!)
{
/*
Call your accurate intersection test here. It is guaranteed
that the ray hits the bounding box of obj. (*obj) has type T,
so you can call methods directly using the "->" operator.
*/
ModelContainer *model = static_cast<ModelContainer*>(*obj);
float t = model->getIntersectionTime(pRay, pStopAtFirstHit, pMaxDist);
// just for visual debugging with an external debug class
#ifdef _DEBUG_VMAPS
if(gCount3 == gCount1)
{
AABox testBox;
testBox = model->getAABoxBounds();
gBoxArray.append(testBox);
}
++gCount3;
#endif
if(t > 0 && t < inf())
{
obj.markBreakNode();
if(firstDistance > t && pMaxDist >= t)
{
firstDistance = t;
if(pStopAtFirstHit) break;
}
}
}
return firstDistance;
}
//=========================================================
bool MapTree::isInLineOfSight(const Vector3& pos1, const Vector3& pos2)
{
bool result = true;
float maxDist = abs((pos2 - pos1).magnitude());
// direction with length of 1
Ray ray = Ray::fromOriginAndDirection(pos1, (pos2 - pos1)/maxDist);
if(getIntersectionTime(ray, maxDist, true) < inf())
{
result = false;
}
return result;
}
//=========================================================
/**
When moving from pos1 to pos2 check if we hit an object. Return true and the position if we hit one
Return the hit pos or the original dest pos
*/
bool MapTree::getObjectHitPos(const Vector3& pPos1, const Vector3& pPos2, Vector3& pResultHitPos, float pModifyDist)
{
bool result;
float maxDist = abs((pPos2 - pPos1).magnitude());
Vector3 dir = (pPos2 - pPos1)/maxDist; // direction with length of 1
Ray ray = Ray::fromOriginAndDirection(pPos1, dir);
float dist = getIntersectionTime(ray, maxDist, false);
if(dist < inf())
{
pResultHitPos = pPos1 + dir * dist;
if(pModifyDist < 0)
{
if(abs((pResultHitPos - pPos1).magnitude()) > -pModifyDist)
{
pResultHitPos = pResultHitPos + dir*pModifyDist;
}
else
{
pResultHitPos = pPos1;
}
}
else
{
pResultHitPos = pResultHitPos + dir*pModifyDist;
}
result = true;
}
else
{
pResultHitPos = pPos2;
result = false;
}
return result;
}
//=========================================================
float MapTree::getHeight(const Vector3& pPos)
{
float height = inf();
Vector3 dir = Vector3(0,-1,0);
Ray ray = Ray::fromOriginAndDirection(pPos, dir); // direction with length of 1
float dist = getIntersectionTime(ray, MAX_CAN_FALL_DISTANCE, false);
if(dist < inf())
{
height = (pPos + dir * dist).y;
}
return(height);
}
//=========================================================
bool MapTree::isInDoors(const Vector3& pos)
{
Vector3 dir = Vector3(0,-1,0);
Ray ray = Ray::fromOriginAndDirection(pos, dir); // direction with length of 1
unsigned int flags;
AABSPTree<ModelContainer*>::RayIntersectionIterator MITR;
AABSPTree<ModelContainer*>::RayIntersectionIterator MITREND;
RayIntersectionIterator<TreeNode, SubModel> SMITR;
RayIntersectionIterator<TreeNode, SubModel> SMITREND;
ModelContainer * mc;
SubModel * sm;
MITR = iTree->beginRayIntersection( ray, MAX_CAN_FALL_DISTANCE );
MITREND = iTree->endRayIntersection();
for(; MITR != MITREND; ++MITR)
{
mc = ((ModelContainer*)*MITR);
Ray relativeRay = Ray::fromOriginAndDirection(ray.origin - mc->getBasePosition(), ray.direction);
SMITR = mc->beginRayIntersection( relativeRay, MAX_CAN_FALL_DISTANCE );
SMITREND = mc->endRayIntersection();
for( ; SMITR != SMITREND; ++SMITR )
{
sm = ((SubModel*)&(*SMITR));
#if 0
if( sm->getIndoorFlag() != 0 )
{
unsigned int i = sm->getIndoorFlag();
printf("=========================================================\n");
printf("Model indoor flags: %u\n", sm->getIndoorFlag());
unsigned int z, b;
for(z = 1, b = 1; b < 32;)
{
if(i & z)
printf(" Bit %u (0x%.8X or %u) is set!\n", b, z, z);
z <<= 1;
b+=1;
}
printf("=========================================================\n");
}
#else
flags = sm->getIndoorFlag();
if( flags != 0 )
{
/* From WoWdev:
Flag Meaning
0x1 Always set
0x4 Has vertex colors (MOCV chunk)
0x8 Outdoor
0x200 Has lights (MOLR chunk)
0x800 Has doodads (MODR chunk)
0x1000 Has water (MLIQ chunk)
0x2000 Indoor
0x40000 Show skybox
**********************
0x8000 seems to be set in the areas in citys (while it has the indoor flag, its not
an indoor area
*/
if( flags & 0x2000 && !(flags & 0x8000) && !(flags & 0x8) )
return true;
}
#endif
}
}
return false;
}
bool MapTree::isOutDoors(const Vector3& pos)
{
Vector3 dir = Vector3(0,-1,0);
Ray ray = Ray::fromOriginAndDirection(pos, dir); // direction with length of 1
unsigned int flags;
AABSPTree<ModelContainer*>::RayIntersectionIterator MITR;
AABSPTree<ModelContainer*>::RayIntersectionIterator MITREND;
RayIntersectionIterator<TreeNode, SubModel> SMITR;
RayIntersectionIterator<TreeNode, SubModel> SMITREND;
ModelContainer * mc;
SubModel * sm;
MITR = iTree->beginRayIntersection( ray, MAX_CAN_FALL_DISTANCE );
MITREND = iTree->endRayIntersection();
for(; MITR != MITREND; ++MITR)
{
mc = ((ModelContainer*)*MITR);
Ray relativeRay = Ray::fromOriginAndDirection(ray.origin - mc->getBasePosition(), ray.direction);
SMITR = mc->beginRayIntersection( relativeRay, MAX_CAN_FALL_DISTANCE );
SMITREND = mc->endRayIntersection();
for( ; SMITR != SMITREND; ++SMITR )
{
sm = ((SubModel*)&(*SMITR));
#if 0
if( sm->getIndoorFlag() != 0 )
{
unsigned int i = sm->getIndoorFlag();
printf("=========================================================\n");
printf("Model indoor flags: %u\n", sm->getIndoorFlag());
unsigned int z, b;
for(z = 1, b = 1; b < 32;)
{
if(i & z)
printf(" Bit %u (0x%.8X or %u) is set!\n", b, z, z);
z <<= 1;
b+=1;
}
printf("=========================================================\n");
}
#else
flags = sm->getIndoorFlag();
if( flags != 0 )
{
/* From WoWdev:
Flag Meaning
0x1 Always set
0x4 Has vertex colors (MOCV chunk)
0x8 Outdoor
0x200 Has lights (MOLR chunk)
0x800 Has doodads (MODR chunk)
0x1000 Has water (MLIQ chunk)
0x2000 Indoor
0x40000 Show skybox
**********************
0x8000 seems to be set in the areas in citys (while it has the indoor flag, its not
an indoor area
*/
if( !(flags & 0x8) )
return false;
}
#endif
}
}
return true;
}
//=========================================================
bool MapTree::loadMap(const std::string& pDirFileName, unsigned int pMapTileIdent)
{
bool result = true;
size_t len = iBasePath.length() + pDirFileName.length();
char *filenameBuffer = new char[len+1];
if(!hasDirFile(pDirFileName))
{
FilesInDir filesInDir;
result = false;
sprintf(filenameBuffer, "%s%s", iBasePath.c_str(), pDirFileName.c_str());
FILE* df = fopen(filenameBuffer, "rb");
if(df)
{
char lineBuffer[FILENAMEBUFFER_SIZE];
result = true;
bool newModelLoaded = false;
while(result && (fgets(lineBuffer, FILENAMEBUFFER_SIZE-1, df) != 0))
{
std::string name = std::string(lineBuffer);
chomp(name);
if(name.length() >1)
{
filesInDir.append(name);
ManagedModelContainer *mc;
if(!isAlreadyLoaded(name))
{
std::string fname = iBasePath;
fname.append(name);
mc = new ManagedModelContainer();
result = mc->readFile(fname.c_str());
if(result)
{
addModelConatiner(name, mc);
newModelLoaded = true;
}
else
delete mc;
}
else
{
mc = getModelContainer(name);
}
mc->incRefCount();
}
}
if(result && newModelLoaded)
{
iTree->balance();
}
if(result && ferror(df) != 0)
{
result = false;
}
fclose(df);
if(result)
{
filesInDir.incRefCount();
addDirFile(pDirFileName, filesInDir);
setLoadedMapTile(pMapTileIdent);
}
}
}
else
{
// Already loaded, so just inc. the ref count if mapTileIdent is new
if(!containsLoadedMapTile(pMapTileIdent))
{
setLoadedMapTile(pMapTileIdent);
FilesInDir& filesInDir = getDirFiles(pDirFileName);
filesInDir.incRefCount();
}
}
delete [] filenameBuffer;
return (result);
}
//=========================================================
void MapTree::unloadMap(const std::string& dirFileName, unsigned int pMapTileIdent)
{
if(hasDirFile(dirFileName) && containsLoadedMapTile(pMapTileIdent))
{
removeLoadedMapTile(pMapTileIdent);
FilesInDir& filesInDir = getDirFiles(dirFileName);
filesInDir.decRefCount();
if(filesInDir.getRefCount() <= 0)
{
Array<std::string> fileNames = filesInDir.getFiles();
bool treeChanged = false;
for(int i=0; i<fileNames.size(); ++i)
{
std::string name = fileNames[i];
ManagedModelContainer* mc = getModelContainer(name);
mc->decRefCount();
if(mc->getRefCount() <= 0)
{
iLoadedModelContainer.remove(name);
iTree->remove(mc);
delete mc;
treeChanged = true;
}
}
iLoadedDirFiles.remove(dirFileName);
if(treeChanged)
{
iTree->balance();
}
}
}
}
//=========================================================
//=========================================================
void MapTree::addModelConatiner(const std::string& pName, ManagedModelContainer *pMc)
{
iLoadedModelContainer.set(pName, pMc);
iTree->insert(pMc);
}
//=========================================================
//=========================================================
//=========================================================
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -