This commit is contained in:
TheLuda 2008-10-14 00:29:20 +02:00
parent d767495d5b
commit 800ee76535
3322 changed files with 903437 additions and 0 deletions

1620
src/shared/vmap/AABSPTree.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,95 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "BaseModel.h"
#include "VMapTools.h"
using namespace G3D;
namespace VMAP
{
//==========================================================
void BaseModel::getMember(Array<TriangleBox>& pMembers)
{
for(unsigned int i=0; i<iNTriangles; i++)
{
pMembers.append(iTriangles[i]);
}
}
//==========================================================
BaseModel::BaseModel(unsigned int pNNodes, unsigned int pNTriangles)
{
init(pNNodes, pNTriangles);
};
//==========================================================
void BaseModel::init(unsigned int pNNodes, unsigned int pNTriangles)
{
iNNodes = pNNodes;
iNTriangles = pNTriangles;
iTriangles = 0;
iTreeNodes = 0;
if(iNNodes >0) iTreeNodes = new TreeNode[iNNodes];
if(iNTriangles >0) iTriangles = new TriangleBox[iNTriangles];
}
//==========================================================
void BaseModel::free()
{
if(getTriangles() != 0) delete [] getTriangles(); setNTriangles(0);
if(getTreeNodes() != 0) delete [] getTreeNodes(); setNNodes(0);
}
//==========================================================
void BaseModel::intersect(const G3D::AABox& pBox, const G3D::Ray& pRay, float& pMaxDist, G3D::Vector3& pOutLocation, G3D::Vector3& /*pOutNormal*/) const
{
bool isInside = false;
float d = MyCollisionDetection::collisionLocationForMovingPointFixedAABox(
pRay.origin, pRay.direction,
pBox,
pOutLocation, isInside);
if (!isInside && ((d > 0) && (d < pMaxDist)))
{
pMaxDist = d;
}
}
//==========================================================
bool BaseModel::intersect(const G3D::AABox& pBox, const G3D::Ray& pRay, float& pMaxDist) const
{
// See if the ray will ever hit this node or its children
Vector3 location;
bool alreadyInsideBounds = false;
bool rayWillHitBounds =
MyCollisionDetection::collisionLocationForMovingPointFixedAABox(
pRay.origin, pRay.direction, pBox, location, alreadyInsideBounds);
bool canHitThisNode = (alreadyInsideBounds ||
(rayWillHitBounds && ((location - pRay.origin).squaredLength() < (pMaxDist * pMaxDist))));
return canHitThisNode;
}
} // VMAP

View file

@ -0,0 +1,99 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _BASEMODEL_H_
#define _BASEMODEL_H_
#include <G3D/AABox.h>
#include <G3D/Vector3.h>
#include "ShortVector.h"
#include "ShortBox.h"
#include "TreeNode.h"
/**
A model is based on triangles. To be able to check intersection we need a BSP-Tree.
This Class holds the array of triangles as well as the management information for the BSP-Tree.
Both are stored in static array and index information is used instead of pointers.
Therefore we can load the whole object as a binary block.
The vectors are relative to a base position.
*/
namespace VMAP
{
class BaseModel
{
protected:
TriangleBox *iTriangles;
TreeNode *iTreeNodes;
unsigned int iNTriangles;
unsigned int iNNodes;
G3D::Vector3 iBasePosition;
public:
BaseModel() { iNTriangles = 0; iNNodes = 0; iTriangles = 0; iTreeNodes = 0;};
BaseModel(unsigned int pNNodes , TreeNode* pTreeNode, unsigned int pNTriangles, TriangleBox* pTriangleBox)
{
iNNodes = pNNodes; iNTriangles = pNTriangles; iTriangles = pTriangleBox; iTreeNodes = pTreeNode;
};
BaseModel(unsigned int pNNodes, unsigned int pNTriangles);
// destructor does nothing ! The subclass controles the array memory and knows when to free it
~BaseModel() {}
void free();
void init(unsigned int pNNodes, unsigned int pNTriangles);
void getMember(G3D::Array<TriangleBox>& pMembers);
inline const TriangleBox& getTriangle(int pPos) const { return(iTriangles[pPos]); }
inline TriangleBox& getTriangle(int pPos) { return(iTriangles[pPos]); }
inline void setTriangle(const TriangleBox& pTriangleBox, int pPos) { iTriangles[pPos] = pTriangleBox; }
inline const TreeNode& getTreeNode(int pPos) const { return(getTreeNodes()[pPos]); }
inline TreeNode& getTreeNode(int pPos) { return(getTreeNodes()[pPos]); }
inline void setTreeNode(const TreeNode& pTreeNode, int pPos) { getTreeNodes()[pPos] = pTreeNode; }
inline void setBasePosition(const G3D::Vector3& pBasePosition) { iBasePosition = pBasePosition; }
inline const G3D::Vector3& getBasePosition() const { return(iBasePosition); }
inline unsigned int getNNodes() const { return(iNNodes); }
inline unsigned int getNTriangles() const { return(iNTriangles); }
inline void setNNodes(unsigned int pNNodes) { iNNodes = pNNodes; }
inline void setNTriangles(unsigned int pNTriangles) { iNTriangles = pNTriangles; }
inline void setTriangleArray(TriangleBox *pGlobalTriangleArray ) { iTriangles = pGlobalTriangleArray ; }
inline void setTreeNodeArray(TreeNode *pGlobalTreeNodeArray ) { iTreeNodes = pGlobalTreeNodeArray ; }
inline TriangleBox* getTriangles() const { return(iTriangles); }
inline TreeNode* getTreeNodes() const{ return(iTreeNodes); }
inline size_t getMemUsage() { return(iNTriangles * sizeof(TriangleBox) + iNNodes * sizeof(TreeNode) + sizeof(BaseModel)); }
void intersect(const G3D::AABox& pBox, const G3D::Ray& pRay, float& pMaxDist, G3D::Vector3& pOutLocation, G3D::Vector3& pOutNormal) const;
bool intersect(const G3D::AABox& pBox, const G3D::Ray& pRay, float& pMaxDist) const;
};
}
#endif /*BASEMODEL_H_*/

View file

@ -0,0 +1,187 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "CoordModelMapping.h"
#include <string.h>
using namespace G3D;
namespace VMAP
{
//============================================================
//============================================================
void CMappingEntry::addFilename(char *pName)
{
std::string name = std::string(pName);
if(!iFilenames.contains(name))
iFilenames.append(std::string(pName));
}
//============================================================
const std::string CMappingEntry::getKeyString() const
{
return(CMappingEntry::getKeyString(iMapId,xPos, yPos));
}
//============================================================
//============================================================
//============================================================
CoordModelMapping::~CoordModelMapping()
{
Array<std::string> keys = iMapObjectFiles.getKeys();
for (int k = 0; k < keys.length(); k++)
{
CMappingEntry *value = getCMappingEntry(keys[k]);
if(value != 0)
{
iMapObjectFiles.remove(keys[k]);
delete value;
}
}
}
//============================================================
int findPosChar(const char *namebuffer, char pSearch, int pCount)
{
int result = -1;
int pos=0;
while(namebuffer[pos] != 0)
{
if(namebuffer[pos] == pSearch)
{
--pCount;
}
if(pCount == 0)
{
result = pos;
break;
}
++pos;
}
return result;
}
//============================================================
bool CoordModelMapping::readCoordinateMapping(const std::string& pDirectoryFileName)
{
FILE *f = fopen(pDirectoryFileName.c_str(), "rb");
bool result = false;
char buffer[500+1];
if(f)
{
result = true;
CMappingEntry* cMappingEntry;
while(fgets(buffer, 500, f))
{
//char namebuffer[500];
char positionbuffer[500];
int xpos, ypos, noVec;
float scale;
xpos = ypos = noVec = 0;
//sscanf(buffer, "%d %d %s %s %f %d", &xpos, &ypos, namebuffer,positionbuffer, &scale, &noVec);
// this is ugly, but the format has no read delimiter and a space could be in the first part of the name
int nameStart = findPosChar(buffer, ' ', 2);// find the 2. space
if(nameStart > -1 && (iFilterMethod == NULL || (*iFilterMethod)(buffer)))
{
++nameStart;
// find the 1. / (now a space only can be found at the end of the name)
int nameEnd = nameStart + findPosChar(&buffer[nameStart], '/', 1);
// find the 1. space (after the name)
nameEnd += findPosChar(&buffer[nameEnd], ' ', 1);
buffer[nameEnd] = 0; // terminate the name
sscanf(buffer, "%d %d", &xpos, &ypos);
sscanf(&buffer[nameEnd+1], "%s %f %d", positionbuffer, &scale, &noVec);
unsigned int mapId = getMapIdFromFilename(std::string(&buffer[nameStart]));
if(!iMapIds.contains(mapId))
{
iMapIds.append(mapId);
}
if(!isWorldAreaMap(mapId))
{
xpos = 0; // store all files under the groupKey
ypos = 0;
}
std::string key = CMappingEntry::getKeyString(mapId, xpos, ypos);
cMappingEntry = getCMappingEntry(key);
if(cMappingEntry == 0)
{
cMappingEntry = new CMappingEntry(mapId, xpos, ypos);
addCMappingEntry(cMappingEntry);
}
char namebuffer2[500];
sprintf(namebuffer2, "%d %s#%s_%f", noVec, &buffer[nameStart], positionbuffer, scale);
cMappingEntry->addFilename(namebuffer2);
//break;
}
}
fclose(f);
}
return result;
}
//============================================================
const NameCollection CoordModelMapping::getFilenamesForCoordinate(unsigned int pMapId, int xPos, int yPos)
{
NameCollection result;
Array<std::string> rawNames;
CMappingEntry *entry = getCMappingEntry(CMappingEntry::getKeyString(pMapId, xPos, yPos));
if(entry != 0)
{
rawNames = entry->getFilenames();
int pos = 0;
while(pos < rawNames.size())
{
char namebuffer[500];
int noVerc;
int startName = findPosChar(rawNames[pos].c_str(), ' ', 1) + 1;
int endName = (int) rawNames[pos].length();
sscanf(rawNames[pos].c_str(), "%d", &noVerc);
memcpy(namebuffer, &rawNames[pos].c_str()[startName], endName-startName);
namebuffer[endName-startName] = 0;
sscanf(rawNames[pos].c_str(), "%d", &noVerc);
std::string modelPosFileName = std::string(namebuffer);
if(noVerc > MIN_VERTICES_FOR_OWN_CONTAINER_FILE)
{
result.appendToSingle(modelPosFileName);
}
else
{
result.appendToMain(modelPosFileName);
}
++pos;
}
}
return result;
}
//=================================================================
}

View file

@ -0,0 +1,144 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _COORDMODELMAPPING_H_
#define _COORDMODELMAPPING_H_
#include <G3D/Table.h>
#include <G3D/Array.h>
/**
This Class is a helper Class to convert the raw vector data into BSP-Trees.
We read the directory file of the raw data output and build logical groups.
Models with a lot of vectors are not merged into a resulting model, but separated into an additional file.
*/
namespace VMAP
{
#define MIN_VERTICES_FOR_OWN_CONTAINER_FILE 65000
// if we are in an instance
#define MIN_INST_VERTICES_FOR_OWN_CONTAINER_FILE 40000
//=====================================================
class NameCollection
{
public:
G3D::Array<std::string> iMainFiles;
G3D::Array<std::string> iSingeFiles;
void appendToMain(std::string pStr) { iMainFiles.append(pStr); }
void appendToSingle(std::string pStr) { iSingeFiles.append(pStr); }
size_t size() { return (iMainFiles.size() + iSingeFiles.size()); }
};
//=====================================================
class CMappingEntry
{
private:
int xPos;
int yPos;
unsigned int iMapId;
G3D::Array<std::string> iFilenames;
public:
CMappingEntry() { };
CMappingEntry(unsigned int pMapId, const int pXPos, const int pYPos)
{
iMapId = pMapId;
xPos = pXPos; yPos = pYPos;
};
~CMappingEntry() {};
void addFilename(char *pName);
const std::string getKeyString() const;
inline const G3D::Array<std::string>& getFilenames() const { return(iFilenames); }
static const std::string getKeyString(unsigned int pMapId, int pXPos, int pYPos)
{
char b[100];
sprintf(b,"%03u_%d_%d", pMapId, pXPos, pYPos);
return(std::string(b));
}
};
//=====================================================
class CoordModelMapping
{
private:
G3D::Table<std::string, CMappingEntry *> iMapObjectFiles;
G3D::Table<std::string, std::string> iProcesseSingleFiles;
G3D::Array<unsigned int> iMapIds;
G3D::Array<unsigned int> iWorldAreaGroups;
bool (*iFilterMethod)(char *pName);
inline void addCMappingEntry(CMappingEntry* pCMappingEntry)
{
iMapObjectFiles.set(pCMappingEntry->getKeyString(), pCMappingEntry);
}
inline CMappingEntry* getCMappingEntry(const std::string& pKey)
{
if(iMapObjectFiles.containsKey(pKey))
return(iMapObjectFiles.get(pKey));
else
return 0;
}
public:
CoordModelMapping() { iFilterMethod = NULL; }
virtual ~CoordModelMapping();
bool readCoordinateMapping(const std::string& pDirectoryFileName);
const NameCollection getFilenamesForCoordinate(unsigned int pMapId, int xPos, int yPos);
static unsigned int getMapIdFromFilename(std::string pName)
{
size_t spos;
spos = pName.find_last_of('/');
std::string basename = pName.substr(0, spos);
spos = basename.find_last_of('/');
std::string groupname = basename.substr(spos+1, basename.length());
unsigned int mapId = atoi(groupname.c_str());
return(mapId);
}
const G3D::Array<unsigned int>& getMaps() const { return iMapIds; }
inline bool isAlreadyProcessedSingleFile(std::string pName) { return(iProcesseSingleFiles.containsKey(pName)); }
inline void addAlreadyProcessedSingleFile(std::string pName) { iProcesseSingleFiles.set(pName,pName); }
inline void addWorldAreaMap(unsigned int pMapId)
{
if(!iWorldAreaGroups.contains(pMapId))
{
iWorldAreaGroups.append(pMapId);
}
}
inline bool isWorldAreaMap(unsigned int pMapId) { return(iWorldAreaGroups.contains(pMapId)); }
void setModelNameFilterMethod(bool (*pFilterMethod)(char *pName)) { iFilterMethod = pFilterMethod; }
};
}
#endif /*_COORDMODELMAPPING_H_*/

View file

@ -0,0 +1,125 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "DebugCmdLogger.h"
using namespace G3D;
namespace VMAP
{
bool CommandFileRW::appendCmd(const Command&
#ifdef _DEBUG
pCommand
#endif
)
{
#ifdef _DEBUG
bool result = false;
if(iWritingEnabled || pCommand.isCoreCmd())
{
FILE* f = fopen(iFileName.c_str(), "ab");
if(f)
{
result = true;
if(fwrite(&pCommand, sizeof(Command), 1, f) != 1) { result = false; }
fclose(f);
}
}
else
{
result = true;
}
return result;
#else
return true;
#endif
}
//=========================================================
bool CommandFileRW::appendCmds(const Array<Command>&
#ifdef _DEBUG
pCmdArray
#endif
)
{
#ifdef _DEBUG
bool result = false;
if(iWritingEnabled)
{
FILE* f;
if(resetfile)
f = fopen(iFileName.c_str(), "wb");
else
f = fopen(iFileName.c_str(), "ab");
resetfile = false;
if(f)
{
result = true;
for(int i=0; i<pCmdArray.size(); ++i)
{
if(fwrite(&pCmdArray[i], sizeof(Command), 1, f) != 1) { result = false; break; }
}
fclose(f);
}
}
else
{
result = true;
}
return result;
#else
return true;
#endif
}
//=========================================================
bool CommandFileRW::getNewCommands(Array<Command>& pCmdArray)
{
bool result = false;
FILE* f = fopen(iFileName.c_str(), "rb");
if(f)
{
Command cmd;
if(fseek(f, iLastPos, SEEK_SET) == 0) { result = true; }
while(result)
{
if(fread(&cmd, sizeof(Command), 1, f) != 1)
{
result = false;
}
iLastPos = ftell(f);
if(cmd.getType() == STOP)
{
break;
}
pCmdArray.append(cmd);
}
fclose(f);
}
if(result)
{
iCommandArray.append(pCmdArray);
}
return(result);
}
//========================================================
}

View file

@ -0,0 +1,116 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _DEBUGCMDLOGGER_H
#define _DEBUGCMDLOGGER_H
#include <G3D/Vector3.h>
#include <G3D/Array.h>
/**
Class is used for debugging. We log activities into a file.
With an external Class we read that log and display the activity in a graphical view.
*/
namespace VMAP
{
//==========================================
enum C_TYPES
{
STOP,
START,
LOAD_TILE,
UNLOAD_TILE,
SET_POS,
TEST_VIS,
LOAD_INSTANCE,
UNLOAD_INSTANCE,
TEST_HEIGHT,
TEST_OBJECT_HIT,
};
class Command
{
int iType;
float floats[9];
int ints[4];
char buffer[100];
public:
Command() { iType = STOP; }
inline int getType() { return iType; }
inline G3D::Vector3 getVector(int pos) { return(G3D::Vector3(floats[pos*3+0], floats[pos*3+1], floats[pos*3+2])); }
inline int getInt(int pos) { return(ints[pos]); }
inline char* getBuffer() { return(buffer); }
void fillStopCmd() { iType = STOP; }
void fillStartCmd() { iType = START; }
void fillLoadTileCmd(int x, int y, G3D::uint32 pMapId) { iType = LOAD_TILE; ints[0] = x; ints[1] = y; ints[2] = pMapId; }
//void fillLoadTileCmd(int x,int y) { iType = LOAD_TILE; ints[0] = x; ints[1] = y; }
void fillUnloadTileCmd(G3D::uint32 pMapId) { iType = UNLOAD_INSTANCE; ints[0] = pMapId; }
void fillUnloadTileCmd(unsigned int pMapId, int x,int y) { iType = UNLOAD_TILE; ints[0] = x; ints[1] = y; ints[0]=pMapId; }
void fillSetPosCmd(G3D::Vector3 pPos) { iType = SET_POS; floats[0] = pPos.x; floats[1]=pPos.y; floats[2]=pPos.z; }
void fillTestVisCmd(int pMapId, G3D::Vector3 pPos1, G3D::Vector3 pPos2, bool result)
{
iType = TEST_VIS; floats[0] = pPos1.x; floats[1]=pPos1.y; floats[2]=pPos1.z;
floats[3] = pPos2.x; floats[4]=pPos2.y; floats[5]=pPos2.z;
ints[0] = result; ints[1] = pMapId;
}
void fillTestHeightCmd(int pMapId, G3D::Vector3 pPos, float result)
{
iType = TEST_HEIGHT; floats[0] = pPos.x; floats[1]=pPos.y; floats[2]=pPos.z;
floats[3] = result; ints[0] = pMapId;
}
void fillTestObjectHitCmd(int pMapId, G3D::Vector3 pPos1, G3D::Vector3 pPos2, G3D::Vector3 pResultPos, bool result)
{
iType = TEST_OBJECT_HIT; floats[0] = pPos1.x; floats[1]=pPos1.y; floats[2]=pPos1.z;
floats[3] = pPos2.x; floats[4]=pPos2.y; floats[5]=pPos2.z;
floats[6] = pResultPos.x; floats[7]=pResultPos.y; floats[8]=pResultPos.z;
ints[0] = result; ints[1] = pMapId;
}
bool isCoreCmd() const { return(iType != TEST_VIS); }
};
//==========================================
class CommandFileRW
{
private:
std::string iFileName;
long iLastPos;
G3D::Array<G3D::Array<Command> > iCommandArray;
bool resetfile;
bool iWritingEnabled;
public:
CommandFileRW() { iLastPos=0; iWritingEnabled = true; resetfile = true;}
CommandFileRW(const std::string& pFileName) { iLastPos = 0; iFileName = pFileName; iWritingEnabled = true; resetfile = true; }
void setResetFile() { resetfile = true; }
void enableWriting(bool pValue) { iWritingEnabled = pValue; }
void setFileName(const std::string& pName) { iFileName = pName; }
bool getNewCommands(G3D::Array<Command>& commandArray);
const G3D::Array<G3D::Array<Command> >& getFullCommandArray() { return iCommandArray; }
bool appendCmd(const Command& pCommand);
bool appendCmds(const G3D::Array<Command>& pCmdArray);
};
}
#endif

View file

@ -0,0 +1,99 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _IVMAPMANAGER_H
#define _IVMAPMANAGER_H
#include<string>
//===========================================================
/**
This is the minimum interface to the VMapMamager.
*/
namespace VMAP
{
enum VMAP_LOAD_RESULT
{
VMAP_LOAD_RESULT_ERROR,
VMAP_LOAD_RESULT_OK,
VMAP_LOAD_RESULT_IGNORED,
};
#define VMAP_INVALID_HEIGHT -100000.0f // for check
#define VMAP_INVALID_HEIGHT_VALUE -200000.0f // real assigned value in unknown height case
//===========================================================
class IVMapManager
{
private:
bool iEnableLineOfSightCalc;
bool iEnableHeightCalc;
public:
IVMapManager() : iEnableLineOfSightCalc(true), iEnableHeightCalc(true) {}
virtual ~IVMapManager(void) {}
virtual int loadMap(const char* pBasePath, unsigned int pMapId, int x, int y) = 0;
virtual bool existsMap(const char* pBasePath, unsigned int pMapId, int x, int y) = 0;
virtual void unloadMap(unsigned int pMapId, int x, int y) = 0;
virtual void unloadMap(unsigned int pMapId) = 0;
virtual bool isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2) = 0;
virtual float getHeight(unsigned int pMapId, float x, float y, float z) = 0;
/**
test if we hit an object. return true if we hit one. rx,ry,rz will hold the hit position or the dest position, if no intersection was found
return a position, that is pReduceDist closer to the origin
*/
virtual bool getObjectHitPos(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float pModifyDist) = 0;
/**
send debug commands
*/
virtual bool processCommand(char *pCommand)= 0;
/**
Enable/disable LOS calculation
It is enabled by default. If it is enabled in mid game the maps have to loaded manualy
*/
void setEnableLineOfSightCalc(bool pVal) { iEnableLineOfSightCalc = pVal; }
/**
Enable/disable model height calculation
It is enabled by default. If it is enabled in mid game the maps have to loaded manualy
*/
void setEnableHeightCalc(bool pVal) { iEnableHeightCalc = pVal; }
bool isLineOfSightCalcEnabled() const { return(iEnableLineOfSightCalc); }
bool isHeightCalcEnabled() const { return(iEnableHeightCalc); }
bool isMapLoadingEnabled() const { return(iEnableLineOfSightCalc || iEnableHeightCalc ); }
virtual std::string getDirFileName(unsigned int pMapId, int x, int y) const =0;
/**
Block maps from being used.
parameter: String of map ids. Delimiter = ","
e.g.: "0,1,530"
*/
virtual void preventMapsFromBeingUsed(const char* pMapIdString) =0;
};
}
#endif

View file

@ -0,0 +1,56 @@
# Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## Process this file with automake to produce Makefile.in
## Sub-directories to parse
## CPP flags for includes, defines, etc.
AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(srcdir)/../../../dep/include -I$(srcdir)/../../framework -I$(srcdir)/../../shared -I$(srcdir)/../../../dep/include/g3dlite
## Build MaNGOS shared library and its parts as convenience library.
# All libraries will be convenience libraries. Might be changed to shared
# later.
noinst_LIBRARIES = libmangosvmaps.a
libmangosvmaps_a_SOURCES = \
AABSPTree.h \
BaseModel.cpp \
BaseModel.h \
CoordModelMapping.cpp \
CoordModelMapping.h \
DebugCmdLogger.cpp \
DebugCmdLogger.h \
IVMapManager.h \
ManagedModelContainer.cpp \
ManagedModelContainer.h \
ModelContainer.cpp \
ModelContainer.h \
NodeValueAccess.h \
ShortBox.h \
ShortVector.h \
SubModel.cpp \
SubModel.h \
TileAssembler.cpp \
TileAssembler.h \
TreeNode.cpp \
TreeNode.h \
VMapDefinitions.h \
VMapFactory.cpp \
VMapFactory.h \
VMapManager.cpp \
VMapManager.h \
VMapTools.h

View file

@ -0,0 +1,35 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ManagedModelContainer.h"
using namespace G3D;
namespace VMAP
{
ManagedModelContainer::ManagedModelContainer(void) : ModelContainer()
{
refCount = 0;
}
ManagedModelContainer::~ManagedModelContainer(void)
{
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _MANAGEDMODELCONTAINER_H
#define _MANAGEDMODELCONTAINER_H
#include "ModelContainer.h"
//=======================================================
/**
This is a ModelContainer with reference count information.
*/
namespace VMAP
{
//=======================================================
class ManagedModelContainer :
public ModelContainer
{
private:
int refCount;
public:
ManagedModelContainer(void) ;
~ManagedModelContainer(void);
void incRefCount() { ++refCount; }
void decRefCount() { --refCount; if(refCount < 0) refCount = 0; }
int getRefCount() { return refCount; }
};
//=======================================================
}
#endif

View file

@ -0,0 +1,375 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <iostream>
#include <fstream>
#include <string.h>
#include "ModelContainer.h"
#include "VMapDefinitions.h"
using namespace G3D;
namespace VMAP
{
//==========================================================
/**
Functions to use ModelContainer with a AABSPTree
*/
size_t hashCode(const ModelContainer& pMc)
{
return (pMc.getBasePosition() * pMc.getNTriangles()).hashCode();
}
//==========================================================
ModelContainer::ModelContainer(unsigned int pNTriangles, unsigned int pNNodes, unsigned int pNSubModel) :
BaseModel(pNNodes, pNTriangles)
{
iNSubModel = pNSubModel;
iSubModel = 0;
if(pNSubModel > 0) iSubModel = new SubModel[iNSubModel];
}
//==========================================================
bool ModelContainer::operator==(const ModelContainer& pMc2) const
{
if (this->iNSubModel == 0 && pMc2.iNSubModel == 0 && this->iSubModel == 0 && pMc2.iSubModel == 0)
return true;
return this == &pMc2;
}
//==========================================================
void ModelContainer::countSubModelsAndNodesAndTriangles(AABSPTree<SubModel *>::Node& pNode, int& nSubModels, int& nNodes, int& nTriangles)
{
// For this node we will need a TreeNode as well as for the internal nodes
++nNodes;
nSubModels += pNode.valueArray.size();
for(int i=0;i<pNode.valueArray.size(); i++)
{
G3D::_AABSPTree::Handle<SubModel*>* h= pNode.valueArray[i];
SubModel *m = h->value;
// add the internal nodes as well
nNodes += m->getNNodes();
nTriangles += m->getNTriangles();
}
if(pNode.child[0] != 0)
{
countSubModelsAndNodesAndTriangles(*pNode.child[0], nSubModels, nNodes, nTriangles);
}
if(pNode.child[1] != 0)
{
countSubModelsAndNodesAndTriangles(*pNode.child[1], nSubModels, nNodes, nTriangles);
}
}
//==========================================================
void ModelContainer::fillContainer(const AABSPTree<SubModel *>::Node& pNode, int &pSubModelPos, int &pTreeNodePos, int &pTrianglePos, Vector3& pLo, Vector3& pHi, Vector3& pFinalLo, Vector3& pFinalHi)
{
// TreeNode for the SubModel
TreeNode treeNode = TreeNode(pNode.valueArray.size(), pSubModelPos);
treeNode.setSplitAxis(pNode.splitAxis);
treeNode.setSplitLocation(pNode.splitLocation);
int currentTreeNodePos = pTreeNodePos++;
Vector3 lo = Vector3(inf(),inf(),inf());
Vector3 hi = Vector3(-inf(),-inf(),-inf());
for(int i=0;i<pNode.valueArray.size(); i++)
{
G3D::_AABSPTree::Handle<SubModel*>* h= pNode.valueArray[i];
SubModel *m = h->value;
memcpy(&getTreeNodes()[pTreeNodePos], &m->getTreeNode(0), sizeof(TreeNode) * m->getNNodes());
memcpy(&getTriangles()[pTrianglePos], &m->getTriangle(0), sizeof(TriangleBox) * m->getNTriangles());
SubModel newModel = SubModel(m->getNTriangles(), getTriangles(), pTrianglePos, m->getNNodes(), getTreeNodes(), pTreeNodePos);
newModel.setReletiveBounds(m->getReletiveBounds().getLo(), m->getReletiveBounds().getHi());
newModel.setBasePosition(m->getBasePosition());
iSubModel[pSubModelPos++] = newModel;
pTreeNodePos += m->getNNodes();
pTrianglePos += m->getNTriangles();
AABox box = m->getAABoxBounds();
lo = lo.min(box.low());
hi = hi.max(box.high());
pFinalLo = pFinalLo.min(lo);
pFinalHi = pFinalHi.max(hi);
}
/*
if(pNode.valueArray.size() == 0) {
int xxx = 0; // just for the breakpoint
}
*/
// get absolute bounds
if(pNode.child[0] != 0)
{
treeNode.setChildPos(0, pTreeNodePos);
fillContainer(*pNode.child[0], pSubModelPos, pTreeNodePos, pTrianglePos, lo, hi,pFinalLo,pFinalHi);
}
if(pNode.child[1] != 0)
{
treeNode.setChildPos(1, pTreeNodePos);
fillContainer(*pNode.child[1], pSubModelPos, pTreeNodePos, pTrianglePos, lo, hi,pFinalLo,pFinalHi);
}
pLo = pLo.min(lo);
pHi = pHi.max(hi);
treeNode.setBounds(lo,hi);
setTreeNode(treeNode, currentTreeNodePos);
}
//==========================================================
/**
Create the structure out of a AABSPTree
*/
ModelContainer::ModelContainer(AABSPTree<SubModel *> *pTree)
{
int nSubModels, nNodes, nTriangles;
nSubModels = nNodes = nTriangles = 0;
countSubModelsAndNodesAndTriangles(*pTree->root, nSubModels, nNodes, nTriangles);
init(nNodes, nTriangles);
iNSubModel = nSubModels;
iSubModel = new SubModel[iNSubModel];
int subModelPos,treeNodePos, trianglePos;
subModelPos = treeNodePos = trianglePos = 0;
Vector3 lo = Vector3(inf(),inf(),inf());
Vector3 hi = Vector3(-inf(),-inf(),-inf());
Vector3 finalLo, finalHi;
finalLo = lo;
finalHi = hi;
fillContainer(*pTree->root, subModelPos, treeNodePos, trianglePos, lo, hi, finalLo, finalHi);
setBounds(finalLo, finalHi);
}
//==========================================================
ModelContainer::~ModelContainer(void)
{
free();
if(iSubModel != 0) delete [] iSubModel;
}
//==========================================================
bool ModelContainer::writeFile(const char *filename)
{
bool result = false;
unsigned int flags=0;
unsigned int size;
FILE *wf =fopen(filename,"wb");
if(wf)
{
fwrite(VMAP_MAGIC,1,8,wf);
result = true;
if(result && fwrite("CTREE01",8,1,wf) != 1) result = false;
if(result && fwrite(&flags,sizeof(unsigned int),1,wf) != 1) result = false;
if(result && fwrite("POS ",4,1,wf) != 1) result = false;
size = sizeof(float)*3;
if(result && fwrite(&size,4,1,wf) != 1) result = false;
Vector3 basePos = getBasePosition();
if(result && fwrite(&basePos,sizeof(float),3,wf) != 3) result = false;
if(result && fwrite("BOX ",4,1,wf) != 1) result = false;
size = sizeof(float)*6;
if(result && fwrite(&size,4,1,wf) != 1) result = false;
Vector3 low = iBox.low();
if(result && fwrite(&low,sizeof(float),3,wf) != 3) result = false;
Vector3 high = iBox.high();
if(result && fwrite(&high,sizeof(float),3,wf) != 3) result = false;
if(result && fwrite("NODE",4,1,wf) != 1) result = false;
size = sizeof(unsigned int)+ sizeof(TreeNode)*getNNodes();
if(result && fwrite(&size,4,1,wf) != 1) result = false;
unsigned int val = getNNodes();
if(result && fwrite(&val,sizeof(unsigned int),1,wf) != 1) result = false;
if(result && fwrite(getTreeNodes(),sizeof(TreeNode),getNNodes(),wf) != getNNodes()) result = false;
if(result && fwrite("TRIB",4,1,wf) != 1) result = false;
size = sizeof(unsigned int)+ sizeof(TriangleBox)*getNTriangles();
if(result && fwrite(&size,4,1,wf) != 1) result = false;
val = getNTriangles();
if(result && fwrite(&val,sizeof(unsigned int),1,wf) != 1) result = false;
if(result && fwrite(getTriangles(),sizeof(TriangleBox),getNTriangles(),wf) != getNTriangles()) result = false;
if(result && fwrite("SUBM",4,1,wf) != 1) result = false;
size = sizeof(unsigned int)+ sizeof(SubModel)*iNSubModel;
if(result && fwrite(&size,4,1,wf) != 1) result = false;
if(result && fwrite(&iNSubModel,sizeof(unsigned int),1,wf) != 1) result = false;
if(result && fwrite(iSubModel,sizeof(SubModel),iNSubModel,wf) != iNSubModel) result = false;
fclose(wf);
}
return(result);
}
//===============================================================
bool ModelContainer::readFile(const char *filename)
{
bool result = false;
unsigned int flags;
unsigned int size;
char ident[8];
char chunk[4];
unsigned int ival;
FILE *rf = fopen(filename, "rb");
if(rf)
{
free();
result = true;
char magic[8]; // Ignore the added magic header
fread(magic,1,8,rf);
if(strncmp(VMAP_MAGIC,magic,8)) result = false;
if(result && fread(ident,8,1,rf) != 1) result = false;
if(result && fread(&flags,sizeof(unsigned int),1,rf) != 1) result = false;
//POS
if(result && fread(chunk,4,1,rf) != 1) result = false;
if(result && fread(&size,4,1,rf) != 1) result = false;
Vector3 basePos;
if(result && fread(&basePos,sizeof(float),3,rf) != 3) result = false;
setBasePosition(basePos);
//---- Box
if(result && fread(chunk,4,1,rf) != 1) result = false;
if(result && fread(&size,4,1,rf) != 1) result = false;
Vector3 low,high;
if(result && fread(&low,sizeof(float),3,rf) != 3) result = false;
if(result && fread(&high,sizeof(float),3,rf) != 3) result = false;
setBounds(low, high);
//---- TreeNodes
if(result && fread(chunk,4,1,rf) != 1) result = false;
if(result && fread(&size,4,1,rf) != 1) result = false;
if(result && fread(&ival,sizeof(unsigned int),1,rf) != 1) result = false;
if(result) setNNodes(ival);
if(result) setTreeNodeArray(new TreeNode[getNNodes()]);
if(result && fread(getTreeNodes(),sizeof(TreeNode),getNNodes(),rf) != getNNodes()) result = false;
//---- TriangleBoxes
if(result && fread(chunk,4,1,rf) != 1) result = false;
if(result && fread(&size,4,1,rf) != 1) result = false;
if(result && fread(&ival,sizeof(unsigned int),1,rf) != 1) result = false;
setNTriangles(ival);
if(result) setTriangleArray(new TriangleBox[getNTriangles()]);
if(result && fread(getTriangles(),sizeof(TriangleBox),getNTriangles(),rf) != getNTriangles()) result = false;
//---- SubModel
if(result && fread(chunk,4,1,rf) != 1) result = false;
if(result && fread(&size,4,1,rf) != 1) result = false;
if(result && fread(&iNSubModel,sizeof(unsigned int),1,rf) != 1) result = false;
if(result) iSubModel = new SubModel[iNSubModel];
if(result)
{
for(unsigned int i=0;i<iNSubModel && result; ++i)
{
unsigned char readBuffer[52]; // this is the size of SubModel on 32 bit systems
if(fread(readBuffer,sizeof(readBuffer),1,rf) != 1) result = false;
iSubModel[i].initFromBinBlock(readBuffer);
iSubModel[i].setTriangleArray(getTriangles());
iSubModel[i].setTreeNodeArray(getTreeNodes());
}
}
fclose(rf);
}
return result;
}
//=================================================================
size_t ModelContainer::getMemUsage()
{
// BaseModel is included in ModelContainer
return(iNSubModel * sizeof(SubModel) + BaseModel::getMemUsage() + sizeof(ModelContainer) - sizeof(BaseModel));
}
//=================================================================
#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
void ModelContainer::intersect(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit, G3D::Vector3& /*pOutLocation*/, G3D::Vector3& /*pOutNormal*/) const
{
IntersectionCallBack<SubModel> intersectCallback;
NodeValueAccess<TreeNode, SubModel> vna = NodeValueAccess<TreeNode, SubModel>(getTreeNodes(), iSubModel);
Ray relativeRay = Ray::fromOriginAndDirection(pRay.origin - getBasePosition(), pRay.direction);
iTreeNodes[0].intersectRay(pRay, intersectCallback, pMaxDist, vna, pStopAtFirstHit, false);
}
//==========================================================
bool ModelContainer::intersect(const G3D::Ray& pRay, float& pMaxDist) const
{
return BaseModel::intersect(getAABoxBounds(), pRay, pMaxDist);
}
//=================================================================
template<typename RayCallback>
void ModelContainer::intersectRay(const G3D::Ray& pRay, RayCallback& intersectCallback, float& pMaxDist, bool pStopAtFirstHit, bool intersectCallbackIsFast)
{
if(intersect(pRay, pMaxDist))
{
NodeValueAccess<TreeNode, SubModel> vna = NodeValueAccess<TreeNode, SubModel>(getTreeNodes(), iSubModel);
iTreeNodes[0].intersectRay(pRay, intersectCallback, distance, vna, pStopAtFirstHit, true);
}
}
//=================================================================
void getBounds(const ModelContainer& pMc, G3D::AABox& pAABox)
{
pAABox = pMc.getAABoxBounds();
}
//=================================================================
void getBounds(const ModelContainer* pMc, G3D::AABox& pAABox)
{
pAABox = pMc->getAABoxBounds();
}
//=================================================================
} // VMAP

View file

@ -0,0 +1,108 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _MODELCONTAINER_H
#define _MODELCONTAINER_H
// load our modified version first !!
#include "AABSPTree.h"
#include <G3D/AABox.h>
#include <G3D/Vector3.h>
#include <G3D/Ray.h>
#include "ShortBox.h"
#include "TreeNode.h"
#include "VMapTools.h"
#include "SubModel.h"
#include "BaseModel.h"
namespace VMAP
{
/**
The ModelContainer is a balanced BSP-Tree of SubModels.
We store a map tile or an instance in one ModelContainer.
The ModelContainer manages the memory used for the tree nodes, the SubModels and its triangles in static arrays.
The tree nodes are used for the BSP-Tree of SubModels as well as for the BSP-Tree of triangles within one SubModel.
The references are done by indexes within these static arrays.
Therefore we are able to just load a binary block and do not need to mess around with memory allocation and pointers.
*/
//=====================================================
class ModelContainer : public BaseModel
{
private:
unsigned int iNSubModel;
SubModel *iSubModel;
G3D::AABox iBox;
ModelContainer (const ModelContainer& c): BaseModel(c) {}
ModelContainer& operator=(const ModelContainer& ) {}
public:
ModelContainer() : BaseModel() { iNSubModel =0; iSubModel = 0; };
// for the mainnode
ModelContainer(unsigned int pNTriangles, unsigned int pNNodes, unsigned int pNSubModel);
ModelContainer(G3D::AABSPTree<SubModel *> *pTree);
~ModelContainer(void);
inline const void setSubModel(const SubModel& pSubModel, int pPos) { iSubModel[pPos] = pSubModel; }
inline const SubModel& getSubModel(int pPos) const { return iSubModel[pPos]; }
inline unsigned int getNSubModel() const { return(iNSubModel); }
void countSubModelsAndNodesAndTriangles(G3D::AABSPTree<SubModel *>::Node& pNode, int& nSubModels, int& nNodes, int& nTriangles);
void fillContainer(const G3D::AABSPTree<SubModel *>::Node& pNode, int &pSubModelPos, int &pTreeNodePos, int &pTrianglePos, G3D::Vector3& pLo, G3D::Vector3& pHi, G3D::Vector3& pFinalLo, G3D::Vector3& pFinalHi);
bool readRawFile(const char *name);
inline const G3D::AABox& getAABoxBounds() const { return(iBox); }
inline void setBounds(const G3D::Vector3& lo, const G3D::Vector3& hi) { iBox.set(lo,hi); }
bool writeFile(const char *filename);
bool readFile(const char *filename);
size_t getMemUsage();
size_t hashCode() { return (getBasePosition() * getNTriangles()).hashCode(); }
void intersect(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit, G3D::Vector3& pOutLocation, G3D::Vector3& pOutNormal) const;
bool intersect(const G3D::Ray& pRay, float& pMaxDist) const;
template<typename RayCallback>
void intersectRay(const G3D::Ray& ray, RayCallback& intersectCallback, float& distance, bool pStopAtFirstHit, bool intersectCallbackIsFast = false);
bool operator==(const ModelContainer& pMc2) const;
};
//=====================================================
//=====================================================
size_t hashCode(const ModelContainer& pMc);
void getBounds(const ModelContainer& pMc, G3D::AABox& pAABox);
void getBounds(const ModelContainer* pMc, G3D::AABox& pAABox);
}
#endif

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NODEVALUEACCESS_H
#define _NODEVALUEACCESS_H
namespace VMAP
{
/**
This is a helper Class to get access to SubModels or triangles when analyzing the BSP-Tree.
*/
template<class TNode, class TValue> class NodeValueAccess
{
private:
TNode const* iNodeArray;
TValue const* iValueArray;
public:
inline NodeValueAccess() : iNodeArray(NULL), iValueArray(NULL) {}
inline NodeValueAccess(TNode const* pNodeArray, TValue const* pValueArray) : iNodeArray(pNodeArray), iValueArray(pValueArray) {}
inline TNode const* getNodePtr() const { return(iNodeArray); }
inline TValue const* getValuePtr() const { return(iValueArray); }
inline TNode const& getNode(unsigned int pPos) const { return(iNodeArray[pPos]); }
inline void setNode(const TNode& pNode, unsigned int pPos) { iNodeArray[pPos] = pNode; }
inline TValue const& getValue(unsigned int pPos) const { return(iValueArray[pPos]); }
inline void setValue(const TValue& pValue, unsigned int pPos) { iValueArray[pPos] = pValue; }
};
}
#endif

148
src/shared/vmap/ShortBox.h Normal file
View file

@ -0,0 +1,148 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SHORTBOX_H
#define _SHORTBOX_H
#include <G3D/Vector3.h>
#include <G3D/AABox.h>
#include <G3D/Triangle.h>
#include <G3D/Ray.h>
#include "ShortVector.h"
/**
This is a box and a triangle Class using ShortVectors. Each vector has 16 bit an a fixed point 12.4 representation.
*/
namespace VMAP
{
class ShortBox
{
private:
ShortVector iV1;
ShortVector iV2;
public:
ShortBox() {}
inline const ShortVector& getLo() const { return(iV1); }
inline const ShortVector& getHi() const { return(iV2); }
inline void setLo(const ShortVector& pV){ iV1 = pV; }
inline void setHi(const ShortVector& pV){ iV2 = pV; }
inline void setLo(const G3D::Vector3& pV){ iV1 = ShortVector(pV); }
inline void setHi(const G3D::Vector3& pV){ iV2 = ShortVector(pV); }
inline bool operator==(const ShortBox& b) const
{
return ((iV1 == b.iV1) && (iV2 == b.iV2));
}
inline bool operator!=(const ShortBox& b) const
{
return !((iV1 == b.iV1) && (iV2 == b.iV2));
}
};
//=====================================================================
#ifdef _DEBUG_VMAPS
#ifndef gBoxArray
extern G3D::Vector3 p1,p2,p3,p4,p5,p6,p7;
extern G3D::Array<G3D::AABox>gBoxArray;
extern G3D::Array<G3D::Triangle>gTriArray;
extern int gCount1, gCount2, gCount3, gCount4;
extern bool myfound;
#endif
#endif
static const G3D::Vector3 dummyZeroPosition = G3D::Vector3(0,0,0);
class TriangleBox
{
private:
ShortVector _vertex[3];
//ShortBox iBox;
public:
inline TriangleBox() { }
inline TriangleBox(const ShortVector& pV1, const ShortVector& pV2, const ShortVector& pV3)
{
_vertex[0] = pV1;
_vertex[1] = pV2;
_vertex[2] = pV3;
}
inline const ShortVector& vertex (int n) const
{
return(_vertex[n]);
}
inline const ShortBox getBounds()const
{
ShortBox box;
ShortVector lo = _vertex[0];
ShortVector hi = lo;
for (int i = 1; i < 3; ++i)
{
lo = lo.min(_vertex[i]);
hi = hi.max(_vertex[i]);
}
box.setLo(lo);
box.setHi(hi);
return(box);
}
inline const G3D::Vector3& getBasePosition() { return(dummyZeroPosition); }
inline const G3D::AABox getAABoxBounds() const { ShortBox box = getBounds(); return(G3D::AABox(box.getLo().getVector3(), box.getHi().getVector3())); }
inline bool operator==(const TriangleBox& t) const
{
return ((_vertex[0] == t._vertex[0]) && (_vertex[1] == t._vertex[1]) &&(_vertex[2] == t._vertex[2]));
}
inline bool operator!=(const TriangleBox& t) const
{
return !((_vertex[0] == t._vertex[0]) && (_vertex[1] == t._vertex[1]) &&(_vertex[2] == t._vertex[2]));
}
inline void intersect(const G3D::Ray& pRay, float& pMaxDist, bool /*pStopAtFirstHitDummy*/, G3D::Vector3& /*pOutLocationDummy*/, G3D::Vector3& /*pOutNormalDummy*/) const
{
static const double epsilon = 0.00001;
G3D::Triangle testT(vertex(0).getVector3(),vertex(1).getVector3(),vertex(2).getVector3());
float t = pRay.intersectionTime(testT);
if ((t < pMaxDist) || t < (pMaxDist + epsilon))
pMaxDist = t;
else
{
testT = G3D::Triangle(vertex(2).getVector3(),vertex(1).getVector3(),vertex(0).getVector3());
#ifdef _DEBUG_VMAPS
{
G3D::Triangle myt(testT.vertex(0)+p6, testT.vertex(1)+p6,testT.vertex(2)+p6);
gTriArray.push_back(myt);
}
#endif
t = pRay.intersectionTime(testT);
if ((t < pMaxDist) || t < (pMaxDist + epsilon))
pMaxDist = t;
}
}
};
}
#endif

View file

@ -0,0 +1,134 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SHORTVECTOR_H
#define _SHORTVECTOR_H
#include <G3D/Vector3.h>
namespace VMAP
{
/**
Vector with 16 bit fix point values 12.4 bit.
*/
class ShortVector
{
private:
short iX;
short iY;
short iZ;
const static short maxvalue = 0x7fff;
const static short minvalue = -0x7fff;
const static int fixpointdiv = 16;
const static short fixpoint_maxvalue = maxvalue / fixpointdiv;
const static short fixpoint_minvalue = minvalue / fixpointdiv;
inline short float2Short(float fv) const
{
short sv;
debugAssert((fv <= fixpoint_maxvalue || fv >= 1000000) && (fv >= fixpoint_minvalue || fv <= -1000000));
if(fv >= fixpoint_maxvalue)
sv=maxvalue;
else if(fv <= fixpoint_minvalue)
sv=minvalue;
else
sv = (short) (fv * fixpointdiv + 0.5);
return(sv);
}
inline float short2Float(short sv) const
{
float fv;
if(sv >= maxvalue)
fv=G3D::inf();
else if(sv <= minvalue)
fv=-G3D::inf();
else
fv = ((float)sv) / fixpointdiv;
return fv;
}
inline float getFX() const { return(short2Float(iX)); }
inline float getFY() const { return(short2Float(iY)); }
inline float getFZ() const { return(short2Float(iZ)); }
public:
inline ShortVector() {}
inline ShortVector(const G3D::Vector3& pVector)
{
iX = float2Short(pVector.x);
iY = float2Short(pVector.y);
iZ = float2Short(pVector.z);
}
inline ShortVector(float pX, float pY, float pZ)
{
iX = float2Short(pX);
iY = float2Short(pY);
iZ = float2Short(pZ);
}
inline ShortVector(short pX, short pY, short pZ)
{
iX = pX;
iY = pY;
iZ = pZ;
}
inline ShortVector(const ShortVector& pShortVector)
{
iX = pShortVector.iX;
iY = pShortVector.iY;
iZ = pShortVector.iZ;
}
inline float getX() const { return(iX); }
inline float getY() const { return(iY); }
inline float getZ() const { return(iZ); }
inline G3D::Vector3 getVector3() const { return(G3D::Vector3(getFX(), getFY(), getFZ())); }
inline ShortVector min(const ShortVector pShortVector)
{
ShortVector result = pShortVector;
if(pShortVector.iX > iX) { result.iX = iX; }
if(pShortVector.iY > iY) { result.iY = iY; }
if(pShortVector.iZ > iZ) { result.iZ = iZ; }
return(result);
}
inline ShortVector max(const ShortVector pShortVector)
{
ShortVector result = pShortVector;
if(pShortVector.iX < iX) { result.iX = iX; }
if(pShortVector.iY < iY) { result.iY = iY; }
if(pShortVector.iZ < iZ) { result.iZ = iZ; }
return(result);
}
inline bool operator==(const ShortVector& v) const
{
return (iX == v.iX && iY == v.iY && iZ == v.iZ);
}
inline bool operator!=(const ShortVector& v) const
{
return !(iX == v.iX && iY == v.iY && iZ == v.iZ);
}
};
}
#endif

View file

@ -0,0 +1,248 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "SubModel.h"
#ifdef _ASSEMBLER_DEBUG
extern FILE *::g_df;
#endif
using namespace G3D;
namespace VMAP
{
//==========================================================
/**
Functions to use ModelContainer with a AABSPTree
*/
unsigned int hashCode(const SubModel& pSm)
{
return pSm.getNTriangles();
}
void getBounds(const SubModel& pSm, G3D::AABox& pAABox)
{
ShortBox box = pSm.getReletiveBounds();
pAABox.set(box.getLo().getVector3()+pSm.getBasePosition(), box.getHi().getVector3()+pSm.getBasePosition());
}
void getBounds(const SubModel* pSm, G3D::AABox& pAABox)
{
ShortBox box = pSm->getReletiveBounds();
pAABox.set(box.getLo().getVector3()+pSm->getBasePosition(), box.getHi().getVector3()+pSm->getBasePosition());
}
//==========================================================
//==========================================================
//==========================================================
//==========================================================
SubModel::SubModel(unsigned int pNTriangles, TriangleBox *pTriangles, unsigned int pTrianglesPos, unsigned int pNNodes, TreeNode *pTreeNodes, unsigned int pNodesPos) :
BaseModel(pNNodes, pTreeNodes, pNTriangles, pTriangles)
{
iTrianglesPos = pTrianglesPos;
iNodesPos = pNodesPos;
iHasInternalMemAlloc = false;
}
//==========================================================
SubModel::~SubModel(void)
{
if(iHasInternalMemAlloc)
{
free();
}
}
//==========================================================
bool SubModel::operator==(const SubModel& pSm2) const
{
bool result = false;
if(getNNodes() == pSm2.getNNodes() &&
getNTriangles() == pSm2.getNTriangles() &&
getBasePosition() == pSm2.getBasePosition() &&
getNodesPos() == pSm2.getNodesPos() &&
getTrianglesPos() == pSm2.getTrianglesPos())
{
result = true;
}
return result;
}
//==========================================================
enum BIN_POSITIONS
{
BP_iNTriangles=8,
BP_iNNodes=12,
BP_iBasePosition=16,
BP_iNodesPos=28,
BP_iTrianglesPos=32,
BP_iHasInternalMemAlloc=36,
BP_iBox=38,
};
/**
This is ugly, but due to compatibility and 64 bit support we have to do that ... sorry
*/
void SubModel::initFromBinBlock(void *pBinBlock)
{
iNTriangles = *((unsigned int *)(((char *) pBinBlock) + BP_iNTriangles));
iNNodes = *((unsigned int *) (((char *) pBinBlock) + BP_iNNodes));
iBasePosition = *((Vector3 *) (((char *) pBinBlock) + BP_iBasePosition));
iNodesPos = *((unsigned int *) (((char *) pBinBlock) + BP_iNodesPos));
iTrianglesPos = *((unsigned int *) (((char *) pBinBlock) + BP_iTrianglesPos));
iHasInternalMemAlloc = *((bool *) (((char *) pBinBlock) + BP_iHasInternalMemAlloc));
iBox = *((ShortBox *) (((char *) pBinBlock) + BP_iBox));
}
//==========================================================
void SubModel::countNodesAndTriangles(AABSPTree<Triangle>::Node& pNode, int &pNNodes, int &pNTriabgles)
{
++pNNodes;
pNTriabgles += pNode.valueArray.size();
#ifdef _ASSEMBLER_DEBUG
fprintf(::g_df, "Nodes: %d, Tris: %d\n",pNNodes, pNTriabgles);
#endif
if(pNode.child[0] != 0)
{
countNodesAndTriangles(*pNode.child[0], pNNodes, pNTriabgles);
}
if(pNode.child[1] != 0)
{
countNodesAndTriangles(*pNode.child[1], pNNodes, pNTriabgles);
}
}
//==========================================================
void SubModel::fillContainer(const AABSPTree<Triangle>::Node& pNode, int &pTreeNodePos, int &pTrianglePos, Vector3& pLo, Vector3& pHi)
{
TreeNode treeNode = TreeNode(pNode.valueArray.size(), pTrianglePos);
treeNode.setSplitAxis(pNode.splitAxis);
treeNode.setSplitLocation(pNode.splitLocation);
int currentTreeNodePos = pTreeNodePos++;
Vector3 lo = Vector3(inf(),inf(),inf());
Vector3 hi = Vector3(-inf(),-inf(),-inf());
for(int i=0;i<pNode.valueArray.size(); i++)
{
G3D::_AABSPTree::Handle<Triangle>* h= pNode.valueArray[i];
Triangle t = h->value;
TriangleBox triangleBox = TriangleBox(t.vertex(0),t.vertex(1), t.vertex(2));
lo = lo.min(triangleBox.getBounds().getLo().getVector3());
hi = hi.max(triangleBox.getBounds().getHi().getVector3());
getTriangles()[pTrianglePos++] = triangleBox;
}
if(pNode.child[0] != 0)
{
treeNode.setChildPos(0, pTreeNodePos);
fillContainer(*pNode.child[0], pTreeNodePos, pTrianglePos, lo, hi);
}
if(pNode.child[1] != 0)
{
treeNode.setChildPos(1, pTreeNodePos);
fillContainer(*pNode.child[1], pTreeNodePos, pTrianglePos, lo, hi);
}
treeNode.setBounds(lo,hi);
// get absolute bounds
pLo = pLo.min(lo);
pHi = pHi.max(hi);
getTreeNodes()[currentTreeNodePos] = treeNode;
}
//==========================================================
SubModel::SubModel(AABSPTree<Triangle> *pTree)
{
int nNodes, nTriangles;
nNodes = nTriangles = 0;
countNodesAndTriangles(*pTree->root, nNodes, nTriangles);
init(nNodes, nTriangles);
iTrianglesPos = 0; // this is the global array
iNodesPos = 0; // this is the global array
iHasInternalMemAlloc = true;
int treeNodePos, trianglePos;
treeNodePos = trianglePos = 0;
Vector3 lo = Vector3(inf(),inf(),inf());
Vector3 hi = Vector3(-inf(),-inf(),-inf());
fillContainer(*pTree->root, treeNodePos, trianglePos, lo, hi);
setReletiveBounds(lo, hi);
}
//==========================================================
#ifdef _DEBUG_VMAPS
#ifndef gBoxArray
extern Vector3 p1,p2,p3,p4,p5,p6,p7;
extern Array<AABox>gBoxArray;
extern Array<G3D::Triangle>gTriArray;
extern int gCount1, gCount2, gCount3, gCount4;
extern bool myfound;
#endif
#endif
//==========================================================
void SubModel::intersect(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit, G3D::Vector3& /*pOutLocation*/, G3D::Vector3& /*pOutNormal*/) const
{
NodeValueAccess<TreeNode, TriangleBox> vna = NodeValueAccess<TreeNode, TriangleBox>(getTreeNodes(), getTriangles());
IntersectionCallBack<TriangleBox> intersectCallback;
Ray relativeRay = Ray::fromOriginAndDirection(pRay.origin - getBasePosition(), pRay.direction);
#ifdef _DEBUG_VMAPS
//p6=getBasePosition();
//gBoxArray.push_back(getAABoxBounds());
#endif
getTreeNode(0).intersectRay(relativeRay, intersectCallback, pMaxDist, vna, pStopAtFirstHit, false);
}
//==========================================================
bool SubModel::intersect(const G3D::Ray& pRay, float& pMaxDist) const
{
return BaseModel::intersect(getAABoxBounds(), pRay, pMaxDist);
}
//==========================================================
template<typename RayCallback>
void SubModel::intersectRay(const Ray& pRay, RayCallback& pIntersectCallback, float& pMaxDist, bool pStopAtFirstHit, bool intersectCallbackIsFast)
{
if(intersect(pRay, pMaxDist))
{
NodeValueAccess<TreeNode, TriangleBox> vna = NodeValueAccess<TreeNode, TriangleBox>(getTreeNodes(), getTriangles());
IntersectionCallBack<TriangleBox> intersectCallback;
getTreeNode(0).intersectRay(pRay, intersectCallback, pMaxDist, vna, pStopAtFirstHit, false);
}
}
//==========================================================
}

102
src/shared/vmap/SubModel.h Normal file
View file

@ -0,0 +1,102 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SUBMODEL_H
#define _SUBMODEL_H
// load our modified version first !!
#include "AABSPTree.h"
#include "ShortVector.h"
#include "ShortBox.h"
#include "TreeNode.h"
#include "VMapTools.h"
#include "BaseModel.h"
namespace VMAP
{
/**
This is a balanced static BSP-Tree of triangles.
The memory for the tree nodes and the triangles are managed by the ModelContainer.
The exception to this is during the conversion of raw data info balanced BSP-Trees.
During this conversion the memory management is done internally.
*/
class SubModel : public BaseModel
{
private:
unsigned int iNodesPos;
unsigned int iTrianglesPos;
bool iHasInternalMemAlloc;
ShortBox iBox;
#ifdef _DEBUG_VIEW
G3D::Array<TriangleBox *> iDrawBox;
#endif
public:
SubModel() : BaseModel(){ };
SubModel(unsigned int pNTriangles, TriangleBox *pTriangles, unsigned int pTrianglesPos, unsigned int pNNodes, TreeNode *pTreeNodes, unsigned int pNodesPos);
SubModel(G3D::AABSPTree<G3D::Triangle> *pTree);
~SubModel(void);
//Gets a 50 byte binary block
void initFromBinBlock(void *pBinBlock);
void fillRenderArray(G3D::Array<TriangleBox> &pArray, const TreeNode* pTreeNode);
void countNodesAndTriangles(G3D::AABSPTree<G3D::Triangle>::Node& pNode, int &pNNodes, int &pNTriabgles);
void fillContainer(const G3D::AABSPTree<G3D::Triangle>::Node& pNode, int &pTreeNodePos, int &pTrianglePos, G3D::Vector3& pLo, G3D::Vector3& pHi);
inline const ShortBox& getReletiveBounds() const { return(iBox); }
inline void setReletiveBounds(const ShortVector& lo, const ShortVector& hi) { iBox.setLo(lo); iBox.setHi(hi); }
inline const G3D::AABox getAABoxBounds() const { return(G3D::AABox(iBox.getLo().getVector3() + getBasePosition(), iBox.getHi().getVector3()+ getBasePosition())); }
// get start pos bases on the global array
inline TriangleBox const* getTriangles() const { return &BaseModel::getTriangle(iTrianglesPos); }
inline TriangleBox * getTriangles() { return &BaseModel::getTriangle(iTrianglesPos); }
// get start pos bases on the global array
inline TreeNode const* getTreeNodes() const { return &BaseModel::getTreeNode(iNodesPos); }
inline TreeNode * getTreeNodes() { return &BaseModel::getTreeNode(iNodesPos); }
// internal method usign internal offset
inline const TreeNode& getTreeNode(int pPos) const { return(SubModel::getTreeNodes()[pPos]); }
// internal method usign internal offset
inline const TriangleBox& getTriangle(int pPos) const { return(SubModel::getTriangles()[pPos]); }
inline unsigned int getNodesPos() const { return(iNodesPos); }
inline unsigned int getTrianglesPos() const { return(iTrianglesPos); }
//unsigned int hashCode() { return (getBasePosition() * getNTriangles()).hashCode(); }
void intersect(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit, G3D::Vector3& pOutLocation, G3D::Vector3& pOutNormal) const;
bool intersect(const G3D::Ray& pRay, float& pMaxDist) const;
template<typename RayCallback>
void intersectRay(const G3D::Ray& ray, RayCallback& intersectCallback, float& distance, bool pStopAtFirstHit, bool intersectCallbackIsFast = false);
bool operator==(const SubModel& pSm2) const;
unsigned int hashCode() const { return BaseModel::getNTriangles(); }
};
unsigned int hashCode(const SubModel& pSm);
void getBounds(const SubModel& pSm, G3D::AABox& pAABox);
void getBounds(const SubModel* pSm, G3D::AABox& pAABox);
//====================================
} // VMAP
#endif

View file

@ -0,0 +1,571 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <G3D/Vector3.h>
#include <G3D/Triangle.h>
#include "TileAssembler.h"
#include "CoordModelMapping.h"
#include "ModelContainer.h"
#include <limits.h>
#include <string.h>
#ifdef _ASSEMBLER_DEBUG
FILE *g_df = NULL;
#endif
using namespace G3D;
namespace VMAP
{
//=================================================================
Vector3 ModelPosition::transform(const Vector3& pIn) const
{
//return(pIn);
Vector3 out = pIn * iScale;
out = izMatrix * out;
out = ixMatrix * out;
out = iyMatrix * out;
return(out);
}
//=================================================================
TileAssembler::TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName)
{
iCurrentUniqueNameId = 0;
iFilterMethod = NULL;
iSrcDir = pSrcDirName;
iDestDir = pDestDirName;
//mkdir(iDestDir);
init();
}
//=================================================================
TileAssembler::~TileAssembler()
{
delete iCoordModelMapping;
}
//=================================================================
void TileAssembler::init()
{
iCoordModelMapping = new CoordModelMapping();
addWorldAreaMapId(0); //Azeroth
addWorldAreaMapId(1); //Kalimdor
addWorldAreaMapId(530); //Expansion01
}
//=================================================================
std::string getModNameFromModPosName(const std::string& pModPosName)
{
size_t spos = pModPosName.find_first_of('#');
std::string modelFileName = pModPosName.substr(0,spos);
return(modelFileName);
}
//=================================================================
unsigned int TileAssembler::getUniqueNameId(const std::string pName)
{
unsigned int result;
if(!iUniqueNameIds.containsKey(pName))
{
++iCurrentUniqueNameId;
iUniqueNameIds.set(pName, iCurrentUniqueNameId);
}
result = iUniqueNameIds.get(pName);
return result;
}
//=================================================================
std::string TileAssembler::getDirEntryNameFromModName(unsigned int pMapId, const std::string& pModPosName)
{
size_t spos;
char buffer[20];
std::string modelFileName = getModNameFromModPosName(pModPosName);
//std::string fext = pModPosName.substr(modelFileName.length(),pModPosName.length());
unsigned int fextId = getUniqueNameId(pModPosName);
sprintf(buffer, "_%07d",fextId);
std::string fext(buffer);
spos = modelFileName.find_last_of('/');
std::string fname = modelFileName.substr(spos+1, modelFileName.length());
spos = fname.find_last_of('.');
fname = fname.substr(0,spos);
sprintf(buffer, "%03u", pMapId);
std::string dirEntry(buffer);
dirEntry.append("_");
dirEntry.append(fname);
dirEntry.append(fext);
dirEntry.append(".vmap");
return(dirEntry);
}
//=================================================================
void emptyArray(Array<ModelContainer*>& mc)
{
int no=mc.size();
while(no > 0)
{
--no;
delete mc[no];
mc.remove(no);
}
}
//=================================================================
bool TileAssembler::convertWorld()
{
#ifdef _ASSEMBLER_DEBUG
# ifdef _DEBUG
::g_df = fopen("../TileAssembler_debug.txt", "wb");
# else
::g_df = fopen("../TileAssembler_release.txt", "wb");
# endif
#endif
bool result = true;
std::string fname = iSrcDir;
fname.append("/");
fname.append("dir");
iCoordModelMapping->setModelNameFilterMethod(iFilterMethod);
iCoordModelMapping->readCoordinateMapping(fname);
Array<unsigned int> mapIds = iCoordModelMapping->getMaps();
if(mapIds.size() == 0)
{
result = false;
}
for(int i=0; i<mapIds.size() && result; ++i)
{
unsigned int mapId = mapIds[i];
#ifdef _ASSEMBLER_DEBUG
if(mapId == 0) // "Azeroth" just for debug
{
for(int x=28; x<29 && result; ++x) //debug
{
for(int y=28; y<29 && result; ++y)
{
#else
// ignore DeeprunTram (369) it is too large for short vector and not important
// ignore test (13), Test (29) , development (451)
if(mapId != 369 && mapId != 13 && mapId != 29 && mapId != 451)
{
for(int x=0; x<66 && result; ++x)
{
for(int y=0; y<66 && result; ++y)
{
#endif
Array<ModelContainer*> mc;
std::string dirname;
char buffer[100];
if(iCoordModelMapping->isWorldAreaMap(mapId) && x<65 && y<65)
{
sprintf(buffer, "%03u_%d_%d",mapId,y,x); // Let's flip x and y here
dirname = std::string(buffer);
}
else
{
sprintf(buffer, "%03u",mapId);
dirname = std::string(buffer);
}
result = fillModelContainerArray(dirname, mapId, x, y, mc);
emptyArray(mc);
}
}
}
}
#ifdef _ASSEMBLER_DEBUG
if(::g_df) fclose(::g_df);
#endif
return result;
}
//=================================================================
bool TileAssembler::fillModelContainerArray(const std::string& pDirFileName, unsigned int pMapId, int pXPos, int pYPos, Array<ModelContainer*>& pMC)
{
bool result = true;
ModelContainer* modelContainer;
NameCollection nameCollection = iCoordModelMapping->getFilenamesForCoordinate(pMapId, pXPos, pYPos);
if(nameCollection.size() > 0)
{
result = false;
char dirfilename[500];
sprintf(dirfilename,"%s/%s.vmdir",iDestDir.c_str(),pDirFileName.c_str());
FILE *dirfile = fopen(dirfilename, "ab");
if(dirfile)
{
result = true;
char destnamebuffer[500];
char fullnamedestnamebuffer[500];
if(nameCollection.iMainFiles.size() >0)
{
sprintf(destnamebuffer,"%03u_%i_%i.vmap",pMapId, pYPos, pXPos); // flip it here too
std::string checkDoubleStr = std::string(dirfilename);
checkDoubleStr.append("##");
checkDoubleStr.append(std::string(destnamebuffer));
// Check, if same file already is in the same dir file
if(!iCoordModelMapping->isAlreadyProcessedSingleFile(checkDoubleStr))
{
iCoordModelMapping->addAlreadyProcessedSingleFile(checkDoubleStr);
fprintf(dirfile, "%s\n",destnamebuffer);
sprintf(fullnamedestnamebuffer,"%s/%s",iDestDir.c_str(),destnamebuffer);
modelContainer = processNames(nameCollection.iMainFiles, fullnamedestnamebuffer);
if(modelContainer)
{
pMC.append(modelContainer);
}
else
{
result = false;
}
}
}
// process the large singe files
int pos = 0;
while(result && (pos < nameCollection.iSingeFiles.size()))
{
std::string destFileName = iDestDir;
destFileName.append("/");
std::string dirEntryName = getDirEntryNameFromModName(pMapId,nameCollection.iSingeFiles[pos]);
std::string checkDoubleStr = std::string(dirfilename);
checkDoubleStr.append("##");
checkDoubleStr.append(nameCollection.iSingeFiles[pos]);
// Check, if same file already is in the same dir file
if(!iCoordModelMapping->isAlreadyProcessedSingleFile(checkDoubleStr))
{
iCoordModelMapping->addAlreadyProcessedSingleFile(checkDoubleStr);
fprintf(dirfile, "%s\n",dirEntryName.c_str());
destFileName.append(dirEntryName);
Array<std::string> positionarray;
positionarray.append(nameCollection.iSingeFiles[pos]);
if(!iCoordModelMapping->isAlreadyProcessedSingleFile(nameCollection.iSingeFiles[pos]))
{
modelContainer = processNames(positionarray, destFileName.c_str());
iCoordModelMapping->addAlreadyProcessedSingleFile(nameCollection.iSingeFiles[pos]);
if(modelContainer)
{
pMC.append(modelContainer);
}
else
{
result = false;
}
}
}
++pos;
}
fclose(dirfile);
}
}
return(result);
}
//=================================================================
void removeEntriesFromTree(AABSPTree<SubModel *>* pTree)
{
Array<SubModel *> submodelArray;
pTree->getMembers(submodelArray);
int no = submodelArray.size();
while(no > 0)
{
--no;
delete submodelArray[no];
}
}
//=================================================================
ModelContainer* TileAssembler::processNames(const Array<std::string>& pPositions, const char* pDestFileName)
{
ModelContainer *modelContainer = 0;
Vector3 basepos = Vector3(0,0,0);
AABSPTree<SubModel *>* mainTree = new AABSPTree<SubModel *>();
int pos = 0;
bool result = true;
while(result && (pos < pPositions.size()))
{
std::string modelPosString = pPositions[pos];
std::string modelFileName = getModNameFromModPosName(modelPosString);
if(!fillModelIntoTree(mainTree, basepos, modelPosString, modelFileName))
{
result = false;
break;
}
++pos;
}
if(result && mainTree->size() > 0)
{
mainTree->balance();
modelContainer = new ModelContainer(mainTree);
modelContainer->writeFile(pDestFileName);
}
removeEntriesFromTree(mainTree);
delete mainTree;
return(modelContainer);
}
//=================================================================
bool TileAssembler::readRawFile(std::string& pModelFilename, ModelPosition& pModelPosition, AABSPTree<SubModel *> *pMainTree)
{
bool result = false;
std::string filename = iSrcDir;
if(filename.length() >0)
filename.append("/");
filename.append(pModelFilename);
FILE *rf = fopen(filename.c_str(), "rb");
if(!rf)
{
// depending on the extractor version, the data could be located in the root dir
std::string baseModelFilename = pModelFilename.substr((pModelFilename.find_first_of("/")+1),pModelFilename.length());
filename = iSrcDir;
if(filename.length() >0)
filename.append("/");
filename.append(baseModelFilename);
rf = fopen(filename.c_str(), "rb");
}
char ident[8];
int trianglecount =0;
#ifdef _ASSEMBLER_DEBUG
int startgroup = 0; //2;
int endgroup = INT_MAX; //2;
fprintf(::g_df,"-------------------------------------------------\n");
fprintf(::g_df,"%s\n", pModelFilename.c_str());
fprintf(::g_df,"-------------------------------------------------\n");
#else
int startgroup = 0;
int endgroup = INT_MAX;
#endif
if(rf)
{
if(fread(&ident, 8, 1, rf) != 1) { fclose(rf); return(false); }
if(strcmp(ident, "VMAP001") == 0)
{
// OK, do nothing
}
else if(strcmp(ident, "VMAP002") == 0)
{
// we have to read one int. This is needed during the export and we have to skip it here
int tempNVectors;
if(fread(&tempNVectors, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); }
}
else
{
// wrong version
fclose(rf);
return(false);
}
G3D::uint32 groups;
char blockId[5];
blockId[4] = 0;
int blocksize;
if(fread(&groups, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); }
for(int g=0;g<(int)groups;g++)
{
// group MUST NOT have more then 65536 indexes !! Array will have a problem with that !! (strange ...)
Array<int> tempIndexArray;
Array<Vector3> tempVertexArray;
AABSPTree<Triangle> *gtree = new AABSPTree<Triangle>();
G3D::uint32 flags;
if(fread(&flags, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); }
G3D::uint32 branches;
if(fread(&blockId, 4, 1, rf) != 1) { fclose(rf); return(false); }
if(strcmp(blockId, "GRP ") != 0) { fclose(rf); return(false); }
if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); }
if(fread(&branches, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); }
for(int b=0;b<(int)branches; b++)
{
G3D::uint32 indexes;
// indexes for each branch (not used jet)
if(fread(&indexes, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); }
}
// ---- indexes
if(fread(&blockId, 4, 1, rf) != 1) { fclose(rf); return(false); }
if(strcmp(blockId, "INDX") != 0) { fclose(rf); return(false); }
if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); }
unsigned int nindexes;
if(fread(&nindexes, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); }
if(nindexes >0)
{
unsigned short *indexarray = new unsigned short[nindexes*sizeof(unsigned short)];
if(fread(indexarray, sizeof(unsigned short), nindexes, rf) != nindexes) { fclose(rf); return(false); }
for(int i=0;i<(int)nindexes; i++)
{
unsigned short val = indexarray[i];
tempIndexArray.append(val);
}
delete indexarray;
}
// ---- vectors
if(fread(&blockId, 4, 1, rf) != 1) {fclose(rf); return(false); }
if(strcmp(blockId, "VERT") != 0) { fclose(rf); return(false); }
if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); }
unsigned int nvectors;
if(fread(&nvectors, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); }
float *vectorarray = 0;
if(nvectors >0)
{
vectorarray = new float[nvectors*sizeof(float)*3];
if(fread(vectorarray, sizeof(float)*3, nvectors, rf) != nvectors) { fclose(rf); return(false); }
}
// ----- liquit
if(flags & 1)
{
// we have liquit -> not handled yet ... skip
if(fread(&blockId, 4, 1, rf) != 1) { fclose(rf); return(false); }
if(strcmp(blockId, "LIQU") != 0) { fclose(rf); return(false); }
if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); }
fseek(rf, blocksize, SEEK_CUR);
}
for(unsigned int i=0, indexNo=0; indexNo<nvectors; indexNo++)
{
Vector3 v = Vector3(vectorarray[i+2], vectorarray[i+1], vectorarray[i+0]);
i+=3;
v = pModelPosition.transform(v);
float swapy = v.y;
v.y = v.x;
v.x = swapy;
tempVertexArray.append(v);
}
// ---- calculate triangles
int rest = nindexes%3;
if(rest != 0)
{
nindexes -= rest;
}
for(unsigned int i=0;i<(nindexes);)
{
Triangle t = Triangle(tempVertexArray[tempIndexArray[i+2]], tempVertexArray[tempIndexArray[i+1]], tempVertexArray[tempIndexArray[i+0]] );
i+=3;
++trianglecount;
if(g>= startgroup && g <= endgroup)
{
gtree->insert(t);
}
}
if(vectorarray != 0)
{
delete vectorarray;
}
if(gtree->size() >0)
{
gtree->balance();
SubModel *sm = new SubModel(gtree);
#ifdef _ASSEMBLER_DEBUG
if(::g_df) fprintf(::g_df,"group trianglies: %d, Tris: %d, Nodes: %d, gtree.triangles: %d\n", g, sm->getNTriangles(), sm->getNNodes(), gtree->memberTable.size());
if(sm->getNTriangles() != gtree->memberTable.size())
{
if(::g_df) fprintf(::g_df,"ERROR !!!! group trianglies: %d, Tris: %d, Nodes: %d, gtree.triangles: %d\n", g, sm->getNTriangles(), sm->getNNodes(), gtree->memberTable.size());
}
#endif
sm->setBasePosition(pModelPosition.iPos);
pMainTree->insert(sm);
}
delete gtree;
}
fclose(rf);
result = true;
}
return(result);
}
//=================================================================
bool TileAssembler::fillModelIntoTree(AABSPTree<SubModel *> *pMainTree, const Vector3& pBasePos, std::string& pPos, std::string& pModelFilename)
{
bool result = false;
ModelPosition modelPosition;
getModelPosition(pPos, modelPosition);
// all should be relative to object base position
modelPosition.moveToBasePos(pBasePos);
modelPosition.init();
if(readRawFile(pModelFilename, modelPosition, pMainTree))
{
result = true;
}
return result;
}
//=================================================================
void TileAssembler::getModelPosition(std::string& pPosString, ModelPosition& pModelPosition)
{
float vposarray[3];
float vdirarray[3];
float scale;
size_t spos = pPosString.find_first_of('#');
std::string stripedPosString = pPosString.substr(spos+1,pPosString.length());
sscanf(stripedPosString.c_str(), "%f,%f,%f_%f,%f,%f_%f",
&vposarray[0],&vposarray[1],&vposarray[2],
&vdirarray[0],&vdirarray[1],&vdirarray[2],
&scale);
pModelPosition.iPos = Vector3(vposarray[0], vposarray[1], vposarray[2]);
pModelPosition.iDir = Vector3(vdirarray[0], vdirarray[1], vdirarray[2]);
pModelPosition.iScale = scale;
}
//==========================================
} // VMAP

View file

@ -0,0 +1,93 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _TILEASSEMBLER_H_
#define _TILEASSEMBLER_H_
// load our modified version first !!
#include "AABSPTree.h"
#include <G3D/Vector3.h>
#include "CoordModelMapping.h"
#include "SubModel.h"
#include "ModelContainer.h"
namespace VMAP
{
/**
This Class is used to convert raw vector data into balanced BSP-Trees.
To start the conversion call convertWorld().
*/
//===============================================
class ModelPosition
{
private:
G3D::Matrix3 ixMatrix;
G3D::Matrix3 iyMatrix;
G3D::Matrix3 izMatrix;
public:
G3D::Vector3 iPos;
G3D::Vector3 iDir;
float iScale;
void init()
{
// Swap x and y the raw data uses the axis differently
ixMatrix = G3D::Matrix3::fromAxisAngle(G3D::Vector3::unitY(),-(G3D::pi()*iDir.x/180.0));
iyMatrix = G3D::Matrix3::fromAxisAngle(G3D::Vector3::unitX(),-(G3D::pi()*iDir.y/180.0));
izMatrix = G3D::Matrix3::fromAxisAngle(G3D::Vector3::unitZ(),-(G3D::pi()*iDir.z/180.0));
}
G3D::Vector3 transform(const G3D::Vector3& pIn) const;
void moveToBasePos(const G3D::Vector3& pBasePos) { iPos -= pBasePos; }
};
//===============================================
class TileAssembler
{
private:
CoordModelMapping *iCoordModelMapping;
std::string iDestDir;
std::string iSrcDir;
bool (*iFilterMethod)(char *pName);
G3D::Table<std::string, unsigned int > iUniqueNameIds;
unsigned int iCurrentUniqueNameId;
public:
TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName);
virtual ~TileAssembler();
bool fillModelContainerArray(const std::string& pDirFileName, unsigned int pMapId, int pXPos, int pYPos, G3D::Array<ModelContainer*>& pMC);
ModelContainer* processNames(const G3D::Array<std::string>& pPosFileNames, const char* pDestFileName);
void init();
bool convertWorld();
bool fillModelIntoTree(G3D::AABSPTree<SubModel *> *pMainTree, const G3D::Vector3& pBasePos, std::string& pPosFilename, std::string& pModelFilename);
void getModelPosition(std::string& pPosString, ModelPosition& pModelPosition);
bool readRawFile(std::string& pModelFilename, ModelPosition& pModelPosition, G3D::AABSPTree<SubModel *> *pMainTree);
void addWorldAreaMapId(unsigned int pMapId) { iCoordModelMapping->addWorldAreaMap(pMapId); }
void setModelNameFilterMethod(bool (*pFilterMethod)(char *pName)) { iFilterMethod = pFilterMethod; }
std::string getDirEntryNameFromModName(unsigned int pMapId, const std::string& pModPosName);
unsigned int getUniqueNameId(const std::string pName);
};
//===============================================
} // VMAP
#endif /*_TILEASSEMBLER_H_*/

View file

@ -0,0 +1,37 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "TreeNode.h"
using namespace G3D;
namespace VMAP
{
TreeNode const* TreeNode::getChild(TreeNode const* pValueArray,int pNo) const
{
if(iChilds[pNo] != -1)
return(&pValueArray[iChilds[pNo]]);
else
return(NULL);
}
//=================================================================
//=================================================================
//=================================================================
}

223
src/shared/vmap/TreeNode.h Normal file
View file

@ -0,0 +1,223 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _TREENODE_H
#define _TREENODE_H
#include "ShortVector.h"
#include "ShortBox.h"
#include "NodeValueAccess.h"
#include "VMapTools.h"
#include <G3D/Vector3.h>
#include <G3D/AABox.h>
namespace VMAP
{
/**
This Class is mainly taken from G3D/AABSPTree.h and modified to match our data structure.
It is the node within our static BSP-Trees.
It does not use pointers but indexes to access the values and other nodes.
*/
//=====================================================
class TreeNode
{
private:
/** Location along the specified axis */
float iSplitLocation;
// Offest or the clients
int iChilds[2];
//Position within the TriangleBox array
unsigned int iStartPosition;
G3D::Vector3::Axis iSplitAxis;
G3D::AABox iBounds;
unsigned short iNumberOfValues;
public:
TreeNode() {}
TreeNode(unsigned short pNValues, unsigned int pStartPosition)
{
iChilds[0] = -1;
iChilds[1] = -1;
iStartPosition = pStartPosition;
iNumberOfValues = pNValues;
}
bool hasChilds() const { return(iChilds[0] >= 0 || iChilds[1] >= 0); }
TreeNode const* getChild(TreeNode const* pValueArray, int pNo) const;
// pChildNo = 0 or 1
inline void setChildPos(int pChildNo, int pChildPosInTreeNodeArray) { iChilds[pChildNo] = pChildPosInTreeNodeArray; }
inline G3D::Vector3::Axis getSplitAxis() const { return(iSplitAxis); }
inline void setSplitAxis(G3D::Vector3::Axis a) { iSplitAxis = a; }
inline void setSplitLocation(float l) { iSplitLocation = l; }
inline void setBounds(const G3D::AABox& pBox) { iBounds = pBox; }
inline void setBounds(const G3D::Vector3& lo, const G3D::Vector3& hi) { iBounds.set(lo,hi); }
inline void getBounds(G3D::AABox& pBox) const { pBox.set(iBounds.low(),iBounds.high()); }
inline float getSplitLocation() const { return(iSplitLocation); }
inline unsigned short getNValues() const { return (iNumberOfValues); }
inline unsigned int getStartPosition() const { return(iStartPosition); }
inline bool operator==(const TreeNode& n) const
{
return ((iSplitLocation == n.iSplitLocation) &&
(iChilds[0] == n.iChilds[0]) && (iChilds[1] == n.iChilds[1]) &&
(iStartPosition == n.iStartPosition) &&
(iSplitAxis == n.iSplitAxis) &&
(iBounds == n.iBounds) &&
(iNumberOfValues == n.iNumberOfValues));
}
inline bool operator!=(const TreeNode& n) const
{
return !((iSplitLocation == n.iSplitLocation) &&
(iChilds[0] == n.iChilds[0]) && (iChilds[1] == n.iChilds[1]) &&
(iStartPosition == n.iStartPosition) &&
(iSplitAxis == n.iSplitAxis) &&
(iBounds == n.iBounds) &&
(iNumberOfValues == n.iNumberOfValues));
}
/** Returns true if the ray intersects this node */
bool intersects(const G3D::Ray& ray, float distance) const {
// See if the ray will ever hit this node or its children
G3D::Vector3 location;
bool alreadyInsideBounds = false;
bool rayWillHitBounds =
MyCollisionDetection::collisionLocationForMovingPointFixedAABox(
ray.origin, ray.direction, iBounds, location, alreadyInsideBounds);
bool canHitThisNode = (alreadyInsideBounds ||
(rayWillHitBounds && ((location - ray.origin).squaredLength() < (distance*distance))));
return canHitThisNode;
}
template<typename RayCallback, typename TNode, typename TValue>
void intersectRay(
const G3D::Ray& ray,
RayCallback& intersectCallback,
float& distance,
const NodeValueAccess<TNode, TValue>& pNodeValueAccess,
bool pStopAtFirstHit,
bool intersectCallbackIsFast) const {
float enterDistance = distance;
if (! intersects(ray, distance)) {
// The ray doesn't hit this node, so it can't hit the children of the node.
return;
}
// Test for intersection against every object at this node.
for (unsigned int v = iStartPosition; v < (iNumberOfValues+iStartPosition); ++v) {
const TValue& nodeValue = pNodeValueAccess.getValue(v);
bool canHitThisObject = true;
if (! intersectCallbackIsFast) {
// See if
G3D::Vector3 location;
const G3D::AABox& bounds = nodeValue.getAABoxBounds();
bool alreadyInsideBounds = false;
bool rayWillHitBounds =
MyCollisionDetection::collisionLocationForMovingPointFixedAABox(
ray.origin, ray.direction, bounds, location, alreadyInsideBounds);
canHitThisObject = (alreadyInsideBounds ||
(rayWillHitBounds && ((location - ray.origin).squaredLength() < (distance*distance))));
}
if (canHitThisObject) {
// It is possible that this ray hits this object. Look for the intersection using the
// callback.
intersectCallback(ray, &nodeValue, pStopAtFirstHit, distance);
}
if(pStopAtFirstHit && distance < enterDistance)
return;
}
// There are three cases to consider next:
//
// 1. the ray can start on one side of the splitting plane and never enter the other,
// 2. the ray can start on one side and enter the other, and
// 3. the ray can travel exactly down the splitting plane
enum {NONE = -1};
int firstChild = NONE;
int secondChild = NONE;
if (ray.origin[iSplitAxis] < iSplitLocation) {
// The ray starts on the small side
firstChild = 0;
if (ray.direction[iSplitAxis] > 0) {
// The ray will eventually reach the other side
secondChild = 1;
}
} else if (ray.origin[iSplitAxis] > iSplitLocation) {
// The ray starts on the large side
firstChild = 1;
if (ray.direction[iSplitAxis] < 0) {
secondChild = 0;
}
} else {
// The ray starts on the splitting plane
if (ray.direction[iSplitAxis] < 0) {
// ...and goes to the small side
firstChild = 0;
} else if (ray.direction[iSplitAxis] > 0) {
// ...and goes to the large side
firstChild = 1;
}
}
// Test on the side closer to the ray origin.
if ((firstChild != NONE) && iChilds[firstChild]>0) {
getChild(pNodeValueAccess.getNodePtr() , firstChild)->intersectRay(ray, intersectCallback, distance, pNodeValueAccess, pStopAtFirstHit,intersectCallbackIsFast);
if(pStopAtFirstHit && distance < enterDistance)
return;
}
if (ray.direction[iSplitAxis] != 0) {
// See if there was an intersection before hitting the splitting plane.
// If so, there is no need to look on the far side and recursion terminates.
float distanceToSplittingPlane = (iSplitLocation - ray.origin[iSplitAxis]) / ray.direction[iSplitAxis];
if (distanceToSplittingPlane > distance) {
// We aren't going to hit anything else before hitting the splitting plane,
// so don't bother looking on the far side of the splitting plane at the other
// child.
return;
}
}
// Test on the side farther from the ray origin.
if ((secondChild != NONE) && iChilds[secondChild]>0) {
getChild(pNodeValueAccess.getNodePtr() , secondChild)->intersectRay(ray, intersectCallback, distance, pNodeValueAccess, pStopAtFirstHit,intersectCallbackIsFast);
}
}
};
}
#endif

View file

@ -0,0 +1,37 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _VMAPDEFINITIONS_H
#define _VMAPDEFINITIONS_H
#include <cstring>
namespace VMAP
{
//=====================================
#define MAX_CAN_FALL_DISTANCE 10.0
const char VMAP_MAGIC[] = "VMAP_2.0";
class VMapDefinitions
{
public:
static const double getMaxCanFallDistance() { return(MAX_CAN_FALL_DISTANCE); }
};
//======================================
}
#endif

View file

@ -0,0 +1,104 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <sys/types.h>
#include "VMapFactory.h"
#include "VMapManager.h"
using namespace G3D;
namespace VMAP
{
extern void chompAndTrim(std::string& str);
VMapManager *gVMapManager = 0;
Table<unsigned int , bool>* iIgnoreSpellIds=0;
//===============================================
// result false, if no more id are found
bool getNextId(const std::string& pString, unsigned int& pStartPos, unsigned int& pId)
{
bool result = false;
unsigned int i;
for(i=pStartPos;i<pString.size(); ++i)
{
if(pString[i] == ',')
{
break;
}
}
if(i>pStartPos)
{
std::string idString = pString.substr(pStartPos, i-pStartPos);
pStartPos = i+1;
chompAndTrim(idString);
pId = atoi(idString.c_str());
result = true;
}
return(result);
}
//===============================================
/**
parameter: String of map ids. Delimiter = ","
*/
void VMapFactory::preventSpellsFromBeingTestedForLoS(const char* pSpellIdString)
{
if(!iIgnoreSpellIds)
iIgnoreSpellIds = new Table<unsigned int , bool>();
if(pSpellIdString != NULL)
{
unsigned int pos =0;
unsigned int id;
std::string confString(pSpellIdString);
chompAndTrim(confString);
while(getNextId(confString, pos, id))
{
iIgnoreSpellIds->set(id, true);
}
}
}
//===============================================
bool VMapFactory::checkSpellForLoS(unsigned int pSpellId)
{
return(!iIgnoreSpellIds->containsKey(pSpellId));
}
//===============================================
// just return the instance
IVMapManager* VMapFactory::createOrGetVMapManager()
{
if(gVMapManager == 0)
gVMapManager= new VMapManager(); // should be taken from config ... Please change if you like :-)
return gVMapManager;
}
//===============================================
// delete all internal data structures
void VMapFactory::clear()
{
if(iIgnoreSpellIds)
delete iIgnoreSpellIds;
if(gVMapManager)
delete gVMapManager;
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _VMAPFACTORY_H
#define _VMAPFACTORY_H
#include "IVMapManager.h"
/**
This is the access point to the VMapManager.
*/
namespace VMAP
{
//===========================================================
class VMapFactory
{
public:
static IVMapManager* createOrGetVMapManager();
static void clear();
static void preventSpellsFromBeingTestedForLoS(const char* pSpellIdString);
static bool checkSpellForLoS(unsigned int pSpellId);
};
}
#endif

View file

@ -0,0 +1,780 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "VMapManager.h"
#include "VMapDefinitions.h"
using namespace G3D;
namespace VMAP
{
//=========================================================
VMapManager::VMapManager()
{
#ifdef _VMAP_LOG_DEBUG
iCommandLogger.setFileName("vmapcmd.log");
iCommandLogger.setResetFile();
#endif
}
//=========================================================
VMapManager::~VMapManager(void)
{
Array<unsigned int > keyArray = iInstanceMapTrees.getKeys();
for(int i=0;i<keyArray.size(); ++i)
{
delete iInstanceMapTrees.get(keyArray[i]);
iInstanceMapTrees.remove(keyArray[i]);
}
}
//=========================================================
Vector3 VMapManager::convertPositionToInternalRep(float x, float y, float z) const
{
float pos[3];
pos[0] = y;
pos[1] = z;
pos[2] = x;
double full = 64.0*533.33333333;
double mid = full/2.0;
pos[0] = full- (pos[0] + mid);
pos[2] = full- (pos[2] + mid);
return(Vector3(pos));
}
//=========================================================
Vector3 VMapManager::convertPositionToMangosRep(float x, float y, float z) const
{
float pos[3];
pos[0] = z;
pos[1] = x;
pos[2] = y;
double full = 64.0*533.33333333;
double mid = full/2.0;
pos[0] = -((mid+pos[0])-full);
pos[1] = -((mid+pos[1])-full);
return(Vector3(pos));
}
//=========================================================
std::string VMapManager::getDirFileName(unsigned int pMapId, int x, int y) const
{
char name[FILENAMEBUFFER_SIZE];
sprintf(name, "%03u_%d_%d%s",pMapId, x, y, DIR_FILENAME_EXTENSION);
return(std::string(name));
}
//=========================================================
std::string VMapManager::getDirFileName(unsigned int pMapId) const
{
char name[FILENAMEBUFFER_SIZE];
sprintf(name, "%03d%s",pMapId, DIR_FILENAME_EXTENSION);
return(std::string(name));
}
//=========================================================
// remote last return or LF
void chomp(std::string& str)
{
while(str.length() >0)
{
char lc = str[str.length()-1];
if(lc == '\r' || lc == '\n')
{
str = str.substr(0,str.length()-1);
}
else
{
break;
}
}
}
//=========================================================
void chompAndTrim(std::string& str)
{
while(str.length() >0)
{
char lc = str[str.length()-1];
if(lc == '\r' || lc == '\n' || lc == ' ' || lc == '"' || lc == '\'')
{
str = str.substr(0,str.length()-1);
}
else
{
break;
}
}
while(str.length() >0)
{
char lc = str[0];
if(lc == ' ' || lc == '"' || lc == '\'')
{
str = str.substr(1,str.length()-1);
}
else
{
break;
}
}
}
//=========================================================
// result false, if no more id are found
bool getNextMapId(const std::string& pString, unsigned int& pStartPos, unsigned int& pId)
{
bool result = false;
unsigned int i;
for(i=pStartPos;i<pString.size(); ++i)
{
if(pString[i] == ',')
{
break;
}
}
if(i>pStartPos)
{
std::string idString = pString.substr(pStartPos, i-pStartPos);
pStartPos = i+1;
chompAndTrim(idString);
pId = atoi(idString.c_str());
result = true;
}
return(result);
}
//=========================================================
/**
Block maps from being used.
parameter: String of map ids. Delimiter = ","
e.g.: "0,1,590"
*/
void VMapManager::preventMapsFromBeingUsed(const char* pMapIdString)
{
if(pMapIdString != NULL)
{
unsigned int pos =0;
unsigned int id;
std::string confString(pMapIdString);
chompAndTrim(confString);
while(getNextMapId(confString, pos, id))
{
iIgnoreMapIds.set(id, true);
}
}
}
//=========================================================
int VMapManager::loadMap(const char* pBasePath, unsigned int pMapId, int x, int y)
{
int result = VMAP_LOAD_RESULT_IGNORED;
if(isMapLoadingEnabled() && !iIgnoreMapIds.containsKey(pMapId))
{
bool loaded = _loadMap(pBasePath, pMapId, x, y, false);
if(!loaded)
{
// if we can't load the map it might be splitted into tiles. Try that one and store the result
loaded = _loadMap(pBasePath, pMapId, x, y, true);
if(loaded)
{
iMapsSplitIntoTiles.set(pMapId, true);
}
}
if(loaded)
{
result = VMAP_LOAD_RESULT_OK;
// just for debugging
#ifdef _VMAP_LOG_DEBUG
Command c = Command();
c.fillLoadTileCmd(x, y, pMapId);
iCommandLogger.appendCmd(c);
#endif
}
else
{
result = VMAP_LOAD_RESULT_ERROR;
}
}
return result;
}
//=========================================================
// load one tile (internal use only)
bool VMapManager::_loadMap(const char* pBasePath, unsigned int pMapId, int x, int y, bool pForceTileLoad)
{
bool result = false;
std::string dirFileName;
if(pForceTileLoad || iMapsSplitIntoTiles.containsKey(pMapId))
{
dirFileName = getDirFileName(pMapId,x,y);
}
else
{
dirFileName = getDirFileName(pMapId);
}
MapTree* instanceTree;
if(!iInstanceMapTrees.containsKey(pMapId))
{
instanceTree = new MapTree(pBasePath);
iInstanceMapTrees.set(pMapId, instanceTree);
}
else
instanceTree = iInstanceMapTrees.get(pMapId);
unsigned int mapTileIdent = MAP_TILE_IDENT(x,y);
result = instanceTree->loadMap(dirFileName, mapTileIdent);
if(!result) // remove on fail
{
if(instanceTree->size() == 0)
{
iInstanceMapTrees.remove(pMapId);
delete instanceTree;
}
}
return(result);
}
//=========================================================
bool VMapManager::_existsMap(const std::string& pBasePath, unsigned int pMapId, int x, int y, bool pForceTileLoad)
{
bool result = false;
std::string dirFileName;
if(pForceTileLoad || iMapsSplitIntoTiles.containsKey(pMapId))
{
dirFileName = getDirFileName(pMapId,x,y);
}
else
{
dirFileName = getDirFileName(pMapId);
}
size_t len = pBasePath.length() + dirFileName.length();
char *filenameBuffer = new char[len+1];
sprintf(filenameBuffer, "%s%s", pBasePath.c_str(), dirFileName.c_str());
FILE* df = fopen(filenameBuffer, "rb");
if(df)
{
char lineBuffer[FILENAMEBUFFER_SIZE];
if (fgets(lineBuffer, FILENAMEBUFFER_SIZE-1, df) != 0)
{
std::string name = std::string(lineBuffer);
chomp(name);
if(name.length() >1)
{
sprintf(filenameBuffer, "%s%s", pBasePath.c_str(), name.c_str());
FILE* df2 = fopen(filenameBuffer, "rb");
if(df2)
{
char magic[8];
fread(magic,1,8,df2);
if(!strncmp(VMAP_MAGIC,magic,8))
result = true;
fclose(df2);
}
}
}
fclose(df);
}
delete[] filenameBuffer;
return result;
}
//=========================================================
bool VMapManager::existsMap(const char* pBasePath, unsigned int pMapId, int x, int y)
{
std::string basePath = std::string(pBasePath);
if(basePath.length() > 0 && (basePath[basePath.length()-1] != '/' || basePath[basePath.length()-1] != '\\'))
{
basePath.append("/");
}
bool found = _existsMap(basePath, pMapId, x, y, false);
if(!found)
{
// if we can't load the map it might be splitted into tiles. Try that one and store the result
found = _existsMap(basePath, pMapId, x, y, true);
if(found)
{
iMapsSplitIntoTiles.set(pMapId, true);
}
}
return found;
}
//=========================================================
void VMapManager::unloadMap(unsigned int pMapId, int x, int y)
{
_unloadMap(pMapId, x, y);
#ifdef _VMAP_LOG_DEBUG
Command c = Command();
c.fillUnloadTileCmd(pMapId, x,y);
iCommandLogger.appendCmd(c);
#endif
}
//=========================================================
void VMapManager::_unloadMap(unsigned int pMapId, int x, int y)
{
if(iInstanceMapTrees.containsKey(pMapId))
{
MapTree* instanceTree = iInstanceMapTrees.get(pMapId);
std::string dirFileName;
if(iMapsSplitIntoTiles.containsKey(pMapId))
{
dirFileName = getDirFileName(pMapId,x,y);
}
else
{
dirFileName = getDirFileName(pMapId);
}
unsigned int mapTileIdent = MAP_TILE_IDENT(x,y);
instanceTree->unloadMap(dirFileName, mapTileIdent);
if(instanceTree->size() == 0)
{
iInstanceMapTrees.remove(pMapId);
delete instanceTree;
}
}
}
//=========================================================
void VMapManager::unloadMap(unsigned int pMapId)
{
if(iInstanceMapTrees.containsKey(pMapId))
{
MapTree* instanceTree = iInstanceMapTrees.get(pMapId);
std::string dirFileName = getDirFileName(pMapId);
instanceTree->unloadMap(dirFileName, 0, true);
if(instanceTree->size() == 0)
{
iInstanceMapTrees.remove(pMapId);
delete instanceTree;
}
#ifdef _VMAP_LOG_DEBUG
Command c = Command();
c.fillUnloadTileCmd(pMapId);
iCommandLogger.appendCmd(c);
#endif
}
}
//==========================================================
bool VMapManager::isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2)
{
bool result = true;
if(isLineOfSightCalcEnabled() && iInstanceMapTrees.containsKey(pMapId))
{
Vector3 pos1 = convertPositionToInternalRep(x1,y1,z1);
Vector3 pos2 = convertPositionToInternalRep(x2,y2,z2);
if(pos1 != pos2)
{
MapTree* mapTree = iInstanceMapTrees.get(pMapId);
result = mapTree->isInLineOfSight(pos1, pos2);
#ifdef _VMAP_LOG_DEBUG
Command c = Command();
// save the orig vectors
c.fillTestVisCmd(pMapId,Vector3(x1,y1,z1),Vector3(x2,y2,z2),result);
iCommandLogger.appendCmd(c);
#endif
}
}
return(result);
}
//=========================================================
/**
get the hit position and return true if we hit something
otherwise the result pos will be the dest pos
*/
bool VMapManager::getObjectHitPos(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float pModifyDist)
{
bool result = false;
rx=x2;
ry=y2;
rz=z2;
if(isLineOfSightCalcEnabled())
{
if(iInstanceMapTrees.containsKey(pMapId))
{
Vector3 pos1 = convertPositionToInternalRep(x1,y1,z1);
Vector3 pos2 = convertPositionToInternalRep(x2,y2,z2);
Vector3 resultPos;
MapTree* mapTree = iInstanceMapTrees.get(pMapId);
result = mapTree->getObjectHitPos(pos1, pos2, resultPos, pModifyDist);
resultPos = convertPositionToMangosRep(resultPos.x,resultPos.y,resultPos.z);
rx = resultPos.x;
ry = resultPos.y;
rz = resultPos.z;
#ifdef _VMAP_LOG_DEBUG
Command c = Command();
c.fillTestObjectHitCmd(pMapId, pos1, pos2, resultPos, result);
iCommandLogger.appendCmd(c);
#endif
}
}
return result;
}
//=========================================================
/**
get height or INVALID_HEIGHT if to hight was calculated
*/
//int gGetHeightCounter = 0;
float VMapManager::getHeight(unsigned int pMapId, float x, float y, float z)
{
float height = VMAP_INVALID_HEIGHT_VALUE; //no height
if(isHeightCalcEnabled() && iInstanceMapTrees.containsKey(pMapId))
{
Vector3 pos = convertPositionToInternalRep(x,y,z);
MapTree* mapTree = iInstanceMapTrees.get(pMapId);
height = mapTree->getHeight(pos);
if(!(height < inf()))
{
height = VMAP_INVALID_HEIGHT_VALUE; //no height
}
#ifdef _VMAP_LOG_DEBUG
Command c = Command();
c.fillTestHeightCmd(pMapId,Vector3(x,y,z),height);
iCommandLogger.appendCmd(c);
#endif
}
return(height);
}
//=========================================================
/**
used for debugging
*/
bool VMapManager::processCommand(char *pCommand)
{
bool result = false;
std::string cmd = std::string(pCommand);
if(cmd == "startlog")
{
#ifdef _VMAP_LOG_DEBUG
iCommandLogger.enableWriting(true);
#endif
result = true;
}
else if(cmd == "stoplog")
{
#ifdef _VMAP_LOG_DEBUG
iCommandLogger.appendCmd(Command()); // Write stop command
iCommandLogger.enableWriting(false);
#endif
result = true;
}
else if(cmd.find_first_of("pos ") == 0)
{
float x,y,z;
sscanf(pCommand, "pos %f,%f,%f",&x,&y,&z);
#ifdef _VMAP_LOG_DEBUG
Command c = Command();
c.fillSetPosCmd(convertPositionToInternalRep(x,y,z));
iCommandLogger.appendCmd(c);
iCommandLogger.enableWriting(false);
#endif
result = true;
}
return result;
}
//=========================================================
//=========================================================
//=========================================================
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
//=========================================================
/**
return dist to hit or inf() if no hit
*/
float MapTree::getIntersectionTime(const Ray& pRay, float pMaxDist, bool pStopAtFirstHit)
{
float firstDistance = inf();
IntersectionCallBack<ModelContainer> intersectionCallBack;
float t = pMaxDist;
iTree->intersectRay(pRay, intersectionCallBack, t, pStopAtFirstHit, false);
#ifdef _DEBUG_VMAPS
{
if(t < pMaxDist)
{
myfound = true;
p4 = pRay.origin + pRay.direction*t;
}
}
#endif
if(t > 0 && t < inf() && pMaxDist > t)
{
firstDistance = t;
}
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);
float resultDist = getIntersectionTime(ray, maxDist, true);
if(resultDist < maxDist)
{
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 < maxDist)
{
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 maxDist = VMapDefinitions::getMaxCanFallDistance();
float dist = getIntersectionTime(ray, maxDist, false);
if(dist < inf())
{
height = (pPos + dir * dist).y;
}
return(height);
}
//=========================================================
bool MapTree::PrepareTree()
{
iTree->balance();
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)
{
addModelContainer(name, mc);
newModelLoaded = true;
}
}
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, bool pForce)
{
if(hasDirFile(dirFileName) && (pForce || containsLoadedMapTile(pMapTileIdent)))
{
if(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::addModelContainer(const std::string& pName, ManagedModelContainer *pMc)
{
iLoadedModelContainer.set(pName, pMc);
iTree->insert(pMc);
}
//=========================================================
//=========================================================
//=========================================================
}

View file

@ -0,0 +1,173 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _VMAPMANAGER_H
#define _VMAPMANAGER_H
// load our modified version first !!
#include "AABSPTree.h"
#include "ManagedModelContainer.h"
#include "IVMapManager.h"
#ifdef _VMAP_LOG_DEBUG
#include "DebugCmdLogger.h"
#endif
#include <G3D/Table.h>
//===========================================================
#define DIR_FILENAME_EXTENSION ".vmdir"
#define FILENAMEBUFFER_SIZE 500
/**
This is the main Class to manage loading and unloading of maps, line of sight, height calculation and so on.
For each map or map tile to load it reads a directory file that contains the ModelContainer files used by this map or map tile.
Each global map or instance has its own dynamic BSP-Tree.
The loaded ModelContainers are included in one of these BSP-Trees.
Additionally a table to match map ids and map names is used.
*/
// Create a value describing the map tile
#define MAP_TILE_IDENT(x,y) ((x<<8) + y)
//===========================================================
namespace VMAP
{
//===========================================================
class FilesInDir
{
private:
int iRefCount;
G3D::Array<std::string> iFiles;
public:
FilesInDir() { iRefCount = 0; }
void append(const std::string& pName) { iFiles.append(pName); }
void incRefCount() { ++iRefCount; }
void decRefCount() { if(iRefCount > 0) --iRefCount; }
int getRefCount() { return iRefCount; }
const G3D::Array<std::string>& getFiles() const { return iFiles; }
};
//===========================================================
//===========================================================
//===========================================================
//===========================================================
class MapTree
{
private:
G3D::AABSPTree<ModelContainer *> *iTree;
// Key: filename, value ModelContainer
G3D::Table<std::string, ManagedModelContainer *> iLoadedModelContainer;
// Key: dir file name, value FilesInDir
G3D::Table<std::string, FilesInDir> iLoadedDirFiles;
// Store all the map tile idents that are loaded for that map
// some maps are not splitted into tiles and we have to make sure, not removing the map before all tiles are removed
G3D::Table<unsigned int, bool> iLoadedMapTiles;
std::string iBasePath;
private:
float getIntersectionTime(const G3D::Ray& pRay, float pMaxDist, bool pStopAtFirstHit);
bool isAlreadyLoaded(const std::string& pName) { return(iLoadedModelContainer.containsKey(pName)); }
void setLoadedMapTile(unsigned int pTileIdent) { iLoadedMapTiles.set(pTileIdent, true); }
void removeLoadedMapTile(unsigned int pTileIdent) { iLoadedMapTiles.remove(pTileIdent); }
bool hasLoadedMapTiles() { return(iLoadedMapTiles.size() > 0); }
bool containsLoadedMapTile(unsigned int pTileIdent) { return(iLoadedMapTiles.containsKey(pTileIdent)); }
public:
ManagedModelContainer *getModelContainer(const std::string& pName) { return(iLoadedModelContainer.get(pName)); }
const bool hasDirFile(const std::string& pDirName) const { return(iLoadedDirFiles.containsKey(pDirName)); }
FilesInDir& getDirFiles(const std::string& pDirName) const { return(iLoadedDirFiles.get(pDirName)); }
public:
MapTree(const char *pBasePath);
~MapTree();
bool isInLineOfSight(const G3D::Vector3& pos1, const G3D::Vector3& pos2);
bool getObjectHitPos(const G3D::Vector3& pos1, const G3D::Vector3& pos2, G3D::Vector3& pResultHitPos, float pModifyDist);
float getHeight(const G3D::Vector3& pPos);
bool PrepareTree();
bool loadMap(const std::string& pDirFileName, unsigned int pMapTileIdent);
void addModelContainer(const std::string& pName, ManagedModelContainer *pMc);
void unloadMap(const std::string& dirFileName, unsigned int pMapTileIdent, bool pForce=false);
void getModelContainer(G3D::Array<ModelContainer *>& pArray ) { iTree->getMembers(pArray); }
const void addDirFile(const std::string& pDirName, const FilesInDir& pFilesInDir) { iLoadedDirFiles.set(pDirName, pFilesInDir); }
size_t size() { return(iTree->size()); }
};
//===========================================================
class MapIdNames
{
public:
std::string iDirName;
std::string iMapGroupName;
};
//===========================================================
class VMapManager : public IVMapManager
{
private:
// Tree to check collision
G3D::Table<unsigned int , MapTree *> iInstanceMapTrees;
G3D::Table<unsigned int , bool> iMapsSplitIntoTiles;
G3D::Table<unsigned int , bool> iIgnoreMapIds;
#ifdef _VMAP_LOG_DEBUG
CommandFileRW iCommandLogger;
#endif
private:
bool _loadMap(const char* pBasePath, unsigned int pMapId, int x, int y, bool pForceTileLoad=false);
void _unloadMap(unsigned int pMapId, int x, int y);
bool _existsMap(const std::string& pBasePath, unsigned int pMapId, int x, int y, bool pForceTileLoad);
public:
// public for debug
G3D::Vector3 convertPositionToInternalRep(float x, float y, float z) const;
G3D::Vector3 convertPositionToMangosRep(float x, float y, float z) const;
std::string getDirFileName(unsigned int pMapId) const;
std::string getDirFileName(unsigned int pMapId, int x, int y) const;
MapTree* getInstanceMapTree(int pMapId) { return(iInstanceMapTrees.get(pMapId)); }
public:
VMapManager();
~VMapManager(void);
int loadMap(const char* pBasePath, unsigned int pMapId, int x, int y);
bool existsMap(const char* pBasePath, unsigned int pMapId, int x, int y);
void unloadMap(unsigned int pMapId, int x, int y);
void unloadMap(unsigned int pMapId);
bool isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2) ;
/**
fill the hit pos and return true, if an object was hit
*/
bool getObjectHitPos(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float pModifyDist);
float getHeight(unsigned int pMapId, float x, float y, float z);
bool processCommand(char *pCommand); // for debug and extensions
void preventMapsFromBeingUsed(const char* pMapIdString);
};
}
#endif

150
src/shared/vmap/VMapTools.h Normal file
View file

@ -0,0 +1,150 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _VMAPTOOLS_H
#define _VMAPTOOLS_H
#include <G3D/CollisionDetection.h>
#include <G3D/AABox.h>
#include "NodeValueAccess.h"
/**
The Class is mainly taken from G3D/AABSPTree.h but modified to be able to use our internal data structure.
This is an iterator that helps us analysing the BSP-Trees.
The collision detection is modified to return true, if we are inside an object.
*/
namespace VMAP
{
template<class TValue>
class IntersectionCallBack {
public:
TValue* closestEntity;
G3D::Vector3 hitLocation;
G3D::Vector3 hitNormal;
void operator()(const G3D::Ray& ray, const TValue* entity, bool pStopAtFirstHit, float& distance) {
entity->intersect(ray, distance, pStopAtFirstHit, hitLocation, hitNormal);
}
};
//==============================================================
//==============================================================
//==============================================================
class MyCollisionDetection
{
private:
public:
static bool collisionLocationForMovingPointFixedAABox(
const G3D::Vector3& origin,
const G3D::Vector3& dir,
const G3D::AABox& box,
G3D::Vector3& location,
bool& Inside)
{
// Integer representation of a floating-point value.
#define IR(x) ((G3D::uint32&)x)
Inside = true;
const G3D::Vector3& MinB = box.low();
const G3D::Vector3& MaxB = box.high();
G3D::Vector3 MaxT(-1.0f, -1.0f, -1.0f);
// Find candidate planes.
for (int i = 0; i < 3; ++i)
{
if (origin[i] < MinB[i])
{
location[i] = MinB[i];
Inside = false;
// Calculate T distances to candidate planes
if (IR(dir[i]))
{
MaxT[i] = (MinB[i] - origin[i]) / dir[i];
}
}
else if (origin[i] > MaxB[i])
{
location[i] = MaxB[i];
Inside = false;
// Calculate T distances to candidate planes
if (IR(dir[i]))
{
MaxT[i] = (MaxB[i] - origin[i]) / dir[i];
}
}
}
if (Inside)
{
// definite hit
location = origin;
return true;
}
// Get largest of the maxT's for final choice of intersection
int WhichPlane = 0;
if (MaxT[1] > MaxT[WhichPlane])
{
WhichPlane = 1;
}
if (MaxT[2] > MaxT[WhichPlane])
{
WhichPlane = 2;
}
// Check final candidate actually inside box
if (IR(MaxT[WhichPlane]) & 0x80000000)
{
// Miss the box
return false;
}
for (int i = 0; i < 3; ++i)
{
if (i != WhichPlane)
{
location[i] = origin[i] + MaxT[WhichPlane] * dir[i];
if ((location[i] < MinB[i]) ||
(location[i] > MaxB[i]))
{
// On this plane we're outside the box extents, so
// we miss the box
return false;
}
}
}
/*
// Choose the normal to be the plane normal facing into the ray
normal = G3D::Vector3::zero();
normal[WhichPlane] = (dir[WhichPlane] > 0) ? -1.0 : 1.0;
*/
return true;
#undef IR
}
};
}
#endif