mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 19:37:03 +00:00
[10165] New collission system (vmap) implementation
Important: * You have to re-extract and assemble vmaps * Update your config file, new option 'vmap.enableIndoorCheck' added New features: * Include WMO+DBC area information for correct subarea identification and indoor check * Support for WMO liquid (fishing/swimming in cities, instances and oterh WMO based environments) Technical changes: * New Bounding Interval Hierarchy (BIH) data structure for better performance * Referenced model data for reduced memory usage, needs more files, but reduces overall file size from ~1.9GB to ~550MB Additional Authors: arrai (DBC handling and indoor detection) faramir118 (windows support and bug investigation) And of course thanks Vladimir for a lot of patience and support!
This commit is contained in:
parent
c2bcfd0f18
commit
5e89098a61
57 changed files with 3472 additions and 5694 deletions
|
|
@ -242,8 +242,8 @@ enum AreaFlags
|
||||||
AREA_FLAG_UNK7 = 0x00400000, // Warsong Hold, Acherus: The Ebon Hold, New Agamand Inn, Vengeance Landing Inn
|
AREA_FLAG_UNK7 = 0x00400000, // Warsong Hold, Acherus: The Ebon Hold, New Agamand Inn, Vengeance Landing Inn
|
||||||
AREA_FLAG_UNK8 = 0x00800000, // Westguard Inn, Acherus: The Ebon Hold, Valgarde
|
AREA_FLAG_UNK8 = 0x00800000, // Westguard Inn, Acherus: The Ebon Hold, Valgarde
|
||||||
AREA_FLAG_OUTDOOR_PVP = 0x01000000, // Wintergrasp and it's subzones
|
AREA_FLAG_OUTDOOR_PVP = 0x01000000, // Wintergrasp and it's subzones
|
||||||
AREA_FLAG_UNK9 = 0x02000000, // unknown
|
AREA_FLAG_INSIDE = 0x02000000, // used for determinating spell related inside/outside questions in Map::IsOutdoors
|
||||||
AREA_FLAG_UNK10 = 0x04000000, // unknown
|
AREA_FLAG_OUTSIDE = 0x04000000, // used for determinating spell related inside/outside questions in Map::IsOutdoors
|
||||||
AREA_FLAG_CAN_HEARTH_AND_RES = 0x08000000 // Wintergrasp and it's subzones
|
AREA_FLAG_CAN_HEARTH_AND_RES = 0x08000000 // Wintergrasp and it's subzones
|
||||||
// 0x20000000 not flyable?
|
// 0x20000000 not flyable?
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,32 @@
|
||||||
typedef std::map<uint16,uint32> AreaFlagByAreaID;
|
typedef std::map<uint16,uint32> AreaFlagByAreaID;
|
||||||
typedef std::map<uint32,uint32> AreaFlagByMapID;
|
typedef std::map<uint32,uint32> AreaFlagByMapID;
|
||||||
|
|
||||||
|
struct WMOAreaTableTripple
|
||||||
|
{
|
||||||
|
WMOAreaTableTripple(int32 r, int32 a, int32 g) : rootId(r), adtId(a), groupId(g)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator <(const WMOAreaTableTripple& b) const
|
||||||
|
{
|
||||||
|
return memcmp(this, &b, sizeof(WMOAreaTableTripple))<0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ordered by entropy; that way memcmp will have a minimal medium runtime
|
||||||
|
int32 groupId;
|
||||||
|
int32 rootId;
|
||||||
|
int32 adtId;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<WMOAreaTableTripple, WMOAreaTableEntry const *> WMOAreaInfoByTripple;
|
||||||
|
|
||||||
DBCStorage <AreaTableEntry> sAreaStore(AreaTableEntryfmt);
|
DBCStorage <AreaTableEntry> sAreaStore(AreaTableEntryfmt);
|
||||||
DBCStorage <AreaGroupEntry> sAreaGroupStore(AreaGroupEntryfmt);
|
DBCStorage <AreaGroupEntry> sAreaGroupStore(AreaGroupEntryfmt);
|
||||||
static AreaFlagByAreaID sAreaFlagByAreaID;
|
static AreaFlagByAreaID sAreaFlagByAreaID;
|
||||||
static AreaFlagByMapID sAreaFlagByMapID; // for instances without generated *.map files
|
static AreaFlagByMapID sAreaFlagByMapID; // for instances without generated *.map files
|
||||||
|
|
||||||
|
static WMOAreaInfoByTripple sWMOAreaInfoByTripple;
|
||||||
|
|
||||||
DBCStorage <AchievementEntry> sAchievementStore(Achievementfmt);
|
DBCStorage <AchievementEntry> sAchievementStore(Achievementfmt);
|
||||||
DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore(AchievementCriteriafmt);
|
DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore(AchievementCriteriafmt);
|
||||||
DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt);
|
DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt);
|
||||||
|
|
@ -157,6 +178,7 @@ static DBCStorage <TaxiPathNodeEntry> sTaxiPathNodeStore(TaxiPathNodeEntryfmt);
|
||||||
DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt);
|
DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt);
|
||||||
DBCStorage <VehicleEntry> sVehicleStore(VehicleEntryfmt);
|
DBCStorage <VehicleEntry> sVehicleStore(VehicleEntryfmt);
|
||||||
DBCStorage <VehicleSeatEntry> sVehicleSeatStore(VehicleSeatEntryfmt);
|
DBCStorage <VehicleSeatEntry> sVehicleSeatStore(VehicleSeatEntryfmt);
|
||||||
|
DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore(WMOAreaTableEntryfmt);
|
||||||
DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreaEntryfmt);
|
DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreaEntryfmt);
|
||||||
DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore(WorldMapOverlayEntryfmt);
|
DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore(WorldMapOverlayEntryfmt);
|
||||||
DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore(WorldSafeLocsEntryfmt);
|
DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore(WorldSafeLocsEntryfmt);
|
||||||
|
|
@ -614,6 +636,14 @@ void LoadDBCStores(const std::string& dataPath)
|
||||||
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sVehicleStore, dbcPath,"Vehicle.dbc");
|
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sVehicleStore, dbcPath,"Vehicle.dbc");
|
||||||
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sVehicleSeatStore, dbcPath,"VehicleSeat.dbc");
|
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sVehicleSeatStore, dbcPath,"VehicleSeat.dbc");
|
||||||
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldMapAreaStore, dbcPath,"WorldMapArea.dbc");
|
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldMapAreaStore, dbcPath,"WorldMapArea.dbc");
|
||||||
|
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWMOAreaTableStore, dbcPath,"WMOAreaTable.dbc");
|
||||||
|
for(uint32 i = 0; i < sWMOAreaTableStore.GetNumRows(); ++i)
|
||||||
|
{
|
||||||
|
if(WMOAreaTableEntry const* entry = sWMOAreaTableStore.LookupEntry(i))
|
||||||
|
{
|
||||||
|
sWMOAreaInfoByTripple.insert(WMOAreaInfoByTripple::value_type(WMOAreaTableTripple(entry->rootId, entry->adtId, entry->groupId), entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldMapOverlayStore, dbcPath,"WorldMapOverlay.dbc");
|
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldMapOverlayStore, dbcPath,"WorldMapOverlay.dbc");
|
||||||
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldSafeLocsStore, dbcPath,"WorldSafeLocs.dbc");
|
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldSafeLocsStore, dbcPath,"WorldSafeLocs.dbc");
|
||||||
|
|
||||||
|
|
@ -702,6 +732,15 @@ int32 GetAreaFlagByAreaID(uint32 area_id)
|
||||||
return i->second;
|
return i->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid)
|
||||||
|
{
|
||||||
|
WMOAreaInfoByTripple::iterator i = sWMOAreaInfoByTripple.find(WMOAreaTableTripple(rootid, adtid, groupid));
|
||||||
|
if(i == sWMOAreaInfoByTripple.end())
|
||||||
|
return NULL;
|
||||||
|
return i->second;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id)
|
AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id)
|
||||||
{
|
{
|
||||||
int32 areaflag = GetAreaFlagByAreaID(area_id);
|
int32 areaflag = GetAreaFlagByAreaID(area_id);
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ TalentSpellPos const* GetTalentSpellPos(uint32 spellId);
|
||||||
int32 GetAreaFlagByAreaID(uint32 area_id); // -1 if not found
|
int32 GetAreaFlagByAreaID(uint32 area_id); // -1 if not found
|
||||||
uint32 GetAreaFlagByMapId(uint32 mapid);
|
uint32 GetAreaFlagByMapId(uint32 mapid);
|
||||||
|
|
||||||
|
WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid);
|
||||||
|
|
||||||
MANGOS_DLL_SPEC AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id);
|
MANGOS_DLL_SPEC AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id);
|
||||||
MANGOS_DLL_SPEC AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag,uint32 map_id);
|
MANGOS_DLL_SPEC AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag,uint32 map_id);
|
||||||
|
|
||||||
|
|
@ -161,6 +163,7 @@ extern TaxiPathNodesByPath sTaxiPathNodesByPath;
|
||||||
extern DBCStorage <TotemCategoryEntry> sTotemCategoryStore;
|
extern DBCStorage <TotemCategoryEntry> sTotemCategoryStore;
|
||||||
extern DBCStorage <VehicleEntry> sVehicleStore;
|
extern DBCStorage <VehicleEntry> sVehicleStore;
|
||||||
extern DBCStorage <VehicleSeatEntry> sVehicleSeatStore;
|
extern DBCStorage <VehicleSeatEntry> sVehicleSeatStore;
|
||||||
|
extern DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore;
|
||||||
//extern DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates
|
//extern DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates
|
||||||
extern DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore;
|
extern DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore;
|
||||||
extern DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore;
|
extern DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore;
|
||||||
|
|
|
||||||
|
|
@ -1781,6 +1781,23 @@ struct VehicleSeatEntry
|
||||||
// 46-57 added in 3.1, floats mostly
|
// 46-57 added in 3.1, floats mostly
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct WMOAreaTableEntry
|
||||||
|
{
|
||||||
|
uint32 Id; // 0 index
|
||||||
|
int32 rootId; // 1 used in root WMO
|
||||||
|
int32 adtId; // 2 used in adt file
|
||||||
|
int32 groupId; // 3 used in group WMO
|
||||||
|
//uint32 field4;
|
||||||
|
//uint32 field5;
|
||||||
|
//uint32 field6;
|
||||||
|
//uint32 field7;
|
||||||
|
//uint32 field8;
|
||||||
|
uint32 Flags; // 9 used for indoor/outdoor determination
|
||||||
|
uint32 areaId; // 10 link to AreaTableEntry.ID
|
||||||
|
//char *Name[16];
|
||||||
|
//uint32 nameFlags;
|
||||||
|
};
|
||||||
|
|
||||||
struct WorldMapAreaEntry
|
struct WorldMapAreaEntry
|
||||||
{
|
{
|
||||||
//uint32 ID; // 0
|
//uint32 ID; // 0
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ const char TaxiPathNodeEntryfmt[]="diiifffiiii";
|
||||||
const char TotemCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxii";
|
const char TotemCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxii";
|
||||||
const char VehicleEntryfmt[]="niffffiiiiiiiifffffffffffffffssssfifixxx";
|
const char VehicleEntryfmt[]="niffffiiiiiiiifffffffffffffffssssfifixxx";
|
||||||
const char VehicleSeatEntryfmt[]="niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiixxxxxxxxxxxx";
|
const char VehicleSeatEntryfmt[]="niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiixxxxxxxxxxxx";
|
||||||
|
const char WMOAreaTableEntryfmt[]="niiixxxxxiixxxxxxxxxxxxxxxxx";
|
||||||
const char WorldMapAreaEntryfmt[]="xinxffffixx";
|
const char WorldMapAreaEntryfmt[]="xinxffffixx";
|
||||||
const char WorldMapOverlayEntryfmt[]="nxiiiixxxxxxxxxxx";
|
const char WorldMapOverlayEntryfmt[]="nxiiiixxxxxxxxxxx";
|
||||||
const char WorldSafeLocsEntryfmt[]="nifffxxxxxxxxxxxxxxxxx";
|
const char WorldSafeLocsEntryfmt[]="nifffxxxxxxxxxxxxxxxxx";
|
||||||
|
|
|
||||||
|
|
@ -313,6 +313,15 @@ bool ChatHandler::HandleGPSCommand(const char* args)
|
||||||
uint32 have_map = GridMap::ExistMap(obj->GetMapId(),gx,gy) ? 1 : 0;
|
uint32 have_map = GridMap::ExistMap(obj->GetMapId(),gx,gy) ? 1 : 0;
|
||||||
uint32 have_vmap = GridMap::ExistVMap(obj->GetMapId(),gx,gy) ? 1 : 0;
|
uint32 have_vmap = GridMap::ExistVMap(obj->GetMapId(),gx,gy) ? 1 : 0;
|
||||||
|
|
||||||
|
if(have_vmap)
|
||||||
|
{
|
||||||
|
if(map->IsOutdoors(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ()))
|
||||||
|
PSendSysMessage("You are OUTdoor");
|
||||||
|
else
|
||||||
|
PSendSysMessage("You are INdoor");
|
||||||
|
}
|
||||||
|
else PSendSysMessage("no VMAP available for area info");
|
||||||
|
|
||||||
PSendSysMessage(LANG_MAP_POSITION,
|
PSendSysMessage(LANG_MAP_POSITION,
|
||||||
obj->GetMapId(), (mapEntry ? mapEntry->name[GetSessionDbcLocale()] : "<unknown>" ),
|
obj->GetMapId(), (mapEntry ? mapEntry->name[GetSessionDbcLocale()] : "<unknown>" ),
|
||||||
zone_id, (zoneEntry ? zoneEntry->area_name[GetSessionDbcLocale()] : "<unknown>" ),
|
zone_id, (zoneEntry ? zoneEntry->area_name[GetSessionDbcLocale()] : "<unknown>" ),
|
||||||
|
|
|
||||||
372
src/game/Map.cpp
372
src/game/Map.cpp
|
|
@ -1075,249 +1075,106 @@ float Map::GetHeight(float x, float y, float z, bool pUseVmaps) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 Map::GetAreaFlag(float x, float y, float z) const
|
inline bool IsOutdoorWMO(uint32 mogpFlags, int32 adtId, int32 rootId, int32 groupId,
|
||||||
|
WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry)
|
||||||
{
|
{
|
||||||
|
bool outdoor = true;
|
||||||
|
|
||||||
|
if(wmoEntry && atEntry)
|
||||||
|
{
|
||||||
|
if(atEntry->flags & AREA_FLAG_OUTSIDE)
|
||||||
|
return true;
|
||||||
|
if(atEntry->flags & AREA_FLAG_INSIDE)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outdoor = mogpFlags&0x8;
|
||||||
|
|
||||||
|
if(wmoEntry)
|
||||||
|
{
|
||||||
|
if(wmoEntry->Flags & 4)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if((wmoEntry->Flags & 2)!=0)
|
||||||
|
outdoor = false;
|
||||||
|
}
|
||||||
|
return outdoor;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Map::IsOutdoors(float x, float y, float z) const
|
||||||
|
{
|
||||||
|
uint32 mogpFlags;
|
||||||
|
int32 adtId, rootId, groupId;
|
||||||
|
|
||||||
|
// no wmo found? -> outside by default
|
||||||
|
if(!GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
AreaTableEntry const* atEntry = 0;
|
||||||
|
WMOAreaTableEntry const* wmoEntry= GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
|
||||||
|
if(wmoEntry)
|
||||||
|
{
|
||||||
|
DEBUG_LOG("Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId);
|
||||||
|
|
||||||
|
atEntry = GetAreaEntryByAreaID(wmoEntry->areaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Map::GetAreaInfo(float x, float y, float z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const
|
||||||
|
{
|
||||||
|
float vmap_z = z;
|
||||||
|
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
||||||
|
if (vmgr->getAreaInfo(GetId(), x, y, vmap_z, flags, adtId, rootId, groupId))
|
||||||
|
{
|
||||||
|
// check if there's terrain between player height and object height
|
||||||
|
if(GridMap *gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||||
|
{
|
||||||
|
float _mapheight = gmap->getHeight(x,y);
|
||||||
|
// z + 2.0f condition taken from GetHeight(), not sure if it's such a great choice...
|
||||||
|
if(z + 2.0f > _mapheight && _mapheight > vmap_z)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const
|
||||||
|
{
|
||||||
|
uint32 mogpFlags;
|
||||||
|
int32 adtId, rootId, groupId;
|
||||||
|
WMOAreaTableEntry const* wmoEntry = 0;
|
||||||
|
AreaTableEntry const* atEntry = 0;
|
||||||
|
bool haveAreaInfo = false;
|
||||||
|
|
||||||
|
if(GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId))
|
||||||
|
{
|
||||||
|
haveAreaInfo = true;
|
||||||
|
if(wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId))
|
||||||
|
atEntry = GetAreaEntryByAreaID(wmoEntry->areaId);
|
||||||
|
}
|
||||||
|
|
||||||
uint16 areaflag;
|
uint16 areaflag;
|
||||||
|
if (atEntry)
|
||||||
|
areaflag = atEntry->exploreFlag;
|
||||||
|
else
|
||||||
|
{
|
||||||
if(GridMap *gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
if(GridMap *gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||||
areaflag = gmap->getArea(x, y);
|
areaflag = gmap->getArea(x, y);
|
||||||
// this used while not all *.map files generated (instances)
|
// this used while not all *.map files generated (instances)
|
||||||
else
|
else
|
||||||
areaflag = GetAreaFlagByMapId(i_id);
|
areaflag = GetAreaFlagByMapId(i_id);
|
||||||
|
|
||||||
//FIXME: some hacks for areas above or underground for ground area
|
|
||||||
// required for area specific spells/etc, until map/vmap data
|
|
||||||
// not provided correct areaflag with this hacks
|
|
||||||
switch(areaflag)
|
|
||||||
{
|
|
||||||
case 1146: // Blade's Edge Mountains
|
|
||||||
case 1409: // Forge Camp: Wrath (Blade's Edge Mountains)
|
|
||||||
if (x > 3025.0f && x < 3207.0f && y > 6987.0f && y < 7165.0f && z < 183.0f)
|
|
||||||
areaflag = 1404; // Blackwing Coven (Blade's Edge Mountains)
|
|
||||||
break;
|
|
||||||
// Acherus: The Ebon Hold (Plaguelands: The Scarlet Enclave)
|
|
||||||
case 1984: // Plaguelands: The Scarlet Enclave
|
|
||||||
case 2076: // Death's Breach (Plaguelands: The Scarlet Enclave)
|
|
||||||
case 2745: // The Noxious Pass (Plaguelands: The Scarlet Enclave)
|
|
||||||
if(z > 350.0f) areaflag = 2048; break;
|
|
||||||
// Acherus: The Ebon Hold (Eastern Plaguelands)
|
|
||||||
case 856: // The Noxious Glade (Eastern Plaguelands)
|
|
||||||
case 2456: // Death's Breach (Eastern Plaguelands)
|
|
||||||
if(z > 350.0f) areaflag = 1950; break;
|
|
||||||
// Winterfin Caverns
|
|
||||||
case 1652: // Coldarra
|
|
||||||
case 1653: // The Westrift
|
|
||||||
case 1661: // Winterfin Village
|
|
||||||
if (x > 3823.0f && x < 4141.5f && y > 6247.0f && y < 64890.0f && z < 42.5f)
|
|
||||||
areaflag = 1723;
|
|
||||||
break;
|
|
||||||
// Moonrest Gardens
|
|
||||||
case 1787:
|
|
||||||
if (x > 3315.3f && x < 3361.6f && y > 2469.4f && y < 2565.8f && z > 197.0f)
|
|
||||||
areaflag = 1786; // Surge Needle (cords not entirely correct, will need round circle if this is really needed(see spell 47097 eff 77))
|
|
||||||
break;
|
|
||||||
// Dalaran
|
|
||||||
case 2492: // Forlorn Woods (Crystalsong Forest)
|
|
||||||
case 2371: // Valley of Echoes (Icecrown Glacier)
|
|
||||||
if (x > 5568.0f && x < 6116.0f && y > 282.0f && y < 982.0f && z > 563.0f)
|
|
||||||
{
|
|
||||||
// Krasus' Landing (Dalaran), fast check
|
|
||||||
if (x > 5758.77f && x < 5869.03f && y < 510.46f)
|
|
||||||
{
|
|
||||||
// Krasus' Landing (Dalaran), with open east side
|
|
||||||
if (y < 449.33f || (x-5813.9f)*(x-5813.9f)+(y-449.33f)*(y-449.33f) < 1864.0f)
|
|
||||||
{
|
|
||||||
areaflag = 2531; // Note: also 2633, possible one flight allowed and other not allowed case
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sunreaver's Sanctuary (Dalaran) (Enter,Left,Right-border lines)
|
if (isOutdoors)
|
||||||
if ((y-548.11f)/(568.80f-548.11f) <= (x-5849.30f)/(5866.57f-5849.30f) &&
|
|
||||||
(y-582.76f)/(622.97f-582.76f) <= (x-5961.64f)/(5886.09f-5961.64f) &&
|
|
||||||
(y-446.79f)/(508.22f-446.79f) >= (x-5867.66f)/(5846.12f-5867.66f))
|
|
||||||
{
|
{
|
||||||
// need exclude 2 shop rooms
|
if (haveAreaInfo)
|
||||||
if (((x-5862.26f)*(x-5862.26f)+(y-554.76f)*(y-554.76f) > 335.85f/*310.64f*/ || z > 671.12f) &&
|
*isOutdoors = IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
|
||||||
((y-580.51f)/(608.37f-580.51f) <= (x-5896.23f)/(5859.79f-5896.23f) ||
|
|
||||||
(y-580.51f)/(610.49f-580.51f) <= (x-5896.23f)/(5919.15f-5896.23f) || z > 669.10f))
|
|
||||||
{
|
|
||||||
areaflag = 2687;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Silver Enclave (Dalaran) (Enter,Left,Right-border lines)
|
|
||||||
if ((y-693.19f)/(737.41f-693.19f) >= (x-5732.80f)/(5769.38f-5732.80f) &&
|
|
||||||
(y-693.19f)/(787.00f-693.19f) >= (x-5732.80f)/(5624.17f-5732.80f) &&
|
|
||||||
(y-737.41f)/(831.30f-737.41f) <= (x-5769.38f)/(5671.15f-5769.38f))
|
|
||||||
{
|
|
||||||
// need exclude ground floor shop room
|
|
||||||
if ((x-5758.07f)*(x-5758.07f)+(y-738.18f)*(y-738.18f) > 83.30f || z > 650.00f)
|
|
||||||
{
|
|
||||||
areaflag = 3007;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dalaran
|
|
||||||
areaflag = 2153;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// The Violet Citadel (Dalaran) or Dalaran
|
|
||||||
case 2484: // The Twilight Rivulet (Crystalsong Forest)
|
|
||||||
case 1593: // Crystalsong Forest
|
|
||||||
// Dalaran
|
|
||||||
if (x > 5568.0f && x < 6116.0f && y > 282.0f && y < 982.0f && z > 563.0f)
|
|
||||||
{
|
|
||||||
// The Violet Citadel (Dalaran), fast check
|
|
||||||
if (x > 5721.1f && x < 5884.66f && y > 764.4f && y < 948.0f)
|
|
||||||
{
|
|
||||||
// The Violet Citadel (Dalaran)
|
|
||||||
if ((x-5803.0f)*(x-5803.0f)+(y-846.18f)*(y-846.18f) < 6690.0f)
|
|
||||||
{
|
|
||||||
areaflag = 2696;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sunreaver's Sanctuary (Dalaran) (Enter,Left,Right-border lines)
|
|
||||||
if ((y-581.27f)/(596.73f-581.27f) <= (x-5858.57f)/(5871.87f-5858.57f) &&
|
|
||||||
(y-582.76f)/(622.97f-582.76f) <= (x-5961.64f)/(5886.09f-5961.64f) &&
|
|
||||||
(y-446.79f)/(508.22f-446.79f) >= (x-5867.66f)/(5846.12f-5867.66f))
|
|
||||||
{
|
|
||||||
areaflag = 2687;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Silver Enclave (Dalaran) (Enter,Left,Right-border lines)
|
|
||||||
if ((y-693.19f)/(737.41f-693.19f) >= (x-5732.80f)/(5769.38f-5732.80f) &&
|
|
||||||
(y-693.19f)/(787.00f-693.19f) >= (x-5732.80f)/(5624.17f-5732.80f) &&
|
|
||||||
(y-737.41f)/(831.30f-737.41f) <= (x-5769.38f)/(5671.15f-5769.38f))
|
|
||||||
{
|
|
||||||
// need exclude ground floor shop room
|
|
||||||
if ((x-5758.07f)*(x-5758.07f)+(y-738.18f)*(y-738.18f) > 64.30f || z > 650.00f)
|
|
||||||
{
|
|
||||||
areaflag = 3007;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dalaran
|
|
||||||
areaflag = 2153;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// Vargoth's Retreat (Dalaran) or The Violet Citadel (Dalaran) or Dalaran
|
|
||||||
case 2504: // Violet Stand (Crystalsong Forest)
|
|
||||||
// Dalaran
|
|
||||||
if (x > 5568.0f && x < 6116.0f && y > 282.0f && y < 982.0f && z > 563.0f)
|
|
||||||
{
|
|
||||||
// The Violet Citadel (Dalaran), fast check
|
|
||||||
if (x > 5721.1f && x < 5884.66f && y > 764.4f && y < 948.0f)
|
|
||||||
{
|
|
||||||
// Vargoth's Retreat (Dalaran), nice slow circle with upper limit
|
|
||||||
if (z < 898.0f && (x-5765.0f)*(x-5765.0f)+(y-862.4f)*(y-862.4f) < 262.0f)
|
|
||||||
{
|
|
||||||
areaflag = 2748;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Violet Citadel (Dalaran)
|
|
||||||
if ((x-5803.0f)*(x-5803.0f)+(y-846.18f)*(y-846.18f) < 6690.0f)
|
|
||||||
{
|
|
||||||
areaflag = 2696;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dalaran
|
|
||||||
areaflag = 2153;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// Maw of Neltharion (cave)
|
|
||||||
case 164: // Dragonblight
|
|
||||||
case 1797: // Obsidian Dragonshrine (Dragonblight)
|
|
||||||
case 1827: // Wintergrasp
|
|
||||||
case 2591: // The Cauldron of Flames (Wintergrasp)
|
|
||||||
if (x > 4364.0f && x < 4632.0f && y > 1545.0f && y < 1886.0f && z < 200.0f) areaflag = 1853; break;
|
|
||||||
// Undercity (sewers enter and path)
|
|
||||||
case 179: // Tirisfal Glades
|
|
||||||
if (x > 1595.0f && x < 1699.0f && y > 535.0f && y < 643.5f && z < 30.5f) areaflag = 685; break;
|
|
||||||
// Undercity (Royal Quarter)
|
|
||||||
case 210: // Silverpine Forest
|
|
||||||
case 316: // The Shining Strand (Silverpine Forest)
|
|
||||||
case 438: // Lordamere Lake (Silverpine Forest)
|
|
||||||
if (x > 1237.0f && x < 1401.0f && y > 284.0f && y < 440.0f && z < -40.0f) areaflag = 685; break;
|
|
||||||
// Undercity (cave and ground zone, part of royal quarter)
|
|
||||||
case 607: // Ruins of Lordaeron (Tirisfal Glades)
|
|
||||||
// ground and near to ground (by city walls)
|
|
||||||
if(z > 0.0f)
|
|
||||||
{
|
|
||||||
if (x > 1510.0f && x < 1839.0f && y > 29.77f && y < 433.0f) areaflag = 685;
|
|
||||||
}
|
|
||||||
// more wide underground, part of royal quarter
|
|
||||||
else
|
else
|
||||||
{
|
*isOutdoors = true;
|
||||||
if (x > 1299.0f && x < 1839.0f && y > 10.0f && y < 440.0f) areaflag = 685;
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
// The Makers' Perch (ground) and Makers' Overlook (ground and cave)
|
|
||||||
case 1335: // Sholazar Basin
|
|
||||||
// The Makers' Perch ground (fast box)
|
|
||||||
if (x > 6100.0f && x < 6250.0f && y > 5650.0f && y < 5800.0f)
|
|
||||||
{
|
|
||||||
// nice slow circle
|
|
||||||
if ((x-6183.0f)*(x-6183.0f)+(y-5717.0f)*(y-5717.0f) < 2500.0f)
|
|
||||||
areaflag = 2189;
|
|
||||||
}
|
|
||||||
// Makers' Overlook (ground and cave)
|
|
||||||
else if (x > 5634.48f && x < 5774.53f && y < 3475.0f && z > 300.0f)
|
|
||||||
{
|
|
||||||
if (y > 3380.26f || (y > 3265.0f && z < 360.0f))
|
|
||||||
areaflag = 2187;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// The Makers' Perch (underground)
|
|
||||||
case 2147: // The Stormwright's Shelf (Sholazar Basin)
|
|
||||||
if (x > 6199.0f && x < 6283.0f && y > 5705.0f && y < 5817.0f && z < 38.0f) areaflag = 2189; break;
|
|
||||||
// Makers' Overlook (deep cave)
|
|
||||||
case 267: // Icecrown
|
|
||||||
if (x > 5684.0f && x < 5798.0f && y > 3035.0f && y < 3367.0f && z < 358.0f) areaflag = 2187; break;
|
|
||||||
// Wyrmrest Temple (Dragonblight)
|
|
||||||
case 1814: // Path of the Titans (Dragonblight)
|
|
||||||
case 1897: // The Dragon Wastes (Dragonblight)
|
|
||||||
// fast box
|
|
||||||
if (x > 3400.0f && x < 3700.0f && y > 130.0f && y < 420.0f)
|
|
||||||
{
|
|
||||||
// nice slow circle
|
|
||||||
if ((x-3546.87f)*(x-3546.87f)+(y-272.71f)*(y-272.71f) < 19600.0f) areaflag = 1791;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// The Forlorn Mine (The Storm Peaks)
|
|
||||||
case 166: // The Storm Peaks
|
|
||||||
case 2207: // Brunnhildar Village (The Storm Peaks)
|
|
||||||
case 2209: // Sifreldar Village (The Storm Peaks)
|
|
||||||
case 2227: // The Foot Steppes (The Storm Peaks)
|
|
||||||
// fast big box
|
|
||||||
if (x > 6812.0f && x < 7049.5f && y > -1474.5f && y < -1162.5f && z < 866.15f)
|
|
||||||
{
|
|
||||||
// east, avoid ground east-south corner wrong detection
|
|
||||||
if (x > 6925.0f && y > -1474.5f && y < -1290.0f)
|
|
||||||
areaflag = 2213;
|
|
||||||
// east middle, wide part
|
|
||||||
else if (x > 6812.0f && y > -1400.0f && y < -1290.0f)
|
|
||||||
areaflag = 2213;
|
|
||||||
// west middle, avoid ground west-south corner wrong detection
|
|
||||||
else if (x > 6833.0f && y > -1474.5f && y < -1233.0f)
|
|
||||||
areaflag = 2213;
|
|
||||||
// west, avoid ground west-south corner wrong detection
|
|
||||||
else if (x > 6885.0f && y > -1474.5f && y < -1162.5f)
|
|
||||||
areaflag = 2213;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return areaflag;
|
return areaflag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1331,10 +1188,50 @@ uint8 Map::GetTerrainType(float x, float y ) const
|
||||||
|
|
||||||
GridMapLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, GridMapLiquidData *data) const
|
GridMapLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, GridMapLiquidData *data) const
|
||||||
{
|
{
|
||||||
|
GridMapLiquidStatus result = LIQUID_MAP_NO_WATER;
|
||||||
|
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
||||||
|
float liquid_level, ground_level = INVALID_HEIGHT;
|
||||||
|
uint32 liquid_type;
|
||||||
|
if (vmgr->GetLiquidLevel(GetId(), x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type))
|
||||||
|
{
|
||||||
|
DEBUG_LOG("getLiquidStatus(): vmap liquid level: %f ground: %f type: %u", liquid_level, ground_level, liquid_type);
|
||||||
|
// Check water level and ground level
|
||||||
|
if (liquid_level > ground_level && z > ground_level - 2)
|
||||||
|
{
|
||||||
|
// All ok in water -> store data
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
data->type = liquid_type;
|
||||||
|
data->level = liquid_level;
|
||||||
|
data->depth_level = ground_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For speed check as int values
|
||||||
|
int delta = int((liquid_level - z) * 10);
|
||||||
|
|
||||||
|
// Get position delta
|
||||||
|
if (delta > 20) // Under water
|
||||||
|
return LIQUID_MAP_UNDER_WATER;
|
||||||
|
if (delta > 0 ) // In water
|
||||||
|
return LIQUID_MAP_IN_WATER;
|
||||||
|
if (delta > -1) // Walk on water
|
||||||
|
return LIQUID_MAP_WATER_WALK;
|
||||||
|
result = LIQUID_MAP_ABOVE_WATER;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
if(GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||||
return gmap->getLiquidStatus(x, y, z, ReqLiquidType, data);
|
{
|
||||||
else
|
GridMapLiquidData map_data;
|
||||||
return LIQUID_MAP_NO_WATER;
|
GridMapLiquidStatus map_result = gmap->getLiquidStatus(x, y, z, ReqLiquidType, &map_data);
|
||||||
|
// Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER:
|
||||||
|
if (map_result != LIQUID_MAP_NO_WATER && (map_data.level > ground_level))
|
||||||
|
{
|
||||||
|
if (data)
|
||||||
|
*data = map_data;
|
||||||
|
return map_result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Map::GetWaterLevel(float x, float y ) const
|
float Map::GetWaterLevel(float x, float y ) const
|
||||||
|
|
@ -1373,15 +1270,16 @@ void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 area
|
||||||
zoneid = entry ? (( entry->zone != 0 ) ? entry->zone : entry->ID) : 0;
|
zoneid = entry ? (( entry->zone != 0 ) ? entry->zone : entry->ID) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Map::IsInWater(float x, float y, float pZ) const
|
bool Map::IsInWater(float x, float y, float pZ, GridMapLiquidData *data) const
|
||||||
{
|
{
|
||||||
// Check surface in x, y point for liquid
|
// Check surface in x, y point for liquid
|
||||||
if (const_cast<Map*>(this)->GetGrid(x, y))
|
if (const_cast<Map*>(this)->GetGrid(x, y))
|
||||||
{
|
{
|
||||||
GridMapLiquidData liquid_status;
|
GridMapLiquidData liquid_status;
|
||||||
if (getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, &liquid_status))
|
GridMapLiquidData *liquid_ptr = data ? data : &liquid_status;
|
||||||
|
if (getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, liquid_ptr))
|
||||||
{
|
{
|
||||||
if (liquid_status.level - liquid_status.depth_level > 2)
|
//if (liquid_prt->level - liquid_prt->depth_level > 2) //???
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -151,11 +151,11 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
|
||||||
// some calls like isInWater should not use vmaps due to processor power
|
// some calls like isInWater should not use vmaps due to processor power
|
||||||
// can return INVALID_HEIGHT if under z+2 z coord not found height
|
// can return INVALID_HEIGHT if under z+2 z coord not found height
|
||||||
float GetHeight(float x, float y, float z, bool pCheckVMap=true) const;
|
float GetHeight(float x, float y, float z, bool pCheckVMap=true) const;
|
||||||
bool IsInWater(float x, float y, float z) const; // does not use z pos. This is for future use
|
bool IsInWater(float x, float y, float z, GridMapLiquidData *data = 0) const;
|
||||||
|
|
||||||
GridMapLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, GridMapLiquidData *data = 0) const;
|
GridMapLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, GridMapLiquidData *data = 0) const;
|
||||||
|
|
||||||
uint16 GetAreaFlag(float x, float y, float z) const;
|
uint16 GetAreaFlag(float x, float y, float z, bool *isOutdoors=0) const;
|
||||||
uint8 GetTerrainType(float x, float y ) const;
|
uint8 GetTerrainType(float x, float y ) const;
|
||||||
float GetWaterLevel(float x, float y ) const;
|
float GetWaterLevel(float x, float y ) const;
|
||||||
bool IsUnderWater(float x, float y, float z) const;
|
bool IsUnderWater(float x, float y, float z) const;
|
||||||
|
|
@ -261,6 +261,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
|
||||||
|
|
||||||
// DynObjects currently
|
// DynObjects currently
|
||||||
uint32 GenerateLocalLowGuid(HighGuid guidhigh);
|
uint32 GenerateLocalLowGuid(HighGuid guidhigh);
|
||||||
|
bool GetAreaInfo(float x, float y, float z, uint32 &mogpflags, int32 &adtId, int32 &rootId, int32 &groupId) const;
|
||||||
|
bool IsOutdoors(float x, float y, float z) const;
|
||||||
private:
|
private:
|
||||||
void LoadMapAndVMap(int gx, int gy);
|
void LoadMapAndVMap(int gx, int gy);
|
||||||
void LoadVMap(int gx, int gy);
|
void LoadVMap(int gx, int gy);
|
||||||
|
|
|
||||||
|
|
@ -1117,7 +1117,9 @@ void Player::HandleDrowning(uint32 time_diff)
|
||||||
uint32 damage = urand(600, 700);
|
uint32 damage = urand(600, 700);
|
||||||
if (m_MirrorTimerFlags&UNDERWATER_INLAVA)
|
if (m_MirrorTimerFlags&UNDERWATER_INLAVA)
|
||||||
EnvironmentalDamage(DAMAGE_LAVA, damage);
|
EnvironmentalDamage(DAMAGE_LAVA, damage);
|
||||||
else
|
// need to skip Slime damage in Undercity,
|
||||||
|
// maybe someone can find better way to handle environmental damage
|
||||||
|
else if (m_zoneUpdateId != 1497)
|
||||||
EnvironmentalDamage(DAMAGE_SLIME, damage);
|
EnvironmentalDamage(DAMAGE_SLIME, damage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6050,7 +6052,7 @@ bool Player::SetPosition(float x, float y, float z, float orientation, bool tele
|
||||||
// code block for underwater state update
|
// code block for underwater state update
|
||||||
UpdateUnderwaterState(m, x, y, z);
|
UpdateUnderwaterState(m, x, y, z);
|
||||||
|
|
||||||
CheckExploreSystem();
|
CheckAreaExploreAndOutdoor();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -6112,7 +6114,7 @@ void Player::SendMovieStart(uint32 MovieId)
|
||||||
SendDirectMessage(&data);
|
SendDirectMessage(&data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::CheckExploreSystem()
|
void Player::CheckAreaExploreAndOutdoor()
|
||||||
{
|
{
|
||||||
if (!isAlive())
|
if (!isAlive())
|
||||||
return;
|
return;
|
||||||
|
|
@ -6120,7 +6122,12 @@ void Player::CheckExploreSystem()
|
||||||
if (isInFlight())
|
if (isInFlight())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint16 areaFlag = GetBaseMap()->GetAreaFlag(GetPositionX(),GetPositionY(),GetPositionZ());
|
bool isOutdoor;
|
||||||
|
uint16 areaFlag = GetBaseMap()->GetAreaFlag(GetPositionX(),GetPositionY(),GetPositionZ(), &isOutdoor);
|
||||||
|
|
||||||
|
if (sWorld.getConfig(CONFIG_BOOL_VMAP_INDOOR_CHECK) && !isOutdoor)
|
||||||
|
RemoveAurasWithAttribute(SPELL_ATTR_OUTDOORS_ONLY);
|
||||||
|
|
||||||
if (areaFlag==0xffff)
|
if (areaFlag==0xffff)
|
||||||
return;
|
return;
|
||||||
int offset = areaFlag / 32;
|
int offset = areaFlag / 32;
|
||||||
|
|
@ -20565,8 +20572,8 @@ void Player::UpdateUnderwaterState( Map* m, float x, float y, float z )
|
||||||
{
|
{
|
||||||
m_MirrorTimerFlags &= ~(UNDERWATER_INWATER|UNDERWATER_INLAVA|UNDERWATER_INSLIME|UNDERWATER_INDARKWATER);
|
m_MirrorTimerFlags &= ~(UNDERWATER_INWATER|UNDERWATER_INLAVA|UNDERWATER_INSLIME|UNDERWATER_INDARKWATER);
|
||||||
// Small hack for enable breath in WMO
|
// Small hack for enable breath in WMO
|
||||||
if (IsInWater())
|
/* if (IsInWater())
|
||||||
m_MirrorTimerFlags|=UNDERWATER_INWATER;
|
m_MirrorTimerFlags|=UNDERWATER_INWATER; */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1951,7 +1951,7 @@ class MANGOS_DLL_SPEC Player : public Unit
|
||||||
void SetSemaphoreTeleportFar(bool semphsetting) { mSemaphoreTeleport_Far = semphsetting; }
|
void SetSemaphoreTeleportFar(bool semphsetting) { mSemaphoreTeleport_Far = semphsetting; }
|
||||||
void ProcessDelayedOperations();
|
void ProcessDelayedOperations();
|
||||||
|
|
||||||
void CheckExploreSystem(void);
|
void CheckAreaExploreAndOutdoor(void);
|
||||||
|
|
||||||
static uint32 TeamForRace(uint8 race);
|
static uint32 TeamForRace(uint8 race);
|
||||||
uint32 GetTeam() const { return m_team; }
|
uint32 GetTeam() const { return m_team; }
|
||||||
|
|
|
||||||
|
|
@ -4189,6 +4189,16 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||||
if(bg->GetStatus() == STATUS_WAIT_LEAVE)
|
if(bg->GetStatus() == STATUS_WAIT_LEAVE)
|
||||||
return SPELL_FAILED_DONT_REPORT;
|
return SPELL_FAILED_DONT_REPORT;
|
||||||
|
|
||||||
|
if(m_caster->GetTypeId() == TYPEID_PLAYER && VMAP::VMapFactory::createOrGetVMapManager()->isLineOfSightCalcEnabled())
|
||||||
|
{
|
||||||
|
if(m_spellInfo->Attributes & SPELL_ATTR_OUTDOORS_ONLY &&
|
||||||
|
!m_caster->GetMap()->IsOutdoors(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ()))
|
||||||
|
return SPELL_FAILED_ONLY_OUTDOORS;
|
||||||
|
|
||||||
|
if(m_spellInfo->Attributes & SPELL_ATTR_INDOORS_ONLY &&
|
||||||
|
m_caster->GetMap()->IsOutdoors(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ()))
|
||||||
|
return SPELL_FAILED_ONLY_INDOORS;
|
||||||
|
}
|
||||||
// only check at first call, Stealth auras are already removed at second call
|
// only check at first call, Stealth auras are already removed at second call
|
||||||
// for now, ignore triggered spells
|
// for now, ignore triggered spells
|
||||||
if( strict && !m_IsTriggeredSpell)
|
if( strict && !m_IsTriggeredSpell)
|
||||||
|
|
|
||||||
|
|
@ -46,9 +46,9 @@
|
||||||
#include "BattleGround.h"
|
#include "BattleGround.h"
|
||||||
#include "BattleGroundEY.h"
|
#include "BattleGroundEY.h"
|
||||||
#include "BattleGroundWS.h"
|
#include "BattleGroundWS.h"
|
||||||
#include "VMapFactory.h"
|
|
||||||
#include "Language.h"
|
#include "Language.h"
|
||||||
#include "SocialMgr.h"
|
#include "SocialMgr.h"
|
||||||
|
#include "VMapFactory.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "TemporarySummon.h"
|
#include "TemporarySummon.h"
|
||||||
#include "ScriptCalls.h"
|
#include "ScriptCalls.h"
|
||||||
|
|
@ -7505,7 +7505,8 @@ void Spell::EffectTransmitted(SpellEffectIndex eff_idx)
|
||||||
|
|
||||||
if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
|
if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
|
||||||
{
|
{
|
||||||
if ( !cMap->IsInWater(fx, fy, fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
|
GridMapLiquidData liqData;
|
||||||
|
if ( !cMap->IsInWater(fx, fy, fz + 1.f/* -0.5f */, &liqData)) // Hack to prevent fishing bobber from failing to land on fishing hole
|
||||||
{ // but this is not proper, we really need to ignore not materialized objects
|
{ // but this is not proper, we really need to ignore not materialized objects
|
||||||
SendCastResult(SPELL_FAILED_NOT_HERE);
|
SendCastResult(SPELL_FAILED_NOT_HERE);
|
||||||
SendChannelUpdate(0);
|
SendChannelUpdate(0);
|
||||||
|
|
@ -7513,7 +7514,8 @@ void Spell::EffectTransmitted(SpellEffectIndex eff_idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace by water level in this case
|
// replace by water level in this case
|
||||||
fz = cMap->GetWaterLevel(fx, fy);
|
//fz = cMap->GetWaterLevel(fx, fy);
|
||||||
|
fz = liqData.level;
|
||||||
}
|
}
|
||||||
// if gameobject is summoning object, it should be spawned right on caster's position
|
// if gameobject is summoning object, it should be spawned right on caster's position
|
||||||
else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
|
else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
|
||||||
|
|
|
||||||
|
|
@ -4448,6 +4448,20 @@ void Unit::RemoveAurasWithInterruptFlags(uint32 flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Unit::RemoveAurasWithAttribute(uint32 flags)
|
||||||
|
{
|
||||||
|
for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end(); )
|
||||||
|
{
|
||||||
|
if (iter->second->GetSpellProto()->Attributes & flags)
|
||||||
|
{
|
||||||
|
RemoveSpellAuraHolder(iter->second);
|
||||||
|
iter = m_spellAuraHolders.begin();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase)
|
void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase)
|
||||||
{
|
{
|
||||||
// single target auras from other casters
|
// single target auras from other casters
|
||||||
|
|
|
||||||
|
|
@ -1526,6 +1526,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
|
||||||
void RemoveRankAurasDueToSpell(uint32 spellId);
|
void RemoveRankAurasDueToSpell(uint32 spellId);
|
||||||
bool RemoveNoStackAurasDueToAuraHolder(SpellAuraHolder *holder);
|
bool RemoveNoStackAurasDueToAuraHolder(SpellAuraHolder *holder);
|
||||||
void RemoveAurasWithInterruptFlags(uint32 flags);
|
void RemoveAurasWithInterruptFlags(uint32 flags);
|
||||||
|
void RemoveAurasWithAttribute(uint32 flags);
|
||||||
void RemoveAurasWithDispelType( DispelType type );
|
void RemoveAurasWithDispelType( DispelType type );
|
||||||
void RemoveAllAuras(AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);
|
void RemoveAllAuras(AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);
|
||||||
void RemoveArenaAuras(bool onleave = false);
|
void RemoveArenaAuras(bool onleave = false);
|
||||||
|
|
|
||||||
|
|
@ -848,6 +848,7 @@ void World::LoadConfigSettings(bool reload)
|
||||||
sLog.outString("Using DataDir %s",m_dataPath.c_str());
|
sLog.outString("Using DataDir %s",m_dataPath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setConfig(CONFIG_BOOL_VMAP_INDOOR_CHECK, "vmap.enableIndoorCheck", true);
|
||||||
bool enableLOS = sConfig.GetBoolDefault("vmap.enableLOS", false);
|
bool enableLOS = sConfig.GetBoolDefault("vmap.enableLOS", false);
|
||||||
bool enableHeight = sConfig.GetBoolDefault("vmap.enableHeight", false);
|
bool enableHeight = sConfig.GetBoolDefault("vmap.enableHeight", false);
|
||||||
std::string ignoreMapIds = sConfig.GetStringDefault("vmap.ignoreMapIds", "");
|
std::string ignoreMapIds = sConfig.GetStringDefault("vmap.ignoreMapIds", "");
|
||||||
|
|
@ -887,7 +888,7 @@ void World::SetInitialWorldSettings()
|
||||||
||m_configUint32Values[CONFIG_UINT32_EXPANSION] && (
|
||m_configUint32Values[CONFIG_UINT32_EXPANSION] && (
|
||||||
!MapManager::ExistMapAndVMap(530,10349.6f,-6357.29f) || !MapManager::ExistMapAndVMap(530,-3961.64f,-13931.2f) ) )
|
!MapManager::ExistMapAndVMap(530,10349.6f,-6357.29f) || !MapManager::ExistMapAndVMap(530,-3961.64f,-13931.2f) ) )
|
||||||
{
|
{
|
||||||
sLog.outError("Correct *.map files not found in path '%smaps' or *.vmap/*vmdir files in '%svmaps'. Please place *.map/*.vmap/*.vmdir files in appropriate directories or correct the DataDir value in the mangosd.conf file.",m_dataPath.c_str(),m_dataPath.c_str());
|
sLog.outError("Correct *.map files not found in path '%smaps' or *.vmtree/*.vmtile files in '%svmaps'. Please place *.map and vmap files in appropriate directories or correct the DataDir value in the mangosd.conf file.",m_dataPath.c_str(),m_dataPath.c_str());
|
||||||
Log::WaitBeforeContinueIfNeed();
|
Log::WaitBeforeContinueIfNeed();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -314,6 +314,7 @@ enum eConfigBoolValues
|
||||||
CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET,
|
CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET,
|
||||||
CONFIG_BOOL_STATS_SAVE_ONLY_ON_LOGOUT,
|
CONFIG_BOOL_STATS_SAVE_ONLY_ON_LOGOUT,
|
||||||
CONFIG_BOOL_CLEAN_CHARACTER_DB,
|
CONFIG_BOOL_CLEAN_CHARACTER_DB,
|
||||||
|
CONFIG_BOOL_VMAP_INDOOR_CHECK,
|
||||||
CONFIG_BOOL_VALUE_COUNT
|
CONFIG_BOOL_VALUE_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,13 @@ BindIP = "0.0.0.0"
|
||||||
# These spells are ignored for LoS calculation
|
# These spells are ignored for LoS calculation
|
||||||
# List of ids with delimiter ','
|
# List of ids with delimiter ','
|
||||||
#
|
#
|
||||||
|
# vmap.enableIndoorCheck
|
||||||
|
# Enable/Disable VMap based indoor check to remove outdoor-only auras (mounts etc.).
|
||||||
|
# Requires VMaps enabled to work.
|
||||||
|
# Default: 1 (Enabled)
|
||||||
|
# 0 (Disabled)
|
||||||
|
#
|
||||||
|
#
|
||||||
# DetectPosCollision
|
# DetectPosCollision
|
||||||
# Check final move position, summon position, etc for visible collision with other objects or
|
# Check final move position, summon position, etc for visible collision with other objects or
|
||||||
# wall (wall only if vmaps are enabled)
|
# wall (wall only if vmaps are enabled)
|
||||||
|
|
@ -194,8 +201,9 @@ PlayerSave.Stats.MinLevel = 0
|
||||||
PlayerSave.Stats.SaveOnlyOnLogout = 1
|
PlayerSave.Stats.SaveOnlyOnLogout = 1
|
||||||
vmap.enableLOS = 0
|
vmap.enableLOS = 0
|
||||||
vmap.enableHeight = 0
|
vmap.enableHeight = 0
|
||||||
vmap.ignoreMapIds = "369"
|
vmap.ignoreMapIds = ""
|
||||||
vmap.ignoreSpellIds = "7720"
|
vmap.ignoreSpellIds = "7720"
|
||||||
|
vmap.enableIndoorCheck = 1
|
||||||
DetectPosCollision = 1
|
DetectPosCollision = 1
|
||||||
TargetPosRecalculateRange = 1.5
|
TargetPosRecalculateRange = 1.5
|
||||||
UpdateUptimeInterval = 10
|
UpdateUptimeInterval = 10
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef __REVISION_NR_H__
|
#ifndef __REVISION_NR_H__
|
||||||
#define __REVISION_NR_H__
|
#define __REVISION_NR_H__
|
||||||
#define REVISION_NR "10164"
|
#define REVISION_NR "10165"
|
||||||
#endif // __REVISION_NR_H__
|
#endif // __REVISION_NR_H__
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
304
src/shared/vmap/BIH.cpp
Normal file
304
src/shared/vmap/BIH.cpp
Normal file
|
|
@ -0,0 +1,304 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2010 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 "BIH.h"
|
||||||
|
|
||||||
|
void BIH::buildHierarchy(std::vector<uint32> &tempTree, buildData &dat, BuildStats &stats)
|
||||||
|
{
|
||||||
|
// create space for the first node
|
||||||
|
tempTree.push_back(3 << 30); // dummy leaf
|
||||||
|
tempTree.insert(tempTree.end(), 2, 0);
|
||||||
|
//tempTree.add(0);
|
||||||
|
|
||||||
|
// seed bbox
|
||||||
|
AABound gridBox = { bounds.low(), bounds.high() };
|
||||||
|
AABound nodeBox = gridBox;
|
||||||
|
// seed subdivide function
|
||||||
|
subdivide(0, dat.numPrims - 1, tempTree, dat, gridBox, nodeBox, 0, 1, stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildData &dat, AABound &gridBox, AABound &nodeBox, int nodeIndex, int depth, BuildStats &stats)
|
||||||
|
{
|
||||||
|
if ((right - left + 1) <= dat.maxPrims || depth >= MAX_STACK_SIZE)
|
||||||
|
{
|
||||||
|
// write leaf node
|
||||||
|
stats.updateLeaf(depth, right - left + 1);
|
||||||
|
createNode(tempTree, nodeIndex, left, right);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// calculate extents
|
||||||
|
int axis = -1, prevAxis, rightOrig;
|
||||||
|
float clipL = G3D::fnan(), clipR = G3D::fnan(), prevClip = G3D::fnan();
|
||||||
|
float split = G3D::fnan(), prevSplit;
|
||||||
|
bool wasLeft = true;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
prevAxis = axis;
|
||||||
|
prevSplit = split;
|
||||||
|
// perform quick consistency checks
|
||||||
|
Vector3 d( gridBox.hi - gridBox.lo );
|
||||||
|
if (d.x < 0 || d.y < 0 || d.z < 0)
|
||||||
|
throw std::logic_error("negative node extents");
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if (nodeBox.hi[i] < gridBox.lo[i] || nodeBox.lo[i] > gridBox.hi[i])
|
||||||
|
{
|
||||||
|
//UI.printError(Module.ACCEL, "Reached tree area in error - discarding node with: %d objects", right - left + 1);
|
||||||
|
throw std::logic_error("invalid node overlap");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// find longest axis
|
||||||
|
axis = d.primaryAxis();
|
||||||
|
split = 0.5f * (gridBox.lo[axis] + gridBox.hi[axis]);
|
||||||
|
// partition L/R subsets
|
||||||
|
clipL = -G3D::inf();
|
||||||
|
clipR = G3D::inf();
|
||||||
|
rightOrig = right; // save this for later
|
||||||
|
float nodeL = G3D::inf();
|
||||||
|
float nodeR = -G3D::inf();
|
||||||
|
for (int i = left; i <= right;)
|
||||||
|
{
|
||||||
|
int obj = dat.indices[i];
|
||||||
|
float minb = dat.primBound[obj].low()[axis];
|
||||||
|
float maxb = dat.primBound[obj].high()[axis];
|
||||||
|
float center = (minb + maxb) * 0.5f;
|
||||||
|
if (center <= split)
|
||||||
|
{
|
||||||
|
// stay left
|
||||||
|
i++;
|
||||||
|
if (clipL < maxb)
|
||||||
|
clipL = maxb;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// move to the right most
|
||||||
|
int t = dat.indices[i];
|
||||||
|
dat.indices[i] = dat.indices[right];
|
||||||
|
dat.indices[right] = t;
|
||||||
|
right--;
|
||||||
|
if (clipR > minb)
|
||||||
|
clipR = minb;
|
||||||
|
}
|
||||||
|
nodeL = std::min(nodeL, minb);
|
||||||
|
nodeR = std::max(nodeR, maxb);
|
||||||
|
}
|
||||||
|
// check for empty space
|
||||||
|
if (nodeL > nodeBox.lo[axis] && nodeR < nodeBox.hi[axis])
|
||||||
|
{
|
||||||
|
float nodeBoxW = nodeBox.hi[axis] - nodeBox.lo[axis];
|
||||||
|
float nodeNewW = nodeR - nodeL;
|
||||||
|
// node box is too big compare to space occupied by primitives?
|
||||||
|
if (1.3f * nodeNewW < nodeBoxW)
|
||||||
|
{
|
||||||
|
stats.updateBVH2();
|
||||||
|
int nextIndex = tempTree.size();
|
||||||
|
// allocate child
|
||||||
|
tempTree.push_back(0);
|
||||||
|
tempTree.push_back(0);
|
||||||
|
tempTree.push_back(0);
|
||||||
|
// write bvh2 clip node
|
||||||
|
stats.updateInner();
|
||||||
|
tempTree[nodeIndex + 0] = (axis << 30) | (1 << 29) | nextIndex;
|
||||||
|
tempTree[nodeIndex + 1] = floatToRawIntBits(nodeL);
|
||||||
|
tempTree[nodeIndex + 2] = floatToRawIntBits(nodeR);
|
||||||
|
// update nodebox and recurse
|
||||||
|
nodeBox.lo[axis] = nodeL;
|
||||||
|
nodeBox.hi[axis] = nodeR;
|
||||||
|
subdivide(left, rightOrig, tempTree, dat, gridBox, nodeBox, nextIndex, depth + 1, stats);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ensure we are making progress in the subdivision
|
||||||
|
if (right == rightOrig)
|
||||||
|
{
|
||||||
|
// all left
|
||||||
|
if (prevAxis == axis && prevSplit == split) {
|
||||||
|
// we are stuck here - create a leaf
|
||||||
|
stats.updateLeaf(depth, right - left + 1);
|
||||||
|
createNode(tempTree, nodeIndex, left, right);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (clipL <= split) {
|
||||||
|
// keep looping on left half
|
||||||
|
gridBox.hi[axis] = split;
|
||||||
|
prevClip = clipL;
|
||||||
|
wasLeft = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
gridBox.hi[axis] = split;
|
||||||
|
prevClip = G3D::fnan();
|
||||||
|
}
|
||||||
|
else if (left > right)
|
||||||
|
{
|
||||||
|
// all right
|
||||||
|
if (prevAxis == axis && prevSplit == split) {
|
||||||
|
// we are stuck here - create a leaf
|
||||||
|
stats.updateLeaf(depth, right - left + 1);
|
||||||
|
createNode(tempTree, nodeIndex, left, right);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
right = rightOrig;
|
||||||
|
if (clipR >= split) {
|
||||||
|
// keep looping on right half
|
||||||
|
gridBox.lo[axis] = split;
|
||||||
|
prevClip = clipR;
|
||||||
|
wasLeft = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
gridBox.lo[axis] = split;
|
||||||
|
prevClip = G3D::fnan();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we are actually splitting stuff
|
||||||
|
if (prevAxis != -1 && !isnan(prevClip))
|
||||||
|
{
|
||||||
|
// second time through - lets create the previous split
|
||||||
|
// since it produced empty space
|
||||||
|
int nextIndex = tempTree.size();
|
||||||
|
// allocate child node
|
||||||
|
tempTree.push_back(0);
|
||||||
|
tempTree.push_back(0);
|
||||||
|
tempTree.push_back(0);
|
||||||
|
if (wasLeft) {
|
||||||
|
// create a node with a left child
|
||||||
|
// write leaf node
|
||||||
|
stats.updateInner();
|
||||||
|
tempTree[nodeIndex + 0] = (prevAxis << 30) | nextIndex;
|
||||||
|
tempTree[nodeIndex + 1] = floatToRawIntBits(prevClip);
|
||||||
|
tempTree[nodeIndex + 2] = floatToRawIntBits(G3D::inf());
|
||||||
|
} else {
|
||||||
|
// create a node with a right child
|
||||||
|
// write leaf node
|
||||||
|
stats.updateInner();
|
||||||
|
tempTree[nodeIndex + 0] = (prevAxis << 30) | (nextIndex - 3);
|
||||||
|
tempTree[nodeIndex + 1] = floatToRawIntBits(-G3D::inf());
|
||||||
|
tempTree[nodeIndex + 2] = floatToRawIntBits(prevClip);
|
||||||
|
}
|
||||||
|
// count stats for the unused leaf
|
||||||
|
depth++;
|
||||||
|
stats.updateLeaf(depth, 0);
|
||||||
|
// now we keep going as we are, with a new nodeIndex:
|
||||||
|
nodeIndex = nextIndex;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// compute index of child nodes
|
||||||
|
int nextIndex = tempTree.size();
|
||||||
|
// allocate left node
|
||||||
|
int nl = right - left + 1;
|
||||||
|
int nr = rightOrig - (right + 1) + 1;
|
||||||
|
if (nl > 0) {
|
||||||
|
tempTree.push_back(0);
|
||||||
|
tempTree.push_back(0);
|
||||||
|
tempTree.push_back(0);
|
||||||
|
} else
|
||||||
|
nextIndex -= 3;
|
||||||
|
// allocate right node
|
||||||
|
if (nr > 0) {
|
||||||
|
tempTree.push_back(0);
|
||||||
|
tempTree.push_back(0);
|
||||||
|
tempTree.push_back(0);
|
||||||
|
}
|
||||||
|
// write leaf node
|
||||||
|
stats.updateInner();
|
||||||
|
tempTree[nodeIndex + 0] = (axis << 30) | nextIndex;
|
||||||
|
tempTree[nodeIndex + 1] = floatToRawIntBits(clipL);
|
||||||
|
tempTree[nodeIndex + 2] = floatToRawIntBits(clipR);
|
||||||
|
// prepare L/R child boxes
|
||||||
|
AABound gridBoxL(gridBox), gridBoxR(gridBox);
|
||||||
|
AABound nodeBoxL(nodeBox), nodeBoxR(nodeBox);
|
||||||
|
gridBoxL.hi[axis] = gridBoxR.lo[axis] = split;
|
||||||
|
nodeBoxL.hi[axis] = clipL;
|
||||||
|
nodeBoxR.lo[axis] = clipR;
|
||||||
|
// recurse
|
||||||
|
if (nl > 0)
|
||||||
|
subdivide(left, right, tempTree, dat, gridBoxL, nodeBoxL, nextIndex, depth + 1, stats);
|
||||||
|
else
|
||||||
|
stats.updateLeaf(depth + 1, 0);
|
||||||
|
if (nr > 0)
|
||||||
|
subdivide(right + 1, rightOrig, tempTree, dat, gridBoxR, nodeBoxR, nextIndex + 3, depth + 1, stats);
|
||||||
|
else
|
||||||
|
stats.updateLeaf(depth + 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BIH::writeToFile(FILE *wf) const
|
||||||
|
{
|
||||||
|
uint32 treeSize = tree.size();
|
||||||
|
uint32 check=0, count=0;
|
||||||
|
check += fwrite(&bounds.low(), sizeof(float), 3, wf);
|
||||||
|
check += fwrite(&bounds.high(), sizeof(float), 3, wf);
|
||||||
|
check += fwrite(&treeSize, sizeof(uint32), 1, wf);
|
||||||
|
check += fwrite(&tree[0], sizeof(uint32), treeSize, wf);
|
||||||
|
count = objects.size();
|
||||||
|
check += fwrite(&count, sizeof(uint32), 1, wf);
|
||||||
|
check += fwrite(&objects[0], sizeof(uint32), count, wf);
|
||||||
|
return check == (3 + 3 + 2 + treeSize + count);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BIH::readFromFile(FILE *rf)
|
||||||
|
{
|
||||||
|
uint32 treeSize;
|
||||||
|
Vector3 lo, hi;
|
||||||
|
uint32 check=0, count=0;
|
||||||
|
check += fread(&lo, sizeof(float), 3, rf);
|
||||||
|
check += fread(&hi, sizeof(float), 3, rf);
|
||||||
|
bounds = AABox(lo, hi);
|
||||||
|
check += fread(&treeSize, sizeof(uint32), 1, rf);
|
||||||
|
tree.resize(treeSize);
|
||||||
|
check += fread(&tree[0], sizeof(uint32), treeSize, rf);
|
||||||
|
check += fread(&count, sizeof(uint32), 1, rf);
|
||||||
|
objects.resize(count); // = new uint32[nObjects];
|
||||||
|
check += fread(&objects[0], sizeof(uint32), count, rf);
|
||||||
|
return check == (3 + 3 + 2 + treeSize + count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BIH::BuildStats::updateLeaf(int depth, int n)
|
||||||
|
{
|
||||||
|
numLeaves++;
|
||||||
|
minDepth = std::min(depth, minDepth);
|
||||||
|
maxDepth = std::max(depth, maxDepth);
|
||||||
|
sumDepth += depth;
|
||||||
|
minObjects = std::min(n, minObjects);
|
||||||
|
maxObjects = std::max(n, maxObjects);
|
||||||
|
sumObjects += n;
|
||||||
|
int nl = std::min(n, 5);
|
||||||
|
++numLeavesN[nl];
|
||||||
|
}
|
||||||
|
|
||||||
|
void BIH::BuildStats::printStats()
|
||||||
|
{
|
||||||
|
printf("Tree stats:\n");
|
||||||
|
printf(" * Nodes: %d\n", numNodes);
|
||||||
|
printf(" * Leaves: %d\n", numLeaves);
|
||||||
|
printf(" * Objects: min %d\n", minObjects);
|
||||||
|
printf(" avg %.2f\n", (float) sumObjects / numLeaves);
|
||||||
|
printf(" avg(n>0) %.2f\n", (float) sumObjects / (numLeaves - numLeavesN[0]));
|
||||||
|
printf(" max %d\n", maxObjects);
|
||||||
|
printf(" * Depth: min %d\n", minDepth);
|
||||||
|
printf(" avg %.2f\n", (float) sumDepth / numLeaves);
|
||||||
|
printf(" max %d\n", maxDepth);
|
||||||
|
printf(" * Leaves w/: N=0 %3d%%\n", 100 * numLeavesN[0] / numLeaves);
|
||||||
|
printf(" N=1 %3d%%\n", 100 * numLeavesN[1] / numLeaves);
|
||||||
|
printf(" N=2 %3d%%\n", 100 * numLeavesN[2] / numLeaves);
|
||||||
|
printf(" N=3 %3d%%\n", 100 * numLeavesN[3] / numLeaves);
|
||||||
|
printf(" N=4 %3d%%\n", 100 * numLeavesN[4] / numLeaves);
|
||||||
|
printf(" N>4 %3d%%\n", 100 * numLeavesN[5] / numLeaves);
|
||||||
|
printf(" * BVH2 nodes: %d (%3d%%)\n", numBVH2, 100 * numBVH2 / (numNodes + numLeaves - 2 * numBVH2));
|
||||||
|
}
|
||||||
391
src/shared/vmap/BIH.h
Normal file
391
src/shared/vmap/BIH.h
Normal file
|
|
@ -0,0 +1,391 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2010 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 _BIH_H
|
||||||
|
#define _BIH_H
|
||||||
|
|
||||||
|
#include <G3D/Vector3.h>
|
||||||
|
#include <G3D/Ray.h>
|
||||||
|
#include <G3D/AABox.h>
|
||||||
|
|
||||||
|
#include <Platform/Define.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#define MAX_STACK_SIZE 64
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define isnan(x) _isnan(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using G3D::Vector3;
|
||||||
|
using G3D::AABox;
|
||||||
|
using G3D::Ray;
|
||||||
|
|
||||||
|
static inline uint32 floatToRawIntBits(float f)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32 ival;
|
||||||
|
float fval;
|
||||||
|
} temp;
|
||||||
|
temp.fval=f;
|
||||||
|
return temp.ival;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float intBitsToFloat(uint32 i)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32 ival;
|
||||||
|
float fval;
|
||||||
|
} temp;
|
||||||
|
temp.ival=i;
|
||||||
|
return temp.fval;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AABound
|
||||||
|
{
|
||||||
|
Vector3 lo, hi;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Bounding Interval Hierarchy Class.
|
||||||
|
Building and Ray-Intersection functions based on BIH from
|
||||||
|
Sunflow, a Java Raytracer, released under MIT/X11 License
|
||||||
|
http://sunflow.sourceforge.net/
|
||||||
|
Copyright (c) 2003-2007 Christopher Kulla
|
||||||
|
*/
|
||||||
|
|
||||||
|
class BIH
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BIH() {};
|
||||||
|
template< class T, class BoundsFunc >
|
||||||
|
void build(const std::vector<T> &primitives, BoundsFunc &getBounds, uint32 leafSize = 3, bool printStats=false)
|
||||||
|
{
|
||||||
|
if(primitives.size() == 0)
|
||||||
|
return;
|
||||||
|
buildData dat;
|
||||||
|
dat.maxPrims = leafSize;
|
||||||
|
dat.numPrims = primitives.size();
|
||||||
|
dat.indices = new uint32[dat.numPrims];
|
||||||
|
dat.primBound = new AABox[dat.numPrims];
|
||||||
|
getBounds(primitives[0], bounds);
|
||||||
|
for (uint32 i=0; i<dat.numPrims; ++i)
|
||||||
|
{
|
||||||
|
dat.indices[i] = i;
|
||||||
|
AABox tb;
|
||||||
|
getBounds(primitives[i], dat.primBound[i]);
|
||||||
|
bounds.merge(dat.primBound[i]);
|
||||||
|
}
|
||||||
|
std::vector<uint32> tempTree;
|
||||||
|
BuildStats stats;
|
||||||
|
buildHierarchy(tempTree, dat, stats);
|
||||||
|
if (printStats)
|
||||||
|
stats.printStats();
|
||||||
|
|
||||||
|
objects.resize(dat.numPrims);
|
||||||
|
for (uint32 i=0; i<dat.numPrims; ++i)
|
||||||
|
objects[i] = dat.indices[i];
|
||||||
|
//nObjects = dat.numPrims;
|
||||||
|
tree = tempTree;
|
||||||
|
delete[] dat.primBound;
|
||||||
|
delete[] dat.indices;
|
||||||
|
}
|
||||||
|
uint32 primCount() { return objects.size(); }
|
||||||
|
|
||||||
|
template<typename RayCallback>
|
||||||
|
void intersectRay(const Ray &r, RayCallback& intersectCallback, float &maxDist, bool stopAtFirst=false) const
|
||||||
|
{
|
||||||
|
float intervalMin = 0.f;
|
||||||
|
float intervalMax = maxDist;
|
||||||
|
Vector3 org = r.origin();
|
||||||
|
Vector3 dir = r.direction();
|
||||||
|
Vector3 invDir;
|
||||||
|
float t1, t2;
|
||||||
|
for(int i=0; i<3; ++i)
|
||||||
|
{
|
||||||
|
invDir[i] = 1.f / dir[i];
|
||||||
|
t1 = (bounds.low()[i] - org[i]) * invDir[i];
|
||||||
|
t2 = (bounds.high()[i] - org[i]) * invDir[i];
|
||||||
|
if (invDir[i] > 0) {
|
||||||
|
if (t1 > intervalMin)
|
||||||
|
intervalMin = t1;
|
||||||
|
if (t2 < intervalMax)
|
||||||
|
intervalMax = t2;
|
||||||
|
} else {
|
||||||
|
if (t2 > intervalMin)
|
||||||
|
intervalMin = t2;
|
||||||
|
if (t1 < intervalMax)
|
||||||
|
intervalMax = t1;
|
||||||
|
}
|
||||||
|
if (intervalMin > intervalMax)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 offsetFront[3];
|
||||||
|
uint32 offsetBack[3];
|
||||||
|
uint32 offsetFront3[3];
|
||||||
|
uint32 offsetBack3[3];
|
||||||
|
// compute custom offsets from direction sign bit
|
||||||
|
|
||||||
|
for(int i=0; i<3; ++i)
|
||||||
|
{
|
||||||
|
offsetFront[i] = floatToRawIntBits(dir[i]) >> 31;
|
||||||
|
offsetBack[i] = offsetFront[i] ^ 1;
|
||||||
|
offsetFront3[i] = offsetFront[i] * 3;
|
||||||
|
offsetBack3[i] = offsetBack[i] * 3;
|
||||||
|
|
||||||
|
// avoid always adding 1 during the inner loop
|
||||||
|
++offsetFront[i];
|
||||||
|
++offsetBack[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
StackNode stack[MAX_STACK_SIZE];
|
||||||
|
int stackPos = 0;
|
||||||
|
int node = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
uint32 tn = tree[node];
|
||||||
|
uint32 axis = (tn & (3 << 30)) >> 30;
|
||||||
|
bool BVH2 = tn & (1 << 29);
|
||||||
|
int offset = tn & ~(7 << 29);
|
||||||
|
if (!BVH2)
|
||||||
|
{
|
||||||
|
if (axis < 3)
|
||||||
|
{
|
||||||
|
// "normal" interior node
|
||||||
|
float tf = (intBitsToFloat(tree[node + offsetFront[axis]]) - org[axis]) * invDir[axis];
|
||||||
|
float tb = (intBitsToFloat(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis];
|
||||||
|
// ray passes between clip zones
|
||||||
|
if (tf < intervalMin && tb > intervalMax)
|
||||||
|
break;
|
||||||
|
int back = offset + offsetBack3[axis];
|
||||||
|
node = back;
|
||||||
|
// ray passes through far node only
|
||||||
|
if (tf < intervalMin) {
|
||||||
|
intervalMin = (tb >= intervalMin) ? tb : intervalMin;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
node = offset + offsetFront3[axis]; // front
|
||||||
|
// ray passes through near node only
|
||||||
|
if (tb > intervalMax) {
|
||||||
|
intervalMax = (tf <= intervalMax) ? tf : intervalMax;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// ray passes through both nodes
|
||||||
|
// push back node
|
||||||
|
stack[stackPos].node = back;
|
||||||
|
stack[stackPos].tnear = (tb >= intervalMin) ? tb : intervalMin;
|
||||||
|
stack[stackPos].tfar = intervalMax;
|
||||||
|
stackPos++;
|
||||||
|
// update ray interval for front node
|
||||||
|
intervalMax = (tf <= intervalMax) ? tf : intervalMax;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// leaf - test some objects
|
||||||
|
int n = tree[node + 1];
|
||||||
|
while (n > 0) {
|
||||||
|
bool hit = intersectCallback(r, objects[offset], maxDist, stopAtFirst);
|
||||||
|
if(stopAtFirst && hit) return;
|
||||||
|
--n;
|
||||||
|
++offset;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (axis>2)
|
||||||
|
return; // should not happen
|
||||||
|
float tf = (intBitsToFloat(tree[node + offsetFront[axis]]) - org[axis]) * invDir[axis];
|
||||||
|
float tb = (intBitsToFloat(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis];
|
||||||
|
node = offset;
|
||||||
|
intervalMin = (tf >= intervalMin) ? tf : intervalMin;
|
||||||
|
intervalMax = (tb <= intervalMax) ? tb : intervalMax;
|
||||||
|
if (intervalMin > intervalMax)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} // traversal loop
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// stack is empty?
|
||||||
|
if (stackPos == 0)
|
||||||
|
return;
|
||||||
|
// move back up the stack
|
||||||
|
stackPos--;
|
||||||
|
intervalMin = stack[stackPos].tnear;
|
||||||
|
if (maxDist < intervalMin)
|
||||||
|
continue;
|
||||||
|
node = stack[stackPos].node;
|
||||||
|
intervalMax = stack[stackPos].tfar;
|
||||||
|
break;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename IsectCallback>
|
||||||
|
void intersectPoint(const Vector3 &p, IsectCallback& intersectCallback) const
|
||||||
|
{
|
||||||
|
if (!bounds.contains(p))
|
||||||
|
return;
|
||||||
|
|
||||||
|
StackNode stack[MAX_STACK_SIZE];
|
||||||
|
int stackPos = 0;
|
||||||
|
int node = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
uint32 tn = tree[node];
|
||||||
|
uint32 axis = (tn & (3 << 30)) >> 30;
|
||||||
|
bool BVH2 = tn & (1 << 29);
|
||||||
|
int offset = tn & ~(7 << 29);
|
||||||
|
if (!BVH2)
|
||||||
|
{
|
||||||
|
if (axis < 3)
|
||||||
|
{
|
||||||
|
// "normal" interior node
|
||||||
|
float tl = intBitsToFloat(tree[node + 1]);
|
||||||
|
float tr = intBitsToFloat(tree[node + 2]);
|
||||||
|
// point is between clip zones
|
||||||
|
if (tl < p[axis] && tr > p[axis])
|
||||||
|
break;
|
||||||
|
int right = offset + 3;
|
||||||
|
node = right;
|
||||||
|
// point is in right node only
|
||||||
|
if (tl < p[axis]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
node = offset; // left
|
||||||
|
// point is in left node only
|
||||||
|
if (tr > p[axis]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// point is in both nodes
|
||||||
|
// push back right node
|
||||||
|
stack[stackPos].node = right;
|
||||||
|
stackPos++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// leaf - test some objects
|
||||||
|
int n = tree[node + 1];
|
||||||
|
while (n > 0) {
|
||||||
|
intersectCallback(p, objects[offset]); // !!!
|
||||||
|
--n;
|
||||||
|
++offset;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // BVH2 node (empty space cut off left and right)
|
||||||
|
{
|
||||||
|
if (axis>2)
|
||||||
|
return; // should not happen
|
||||||
|
float tl = intBitsToFloat(tree[node + 1]);
|
||||||
|
float tr = intBitsToFloat(tree[node + 2]);
|
||||||
|
node = offset;
|
||||||
|
if (tl > p[axis] || tr < p[axis])
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} // traversal loop
|
||||||
|
|
||||||
|
// stack is empty?
|
||||||
|
if (stackPos == 0)
|
||||||
|
return;
|
||||||
|
// move back up the stack
|
||||||
|
stackPos--;
|
||||||
|
node = stack[stackPos].node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool writeToFile(FILE *wf) const;
|
||||||
|
bool readFromFile(FILE *rf);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<uint32> tree;
|
||||||
|
std::vector<uint32> objects;
|
||||||
|
AABox bounds;
|
||||||
|
|
||||||
|
struct buildData
|
||||||
|
{
|
||||||
|
uint32 *indices;
|
||||||
|
AABox *primBound;
|
||||||
|
uint32 numPrims;
|
||||||
|
int maxPrims;
|
||||||
|
};
|
||||||
|
struct StackNode
|
||||||
|
{
|
||||||
|
uint32 node;
|
||||||
|
float tnear;
|
||||||
|
float tfar;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BuildStats
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int numNodes;
|
||||||
|
int numLeaves;
|
||||||
|
int sumObjects;
|
||||||
|
int minObjects;
|
||||||
|
int maxObjects;
|
||||||
|
int sumDepth;
|
||||||
|
int minDepth;
|
||||||
|
int maxDepth;
|
||||||
|
int numLeavesN[6];
|
||||||
|
int numBVH2;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BuildStats():
|
||||||
|
numNodes(0), numLeaves(0), sumObjects(0), minObjects(0x0FFFFFFF),
|
||||||
|
maxObjects(0xFFFFFFFF), sumDepth(0), minDepth(0x0FFFFFFF),
|
||||||
|
maxDepth(0xFFFFFFFF), numBVH2(0)
|
||||||
|
{
|
||||||
|
for(int i=0; i<6; ++i) numLeavesN[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateInner() { numNodes++; }
|
||||||
|
void updateBVH2() { numBVH2++; }
|
||||||
|
void updateLeaf(int depth, int n);
|
||||||
|
void printStats();
|
||||||
|
};
|
||||||
|
|
||||||
|
void buildHierarchy(std::vector<uint32> &tempTree, buildData &dat, BuildStats &stats);
|
||||||
|
|
||||||
|
void createNode(std::vector<uint32> &tempTree, int nodeIndex, uint32 left, uint32 right) {
|
||||||
|
// write leaf node
|
||||||
|
tempTree[nodeIndex + 0] = (3 << 30) | left;
|
||||||
|
tempTree[nodeIndex + 1] = right - left + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subdivide(int left, int right, std::vector<uint32> &tempTree, buildData &dat, AABound &gridBox, AABound &nodeBox, int nodeIndex, int depth, BuildStats &stats);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _BIH_H
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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_*/
|
|
||||||
|
|
@ -1,197 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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>
|
|
||||||
#include <stdio.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));
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string CMappingEntry::getKeyString( unsigned int pMapId, int pXPos, int pYPos )
|
|
||||||
{
|
|
||||||
char b[100];
|
|
||||||
sprintf(b,"%03u_%d_%d", pMapId, pXPos, pYPos);
|
|
||||||
return(std::string(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================
|
|
||||||
//============================================================
|
|
||||||
//============================================================
|
|
||||||
|
|
||||||
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");
|
|
||||||
if(!f)
|
|
||||||
{
|
|
||||||
printf("ERROR: Can't open file: %s\n",pDirectoryFileName.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buffer[500+1];
|
|
||||||
|
|
||||||
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);
|
|
||||||
printf("Coords for map %u...\n",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 true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=================================================================
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,139 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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(const std::string& pStr) { iMainFiles.append(pStr); }
|
|
||||||
void appendToSingle(const 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);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
//=====================================================
|
|
||||||
|
|
||||||
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(const 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; }
|
|
||||||
bool isAlreadyProcessedSingleFile(const std::string& pName) const { return iProcesseSingleFiles.containsKey(pName); }
|
|
||||||
void addAlreadyProcessedSingleFile(const std::string& pName) { iProcesseSingleFiles.set(pName,pName); }
|
|
||||||
|
|
||||||
inline void addWorldAreaMap(unsigned int pMapId)
|
|
||||||
{
|
|
||||||
if(!iWorldAreaGroups.contains(pMapId))
|
|
||||||
{
|
|
||||||
iWorldAreaGroups.append(pMapId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool isWorldAreaMap(unsigned int pMapId) const { return(iWorldAreaGroups.contains(pMapId)); }
|
|
||||||
void setModelNameFilterMethod(bool (*pFilterMethod)(char *pName)) { iFilterMethod = pFilterMethod; }
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#endif /*_COORDMODELMAPPING_H_*/
|
|
||||||
|
|
@ -1,126 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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"
|
|
||||||
#include <stdio.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);
|
|
||||||
}
|
|
||||||
//========================================================
|
|
||||||
}
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#define _IVMAPMANAGER_H
|
#define _IVMAPMANAGER_H
|
||||||
|
|
||||||
#include<string>
|
#include<string>
|
||||||
|
#include <Platform/Define.h>
|
||||||
|
|
||||||
//===========================================================
|
//===========================================================
|
||||||
|
|
||||||
|
|
@ -93,6 +94,12 @@ namespace VMAP
|
||||||
e.g.: "0,1,530"
|
e.g.: "0,1,530"
|
||||||
*/
|
*/
|
||||||
virtual void preventMapsFromBeingUsed(const char* pMapIdString) =0;
|
virtual void preventMapsFromBeingUsed(const char* pMapIdString) =0;
|
||||||
|
/**
|
||||||
|
Query world model area info.
|
||||||
|
\param z gets adjusted to the ground height for which this are info is valid
|
||||||
|
*/
|
||||||
|
virtual bool getAreaInfo(unsigned int pMapId, float x, float y, float &z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const=0;
|
||||||
|
virtual bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float &level, float &floor, uint32 &type) const=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,30 +27,20 @@ AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(sr
|
||||||
noinst_LIBRARIES = libmangosvmaps.a
|
noinst_LIBRARIES = libmangosvmaps.a
|
||||||
|
|
||||||
libmangosvmaps_a_SOURCES = \
|
libmangosvmaps_a_SOURCES = \
|
||||||
AABSPTree.h \
|
BIH.h \
|
||||||
BaseModel.cpp \
|
BIH.cpp \
|
||||||
BaseModel.h \
|
|
||||||
CoordModelMapping.cpp \
|
|
||||||
CoordModelMapping.h \
|
|
||||||
DebugCmdLogger.cpp \
|
|
||||||
DebugCmdLogger.h \
|
|
||||||
IVMapManager.h \
|
IVMapManager.h \
|
||||||
ManagedModelContainer.cpp \
|
MapTree.cpp \
|
||||||
ManagedModelContainer.h \
|
MapTree.h \
|
||||||
ModelContainer.cpp \
|
ModelInstance.cpp \
|
||||||
ModelContainer.h \
|
ModelInstance.h \
|
||||||
NodeValueAccess.h \
|
|
||||||
ShortBox.h \
|
|
||||||
ShortVector.h \
|
|
||||||
SubModel.cpp \
|
|
||||||
SubModel.h \
|
|
||||||
TileAssembler.cpp \
|
TileAssembler.cpp \
|
||||||
TileAssembler.h \
|
TileAssembler.h \
|
||||||
TreeNode.cpp \
|
|
||||||
TreeNode.h \
|
|
||||||
VMapDefinitions.h \
|
VMapDefinitions.h \
|
||||||
VMapFactory.cpp \
|
VMapFactory.cpp \
|
||||||
VMapFactory.h \
|
VMapFactory.h \
|
||||||
VMapManager.cpp \
|
VMapManager2.cpp \
|
||||||
VMapManager.h \
|
VMapManager2.h \
|
||||||
VMapTools.h
|
VMapTools.h \
|
||||||
|
WorldModel.cpp \
|
||||||
|
WorldModel.h
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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
|
|
||||||
467
src/shared/vmap/MapTree.cpp
Normal file
467
src/shared/vmap/MapTree.cpp
Normal file
|
|
@ -0,0 +1,467 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2010 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 "MapTree.h"
|
||||||
|
#include "ModelInstance.h"
|
||||||
|
#include "VMapManager2.h"
|
||||||
|
#include "VMapDefinitions.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
using G3D::Vector3;
|
||||||
|
|
||||||
|
namespace VMAP
|
||||||
|
{
|
||||||
|
|
||||||
|
class MapRayCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MapRayCallback(ModelInstance *val): prims(val) {}
|
||||||
|
ModelInstance *prims;
|
||||||
|
bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool pStopAtFirstHit=true)
|
||||||
|
{
|
||||||
|
return prims[entry].intersectRay(ray, distance, pStopAtFirstHit);
|
||||||
|
//std::cout << "trying to intersect '" << entity->name << "'\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AreaInfoCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AreaInfoCallback(ModelInstance *val): prims(val) {}
|
||||||
|
void operator()(const Vector3& point, uint32 entry)
|
||||||
|
{
|
||||||
|
#ifdef VMAP_DEBUG
|
||||||
|
DEBUG_LOG("trying to intersect '%s'", prims[entry].name.c_str());
|
||||||
|
#endif
|
||||||
|
prims[entry].intersectPoint(point, aInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelInstance *prims;
|
||||||
|
AreaInfo aInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LocationInfoCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LocationInfoCallback(ModelInstance *val, LocationInfo &info): prims(val), locInfo(info), result(false) {}
|
||||||
|
void operator()(const Vector3& point, uint32 entry)
|
||||||
|
{
|
||||||
|
#ifdef VMAP_DEBUG
|
||||||
|
DEBUG_LOG("trying to intersect '%s'", prims[entry].name.c_str());
|
||||||
|
#endif
|
||||||
|
if (prims[entry].GetLocationInfo(point, locInfo))
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelInstance *prims;
|
||||||
|
LocationInfo &locInfo;
|
||||||
|
bool result;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
std::string StaticMapTree::getTileFileName(uint32 mapID, uint32 tileX, uint32 tileY)
|
||||||
|
{
|
||||||
|
std::stringstream tilefilename;
|
||||||
|
tilefilename.fill('0');
|
||||||
|
tilefilename << std::setw(3) << mapID << "_";
|
||||||
|
//tilefilename << std::setw(2) << tileX << "_" << std::setw(2) << tileY << ".vmtile";
|
||||||
|
tilefilename << std::setw(2) << tileY << "_" << std::setw(2) << tileX << ".vmtile";
|
||||||
|
return tilefilename.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StaticMapTree::getAreaInfo(Vector3 &pos, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const
|
||||||
|
{
|
||||||
|
AreaInfoCallback intersectionCallBack(iTreeValues);
|
||||||
|
iTree.intersectPoint(pos, intersectionCallBack);
|
||||||
|
if (intersectionCallBack.aInfo.result)
|
||||||
|
{
|
||||||
|
flags = intersectionCallBack.aInfo.flags;
|
||||||
|
adtId = intersectionCallBack.aInfo.adtId;
|
||||||
|
rootId = intersectionCallBack.aInfo.rootId;
|
||||||
|
groupId = intersectionCallBack.aInfo.groupId;
|
||||||
|
pos.z = intersectionCallBack.aInfo.ground_Z;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StaticMapTree::GetLocationInfo(const Vector3 &pos, LocationInfo &info) const
|
||||||
|
{
|
||||||
|
LocationInfoCallback intersectionCallBack(iTreeValues, info);
|
||||||
|
iTree.intersectPoint(pos, intersectionCallBack);
|
||||||
|
return intersectionCallBack.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticMapTree::StaticMapTree(uint32 mapID, const std::string &basePath):
|
||||||
|
iMapID(mapID), iTreeValues(0), iBasePath(basePath)
|
||||||
|
{
|
||||||
|
if (iBasePath.length() > 0 && (iBasePath[iBasePath.length()-1] != '/' || iBasePath[iBasePath.length()-1] != '\\'))
|
||||||
|
{
|
||||||
|
iBasePath.append("/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
//! Make sure to call unloadMap() to unregister acquired model references before destroying
|
||||||
|
StaticMapTree::~StaticMapTree()
|
||||||
|
{
|
||||||
|
delete[] iTreeValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
/**
|
||||||
|
return dist to hit or inf() if no hit
|
||||||
|
*/
|
||||||
|
|
||||||
|
float StaticMapTree::getIntersectionTime(const G3D::Ray& pRay, float pMaxDist, bool pStopAtFirstHit) const
|
||||||
|
{
|
||||||
|
float distance = pMaxDist;
|
||||||
|
MapRayCallback intersectionCallBack(iTreeValues);
|
||||||
|
iTree.intersectRay(pRay, intersectionCallBack, distance, pStopAtFirstHit);
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
bool StaticMapTree::isInLineOfSight(const Vector3& pos1, const Vector3& pos2) const
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
float maxDist = (pos2 - pos1).magnitude();
|
||||||
|
// valid map coords should *never ever* produce float overflow, but this would produce NaNs too:
|
||||||
|
ASSERT(maxDist < std::numeric_limits<float>::max());
|
||||||
|
// prevent NaN values which can cause BIH intersection to enter infinite loop
|
||||||
|
if (maxDist < 1e-10f)
|
||||||
|
return true;
|
||||||
|
// direction with length of 1
|
||||||
|
G3D::Ray ray = G3D::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 StaticMapTree::getObjectHitPos(const Vector3& pPos1, const Vector3& pPos2, Vector3& pResultHitPos, float pModifyDist) const
|
||||||
|
{
|
||||||
|
bool result=false;
|
||||||
|
float maxDist = (pPos2 - pPos1).magnitude();
|
||||||
|
// valid map coords should *never ever* produce float overflow, but this would produce NaNs too:
|
||||||
|
ASSERT(maxDist < std::numeric_limits<float>::max());
|
||||||
|
// prevent NaN values which can cause BIH intersection to enter infinite loop
|
||||||
|
if (maxDist < 1e-10f)
|
||||||
|
{
|
||||||
|
pResultHitPos = pPos2;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Vector3 dir = (pPos2 - pPos1)/maxDist; // direction with length of 1
|
||||||
|
G3D::Ray ray(pPos1, dir);
|
||||||
|
float dist = getIntersectionTime(ray, maxDist, false);
|
||||||
|
if (dist < maxDist)
|
||||||
|
{
|
||||||
|
pResultHitPos = pPos1 + dir * dist;
|
||||||
|
if (pModifyDist < 0)
|
||||||
|
{
|
||||||
|
if ((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 StaticMapTree::getHeight(const Vector3& pPos) const
|
||||||
|
{
|
||||||
|
float height = G3D::inf();
|
||||||
|
Vector3 dir = Vector3(0,0,-1);
|
||||||
|
G3D::Ray ray(pPos, dir); // direction with length of 1
|
||||||
|
float maxDist = VMapDefinitions::getMaxCanFallDistance();
|
||||||
|
float dist = getIntersectionTime(ray, maxDist, false);
|
||||||
|
if (dist < maxDist)
|
||||||
|
{
|
||||||
|
height = pPos.z - dist;
|
||||||
|
}
|
||||||
|
return(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
bool StaticMapTree::CanLoadMap(const std::string &vmapPath, uint32 mapID, uint32 tileX, uint32 tileY)
|
||||||
|
{
|
||||||
|
std::string basePath = vmapPath;
|
||||||
|
if (basePath.length() > 0 && (basePath[basePath.length()-1] != '/' || basePath[basePath.length()-1] != '\\'))
|
||||||
|
basePath.append("/");
|
||||||
|
std::string fullname = basePath + VMapManager2::getMapFileName(mapID);
|
||||||
|
bool success = true;
|
||||||
|
FILE *rf = fopen(fullname.c_str(), "rb");
|
||||||
|
if (!rf)
|
||||||
|
return false;
|
||||||
|
// TODO: check magic number when implemented...
|
||||||
|
char tiled;
|
||||||
|
char chunk[8];
|
||||||
|
if (!readChunk(rf, chunk, VMAP_MAGIC, 8) || fread(&tiled, sizeof(char), 1, rf) != 1)
|
||||||
|
{
|
||||||
|
fclose(rf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tiled)
|
||||||
|
{
|
||||||
|
std::string tilefile = basePath + getTileFileName(mapID, tileX, tileY);
|
||||||
|
FILE* tf = fopen(tilefile.c_str(), "rb");
|
||||||
|
if (!tf)
|
||||||
|
success = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
|
||||||
|
success = false;
|
||||||
|
fclose(tf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(rf);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
bool StaticMapTree::InitMap(const std::string &fname, VMapManager2 *vm)
|
||||||
|
{
|
||||||
|
DEBUG_LOG("Initializing StaticMapTree '%s'", fname.c_str());
|
||||||
|
bool success = true;
|
||||||
|
std::string fullname = iBasePath + fname;
|
||||||
|
FILE *rf = fopen(fullname.c_str(), "rb");
|
||||||
|
if (!rf)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char chunk[8];
|
||||||
|
//general info
|
||||||
|
if (!readChunk(rf, chunk, VMAP_MAGIC, 8)) success = false;
|
||||||
|
char tiled;
|
||||||
|
if (success && fread(&tiled, sizeof(char), 1, rf) != 1) success = false;
|
||||||
|
iIsTiled = bool(tiled);
|
||||||
|
// Nodes
|
||||||
|
if (success && !readChunk(rf, chunk, "NODE", 4)) success = false;
|
||||||
|
if (success) success = iTree.readFromFile(rf);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
iNTreeValues = iTree.primCount();
|
||||||
|
iTreeValues = new ModelInstance[iNTreeValues];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success && !readChunk(rf, chunk, "GOBJ", 4)) success = false;
|
||||||
|
// global model spawns
|
||||||
|
// only non-tiled maps have them, and if so exactly one (so far at least...)
|
||||||
|
ModelSpawn spawn;
|
||||||
|
#ifdef VMAP_DEBUG
|
||||||
|
DEBUG_LOG("Map isTiled: %u", static_cast<uint32>(iIsTiled));
|
||||||
|
#endif
|
||||||
|
if (!iIsTiled && ModelSpawn::readFromFile(rf, spawn))
|
||||||
|
{
|
||||||
|
WorldModel *model = vm->acquireModelInstance(iBasePath, spawn.name);
|
||||||
|
DEBUG_LOG("StaticMapTree::InitMap(): loading %s", spawn.name.c_str());
|
||||||
|
if (model)
|
||||||
|
{
|
||||||
|
// assume that global model always is the first and only tree value (could be improved...)
|
||||||
|
iTreeValues[0] = ModelInstance(spawn, model);
|
||||||
|
iLoadedSpawns[0] = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
ERROR_LOG("StaticMapTree::InitMap() could not acquire WorldModel pointer for '%s'!", spawn.name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(rf);
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
void StaticMapTree::UnloadMap(VMapManager2 *vm)
|
||||||
|
{
|
||||||
|
for (loadedSpawnMap::iterator i = iLoadedSpawns.begin(); i != iLoadedSpawns.end(); ++i)
|
||||||
|
{
|
||||||
|
iTreeValues[i->first].setUnloaded();
|
||||||
|
for (uint32 refCount = 0; refCount < i->second; ++refCount)
|
||||||
|
vm->releaseModelInstance(iTreeValues[i->first].name);
|
||||||
|
}
|
||||||
|
iLoadedSpawns.clear();
|
||||||
|
iLoadedTiles.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
bool StaticMapTree::LoadMapTile(uint32 tileX, uint32 tileY, VMapManager2 *vm)
|
||||||
|
{
|
||||||
|
if (!iIsTiled)
|
||||||
|
{
|
||||||
|
// currently, core creates grids for all maps, whether it has terrain tiles or not
|
||||||
|
// so we need "fake" tile loads to know when we can unload map geometry
|
||||||
|
iLoadedTiles[packTileID(tileX, tileY)] = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!iTreeValues)
|
||||||
|
{
|
||||||
|
ERROR_LOG("StaticMapTree::LoadMapTile(): Tree has not been initialized! [%u,%u]", tileX, tileY);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
std::string tilefile = iBasePath + getTileFileName(iMapID, tileX, tileY);
|
||||||
|
FILE* tf = fopen(tilefile.c_str(), "rb");
|
||||||
|
if (tf)
|
||||||
|
{
|
||||||
|
char chunk[8];
|
||||||
|
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
|
||||||
|
result = false;
|
||||||
|
uint32 numSpawns;
|
||||||
|
if (result && fread(&numSpawns, sizeof(uint32), 1, tf) != 1)
|
||||||
|
result = false;
|
||||||
|
for (uint32 i=0; i<numSpawns && result; ++i)
|
||||||
|
{
|
||||||
|
// read model spawns
|
||||||
|
ModelSpawn spawn;
|
||||||
|
result = ModelSpawn::readFromFile(tf, spawn);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
// acquire model instance
|
||||||
|
WorldModel *model = vm->acquireModelInstance(iBasePath, spawn.name);
|
||||||
|
if (!model)
|
||||||
|
ERROR_LOG("StaticMapTree::LoadMapTile() could not acquire WorldModel pointer for '%s'!", spawn.name.c_str());
|
||||||
|
|
||||||
|
// update tree
|
||||||
|
uint32 referencedVal;
|
||||||
|
|
||||||
|
fread(&referencedVal, sizeof(uint32), 1, tf);
|
||||||
|
if (!iLoadedSpawns.count(referencedVal))
|
||||||
|
{
|
||||||
|
#ifdef VMAP_DEBUG
|
||||||
|
if (referencedVal > iNTreeValues)
|
||||||
|
{
|
||||||
|
DEBUG_LOG("invalid tree element! (%u/%u)", referencedVal, iNTreeValues);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
iTreeValues[referencedVal] = ModelInstance(spawn, model);
|
||||||
|
iLoadedSpawns[referencedVal] = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++iLoadedSpawns[referencedVal];
|
||||||
|
#ifdef VMAP_DEBUG
|
||||||
|
if (iTreeValues[referencedVal].ID != spawn.ID)
|
||||||
|
DEBUG_LOG("Error: trying to load wrong spawn in node!");
|
||||||
|
else if (iTreeValues[referencedVal].name != spawn.name)
|
||||||
|
DEBUG_LOG("Error: name mismatch on GUID=%u", spawn.ID);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iLoadedTiles[packTileID(tileX, tileY)] = true;
|
||||||
|
fclose(tf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
iLoadedTiles[packTileID(tileX, tileY)] = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
void StaticMapTree::UnloadMapTile(uint32 tileX, uint32 tileY, VMapManager2 *vm)
|
||||||
|
{
|
||||||
|
uint32 tileID = packTileID(tileX, tileY);
|
||||||
|
loadedTileMap::iterator tile = iLoadedTiles.find(tileID);
|
||||||
|
if (tile == iLoadedTiles.end())
|
||||||
|
{
|
||||||
|
ERROR_LOG("StaticMapTree::UnloadMapTile(): Trying to unload non-loaded tile. Map:%u X:%u Y:%u", iMapID, tileX, tileY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (tile->second) // file associated with tile
|
||||||
|
{
|
||||||
|
std::string tilefile = iBasePath + getTileFileName(iMapID, tileX, tileY);
|
||||||
|
FILE* tf = fopen(tilefile.c_str(), "rb");
|
||||||
|
if (tf)
|
||||||
|
{
|
||||||
|
bool result=true;
|
||||||
|
char chunk[8];
|
||||||
|
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
|
||||||
|
result = false;
|
||||||
|
uint32 numSpawns;
|
||||||
|
if (fread(&numSpawns, sizeof(uint32), 1, tf) != 1)
|
||||||
|
result = false;
|
||||||
|
for (uint32 i=0; i<numSpawns && result; ++i)
|
||||||
|
{
|
||||||
|
// read model spawns
|
||||||
|
ModelSpawn spawn;
|
||||||
|
result = ModelSpawn::readFromFile(tf, spawn);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
// release model instance
|
||||||
|
vm->releaseModelInstance(spawn.name);
|
||||||
|
|
||||||
|
// update tree
|
||||||
|
uint32 referencedNode;
|
||||||
|
|
||||||
|
fread(&referencedNode, sizeof(uint32), 1, tf);
|
||||||
|
if (!iLoadedSpawns.count(referencedNode))
|
||||||
|
{
|
||||||
|
ERROR_LOG("Trying to unload non-referenced model '%s' (ID:%u)", spawn.name.c_str(), spawn.ID);
|
||||||
|
}
|
||||||
|
else if (--iLoadedSpawns[referencedNode] == 0)
|
||||||
|
{
|
||||||
|
iTreeValues[referencedNode].setUnloaded();
|
||||||
|
iLoadedSpawns.erase(referencedNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(tf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iLoadedTiles.erase(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
97
src/shared/vmap/MapTree.h
Normal file
97
src/shared/vmap/MapTree.h
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2010 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 _MAPTREE_H
|
||||||
|
#define _MAPTREE_H
|
||||||
|
|
||||||
|
#include "Platform/Define.h"
|
||||||
|
#include "Utilities/UnorderedMap.h"
|
||||||
|
#include "BIH.h"
|
||||||
|
|
||||||
|
namespace VMAP
|
||||||
|
{
|
||||||
|
class ModelInstance;
|
||||||
|
class GroupModel;
|
||||||
|
class VMapManager2;
|
||||||
|
|
||||||
|
struct LocationInfo
|
||||||
|
{
|
||||||
|
LocationInfo(): hitInstance(0), hitModel(0), ground_Z(-G3D::inf()) {};
|
||||||
|
const ModelInstance *hitInstance;
|
||||||
|
const GroupModel *hitModel;
|
||||||
|
float ground_Z;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StaticMapTree
|
||||||
|
{
|
||||||
|
typedef UNORDERED_MAP<uint32, bool> loadedTileMap;
|
||||||
|
typedef UNORDERED_MAP<uint32, uint32> loadedSpawnMap;
|
||||||
|
private:
|
||||||
|
uint32 iMapID;
|
||||||
|
bool iIsTiled;
|
||||||
|
BIH iTree;
|
||||||
|
ModelInstance *iTreeValues; // the tree entries
|
||||||
|
uint32 iNTreeValues;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// empty tiles have no tile file, hence map with bool instead of just a set (consistency check)
|
||||||
|
loadedTileMap iLoadedTiles;
|
||||||
|
// stores <tree_index, reference_count> to invalidate tree values, unload map, and to be able to report errors
|
||||||
|
loadedSpawnMap iLoadedSpawns;
|
||||||
|
std::string iBasePath;
|
||||||
|
|
||||||
|
private:
|
||||||
|
float getIntersectionTime(const G3D::Ray& pRay, float pMaxDist, bool pStopAtFirstHit) const;
|
||||||
|
//bool containsLoadedMapTile(unsigned int pTileIdent) const { return(iLoadedMapTiles.containsKey(pTileIdent)); }
|
||||||
|
public:
|
||||||
|
static std::string getTileFileName(uint32 mapID, uint32 tileX, uint32 tileY);
|
||||||
|
static uint32 packTileID(uint32 tileX, uint32 tileY) { return tileX<<16 | tileY; }
|
||||||
|
static void unpackTileID(uint32 ID, uint32 &tileX, uint32 &tileY) { tileX = ID>>16; tileY = ID&0xFF; }
|
||||||
|
static bool CanLoadMap(const std::string &basePath, uint32 mapID, uint32 tileX, uint32 tileY);
|
||||||
|
|
||||||
|
StaticMapTree(uint32 mapID, const std::string &basePath);
|
||||||
|
~StaticMapTree();
|
||||||
|
|
||||||
|
bool isInLineOfSight(const G3D::Vector3& pos1, const G3D::Vector3& pos2) const;
|
||||||
|
bool getObjectHitPos(const G3D::Vector3& pos1, const G3D::Vector3& pos2, G3D::Vector3& pResultHitPos, float pModifyDist) const;
|
||||||
|
float getHeight(const G3D::Vector3& pPos) const;
|
||||||
|
bool getAreaInfo(G3D::Vector3 &pos, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const;
|
||||||
|
bool GetLocationInfo(const Vector3 &pos, LocationInfo &info) const;
|
||||||
|
|
||||||
|
bool InitMap(const std::string &fname, VMapManager2 *vm);
|
||||||
|
void UnloadMap(VMapManager2 *vm);
|
||||||
|
bool LoadMapTile(uint32 tileX, uint32 tileY, VMapManager2 *vm);
|
||||||
|
void UnloadMapTile(uint32 tileX, uint32 tileY, VMapManager2 *vm);
|
||||||
|
bool isTiled() const { return iIsTiled; }
|
||||||
|
uint32 numLoadedTiles() const { return iLoadedTiles.size(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AreaInfo
|
||||||
|
{
|
||||||
|
AreaInfo(): result(false), ground_Z(-G3D::inf()) {};
|
||||||
|
bool result;
|
||||||
|
float ground_Z;
|
||||||
|
uint32 flags;
|
||||||
|
int32 adtId;
|
||||||
|
int32 rootId;
|
||||||
|
int32 groupId;
|
||||||
|
};
|
||||||
|
} // VMAP
|
||||||
|
|
||||||
|
#endif // _MAPTREE_H
|
||||||
|
|
@ -1,375 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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;
|
|
||||||
|
|
||||||
// not allowed copy
|
|
||||||
explicit ModelContainer (const ModelContainer&);
|
|
||||||
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 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
|
|
||||||
217
src/shared/vmap/ModelInstance.cpp
Normal file
217
src/shared/vmap/ModelInstance.cpp
Normal file
|
|
@ -0,0 +1,217 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2010 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 "ModelInstance.h"
|
||||||
|
#include "WorldModel.h"
|
||||||
|
#include "MapTree.h"
|
||||||
|
#include "VMapDefinitions.h"
|
||||||
|
|
||||||
|
using G3D::Vector3;
|
||||||
|
using G3D::Ray;
|
||||||
|
|
||||||
|
namespace VMAP
|
||||||
|
{
|
||||||
|
ModelInstance::ModelInstance(const ModelSpawn &spawn, WorldModel *model): ModelSpawn(spawn), iModel(model)
|
||||||
|
{
|
||||||
|
iInvRot = G3D::Matrix3::fromEulerAnglesZYX(G3D::pi()*iRot.y/180.f, G3D::pi()*iRot.x/180.f, G3D::pi()*iRot.z/180.f).inverse();
|
||||||
|
iInvScale = 1.f/iScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModelInstance::intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit) const
|
||||||
|
{
|
||||||
|
if (!iModel)
|
||||||
|
{
|
||||||
|
#ifdef VMAP_DEBUG
|
||||||
|
DEBUG_LOG("<object not loaded>");
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
float time = pRay.intersectionTime(iBound);
|
||||||
|
if (time == G3D::inf())
|
||||||
|
{
|
||||||
|
#ifdef VMAP_DEBUG
|
||||||
|
DEBUG_LOG("Ray does not hit '%s'", name.c_str());
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// child bounds are defined in object space:
|
||||||
|
Vector3 p = iInvRot * (pRay.origin() - iPos) * iInvScale;
|
||||||
|
Ray modRay(p, iInvRot * pRay.direction());
|
||||||
|
float distance = pMaxDist * iInvScale;
|
||||||
|
bool hit = iModel->IntersectRay(modRay, distance, pStopAtFirstHit);
|
||||||
|
distance *= iScale;
|
||||||
|
pMaxDist = distance;
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelInstance::intersectPoint(const G3D::Vector3& p, AreaInfo &info) const
|
||||||
|
{
|
||||||
|
if (!iModel)
|
||||||
|
{
|
||||||
|
#ifdef VMAP_DEBUG
|
||||||
|
DEBUG_LOG("<object not loaded>");
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// M2 files don't contain area info, only WMO files
|
||||||
|
if (flags & MOD_M2)
|
||||||
|
return;
|
||||||
|
if (!iBound.contains(p))
|
||||||
|
return;
|
||||||
|
// child bounds are defined in object space:
|
||||||
|
Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
|
||||||
|
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
|
||||||
|
float zDist;
|
||||||
|
if (iModel->IntersectPoint(pModel, zDirModel, zDist, info))
|
||||||
|
{
|
||||||
|
Vector3 modelGround = pModel + zDist * zDirModel;
|
||||||
|
// Transform back to world space. Note that:
|
||||||
|
// Mat * vec == vec * Mat.transpose()
|
||||||
|
// and for rotation matrices: Mat.inverse() == Mat.transpose()
|
||||||
|
float world_Z = ((modelGround * iInvRot) * iScale + iPos).z;
|
||||||
|
if (info.ground_Z < world_Z)
|
||||||
|
{
|
||||||
|
info.ground_Z = world_Z;
|
||||||
|
info.adtId = adtId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModelInstance::GetLocationInfo(const G3D::Vector3& p, LocationInfo &info) const
|
||||||
|
{
|
||||||
|
if (!iModel)
|
||||||
|
{
|
||||||
|
#ifdef VMAP_DEBUG
|
||||||
|
DEBUG_LOG("<object not loaded>");
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// M2 files don't contain area info, only WMO files
|
||||||
|
if (flags & MOD_M2)
|
||||||
|
return false;
|
||||||
|
if (!iBound.contains(p))
|
||||||
|
return false;
|
||||||
|
// child bounds are defined in object space:
|
||||||
|
Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
|
||||||
|
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
|
||||||
|
float zDist;
|
||||||
|
if (iModel->GetLocationInfo(pModel, zDirModel, zDist, info))
|
||||||
|
{
|
||||||
|
Vector3 modelGround = pModel + zDist * zDirModel;
|
||||||
|
// Transform back to world space. Note that:
|
||||||
|
// Mat * vec == vec * Mat.transpose()
|
||||||
|
// and for rotation matrices: Mat.inverse() == Mat.transpose()
|
||||||
|
float world_Z = ((modelGround * iInvRot) * iScale + iPos).z;
|
||||||
|
if (info.ground_Z < world_Z) // hm...could it be handled automatically with zDist at intersection?
|
||||||
|
{
|
||||||
|
info.ground_Z = world_Z;
|
||||||
|
info.hitInstance = this;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModelInstance::GetLiquidLevel(const G3D::Vector3& p, LocationInfo &info, float &liqHeight) const
|
||||||
|
{
|
||||||
|
// child bounds are defined in object space:
|
||||||
|
Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
|
||||||
|
//Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
|
||||||
|
float zDist;
|
||||||
|
if (info.hitModel->GetLiquidLevel(pModel, zDist))
|
||||||
|
{
|
||||||
|
// calculate world height (zDist in model coords):
|
||||||
|
// assume WMO not tilted (wouldn't make much sense anyway)
|
||||||
|
liqHeight = zDist * iScale + iPos.z;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModelSpawn::readFromFile(FILE *rf, ModelSpawn &spawn)
|
||||||
|
{
|
||||||
|
uint32 check=0, nameLen;
|
||||||
|
check += fread(&spawn.flags, sizeof(uint32), 1, rf);
|
||||||
|
// EoF?
|
||||||
|
if (!check)
|
||||||
|
{
|
||||||
|
if (ferror(rf))
|
||||||
|
ERROR_LOG("Error reading ModelSpawn!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
check += fread(&spawn.adtId, sizeof(uint16), 1, rf);
|
||||||
|
check += fread(&spawn.ID, sizeof(uint32), 1, rf);
|
||||||
|
check += fread(&spawn.iPos, sizeof(float), 3, rf);
|
||||||
|
check += fread(&spawn.iRot, sizeof(float), 3, rf);
|
||||||
|
check += fread(&spawn.iScale, sizeof(float), 1, rf);
|
||||||
|
bool has_bound = (spawn.flags & MOD_HAS_BOUND);
|
||||||
|
if (has_bound) // only WMOs have bound in MPQ, only available after computation
|
||||||
|
{
|
||||||
|
Vector3 bLow, bHigh;
|
||||||
|
check += fread(&bLow, sizeof(float), 3, rf);
|
||||||
|
check += fread(&bHigh, sizeof(float), 3, rf);
|
||||||
|
spawn.iBound = G3D::AABox(bLow, bHigh);
|
||||||
|
}
|
||||||
|
check += fread(&nameLen, sizeof(uint32), 1, rf);
|
||||||
|
if(check != (has_bound ? 17 : 11))
|
||||||
|
{
|
||||||
|
ERROR_LOG("Error reading ModelSpawn!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char nameBuff[500];
|
||||||
|
if (nameLen>500) // file names should never be that long, must be file error
|
||||||
|
{
|
||||||
|
ERROR_LOG("Error reading ModelSpawn, file name too long!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
check = fread(nameBuff, sizeof(char), nameLen, rf);
|
||||||
|
if (check != nameLen)
|
||||||
|
{
|
||||||
|
ERROR_LOG("Error reading name string of ModelSpawn!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
spawn.name = std::string(nameBuff, nameLen);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModelSpawn::writeToFile(FILE *wf, const ModelSpawn &spawn)
|
||||||
|
{
|
||||||
|
uint32 check=0;
|
||||||
|
check += fwrite(&spawn.flags, sizeof(uint32), 1, wf);
|
||||||
|
check += fwrite(&spawn.adtId, sizeof(uint16), 1, wf);
|
||||||
|
check += fwrite(&spawn.ID, sizeof(uint32), 1, wf);
|
||||||
|
check += fwrite(&spawn.iPos, sizeof(float), 3, wf);
|
||||||
|
check += fwrite(&spawn.iRot, sizeof(float), 3, wf);
|
||||||
|
check += fwrite(&spawn.iScale, sizeof(float), 1, wf);
|
||||||
|
bool has_bound = (spawn.flags & MOD_HAS_BOUND);
|
||||||
|
if(has_bound) // only WMOs have bound in MPQ, only available after computation
|
||||||
|
{
|
||||||
|
check += fwrite(&spawn.iBound.low(), sizeof(float), 3, wf);
|
||||||
|
check += fwrite(&spawn.iBound.high(), sizeof(float), 3, wf);
|
||||||
|
}
|
||||||
|
uint32 nameLen = spawn.name.length();
|
||||||
|
check += fwrite(&nameLen, sizeof(uint32), 1, wf);
|
||||||
|
if(check != (has_bound ? 17 : 11)) return false;
|
||||||
|
check = fwrite(spawn.name.c_str(), sizeof(char), nameLen, wf);
|
||||||
|
if(check != nameLen) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
81
src/shared/vmap/ModelInstance.h
Normal file
81
src/shared/vmap/ModelInstance.h
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2010 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 _MODELINSTANCE_H_
|
||||||
|
#define _MODELINSTANCE_H_
|
||||||
|
|
||||||
|
#include <G3D/Matrix3.h>
|
||||||
|
#include <G3D/Vector3.h>
|
||||||
|
#include <G3D/AABox.h>
|
||||||
|
#include <G3D/Ray.h>
|
||||||
|
|
||||||
|
#include "Platform/Define.h"
|
||||||
|
|
||||||
|
namespace VMAP
|
||||||
|
{
|
||||||
|
class WorldModel;
|
||||||
|
struct AreaInfo;
|
||||||
|
struct LocationInfo;
|
||||||
|
|
||||||
|
enum ModelFlags
|
||||||
|
{
|
||||||
|
MOD_M2 = 1,
|
||||||
|
MOD_WORLDSPAWN = 1<<1,
|
||||||
|
MOD_HAS_BOUND = 1<<2
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModelSpawn
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name
|
||||||
|
uint32 flags;
|
||||||
|
uint16 adtId;
|
||||||
|
uint32 ID;
|
||||||
|
G3D::Vector3 iPos;
|
||||||
|
G3D::Vector3 iRot;
|
||||||
|
float iScale;
|
||||||
|
G3D::AABox iBound;
|
||||||
|
std::string name;
|
||||||
|
bool operator==(const ModelSpawn &other) const { return ID == other.ID; }
|
||||||
|
//uint32 hashCode() const { return ID; }
|
||||||
|
// temp?
|
||||||
|
const G3D::AABox& getBounds() const { return iBound; }
|
||||||
|
|
||||||
|
|
||||||
|
static bool readFromFile(FILE *rf, ModelSpawn &spawn);
|
||||||
|
static bool writeToFile(FILE *rw, const ModelSpawn &spawn);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModelInstance: public ModelSpawn
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModelInstance(): iModel(0) {}
|
||||||
|
ModelInstance(const ModelSpawn &spawn, WorldModel *model);
|
||||||
|
void setUnloaded() { iModel = 0; }
|
||||||
|
bool intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit) const;
|
||||||
|
void intersectPoint(const G3D::Vector3& p, AreaInfo &info) const;
|
||||||
|
bool GetLocationInfo(const G3D::Vector3& p, LocationInfo &info) const;
|
||||||
|
bool GetLiquidLevel(const G3D::Vector3& p, LocationInfo &info, float &liqHeight) const;
|
||||||
|
protected:
|
||||||
|
G3D::Matrix3 iInvRot;
|
||||||
|
float iInvScale;
|
||||||
|
WorldModel *iModel;
|
||||||
|
};
|
||||||
|
} // namespace VMAP
|
||||||
|
|
||||||
|
#endif // _MODELINSTANCE
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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
|
|
||||||
|
|
@ -1,148 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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
|
|
||||||
|
|
@ -1,134 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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
|
|
||||||
|
|
@ -1,248 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//==========================================================
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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
|
|
||||||
|
|
@ -16,36 +16,42 @@
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <G3D/Vector3.h>
|
#include "WorldModel.h"
|
||||||
#include <G3D/Triangle.h>
|
|
||||||
|
|
||||||
#include "TileAssembler.h"
|
#include "TileAssembler.h"
|
||||||
#include "CoordModelMapping.h"
|
#include "MapTree.h"
|
||||||
#include "ModelContainer.h"
|
#include "BIH.h"
|
||||||
|
#include "VMapDefinitions.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <set>
|
||||||
#include <string.h>
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#ifdef _ASSEMBLER_DEBUG
|
using G3D::Vector3;
|
||||||
FILE *g_df = NULL;
|
using G3D::AABox;
|
||||||
#endif
|
using G3D::inf;
|
||||||
|
using std::pair;
|
||||||
|
|
||||||
using namespace G3D;
|
template<> struct BoundsTrait<VMAP::ModelSpawn*>
|
||||||
|
{
|
||||||
|
static void getBounds(const VMAP::ModelSpawn* const &obj, G3D::AABox& out) { out = obj->getBounds(); }
|
||||||
|
};
|
||||||
|
|
||||||
namespace VMAP
|
namespace VMAP
|
||||||
{
|
{
|
||||||
//=================================================================
|
bool readChunk(FILE *rf, char *dest, const char *compare, uint32 len)
|
||||||
|
{
|
||||||
|
if (fread(dest, sizeof(char), len, rf) != len) return false;
|
||||||
|
return memcmp(dest, compare, len) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
Vector3 ModelPosition::transform(const Vector3& pIn) const
|
Vector3 ModelPosition::transform(const Vector3& pIn) const
|
||||||
{
|
{
|
||||||
//return(pIn);
|
|
||||||
Vector3 out = pIn * iScale;
|
Vector3 out = pIn * iScale;
|
||||||
out = izMatrix * out;
|
out = iRotation * out;
|
||||||
out = ixMatrix * out;
|
|
||||||
out = iyMatrix * out;
|
|
||||||
return(out);
|
return(out);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//=================================================================
|
//=================================================================
|
||||||
|
|
||||||
TileAssembler::TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName)
|
TileAssembler::TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName)
|
||||||
|
|
@ -55,318 +61,300 @@ namespace VMAP
|
||||||
iSrcDir = pSrcDirName;
|
iSrcDir = pSrcDirName;
|
||||||
iDestDir = pDestDirName;
|
iDestDir = pDestDirName;
|
||||||
//mkdir(iDestDir);
|
//mkdir(iDestDir);
|
||||||
init();
|
//init();
|
||||||
}
|
}
|
||||||
|
|
||||||
//=================================================================
|
|
||||||
|
|
||||||
TileAssembler::~TileAssembler()
|
TileAssembler::~TileAssembler()
|
||||||
{
|
{
|
||||||
delete iCoordModelMapping;
|
//delete iCoordModelMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=================================================================
|
bool TileAssembler::convertWorld2()
|
||||||
|
|
||||||
void TileAssembler::init()
|
|
||||||
{
|
{
|
||||||
iCoordModelMapping = new CoordModelMapping();
|
std::set<std::string> spawnedModelFiles;
|
||||||
addWorldAreaMapId(0); //Azeroth
|
bool success = readMapSpawns();
|
||||||
addWorldAreaMapId(1); //Kalimdor
|
if (!success)
|
||||||
addWorldAreaMapId(530); //Expansion01
|
|
||||||
addWorldAreaMapId(571); //Expansion02
|
|
||||||
}
|
|
||||||
//=================================================================
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
std::string fname = iSrcDir;
|
|
||||||
fname.append("/");
|
|
||||||
fname.append("dir");
|
|
||||||
iCoordModelMapping->setModelNameFilterMethod(iFilterMethod);
|
|
||||||
|
|
||||||
printf("Read coordinate mapping...\n");
|
|
||||||
if(!iCoordModelMapping->readCoordinateMapping(fname))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Array<unsigned int> mapIds = iCoordModelMapping->getMaps();
|
// export Map data
|
||||||
if(mapIds.size() == 0)
|
for (MapData::iterator map_iter = mapData.begin(); map_iter != mapData.end() && success; ++map_iter)
|
||||||
{
|
{
|
||||||
printf("Fatal error: empty map list!\n");
|
// build global map tree
|
||||||
return false;
|
std::vector<ModelSpawn*> mapSpawns;
|
||||||
}
|
UniqueEntryMap::iterator entry;
|
||||||
|
printf("Calculating model bounds for map %u...\n", map_iter->first);
|
||||||
for(int i=0; i<mapIds.size(); ++i)
|
for (entry = map_iter->second->UniqueEntries.begin(); entry != map_iter->second->UniqueEntries.end(); ++entry)
|
||||||
{
|
{
|
||||||
unsigned int mapId = mapIds[i];
|
// M2 models don't have a bound set in WDT/ADT placement data, i still think they're not used for LoS at all on retail
|
||||||
|
if (entry->second.flags & MOD_M2)
|
||||||
#ifdef _ASSEMBLER_DEBUG
|
|
||||||
if(mapId == 0) // "Azeroth" just for debug
|
|
||||||
{
|
{
|
||||||
for(int x=28; x<29; ++x) //debug
|
if (!calculateTransformedBound(entry->second))
|
||||||
{
|
|
||||||
for(int y=28; y<29; ++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; ++x)
|
|
||||||
{
|
|
||||||
for(int y=0; y<66; ++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);
|
|
||||||
printf("%s...\n",dirname.c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sprintf(buffer, "%03u",mapId);
|
|
||||||
dirname = std::string(buffer);
|
|
||||||
|
|
||||||
// prevent spam for small maps
|
|
||||||
if(x==0 && y==0)
|
|
||||||
printf("%s...\n",dirname.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool result = fillModelContainerArray(dirname, mapId, x, y, mc);
|
|
||||||
emptyArray(mc);
|
|
||||||
|
|
||||||
if(!result)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef _ASSEMBLER_DEBUG
|
|
||||||
if(::g_df) fclose(::g_df);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=================================================================
|
|
||||||
|
|
||||||
bool TileAssembler::fillModelContainerArray(const std::string& pDirFileName, unsigned int pMapId, int pXPos, int pYPos, Array<ModelContainer*>& pMC)
|
|
||||||
{
|
|
||||||
ModelContainer* modelContainer;
|
|
||||||
|
|
||||||
NameCollection nameCollection = iCoordModelMapping->getFilenamesForCoordinate(pMapId, pXPos, pYPos);
|
|
||||||
if(nameCollection.size() == 0)
|
|
||||||
return true; // no data...
|
|
||||||
|
|
||||||
char dirfilename[500];
|
|
||||||
sprintf(dirfilename,"%s/%s.vmdir",iDestDir.c_str(),pDirFileName.c_str());
|
|
||||||
FILE *dirfile = fopen(dirfilename, "ab");
|
|
||||||
if(!dirfile)
|
|
||||||
{
|
|
||||||
printf("ERROR: Can't create file %s",dirfilename);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
printf("warning: (if) problems in processing data for %s\n",destnamebuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// process the large singe files
|
|
||||||
int pos = 0;
|
|
||||||
while(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
|
|
||||||
printf("warning: (while) problems in processing data for %s\n",destFileName.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(dirfile);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=================================================================
|
|
||||||
|
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
++pos;
|
else if (entry->second.flags & MOD_WORLDSPAWN) // WMO maps and terrain maps use different origin, so we need to adapt :/
|
||||||
}
|
|
||||||
if(result && mainTree->size() > 0)
|
|
||||||
{
|
{
|
||||||
mainTree->balance();
|
// TODO: remove extractor hack and uncomment below line:
|
||||||
modelContainer = new ModelContainer(mainTree);
|
//entry->second.iPos += Vector3(533.33333f*32, 533.33333f*32, 0.f);
|
||||||
modelContainer->writeFile(pDestFileName);
|
entry->second.iBound = entry->second.iBound + Vector3(533.33333f*32, 533.33333f*32, 0.f);
|
||||||
}
|
}
|
||||||
removeEntriesFromTree(mainTree);
|
mapSpawns.push_back(&(entry->second));
|
||||||
|
spawnedModelFiles.insert(entry->second.name);
|
||||||
delete mainTree;
|
|
||||||
|
|
||||||
return(modelContainer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("Creating map tree...\n");
|
||||||
|
BIH pTree;
|
||||||
|
pTree.build(mapSpawns, BoundsTrait<ModelSpawn*>::getBounds);
|
||||||
|
|
||||||
|
// ===> possibly move this code to StaticMapTree class
|
||||||
|
std::map<uint32, uint32> modelNodeIdx;
|
||||||
|
for (uint32 i=0; i<mapSpawns.size(); ++i)
|
||||||
|
modelNodeIdx.insert(pair<uint32, uint32>(mapSpawns[i]->ID, i));
|
||||||
|
|
||||||
|
// write map tree file
|
||||||
|
std::stringstream mapfilename;
|
||||||
|
mapfilename << iDestDir << "/" << std::setfill('0') << std::setw(3) << map_iter->first << ".vmtree";
|
||||||
|
FILE *mapfile = fopen(mapfilename.str().c_str(), "wb");
|
||||||
|
if (!mapfile)
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
printf("Cannot open %s\n", mapfilename.str().c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//general info
|
||||||
|
if (success && fwrite(VMAP_MAGIC, 1, 8, mapfile) != 8) success = false;
|
||||||
|
uint32 globalTileID = StaticMapTree::packTileID(65, 65);
|
||||||
|
pair<TileMap::iterator, TileMap::iterator> globalRange = map_iter->second->TileEntries.equal_range(globalTileID);
|
||||||
|
char isTiled = globalRange.first == globalRange.second; // only maps without terrain (tiles) have global WMO
|
||||||
|
if (success && fwrite(&isTiled, sizeof(char), 1, mapfile) != 1) success = false;
|
||||||
|
// Nodes
|
||||||
|
if (success && fwrite("NODE", 4, 1, mapfile) != 1) success = false;
|
||||||
|
if (success) success = pTree.writeToFile(mapfile);
|
||||||
|
// global map spawns (WDT), if any (most instances)
|
||||||
|
if (success && fwrite("GOBJ", 4, 1, mapfile) != 1) success = false;
|
||||||
|
|
||||||
|
for (TileMap::iterator glob=globalRange.first; glob != globalRange.second && success; ++glob)
|
||||||
|
{
|
||||||
|
success = ModelSpawn::writeToFile(mapfile, map_iter->second->UniqueEntries[glob->second]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(mapfile);
|
||||||
|
|
||||||
|
// <====
|
||||||
|
|
||||||
|
// write map tile files, similar to ADT files, only with extra BSP tree node info
|
||||||
|
TileMap &tileEntries = map_iter->second->TileEntries;
|
||||||
|
TileMap::iterator tile;
|
||||||
|
for (tile = tileEntries.begin(); tile != tileEntries.end(); ++tile)
|
||||||
|
{
|
||||||
|
const ModelSpawn &spawn = map_iter->second->UniqueEntries[tile->second];
|
||||||
|
if (spawn.flags & MOD_WORLDSPAWN) // WDT spawn, saved as tile 65/65 currently...
|
||||||
|
continue;
|
||||||
|
uint32 nSpawns = tileEntries.count(tile->first);
|
||||||
|
std::stringstream tilefilename;
|
||||||
|
tilefilename.fill('0');
|
||||||
|
tilefilename << iDestDir << "/" << std::setw(3) << map_iter->first << "_";
|
||||||
|
uint32 x, y;
|
||||||
|
StaticMapTree::unpackTileID(tile->first, x, y);
|
||||||
|
tilefilename << std::setw(2) << x << "_" << std::setw(2) << y << ".vmtile";
|
||||||
|
FILE *tilefile = fopen(tilefilename.str().c_str(), "wb");
|
||||||
|
// file header
|
||||||
|
if (success && fwrite(VMAP_MAGIC, 1, 8, tilefile) != 8) success = false;
|
||||||
|
// write number of tile spawns
|
||||||
|
if (success && fwrite(&nSpawns, sizeof(uint32), 1, tilefile) != 1) success = false;
|
||||||
|
// write tile spawns
|
||||||
|
for (uint32 s=0; s<nSpawns; ++s)
|
||||||
|
{
|
||||||
|
if (s)
|
||||||
|
++tile;
|
||||||
|
const ModelSpawn &spawn2 = map_iter->second->UniqueEntries[tile->second];
|
||||||
|
success = success && ModelSpawn::writeToFile(tilefile, spawn2);
|
||||||
|
// MapTree nodes to update when loading tile:
|
||||||
|
std::map<uint32, uint32>::iterator nIdx = modelNodeIdx.find(spawn2.ID);
|
||||||
|
if (success && fwrite(&nIdx->second, sizeof(uint32), 1, tilefile) != 1) success = false;
|
||||||
|
}
|
||||||
|
fclose(tilefile);
|
||||||
|
}
|
||||||
|
// break; //test, extract only first map; TODO: remvoe this line
|
||||||
|
}
|
||||||
|
|
||||||
|
// export objects
|
||||||
|
std::cout << "\nConverting Model Files" << std::endl;
|
||||||
|
for (std::set<std::string>::iterator mfile = spawnedModelFiles.begin(); mfile != spawnedModelFiles.end(); ++mfile)
|
||||||
|
{
|
||||||
|
std::cout << "Converting " << *mfile << std::endl;
|
||||||
|
if (!convertRawFile(*mfile))
|
||||||
|
{
|
||||||
|
std::cout << "error converting " << *mfile << std::endl;
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//cleanup:
|
||||||
|
for (MapData::iterator map_iter = mapData.begin(); map_iter != mapData.end(); ++map_iter)
|
||||||
|
{
|
||||||
|
delete map_iter->second;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TileAssembler::readMapSpawns()
|
||||||
|
{
|
||||||
|
std::string fname = iSrcDir + "/dir_bin";
|
||||||
|
FILE *dirf = fopen(fname.c_str(), "rb");
|
||||||
|
if (!dirf)
|
||||||
|
{
|
||||||
|
printf("Could not read dir_bin file!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
printf("Read coordinate mapping...\n");
|
||||||
|
uint32 mapID, tileX, tileY, check=0;
|
||||||
|
G3D::Vector3 v1, v2;
|
||||||
|
ModelSpawn spawn;
|
||||||
|
while (!feof(dirf))
|
||||||
|
{
|
||||||
|
check = 0;
|
||||||
|
// read mapID, tileX, tileY, Flags, adtID, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name
|
||||||
|
check += fread(&mapID, sizeof(uint32), 1, dirf);
|
||||||
|
if (check == 0) // EoF...
|
||||||
|
break;
|
||||||
|
check += fread(&tileX, sizeof(uint32), 1, dirf);
|
||||||
|
check += fread(&tileY, sizeof(uint32), 1, dirf);
|
||||||
|
if (!ModelSpawn::readFromFile(dirf, spawn))
|
||||||
|
break;
|
||||||
|
|
||||||
|
MapSpawns *current;
|
||||||
|
MapData::iterator map_iter = mapData.find(mapID);
|
||||||
|
if (map_iter == mapData.end())
|
||||||
|
{
|
||||||
|
printf("spawning Map %d\n", mapID);
|
||||||
|
mapData[mapID] = current = new MapSpawns();
|
||||||
|
}
|
||||||
|
else current = (*map_iter).second;
|
||||||
|
current->UniqueEntries.insert(pair<uint32, ModelSpawn>(spawn.ID, spawn));
|
||||||
|
current->TileEntries.insert(pair<uint32, uint32>(StaticMapTree::packTileID(tileX, tileY), spawn.ID));
|
||||||
|
}
|
||||||
|
bool success = (ferror(dirf) == 0);
|
||||||
|
fclose(dirf);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TileAssembler::calculateTransformedBound(ModelSpawn &spawn)
|
||||||
|
{
|
||||||
|
std::string modelFilename = iSrcDir + "/" + spawn.name;
|
||||||
|
ModelPosition modelPosition;
|
||||||
|
modelPosition.iDir = spawn.iRot;
|
||||||
|
modelPosition.iScale = spawn.iScale;
|
||||||
|
modelPosition.init();
|
||||||
|
|
||||||
|
FILE *rf = fopen(modelFilename.c_str(), "rb");
|
||||||
|
if (!rf)
|
||||||
|
{
|
||||||
|
printf("ERROR: Can't open model file: %s\n", modelFilename.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AABox modelBound;
|
||||||
|
bool boundEmpty=true;
|
||||||
|
char ident[8];
|
||||||
|
|
||||||
|
int readOperation = 1;
|
||||||
|
|
||||||
|
// temporary use defines to simplify read/check code (close file and return at fail)
|
||||||
|
#define READ_OR_RETURN(V,S) if(fread((V), (S), 1, rf) != 1) { \
|
||||||
|
fclose(rf); printf("readfail, op = %i\n", readOperation); return(false); }readOperation++;
|
||||||
|
#define CMP_OR_RETURN(V,S) if(strcmp((V),(S)) != 0) { \
|
||||||
|
fclose(rf); printf("cmpfail, %s!=%s\n", V, S);return(false); }
|
||||||
|
|
||||||
|
READ_OR_RETURN(&ident, 8);
|
||||||
|
CMP_OR_RETURN(ident, "VMAP003");
|
||||||
|
|
||||||
|
// we have to read one int. This is needed during the export and we have to skip it here
|
||||||
|
uint32 tempNVectors;
|
||||||
|
READ_OR_RETURN(&tempNVectors, sizeof(tempNVectors));
|
||||||
|
|
||||||
|
uint32 groups, wmoRootId;
|
||||||
|
char blockId[5];
|
||||||
|
blockId[4] = 0;
|
||||||
|
int blocksize;
|
||||||
|
float *vectorarray = 0;
|
||||||
|
|
||||||
|
READ_OR_RETURN(&groups, sizeof(uint32));
|
||||||
|
READ_OR_RETURN(&wmoRootId, sizeof(uint32));
|
||||||
|
if (groups != 1) printf("Warning: '%s' does not seem to be a M2 model!\n", modelFilename.c_str());
|
||||||
|
|
||||||
|
for (uint32 g=0; g<groups; ++g) // should be only one for M2 files...
|
||||||
|
{
|
||||||
|
fseek(rf, 3*sizeof(uint32) + 6*sizeof(float), SEEK_CUR);
|
||||||
|
|
||||||
|
READ_OR_RETURN(&blockId, 4);
|
||||||
|
CMP_OR_RETURN(blockId, "GRP ");
|
||||||
|
READ_OR_RETURN(&blocksize, sizeof(int));
|
||||||
|
fseek(rf, blocksize, SEEK_CUR);
|
||||||
|
|
||||||
|
// ---- indexes
|
||||||
|
READ_OR_RETURN(&blockId, 4);
|
||||||
|
CMP_OR_RETURN(blockId, "INDX");
|
||||||
|
READ_OR_RETURN(&blocksize, sizeof(int));
|
||||||
|
fseek(rf, blocksize, SEEK_CUR);
|
||||||
|
|
||||||
|
// ---- vectors
|
||||||
|
READ_OR_RETURN(&blockId, 4);
|
||||||
|
CMP_OR_RETURN(blockId, "VERT");
|
||||||
|
READ_OR_RETURN(&blocksize, sizeof(int));
|
||||||
|
uint32 nvectors;
|
||||||
|
READ_OR_RETURN(&nvectors, sizeof(uint32));
|
||||||
|
|
||||||
|
if (nvectors >0)
|
||||||
|
{
|
||||||
|
vectorarray = new float[nvectors*3];
|
||||||
|
READ_OR_RETURN(vectorarray, nvectors*sizeof(float)*3);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "error: model '" << spawn.name << "' has no geometry!" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32 i=0, indexNo=0; indexNo<nvectors; indexNo++, i+=3)
|
||||||
|
{
|
||||||
|
Vector3 v = Vector3(vectorarray[i+0], vectorarray[i+1], vectorarray[i+2]);
|
||||||
|
v = modelPosition.transform(v);
|
||||||
|
|
||||||
|
if (boundEmpty)
|
||||||
|
modelBound = AABox(v, v), boundEmpty=false;
|
||||||
|
else
|
||||||
|
modelBound.merge(v);
|
||||||
|
}
|
||||||
|
delete[] vectorarray;
|
||||||
|
// drop of temporary use defines
|
||||||
|
#undef READ_OR_RETURN
|
||||||
|
#undef CMP_OR_RETURN
|
||||||
|
}
|
||||||
|
spawn.iBound = modelBound + spawn.iPos;
|
||||||
|
spawn.flags |= MOD_HAS_BOUND;
|
||||||
|
fclose(rf);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WMOLiquidHeader
|
||||||
|
{
|
||||||
|
int xverts, yverts, xtiles, ytiles;
|
||||||
|
float pos_x;
|
||||||
|
float pos_y;
|
||||||
|
float pos_z;
|
||||||
|
short type;
|
||||||
|
};
|
||||||
//=================================================================
|
//=================================================================
|
||||||
bool TileAssembler::readRawFile(std::string& pModelFilename, ModelPosition& pModelPosition, AABSPTree<SubModel *> *pMainTree)
|
bool TileAssembler::convertRawFile(const std::string& pModelFilename)
|
||||||
{
|
{
|
||||||
|
bool success = true;
|
||||||
std::string filename = iSrcDir;
|
std::string filename = iSrcDir;
|
||||||
if (filename.length() >0)
|
if (filename.length() >0)
|
||||||
filename.append("/");
|
filename.append("/");
|
||||||
filename.append(pModelFilename);
|
filename.append(pModelFilename);
|
||||||
FILE *rf = fopen(filename.c_str(), "rb");
|
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rf)
|
if (!rf)
|
||||||
{
|
{
|
||||||
|
|
@ -377,95 +365,74 @@ namespace VMAP
|
||||||
|
|
||||||
char ident[8];
|
char ident[8];
|
||||||
|
|
||||||
int trianglecount =0;
|
int readOperation = 1;
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
// temporary use defines to simplify read/check code (close file and return at fail)
|
// temporary use defines to simplify read/check code (close file and return at fail)
|
||||||
#define READ_OR_RETURN(V,S) if(fread((V), (S), 1, rf) != 1) { \
|
#define READ_OR_RETURN(V,S) if(fread((V), (S), 1, rf) != 1) { \
|
||||||
fclose(rf); return(false); }
|
fclose(rf); printf("readfail, op = %i\n", readOperation); return(false); }readOperation++;
|
||||||
#define CMP_OR_RETURN(V,S) if(strcmp((V),(S)) != 0) { \
|
#define CMP_OR_RETURN(V,S) if(strcmp((V),(S)) != 0) { \
|
||||||
fclose(rf); return(false); }
|
fclose(rf); printf("cmpfail, %s!=%s\n", V, S);return(false); }
|
||||||
|
|
||||||
READ_OR_RETURN(&ident, 8);
|
READ_OR_RETURN(&ident, 8);
|
||||||
if(strcmp(ident, "VMAP001") == 0)
|
CMP_OR_RETURN(ident, "VMAP003");
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
READ_OR_RETURN(&tempNVectors, sizeof(int));
|
|
||||||
|
|
||||||
}
|
// we have to read one int. This is needed during the export and we have to skip it here
|
||||||
else
|
uint32 tempNVectors;
|
||||||
{
|
READ_OR_RETURN(&tempNVectors, sizeof(tempNVectors));
|
||||||
// wrong version
|
|
||||||
fclose(rf);
|
uint32 groups;
|
||||||
return(false);
|
uint32 RootWMOID;
|
||||||
}
|
|
||||||
G3D::uint32 groups;
|
|
||||||
char blockId[5];
|
char blockId[5];
|
||||||
blockId[4] = 0;
|
blockId[4] = 0;
|
||||||
int blocksize;
|
int blocksize;
|
||||||
|
|
||||||
READ_OR_RETURN(&groups, sizeof(G3D::uint32));
|
READ_OR_RETURN(&groups, sizeof(uint32));
|
||||||
|
READ_OR_RETURN(&RootWMOID, sizeof(uint32));
|
||||||
|
|
||||||
for(int g=0;g<(int)groups;g++)
|
std::vector<GroupModel> groupsArray;
|
||||||
|
|
||||||
|
for (uint32 g=0; g<groups; ++g)
|
||||||
{
|
{
|
||||||
// group MUST NOT have more then 65536 indexes !! Array will have a problem with that !! (strange ...)
|
std::vector<MeshTriangle> triangles;
|
||||||
Array<int> tempIndexArray;
|
std::vector<Vector3> vertexArray;
|
||||||
Array<Vector3> tempVertexArray;
|
|
||||||
|
|
||||||
AABSPTree<Triangle> *gtree = new AABSPTree<Triangle>();
|
uint32 mogpflags, GroupWMOID;
|
||||||
|
READ_OR_RETURN(&mogpflags, sizeof(uint32));
|
||||||
|
READ_OR_RETURN(&GroupWMOID, sizeof(uint32));
|
||||||
|
|
||||||
// add free gtree at fail
|
float bbox1[3], bbox2[3];
|
||||||
#undef READ_OR_RETURN
|
READ_OR_RETURN(bbox1, sizeof(float)*3);
|
||||||
#undef CMP_OR_RETURN
|
READ_OR_RETURN(bbox2, sizeof(float)*3);
|
||||||
#define READ_OR_RETURN(V,S) if(fread((V), (S), 1, rf) != 1) { \
|
|
||||||
fclose(rf); delete gtree; return(false); }
|
|
||||||
#define CMP_OR_RETURN(V,S) if(strcmp((V),(S)) != 0) { \
|
|
||||||
fclose(rf); delete gtree; return(false); }
|
|
||||||
|
|
||||||
G3D::uint32 flags;
|
uint32 liquidflags;
|
||||||
READ_OR_RETURN(&flags, sizeof(G3D::uint32));
|
READ_OR_RETURN(&liquidflags, sizeof(uint32));
|
||||||
|
|
||||||
G3D::uint32 branches;
|
// will this ever be used? what is it good for anyway??
|
||||||
|
uint32 branches;
|
||||||
READ_OR_RETURN(&blockId, 4);
|
READ_OR_RETURN(&blockId, 4);
|
||||||
CMP_OR_RETURN(blockId, "GRP ");
|
CMP_OR_RETURN(blockId, "GRP ");
|
||||||
READ_OR_RETURN(&blocksize, sizeof(int));
|
READ_OR_RETURN(&blocksize, sizeof(int));
|
||||||
READ_OR_RETURN(&branches, sizeof(G3D::uint32));
|
READ_OR_RETURN(&branches, sizeof(uint32));
|
||||||
for(int b=0;b<(int)branches; b++)
|
for (uint32 b=0; b<branches; ++b)
|
||||||
{
|
{
|
||||||
G3D::uint32 indexes;
|
uint32 indexes;
|
||||||
// indexes for each branch (not used jet)
|
// indexes for each branch (not used jet)
|
||||||
READ_OR_RETURN(&indexes, sizeof(G3D::uint32));
|
READ_OR_RETURN(&indexes, sizeof(uint32));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- indexes
|
// ---- indexes
|
||||||
READ_OR_RETURN(&blockId, 4);
|
READ_OR_RETURN(&blockId, 4);
|
||||||
CMP_OR_RETURN(blockId, "INDX");
|
CMP_OR_RETURN(blockId, "INDX");
|
||||||
READ_OR_RETURN(&blocksize, sizeof(int));
|
READ_OR_RETURN(&blocksize, sizeof(int));
|
||||||
unsigned int nindexes;
|
uint32 nindexes;
|
||||||
READ_OR_RETURN(&nindexes, sizeof(G3D::uint32));
|
READ_OR_RETURN(&nindexes, sizeof(uint32));
|
||||||
if (nindexes >0)
|
if (nindexes >0)
|
||||||
{
|
{
|
||||||
unsigned short *indexarray = new unsigned short[nindexes*sizeof(unsigned short)];
|
uint16 *indexarray = new uint16[nindexes];
|
||||||
READ_OR_RETURN(indexarray, nindexes*sizeof(unsigned short));
|
READ_OR_RETURN(indexarray, nindexes*sizeof(uint16));
|
||||||
for(int i=0;i<(int)nindexes; i++)
|
for (uint32 i=0; i<nindexes; i+=3)
|
||||||
{
|
{
|
||||||
unsigned short val = indexarray[i];
|
triangles.push_back(MeshTriangle(indexarray[i], indexarray[i+1], indexarray[i+2]));
|
||||||
tempIndexArray.append(val);
|
|
||||||
}
|
}
|
||||||
delete[] indexarray;
|
delete[] indexarray;
|
||||||
}
|
}
|
||||||
|
|
@ -474,128 +441,56 @@ namespace VMAP
|
||||||
READ_OR_RETURN(&blockId, 4);
|
READ_OR_RETURN(&blockId, 4);
|
||||||
CMP_OR_RETURN(blockId, "VERT");
|
CMP_OR_RETURN(blockId, "VERT");
|
||||||
READ_OR_RETURN(&blocksize, sizeof(int));
|
READ_OR_RETURN(&blocksize, sizeof(int));
|
||||||
unsigned int nvectors;
|
uint32 nvectors;
|
||||||
READ_OR_RETURN(&nvectors, sizeof(int));
|
READ_OR_RETURN(&nvectors, sizeof(uint32));
|
||||||
|
|
||||||
float *vectorarray = 0;
|
|
||||||
|
|
||||||
// add vectorarray free
|
|
||||||
#undef READ_OR_RETURN
|
|
||||||
#undef CMP_OR_RETURN
|
|
||||||
#define READ_OR_RETURN(V,S) if(fread((V), (S), 1, rf) != 1) { \
|
|
||||||
fclose(rf); delete gtree; delete[] vectorarray; return(false); }
|
|
||||||
#define CMP_OR_RETURN(V,S) if(strcmp((V),(S)) != 0) { \
|
|
||||||
fclose(rf); delete gtree; delete[] vectorarray; return(false); }
|
|
||||||
|
|
||||||
if (nvectors >0)
|
if (nvectors >0)
|
||||||
{
|
{
|
||||||
vectorarray = new float[nvectors*sizeof(float)*3];
|
float *vectorarray = new float[nvectors*3];
|
||||||
READ_OR_RETURN(vectorarray, nvectors*sizeof(float)*3);
|
READ_OR_RETURN(vectorarray, nvectors*sizeof(float)*3);
|
||||||
}
|
for (uint32 i=0; i<nvectors; ++i)
|
||||||
// ----- liquit
|
|
||||||
if(flags & 1)
|
|
||||||
{
|
{
|
||||||
// we have liquit -> not handled yet ... skip
|
vertexArray.push_back( Vector3(vectorarray + 3*i) );
|
||||||
|
}
|
||||||
|
delete[] vectorarray;
|
||||||
|
}
|
||||||
|
// ----- liquid
|
||||||
|
WmoLiquid *liquid = 0;
|
||||||
|
if (liquidflags& 1)
|
||||||
|
{
|
||||||
|
WMOLiquidHeader hlq;
|
||||||
READ_OR_RETURN(&blockId, 4);
|
READ_OR_RETURN(&blockId, 4);
|
||||||
CMP_OR_RETURN(blockId, "LIQU");
|
CMP_OR_RETURN(blockId, "LIQU");
|
||||||
READ_OR_RETURN(&blocksize, sizeof(int));
|
READ_OR_RETURN(&blocksize, sizeof(int));
|
||||||
fseek(rf, blocksize, SEEK_CUR);
|
READ_OR_RETURN(&hlq, sizeof(WMOLiquidHeader));
|
||||||
|
liquid = new WmoLiquid(hlq.xtiles, hlq.ytiles, Vector3(hlq.pos_x, hlq.pos_y, hlq.pos_z), hlq.type);
|
||||||
|
uint32 size = hlq.xverts*hlq.yverts;
|
||||||
|
READ_OR_RETURN(liquid->GetHeightStorage(), size*sizeof(float));
|
||||||
|
size = hlq.xtiles*hlq.ytiles;
|
||||||
|
READ_OR_RETURN(liquid->GetFlagsStorage(), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
groupsArray.push_back(GroupModel(mogpflags, GroupWMOID, AABox(Vector3(bbox1), Vector3(bbox2))));
|
||||||
for(unsigned int i=0, indexNo=0; indexNo<nvectors; indexNo++)
|
groupsArray.back().setMeshData(vertexArray, triangles);
|
||||||
{
|
groupsArray.back().setLiquidData(liquid);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// drop of temporary use defines
|
// drop of temporary use defines
|
||||||
#undef READ_OR_RETURN
|
#undef READ_OR_RETURN
|
||||||
#undef CMP_OR_RETURN
|
#undef CMP_OR_RETURN
|
||||||
|
|
||||||
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);
|
fclose(rf);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=================================================================
|
// write WorldModel
|
||||||
|
WorldModel model;
|
||||||
bool TileAssembler::fillModelIntoTree(AABSPTree<SubModel *> *pMainTree, const Vector3& pBasePos, std::string& pPos, std::string& pModelFilename)
|
model.setRootWmoID(RootWMOID);
|
||||||
|
if (groupsArray.size())
|
||||||
{
|
{
|
||||||
ModelPosition modelPosition;
|
model.setGroupModels(groupsArray);
|
||||||
getModelPosition(pPos, modelPosition);
|
success = model.writeFile(iDestDir + "/" + pModelFilename + ".vmo");
|
||||||
// all should be relative to object base position
|
|
||||||
modelPosition.moveToBasePos(pBasePos);
|
|
||||||
|
|
||||||
modelPosition.init();
|
|
||||||
|
|
||||||
return readRawFile(pModelFilename, modelPosition, pMainTree);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//=================================================================
|
//std::cout << "readRawFile2: '" << pModelFilename << "' tris: " << nElements << " nodes: " << nNodes << std::endl;
|
||||||
void TileAssembler::getModelPosition(std::string& pPosString, ModelPosition& pModelPosition)
|
return success;
|
||||||
{
|
}
|
||||||
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
|
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,11 @@
|
||||||
#ifndef _TILEASSEMBLER_H_
|
#ifndef _TILEASSEMBLER_H_
|
||||||
#define _TILEASSEMBLER_H_
|
#define _TILEASSEMBLER_H_
|
||||||
|
|
||||||
// load our modified version first !!
|
|
||||||
#include "AABSPTree.h"
|
|
||||||
|
|
||||||
#include <G3D/Vector3.h>
|
#include <G3D/Vector3.h>
|
||||||
|
#include <G3D/Matrix3.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "CoordModelMapping.h"
|
#include "ModelInstance.h"
|
||||||
#include "SubModel.h"
|
|
||||||
#include "ModelContainer.h"
|
|
||||||
|
|
||||||
namespace VMAP
|
namespace VMAP
|
||||||
{
|
{
|
||||||
|
|
@ -39,55 +36,54 @@ namespace VMAP
|
||||||
class ModelPosition
|
class ModelPosition
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
G3D::Matrix3 ixMatrix;
|
G3D::Matrix3 iRotation;
|
||||||
G3D::Matrix3 iyMatrix;
|
|
||||||
G3D::Matrix3 izMatrix;
|
|
||||||
public:
|
public:
|
||||||
G3D::Vector3 iPos;
|
G3D::Vector3 iPos;
|
||||||
G3D::Vector3 iDir;
|
G3D::Vector3 iDir;
|
||||||
float iScale;
|
float iScale;
|
||||||
void init()
|
void init()
|
||||||
{
|
{
|
||||||
|
iRotation = G3D::Matrix3::fromEulerAnglesZYX(G3D::pi()*iDir.y/180.f, G3D::pi()*iDir.x/180.f, G3D::pi()*iDir.z/180.f);
|
||||||
// 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;
|
G3D::Vector3 transform(const G3D::Vector3& pIn) const;
|
||||||
void moveToBasePos(const G3D::Vector3& pBasePos) { iPos -= pBasePos; }
|
void moveToBasePos(const G3D::Vector3& pBasePos) { iPos -= pBasePos; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef std::map<uint32, ModelSpawn> UniqueEntryMap;
|
||||||
|
typedef std::multimap<uint32, uint32> TileMap;
|
||||||
|
|
||||||
|
struct MapSpawns
|
||||||
|
{
|
||||||
|
UniqueEntryMap UniqueEntries;
|
||||||
|
TileMap TileEntries;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<uint32, MapSpawns*> MapData;
|
||||||
//===============================================
|
//===============================================
|
||||||
|
|
||||||
class TileAssembler
|
class TileAssembler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
CoordModelMapping *iCoordModelMapping;
|
|
||||||
std::string iDestDir;
|
std::string iDestDir;
|
||||||
std::string iSrcDir;
|
std::string iSrcDir;
|
||||||
bool (*iFilterMethod)(char *pName);
|
bool (*iFilterMethod)(char *pName);
|
||||||
G3D::Table<std::string, unsigned int > iUniqueNameIds;
|
G3D::Table<std::string, unsigned int > iUniqueNameIds;
|
||||||
unsigned int iCurrentUniqueNameId;
|
unsigned int iCurrentUniqueNameId;
|
||||||
|
MapData mapData;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName);
|
TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName);
|
||||||
virtual ~TileAssembler();
|
virtual ~TileAssembler();
|
||||||
|
|
||||||
bool fillModelContainerArray(const std::string& pDirFileName, unsigned int pMapId, int pXPos, int pYPos, G3D::Array<ModelContainer*>& pMC);
|
bool convertWorld2();
|
||||||
ModelContainer* processNames(const G3D::Array<std::string>& pPosFileNames, const char* pDestFileName);
|
bool readMapSpawns();
|
||||||
|
bool calculateTransformedBound(ModelSpawn &spawn);
|
||||||
|
|
||||||
void init();
|
bool convertRawFile(const std::string& pModelFilename);
|
||||||
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; }
|
void setModelNameFilterMethod(bool (*pFilterMethod)(char *pName)) { iFilterMethod = pFilterMethod; }
|
||||||
std::string getDirEntryNameFromModName(unsigned int pMapId, const std::string& pModPosName);
|
std::string getDirEntryNameFromModName(unsigned int pMapId, const std::string& pModPosName);
|
||||||
unsigned int getUniqueNameId(const std::string pName);
|
unsigned int getUniqueNameId(const std::string pName);
|
||||||
};
|
};
|
||||||
//===============================================
|
|
||||||
} // VMAP
|
} // VMAP
|
||||||
#endif /*_TILEASSEMBLER_H_*/
|
#endif /*_TILEASSEMBLER_H_*/
|
||||||
|
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
//=================================================================
|
|
||||||
//=================================================================
|
|
||||||
//=================================================================
|
|
||||||
}
|
|
||||||
|
|
@ -1,223 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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
|
|
||||||
|
|
@ -20,11 +20,13 @@
|
||||||
#define _VMAPDEFINITIONS_H
|
#define _VMAPDEFINITIONS_H
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#define LIQUID_TILE_SIZE (533.333f / 128.f)
|
||||||
|
|
||||||
namespace VMAP
|
namespace VMAP
|
||||||
{
|
{
|
||||||
//=====================================
|
//=====================================
|
||||||
#define MAX_CAN_FALL_DISTANCE 10.0f
|
#define MAX_CAN_FALL_DISTANCE 10.0f
|
||||||
const char VMAP_MAGIC[] = "VMAP_2.0";
|
const char VMAP_MAGIC[] = "VMAP_3.0";
|
||||||
|
|
||||||
class VMapDefinitions
|
class VMapDefinitions
|
||||||
{
|
{
|
||||||
|
|
@ -33,5 +35,21 @@ namespace VMAP
|
||||||
};
|
};
|
||||||
|
|
||||||
//======================================
|
//======================================
|
||||||
|
|
||||||
|
// defined in TileAssembler.cpp currently...
|
||||||
|
bool readChunk(FILE *rf, char *dest, const char *compare, uint32 len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NO_CORE_FUNCS
|
||||||
|
#include "Errors.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#define ERROR_LOG(...) sLog.outError(__VA_ARGS__);
|
||||||
|
#else
|
||||||
|
#include <assert.h>
|
||||||
|
#define ASSERT(x) assert(x)
|
||||||
|
#define DEBUG_LOG(...) do{ printf(__VA_ARGS__); printf("\n"); } while(0)
|
||||||
|
#define DETAIL_LOG(...) do{ printf(__VA_ARGS__); printf("\n"); } while(0)
|
||||||
|
#define ERROR_LOG(...) do{ printf("ERROR:"); printf(__VA_ARGS__); printf("\n"); } while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif // _VMAPDEFINITIONS_H
|
||||||
|
|
|
||||||
|
|
@ -18,15 +18,41 @@
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include "VMapFactory.h"
|
#include "VMapFactory.h"
|
||||||
#include "VMapManager.h"
|
#include "VMapManager2.h"
|
||||||
|
|
||||||
using namespace G3D;
|
using namespace G3D;
|
||||||
|
|
||||||
namespace VMAP
|
namespace VMAP
|
||||||
{
|
{
|
||||||
extern void chompAndTrim(std::string& str);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VMapManager *gVMapManager = 0;
|
IVMapManager *gVMapManager = 0;
|
||||||
Table<unsigned int , bool>* iIgnoreSpellIds=0;
|
Table<unsigned int , bool>* iIgnoreSpellIds=0;
|
||||||
|
|
||||||
//===============================================
|
//===============================================
|
||||||
|
|
@ -88,7 +114,7 @@ namespace VMAP
|
||||||
IVMapManager* VMapFactory::createOrGetVMapManager()
|
IVMapManager* VMapFactory::createOrGetVMapManager()
|
||||||
{
|
{
|
||||||
if(gVMapManager == 0)
|
if(gVMapManager == 0)
|
||||||
gVMapManager= new VMapManager(); // should be taken from config ... Please change if you like :-)
|
gVMapManager= new VMapManager2(); // should be taken from config ... Please change if you like :-)
|
||||||
return gVMapManager;
|
return gVMapManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,774 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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);
|
|
||||||
}
|
|
||||||
std::string fb = pBasePath + dirFileName;
|
|
||||||
FILE* df = fopen(fb.c_str(), "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)
|
|
||||||
{
|
|
||||||
std::string fb2 = pBasePath + name;
|
|
||||||
FILE* df2 = fopen(fb2.c_str(), "rb");
|
|
||||||
if(df2)
|
|
||||||
{
|
|
||||||
char magic[8];
|
|
||||||
fread(magic,1,8,df2);
|
|
||||||
if(!strncmp(VMAP_MAGIC,magic,8))
|
|
||||||
result = true;
|
|
||||||
fclose(df2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(df);
|
|
||||||
}
|
|
||||||
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 height 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;
|
|
||||||
if(!hasDirFile(pDirFileName))
|
|
||||||
{
|
|
||||||
FilesInDir filesInDir;
|
|
||||||
result = false;
|
|
||||||
std::string fb = iBasePath + pDirFileName;
|
|
||||||
FILE* df = fopen(fb.c_str(), "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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
//=========================================================
|
|
||||||
//=========================================================
|
|
||||||
//=========================================================
|
|
||||||
}
|
|
||||||
|
|
@ -1,173 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2005-2010 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) const { return(iLoadedModelContainer.containsKey(pName)); }
|
|
||||||
void setLoadedMapTile(unsigned int pTileIdent) { iLoadedMapTiles.set(pTileIdent, true); }
|
|
||||||
void removeLoadedMapTile(unsigned int pTileIdent) { iLoadedMapTiles.remove(pTileIdent); }
|
|
||||||
bool hasLoadedMapTiles() const { return iLoadedMapTiles.size() > 0; }
|
|
||||||
bool containsLoadedMapTile(unsigned int pTileIdent) const { return(iLoadedMapTiles.containsKey(pTileIdent)); }
|
|
||||||
public:
|
|
||||||
ManagedModelContainer *getModelContainer(const std::string& pName) { return(iLoadedModelContainer.get(pName)); }
|
|
||||||
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); }
|
|
||||||
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
|
|
||||||
336
src/shared/vmap/VMapManager2.cpp
Normal file
336
src/shared/vmap/VMapManager2.cpp
Normal file
|
|
@ -0,0 +1,336 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2010 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 <iomanip>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include "VMapManager2.h"
|
||||||
|
#include "MapTree.h"
|
||||||
|
#include "ModelInstance.h"
|
||||||
|
#include "WorldModel.h"
|
||||||
|
#include "VMapDefinitions.h"
|
||||||
|
|
||||||
|
using G3D::Vector3;
|
||||||
|
|
||||||
|
namespace VMAP
|
||||||
|
{
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
VMapManager2::VMapManager2()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
VMapManager2::~VMapManager2(void)
|
||||||
|
{
|
||||||
|
for (InstanceTreeMap::iterator i = iInstanceMapTrees.begin(); i != iInstanceMapTrees.end(); ++i)
|
||||||
|
{
|
||||||
|
delete i->second;
|
||||||
|
}
|
||||||
|
for (ModelFileMap::iterator i = iLoadedModelFiles.begin(); i != iLoadedModelFiles.end(); ++i)
|
||||||
|
{
|
||||||
|
delete i->second.getModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
Vector3 VMapManager2::convertPositionToInternalRep(float x, float y, float z) const
|
||||||
|
{
|
||||||
|
Vector3 pos;
|
||||||
|
const float mid = 0.5f * 64.0f * 533.33333333f;
|
||||||
|
pos.x = mid - x;
|
||||||
|
pos.y = mid - y;
|
||||||
|
pos.z = z;
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
Vector3 VMapManager2::convertPositionToMangosRep(float x, float y, float z) const
|
||||||
|
{
|
||||||
|
Vector3 pos;
|
||||||
|
const float mid = 0.5f * 64.0f * 533.33333333f;
|
||||||
|
pos.x = mid - x;
|
||||||
|
pos.y = mid - y;
|
||||||
|
pos.z = z;
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
// move to MapTree too?
|
||||||
|
std::string VMapManager2::getMapFileName(unsigned int pMapId)
|
||||||
|
{
|
||||||
|
std::stringstream fname;
|
||||||
|
fname.width(3);
|
||||||
|
fname << std::setfill('0') << pMapId << std::string(MAP_FILENAME_EXTENSION2);
|
||||||
|
return fname.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
/**
|
||||||
|
Block maps from being used.
|
||||||
|
parameter: String of map ids. Delimiter = ","
|
||||||
|
e.g.: "0,1,590"
|
||||||
|
*/
|
||||||
|
|
||||||
|
void VMapManager2::preventMapsFromBeingUsed(const char* pMapIdString)
|
||||||
|
{
|
||||||
|
iIgnoreMapIds.clear();
|
||||||
|
if (pMapIdString != NULL)
|
||||||
|
{
|
||||||
|
std::string map_str;
|
||||||
|
std::stringstream map_ss;
|
||||||
|
map_ss.str(std::string(pMapIdString));
|
||||||
|
while (std::getline(map_ss, map_str, ','))
|
||||||
|
{
|
||||||
|
std::stringstream ss2(map_str);
|
||||||
|
int map_num = -1;
|
||||||
|
ss2 >> map_num;
|
||||||
|
if (map_num >= 0)
|
||||||
|
{
|
||||||
|
DETAIL_LOG("Ignoring Map %i for VMaps", map_num);
|
||||||
|
iIgnoreMapIds[map_num] = true;
|
||||||
|
// unload map in case it is loaded
|
||||||
|
unloadMap(map_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
int VMapManager2::loadMap(const char* pBasePath, unsigned int pMapId, int x, int y)
|
||||||
|
{
|
||||||
|
int result = VMAP_LOAD_RESULT_IGNORED;
|
||||||
|
if (isMapLoadingEnabled() && !iIgnoreMapIds.count(pMapId))
|
||||||
|
{
|
||||||
|
if (_loadMap(pMapId, pBasePath, x, y))
|
||||||
|
result = VMAP_LOAD_RESULT_OK;
|
||||||
|
else
|
||||||
|
result = VMAP_LOAD_RESULT_ERROR;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// load one tile (internal use only)
|
||||||
|
|
||||||
|
bool VMapManager2::_loadMap(unsigned int pMapId, const std::string &basePath, uint32 tileX, uint32 tileY)
|
||||||
|
{
|
||||||
|
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(pMapId);
|
||||||
|
if (instanceTree == iInstanceMapTrees.end())
|
||||||
|
{
|
||||||
|
std::string mapFileName = getMapFileName(pMapId);
|
||||||
|
StaticMapTree *newTree = new StaticMapTree(pMapId, basePath);
|
||||||
|
if (!newTree->InitMap(mapFileName, this))
|
||||||
|
return false;
|
||||||
|
instanceTree = iInstanceMapTrees.insert(InstanceTreeMap::value_type(pMapId, newTree)).first;
|
||||||
|
}
|
||||||
|
return instanceTree->second->LoadMapTile(tileX, tileY, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
void VMapManager2::unloadMap(unsigned int pMapId)
|
||||||
|
{
|
||||||
|
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(pMapId);
|
||||||
|
if (instanceTree != iInstanceMapTrees.end())
|
||||||
|
{
|
||||||
|
instanceTree->second->UnloadMap(this);
|
||||||
|
if (instanceTree->second->numLoadedTiles() == 0)
|
||||||
|
{
|
||||||
|
delete instanceTree->second;
|
||||||
|
iInstanceMapTrees.erase(pMapId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
void VMapManager2::unloadMap(unsigned int pMapId, int x, int y)
|
||||||
|
{
|
||||||
|
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(pMapId);
|
||||||
|
if (instanceTree != iInstanceMapTrees.end())
|
||||||
|
{
|
||||||
|
instanceTree->second->UnloadMapTile(x, y, this);
|
||||||
|
if (instanceTree->second->numLoadedTiles() == 0)
|
||||||
|
{
|
||||||
|
delete instanceTree->second;
|
||||||
|
iInstanceMapTrees.erase(pMapId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================
|
||||||
|
|
||||||
|
bool VMapManager2::isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2)
|
||||||
|
{
|
||||||
|
if (!isLineOfSightCalcEnabled()) return true;
|
||||||
|
bool result = true;
|
||||||
|
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(pMapId);
|
||||||
|
if (instanceTree != iInstanceMapTrees.end())
|
||||||
|
{
|
||||||
|
Vector3 pos1 = convertPositionToInternalRep(x1,y1,z1);
|
||||||
|
Vector3 pos2 = convertPositionToInternalRep(x2,y2,z2);
|
||||||
|
if (pos1 != pos2)
|
||||||
|
{
|
||||||
|
result = instanceTree->second->isInLineOfSight(pos1, pos2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
//=========================================================
|
||||||
|
/**
|
||||||
|
get the hit position and return true if we hit something
|
||||||
|
otherwise the result pos will be the dest pos
|
||||||
|
*/
|
||||||
|
bool VMapManager2::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())
|
||||||
|
{
|
||||||
|
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(pMapId);
|
||||||
|
if (instanceTree != iInstanceMapTrees.end())
|
||||||
|
{
|
||||||
|
Vector3 pos1 = convertPositionToInternalRep(x1,y1,z1);
|
||||||
|
Vector3 pos2 = convertPositionToInternalRep(x2,y2,z2);
|
||||||
|
Vector3 resultPos;
|
||||||
|
result = instanceTree->second->getObjectHitPos(pos1, pos2, resultPos, pModifyDist);
|
||||||
|
resultPos = convertPositionToMangosRep(resultPos.x,resultPos.y,resultPos.z);
|
||||||
|
rx = resultPos.x;
|
||||||
|
ry = resultPos.y;
|
||||||
|
rz = resultPos.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
/**
|
||||||
|
get height or INVALID_HEIGHT if no height available
|
||||||
|
*/
|
||||||
|
|
||||||
|
float VMapManager2::getHeight(unsigned int pMapId, float x, float y, float z)
|
||||||
|
{
|
||||||
|
float height = VMAP_INVALID_HEIGHT_VALUE; //no height
|
||||||
|
if (isHeightCalcEnabled())
|
||||||
|
{
|
||||||
|
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(pMapId);
|
||||||
|
if (instanceTree != iInstanceMapTrees.end())
|
||||||
|
{
|
||||||
|
Vector3 pos = convertPositionToInternalRep(x,y,z);
|
||||||
|
height = instanceTree->second->getHeight(pos);
|
||||||
|
if (!(height < G3D::inf()))
|
||||||
|
{
|
||||||
|
height = VMAP_INVALID_HEIGHT_VALUE; //no height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
bool VMapManager2::getAreaInfo(unsigned int pMapId, float x, float y, float &z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const
|
||||||
|
{
|
||||||
|
bool result=false;
|
||||||
|
InstanceTreeMap::const_iterator instanceTree = iInstanceMapTrees.find(pMapId);
|
||||||
|
if (instanceTree != iInstanceMapTrees.end())
|
||||||
|
{
|
||||||
|
Vector3 pos = convertPositionToInternalRep(x, y, z);
|
||||||
|
result = instanceTree->second->getAreaInfo(pos, flags, adtId, rootId, groupId);
|
||||||
|
// z is not touched by convertPositionToMangosRep(), so just copy
|
||||||
|
z = pos.z;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VMapManager2::GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float &level, float &floor, uint32 &type) const
|
||||||
|
{
|
||||||
|
InstanceTreeMap::const_iterator instanceTree = iInstanceMapTrees.find(pMapId);
|
||||||
|
if (instanceTree != iInstanceMapTrees.end())
|
||||||
|
{
|
||||||
|
LocationInfo info;
|
||||||
|
Vector3 pos = convertPositionToInternalRep(x, y, z);
|
||||||
|
if (instanceTree->second->GetLocationInfo(pos, info))
|
||||||
|
{
|
||||||
|
floor = info.ground_Z;
|
||||||
|
type = info.hitModel->GetLiquidType();
|
||||||
|
if (ReqLiquidType && !(type & ReqLiquidType))
|
||||||
|
return false;
|
||||||
|
if (info.hitInstance->GetLiquidLevel(pos, info, level))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
WorldModel* VMapManager2::acquireModelInstance(const std::string &basepath, const std::string &filename)
|
||||||
|
{
|
||||||
|
ModelFileMap::iterator model = iLoadedModelFiles.find(filename);
|
||||||
|
if (model == iLoadedModelFiles.end())
|
||||||
|
{
|
||||||
|
WorldModel *worldmodel = new WorldModel();
|
||||||
|
if (!worldmodel->readFile(basepath + filename + ".vmo"))
|
||||||
|
{
|
||||||
|
ERROR_LOG("VMapManager2: could not load '%s%s.vmo'!", basepath.c_str(), filename.c_str());
|
||||||
|
delete worldmodel;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
DEBUG_LOG("VMapManager2: loading file '%s%s'.", basepath.c_str(), filename.c_str());
|
||||||
|
model = iLoadedModelFiles.insert(std::pair<std::string, ManagedModel>(filename, ManagedModel())).first;
|
||||||
|
model->second.setModel(worldmodel);
|
||||||
|
}
|
||||||
|
model->second.incRefCount();
|
||||||
|
return model->second.getModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VMapManager2::releaseModelInstance(const std::string &filename)
|
||||||
|
{
|
||||||
|
ModelFileMap::iterator model = iLoadedModelFiles.find(filename);
|
||||||
|
if (model == iLoadedModelFiles.end())
|
||||||
|
{
|
||||||
|
ERROR_LOG("VMapManager2: trying to unload non-loaded file '%s'!", filename.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( model->second.decRefCount() == 0)
|
||||||
|
{
|
||||||
|
DEBUG_LOG("VMapManager2: unloading file '%s'", filename.c_str());
|
||||||
|
delete model->second.getModel();
|
||||||
|
iLoadedModelFiles.erase(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
bool VMapManager2::existsMap(const char* pBasePath, unsigned int pMapId, int x, int y)
|
||||||
|
{
|
||||||
|
return StaticMapTree::CanLoadMap(std::string(pBasePath), pMapId, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace VMAP
|
||||||
114
src/shared/vmap/VMapManager2.h
Normal file
114
src/shared/vmap/VMapManager2.h
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2010 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 _VMAPMANAGER2_H
|
||||||
|
#define _VMAPMANAGER2_H
|
||||||
|
|
||||||
|
#include "IVMapManager.h"
|
||||||
|
#include "Utilities/UnorderedMap.h"
|
||||||
|
#include "Platform/Define.h"
|
||||||
|
#include <G3D/Vector3.h>
|
||||||
|
|
||||||
|
//===========================================================
|
||||||
|
|
||||||
|
#define MAP_FILENAME_EXTENSION2 ".vmtree"
|
||||||
|
|
||||||
|
#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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//===========================================================
|
||||||
|
|
||||||
|
namespace VMAP
|
||||||
|
{
|
||||||
|
class StaticMapTree;
|
||||||
|
class WorldModel;
|
||||||
|
|
||||||
|
class ManagedModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ManagedModel(): iModel(0), iRefCount(0) {}
|
||||||
|
void setModel(WorldModel *model) { iModel = model; }
|
||||||
|
WorldModel *getModel() { return iModel; }
|
||||||
|
void incRefCount() { ++iRefCount; }
|
||||||
|
int decRefCount() { return --iRefCount; }
|
||||||
|
protected:
|
||||||
|
WorldModel *iModel;
|
||||||
|
int iRefCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef UNORDERED_MAP<uint32 , StaticMapTree *> InstanceTreeMap;
|
||||||
|
typedef UNORDERED_MAP<std::string, ManagedModel> ModelFileMap;
|
||||||
|
|
||||||
|
class VMapManager2 : public IVMapManager
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
// Tree to check collision
|
||||||
|
ModelFileMap iLoadedModelFiles;
|
||||||
|
InstanceTreeMap iInstanceMapTrees;
|
||||||
|
// UNORDERED_MAP<unsigned int , bool> iMapsSplitIntoTiles;
|
||||||
|
UNORDERED_MAP<unsigned int , bool> iIgnoreMapIds;
|
||||||
|
|
||||||
|
bool _loadMap(uint32 pMapId, const std::string &basePath, uint32 tileX, uint32 tileY);
|
||||||
|
/* void _unloadMap(uint32 pMapId, uint32 x, uint32 y); */
|
||||||
|
|
||||||
|
public:
|
||||||
|
// public for debug
|
||||||
|
G3D::Vector3 convertPositionToInternalRep(float x, float y, float z) const;
|
||||||
|
G3D::Vector3 convertPositionToMangosRep(float x, float y, float z) const;
|
||||||
|
static std::string getMapFileName(unsigned int pMapId);
|
||||||
|
|
||||||
|
VMapManager2();
|
||||||
|
~VMapManager2(void);
|
||||||
|
|
||||||
|
int loadMap(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) { return false; } // for debug and extensions
|
||||||
|
|
||||||
|
void preventMapsFromBeingUsed(const char* pMapIdString);
|
||||||
|
bool getAreaInfo(unsigned int pMapId, float x, float y, float &z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const;
|
||||||
|
bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float &level, float &floor, uint32 &type) const;
|
||||||
|
|
||||||
|
WorldModel* acquireModelInstance(const std::string &basepath, const std::string &filename);
|
||||||
|
void releaseModelInstance(const std::string &filename);
|
||||||
|
|
||||||
|
// what's the use of this? o.O
|
||||||
|
virtual std::string getDirFileName(unsigned int pMapId, int x, int y) const
|
||||||
|
{
|
||||||
|
return getMapFileName(pMapId);
|
||||||
|
}
|
||||||
|
virtual bool existsMap(const char* pBasePath, unsigned int pMapId, int x, int y);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
567
src/shared/vmap/WorldModel.cpp
Normal file
567
src/shared/vmap/WorldModel.cpp
Normal file
|
|
@ -0,0 +1,567 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2010 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 "WorldModel.h"
|
||||||
|
#include "VMapDefinitions.h"
|
||||||
|
#include "MapTree.h"
|
||||||
|
|
||||||
|
using G3D::Vector3;
|
||||||
|
using G3D::Ray;
|
||||||
|
|
||||||
|
template<> struct BoundsTrait<VMAP::GroupModel>
|
||||||
|
{
|
||||||
|
static void getBounds(const VMAP::GroupModel& obj, G3D::AABox& out) { out = obj.GetBound(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
namespace VMAP
|
||||||
|
{
|
||||||
|
bool IntersectTriangle(const MeshTriangle &tri, std::vector<Vector3>::const_iterator points, const G3D::Ray &ray, float &distance)
|
||||||
|
{
|
||||||
|
static const float EPS = 1e-5f;
|
||||||
|
|
||||||
|
// See RTR2 ch. 13.7 for the algorithm.
|
||||||
|
|
||||||
|
const Vector3 e1 = points[tri.idx1] - points[tri.idx0];
|
||||||
|
const Vector3 e2 = points[tri.idx2] - points[tri.idx0];
|
||||||
|
const Vector3 p(ray.direction().cross(e2));
|
||||||
|
const float a = e1.dot(p);
|
||||||
|
|
||||||
|
if (abs(a) < EPS) {
|
||||||
|
// Determinant is ill-conditioned; abort early
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float f = 1.0f / a;
|
||||||
|
const Vector3 s(ray.origin() - points[tri.idx0]);
|
||||||
|
const float u = f * s.dot(p);
|
||||||
|
|
||||||
|
if ((u < 0.0f) || (u > 1.0f)) {
|
||||||
|
// We hit the plane of the m_geometry, but outside the m_geometry
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vector3 q(s.cross(e1));
|
||||||
|
const float v = f * ray.direction().dot(q);
|
||||||
|
|
||||||
|
if ((v < 0.0f) || ((u + v) > 1.0f)) {
|
||||||
|
// We hit the plane of the triangle, but outside the triangle
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float t = f * e2.dot(q);
|
||||||
|
|
||||||
|
if ((t > 0.0f) && (t < distance))
|
||||||
|
{
|
||||||
|
// This is a new hit, closer than the previous one
|
||||||
|
distance = t;
|
||||||
|
|
||||||
|
/* baryCoord[0] = 1.0 - u - v;
|
||||||
|
baryCoord[1] = u;
|
||||||
|
baryCoord[2] = v; */
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// This hit is after the previous hit, so ignore it
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TriBoundFunc
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TriBoundFunc(std::vector<Vector3> &vert): vertices(vert.begin()) {}
|
||||||
|
void operator()(const MeshTriangle &tri, G3D::AABox &out) const
|
||||||
|
{
|
||||||
|
G3D::Vector3 lo = vertices[tri.idx0];
|
||||||
|
G3D::Vector3 hi = lo;
|
||||||
|
|
||||||
|
lo = (lo.min(vertices[tri.idx1])).min(vertices[tri.idx2]);
|
||||||
|
hi = (hi.max(vertices[tri.idx1])).max(vertices[tri.idx2]);
|
||||||
|
|
||||||
|
out = G3D::AABox(lo, hi);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
const std::vector<Vector3>::const_iterator vertices;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ===================== WmoLiquid ==================================
|
||||||
|
|
||||||
|
WmoLiquid::WmoLiquid(uint32 width, uint32 height, const Vector3 &corner, uint32 type):
|
||||||
|
iTilesX(width), iTilesY(height), iCorner(corner), iType(type)
|
||||||
|
{
|
||||||
|
iHeight = new float[(width+1)*(height+1)];
|
||||||
|
iFlags = new uint8[width*height];
|
||||||
|
}
|
||||||
|
|
||||||
|
WmoLiquid::WmoLiquid(const WmoLiquid &other): iHeight(0), iFlags(0)
|
||||||
|
{
|
||||||
|
*this = other; // use assignment operator...
|
||||||
|
}
|
||||||
|
|
||||||
|
WmoLiquid::~WmoLiquid()
|
||||||
|
{
|
||||||
|
delete[] iHeight;
|
||||||
|
delete[] iFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
WmoLiquid& WmoLiquid::operator=(const WmoLiquid &other)
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
iTilesX = other.iTilesX;
|
||||||
|
iTilesY = other.iTilesY;
|
||||||
|
iCorner = other.iCorner;
|
||||||
|
iType = other.iType;
|
||||||
|
delete iHeight;
|
||||||
|
delete iFlags;
|
||||||
|
if (other.iHeight)
|
||||||
|
{
|
||||||
|
iHeight = new float[(iTilesX+1)*(iTilesY+1)];
|
||||||
|
memcpy(iHeight, other.iHeight, (iTilesX+1)*(iTilesY+1)*sizeof(float));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
iHeight = 0;
|
||||||
|
if (other.iFlags)
|
||||||
|
{
|
||||||
|
iFlags = new uint8[iTilesX * iTilesY];
|
||||||
|
memcpy(iFlags, other.iFlags, iTilesX * iTilesY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
iFlags = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WmoLiquid::GetLiquidHeight(const Vector3 &pos, float &liqHeight) const
|
||||||
|
{
|
||||||
|
float tx_f = (pos.x - iCorner.x)/LIQUID_TILE_SIZE;
|
||||||
|
uint32 tx = uint32(tx_f);
|
||||||
|
if (tx<0 || tx >= iTilesX) return false;
|
||||||
|
float ty_f = (pos.y - iCorner.y)/LIQUID_TILE_SIZE;
|
||||||
|
uint32 ty = uint32(ty_f);
|
||||||
|
if (ty<0 || ty >= iTilesY) return false;
|
||||||
|
|
||||||
|
// check if tile shall be used for liquid level
|
||||||
|
// checking for 0x08 *might* be enough, but disabled tiles always are 0x?F:
|
||||||
|
if ((iFlags[tx + ty*iTilesX] & 0x0F) == 0x0F)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// (dx, dy) coordinates inside tile, in [0,1]^2
|
||||||
|
float dx = tx_f - (float)tx;
|
||||||
|
float dy = ty_f - (float)ty;
|
||||||
|
|
||||||
|
/* Tesselate tile to two triangles (not sure if client does it exactly like this)
|
||||||
|
|
||||||
|
^ dy
|
||||||
|
|
|
||||||
|
1 x---------x (1,1)
|
||||||
|
| (b) / |
|
||||||
|
| / |
|
||||||
|
| / |
|
||||||
|
| / (a) |
|
||||||
|
x---------x---> dx
|
||||||
|
0 1
|
||||||
|
*/
|
||||||
|
const uint32 rowOffset = iTilesX + 1;
|
||||||
|
if (dx > dy) // case (a)
|
||||||
|
{
|
||||||
|
float sx = iHeight[tx+1 + ty * rowOffset] - iHeight[tx + ty * rowOffset];
|
||||||
|
float sy = iHeight[tx+1 + (ty+1) * rowOffset] - iHeight[tx+1 + ty * rowOffset];
|
||||||
|
liqHeight = iHeight[tx + ty * rowOffset] + dx * sx + dy * sy;
|
||||||
|
}
|
||||||
|
else // case (b)
|
||||||
|
{
|
||||||
|
float sx = iHeight[tx+1 + (ty+1) * rowOffset] - iHeight[tx + (ty+1) * rowOffset];
|
||||||
|
float sy = iHeight[tx + (ty+1) * rowOffset] - iHeight[tx + ty * rowOffset];
|
||||||
|
liqHeight = iHeight[tx + ty * rowOffset] + dx * sx + dy * sy;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 WmoLiquid::GetFileSize()
|
||||||
|
{
|
||||||
|
return 2 * sizeof(uint32) +
|
||||||
|
sizeof(Vector3) +
|
||||||
|
(iTilesX + 1)*(iTilesY + 1) * sizeof(float) +
|
||||||
|
iTilesX * iTilesY;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WmoLiquid::writeToFile(FILE *wf)
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
if (result && fwrite(&iTilesX, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
if (result && fwrite(&iTilesY, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
if (result && fwrite(&iCorner, sizeof(Vector3), 1, wf) != 1) result = false;
|
||||||
|
if (result && fwrite(&iType, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
uint32 size = (iTilesX + 1)*(iTilesY + 1);
|
||||||
|
if (result && fwrite(iHeight, sizeof(float), size, wf) != size) result = false;
|
||||||
|
size = iTilesX*iTilesY;
|
||||||
|
if (result && fwrite(iFlags, sizeof(uint8), size, wf) != size) result = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WmoLiquid::readFromFile(FILE *rf, WmoLiquid *&out)
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
WmoLiquid *liquid = new WmoLiquid();
|
||||||
|
if (result && fread(&liquid->iTilesX, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
if (result && fread(&liquid->iTilesY, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
if (result && fread(&liquid->iCorner, sizeof(Vector3), 1, rf) != 1) result = false;
|
||||||
|
if (result && fread(&liquid->iType, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
uint32 size = (liquid->iTilesX + 1)*(liquid->iTilesY + 1);
|
||||||
|
liquid->iHeight = new float[size];
|
||||||
|
if (result && fread(liquid->iHeight, sizeof(float), size, rf) != size) result = false;
|
||||||
|
size = liquid->iTilesX * liquid->iTilesY;
|
||||||
|
liquid->iFlags = new uint8[size];
|
||||||
|
if (result && fread(liquid->iFlags, sizeof(uint8), size, rf) != size) result = false;
|
||||||
|
if (!result)
|
||||||
|
delete liquid;
|
||||||
|
out = liquid;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== GroupModel ==================================
|
||||||
|
|
||||||
|
GroupModel::GroupModel(const GroupModel &other):
|
||||||
|
iBound(other.iBound), iMogpFlags(other.iMogpFlags), iGroupWMOID(other.iGroupWMOID),
|
||||||
|
vertices(other.vertices), triangles(other.triangles), meshTree(other.meshTree), iLiquid(0)
|
||||||
|
{
|
||||||
|
if (other.iLiquid)
|
||||||
|
iLiquid = new WmoLiquid(*other.iLiquid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupModel::setMeshData(std::vector<Vector3> &vert, std::vector<MeshTriangle> &tri)
|
||||||
|
{
|
||||||
|
vertices.swap(vert);
|
||||||
|
triangles.swap(tri);
|
||||||
|
TriBoundFunc bFunc(vertices);
|
||||||
|
meshTree.build(triangles, bFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupModel::writeToFile(FILE *wf)
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
uint32 chunkSize, count;
|
||||||
|
|
||||||
|
if (result && fwrite(&iBound, sizeof(G3D::AABox), 1, wf) != 1) result = false;
|
||||||
|
if (result && fwrite(&iMogpFlags, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
if (result && fwrite(&iGroupWMOID, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
|
||||||
|
// write vertices
|
||||||
|
if (result && fwrite("VERT", 1, 4, wf) != 4) result = false;
|
||||||
|
count = vertices.size();
|
||||||
|
chunkSize = sizeof(uint32)+ sizeof(Vector3)*count;
|
||||||
|
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
if (!count) // models without (collision) geometry end here, unsure if they are useful
|
||||||
|
return result;
|
||||||
|
if (result && fwrite(&vertices[0], sizeof(Vector3), count, wf) != count) result = false;
|
||||||
|
|
||||||
|
// write triangle mesh
|
||||||
|
if (result && fwrite("TRIM", 1, 4, wf) != 4) result = false;
|
||||||
|
count = triangles.size();
|
||||||
|
chunkSize = sizeof(uint32)+ sizeof(MeshTriangle)*count;
|
||||||
|
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
if (result && fwrite(&triangles[0], sizeof(MeshTriangle), count, wf) != count) result = false;
|
||||||
|
|
||||||
|
// write mesh BIH
|
||||||
|
if (result && fwrite("MBIH", 1, 4, wf) != 4) result = false;
|
||||||
|
if (result) result = meshTree.writeToFile(wf);
|
||||||
|
|
||||||
|
// write liquid data
|
||||||
|
if (result && fwrite("LIQU", 1, 4, wf) != 4) result = false;
|
||||||
|
if (!iLiquid)
|
||||||
|
{
|
||||||
|
chunkSize = 0;
|
||||||
|
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
chunkSize = iLiquid->GetFileSize();
|
||||||
|
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
if (result) result = iLiquid->writeToFile(wf);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupModel::readFromFile(FILE *rf)
|
||||||
|
{
|
||||||
|
char chunk[8];
|
||||||
|
bool result = true;
|
||||||
|
uint32 chunkSize, count;
|
||||||
|
triangles.clear();
|
||||||
|
vertices.clear();
|
||||||
|
delete iLiquid;
|
||||||
|
iLiquid = 0;
|
||||||
|
|
||||||
|
if (result && fread(&iBound, sizeof(G3D::AABox), 1, rf) != 1) result = false;
|
||||||
|
if (result && fread(&iMogpFlags, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
if (result && fread(&iGroupWMOID, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
|
||||||
|
// read vertices
|
||||||
|
if (result && !readChunk(rf, chunk, "VERT", 4)) result = false;
|
||||||
|
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
if (!count) // models without (collision) geometry end here, unsure if they are useful
|
||||||
|
return result;
|
||||||
|
if (result) vertices.resize(count);
|
||||||
|
if (result && fread(&vertices[0], sizeof(Vector3), count, rf) != count) result = false;
|
||||||
|
|
||||||
|
// read triangle mesh
|
||||||
|
if (result && !readChunk(rf, chunk, "TRIM", 4)) result = false;
|
||||||
|
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
if (result) triangles.resize(count);
|
||||||
|
if (result && fread(&triangles[0], sizeof(MeshTriangle), count, rf) != count) result = false;
|
||||||
|
|
||||||
|
// read mesh BIH
|
||||||
|
if (result && !readChunk(rf, chunk, "MBIH", 4)) result = false;
|
||||||
|
if (result) result = meshTree.readFromFile(rf);
|
||||||
|
|
||||||
|
// write liquid data
|
||||||
|
if (result && !readChunk(rf, chunk, "LIQU", 4)) result = false;
|
||||||
|
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
if (result && chunkSize > 0)
|
||||||
|
result = WmoLiquid::readFromFile(rf, iLiquid);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GModelRayCallback
|
||||||
|
{
|
||||||
|
GModelRayCallback(const std::vector<MeshTriangle> &tris, const std::vector<Vector3> &vert):
|
||||||
|
vertices(vert.begin()), triangles(tris.begin()), hit(false) {}
|
||||||
|
bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool pStopAtFirstHit)
|
||||||
|
{
|
||||||
|
bool result = IntersectTriangle(triangles[entry], vertices, ray, distance);
|
||||||
|
if (result) hit=true;
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
std::vector<Vector3>::const_iterator vertices;
|
||||||
|
std::vector<MeshTriangle>::const_iterator triangles;
|
||||||
|
bool hit;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool GroupModel::IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const
|
||||||
|
{
|
||||||
|
if (!triangles.size())
|
||||||
|
return false;
|
||||||
|
GModelRayCallback callback(triangles, vertices);
|
||||||
|
meshTree.intersectRay(ray, callback, distance, stopAtFirstHit);
|
||||||
|
return callback.hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupModel::IsInsideObject(const Vector3 &pos, const Vector3 &down, float &z_dist) const
|
||||||
|
{
|
||||||
|
if (!triangles.size() || !iBound.contains(pos))
|
||||||
|
return false;
|
||||||
|
GModelRayCallback callback(triangles, vertices);
|
||||||
|
Vector3 rPos = pos - 0.1f * down;
|
||||||
|
float dist = G3D::inf();
|
||||||
|
G3D::Ray ray(rPos, down);
|
||||||
|
bool hit = IntersectRay(ray, dist, false);
|
||||||
|
if (hit)
|
||||||
|
z_dist = dist - 0.1f;
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GroupModel::GetLiquidLevel(const Vector3 &pos, float &liqHeight) const
|
||||||
|
{
|
||||||
|
if (iLiquid)
|
||||||
|
return iLiquid->GetLiquidHeight(pos, liqHeight);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 GroupModel::GetLiquidType() const
|
||||||
|
{
|
||||||
|
// convert to type mask, matching MAP_LIQUID_TYPE_* defines in Map.h
|
||||||
|
if (iLiquid)
|
||||||
|
return (1 << iLiquid->GetType());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== WorldModel ==================================
|
||||||
|
|
||||||
|
void WorldModel::setGroupModels(std::vector<GroupModel> &models)
|
||||||
|
{
|
||||||
|
groupModels.swap(models);
|
||||||
|
groupTree.build(groupModels, BoundsTrait<GroupModel>::getBounds, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WModelRayCallBack
|
||||||
|
{
|
||||||
|
WModelRayCallBack(const std::vector<GroupModel> &mod): models(mod.begin()), hit(false) {}
|
||||||
|
bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool pStopAtFirstHit)
|
||||||
|
{
|
||||||
|
bool result = models[entry].IntersectRay(ray, distance, pStopAtFirstHit);
|
||||||
|
if (result) hit=true;
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
std::vector<GroupModel>::const_iterator models;
|
||||||
|
bool hit;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool WorldModel::IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const
|
||||||
|
{
|
||||||
|
// small M2 workaround, maybe better make separate class with virtual intersection funcs
|
||||||
|
// in any case, there's no need to use a bound tree if we only have one submodel
|
||||||
|
if (groupModels.size() == 1)
|
||||||
|
return groupModels[0].IntersectRay(ray, distance, stopAtFirstHit);
|
||||||
|
|
||||||
|
WModelRayCallBack isc(groupModels);
|
||||||
|
groupTree.intersectRay(ray, isc, distance, stopAtFirstHit);
|
||||||
|
return isc.hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WModelAreaCallback {
|
||||||
|
public:
|
||||||
|
WModelAreaCallback(const std::vector<GroupModel> &vals, const Vector3 &down):
|
||||||
|
prims(vals.begin()), hit(vals.end()), minVol(G3D::inf()), zDist(G3D::inf()), zVec(down) {}
|
||||||
|
std::vector<GroupModel>::const_iterator prims;
|
||||||
|
std::vector<GroupModel>::const_iterator hit;
|
||||||
|
float minVol;
|
||||||
|
float zDist;
|
||||||
|
Vector3 zVec;
|
||||||
|
void operator()(const Vector3& point, uint32 entry)
|
||||||
|
{
|
||||||
|
float group_Z;
|
||||||
|
//float pVol = prims[entry].GetBound().volume();
|
||||||
|
//if(pVol < minVol)
|
||||||
|
//{
|
||||||
|
/* if (prims[entry].iBound.contains(point)) */
|
||||||
|
if (prims[entry].IsInsideObject(point, zVec, group_Z))
|
||||||
|
{
|
||||||
|
//minVol = pVol;
|
||||||
|
//hit = prims + entry;
|
||||||
|
if (group_Z < zDist)
|
||||||
|
{
|
||||||
|
zDist = group_Z;
|
||||||
|
hit = prims + entry;
|
||||||
|
}
|
||||||
|
#ifdef VMAP_DEBUG
|
||||||
|
const GroupModel &gm = prims[entry];
|
||||||
|
printf("%10u %8X %7.3f,%7.3f,%7.3f | %7.3f,%7.3f,%7.3f | z=%f, p_z=%f\n", gm.GetWmoID(), gm.GetMogpFlags(),
|
||||||
|
gm.GetBound().low().x, gm.GetBound().low().y, gm.GetBound().low().z,
|
||||||
|
gm.GetBound().high().x, gm.GetBound().high().y, gm.GetBound().high().z, group_Z, point.z);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//}
|
||||||
|
//std::cout << "trying to intersect '" << prims[entry].name << "'\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool WorldModel::IntersectPoint(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, AreaInfo &info) const
|
||||||
|
{
|
||||||
|
if (!groupModels.size())
|
||||||
|
return false;
|
||||||
|
WModelAreaCallback callback(groupModels, down);
|
||||||
|
groupTree.intersectPoint(p, callback);
|
||||||
|
if (callback.hit != groupModels.end())
|
||||||
|
{
|
||||||
|
info.rootId = RootWMOID;
|
||||||
|
info.groupId = callback.hit->GetWmoID();
|
||||||
|
info.flags = callback.hit->GetMogpFlags();
|
||||||
|
info.result = true;
|
||||||
|
dist = callback.zDist;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorldModel::GetLocationInfo(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, LocationInfo &info) const
|
||||||
|
{
|
||||||
|
if (!groupModels.size())
|
||||||
|
return false;
|
||||||
|
WModelAreaCallback callback(groupModels, down);
|
||||||
|
groupTree.intersectPoint(p, callback);
|
||||||
|
if (callback.hit != groupModels.end())
|
||||||
|
{
|
||||||
|
info.hitModel = &(*callback.hit);
|
||||||
|
dist = callback.zDist;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorldModel::writeFile(const std::string &filename)
|
||||||
|
{
|
||||||
|
FILE *wf = fopen(filename.c_str(), "wb");
|
||||||
|
if (!wf)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
uint32 chunkSize, count;
|
||||||
|
result = fwrite(VMAP_MAGIC,1,8,wf) == 8;
|
||||||
|
if (result && fwrite("WMOD", 1, 4, wf) != 4) result = false;
|
||||||
|
chunkSize = sizeof(uint32) + sizeof(uint32);
|
||||||
|
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
if (result && fwrite(&RootWMOID, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
|
||||||
|
// write group models
|
||||||
|
count=groupModels.size();
|
||||||
|
if (count)
|
||||||
|
{
|
||||||
|
if (result && fwrite("GMOD", 1, 4, wf) != 4) result = false;
|
||||||
|
//chunkSize = sizeof(uint32)+ sizeof(GroupModel)*count;
|
||||||
|
//if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false;
|
||||||
|
for (uint32 i=0; i<groupModels.size() && result; ++i)
|
||||||
|
result = groupModels[i].writeToFile(wf);
|
||||||
|
|
||||||
|
// write group BIH
|
||||||
|
if (result && fwrite("GBIH", 1, 4, wf) != 4) result = false;
|
||||||
|
if (result) result = groupTree.writeToFile(wf);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(wf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorldModel::readFile(const std::string &filename)
|
||||||
|
{
|
||||||
|
FILE *rf = fopen(filename.c_str(), "rb");
|
||||||
|
if (!rf)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
uint32 chunkSize, count;
|
||||||
|
char chunk[8]; // Ignore the added magic header
|
||||||
|
if (!readChunk(rf, chunk, VMAP_MAGIC, 8)) result = false;
|
||||||
|
|
||||||
|
if (result && !readChunk(rf, chunk, "WMOD", 4)) result = false;
|
||||||
|
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
if (result && fread(&RootWMOID, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
|
||||||
|
// read group models
|
||||||
|
if (result && readChunk(rf, chunk, "GMOD", 4))
|
||||||
|
{
|
||||||
|
//if (fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
|
||||||
|
if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
if (result) groupModels.resize(count);
|
||||||
|
//if (result && fread(&groupModels[0], sizeof(GroupModel), count, rf) != count) result = false;
|
||||||
|
for (uint32 i=0; i<count && result; ++i)
|
||||||
|
result = groupModels[i].readFromFile(rf);
|
||||||
|
|
||||||
|
// read group BIH
|
||||||
|
if (result && !readChunk(rf, chunk, "GBIH", 4)) result = false;
|
||||||
|
if (result) result = groupTree.readFromFile(rf);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(rf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
123
src/shared/vmap/WorldModel.h
Normal file
123
src/shared/vmap/WorldModel.h
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2010 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 _WORLDMODEL_H
|
||||||
|
#define _WORLDMODEL_H
|
||||||
|
|
||||||
|
#include <G3D/HashTrait.h>
|
||||||
|
#include <G3D/Vector3.h>
|
||||||
|
#include <G3D/AABox.h>
|
||||||
|
#include <G3D/Ray.h>
|
||||||
|
#include "BIH.h"
|
||||||
|
|
||||||
|
#include "Platform/Define.h"
|
||||||
|
|
||||||
|
namespace VMAP
|
||||||
|
{
|
||||||
|
class TreeNode;
|
||||||
|
struct AreaInfo;
|
||||||
|
struct LocationInfo;
|
||||||
|
|
||||||
|
class MeshTriangle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MeshTriangle(){};
|
||||||
|
MeshTriangle(uint32 na, uint32 nb, uint32 nc): idx0(na), idx1(nb), idx2(nc) {};
|
||||||
|
|
||||||
|
uint32 idx0;
|
||||||
|
uint32 idx1;
|
||||||
|
uint32 idx2;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WmoLiquid
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WmoLiquid(uint32 width, uint32 height, const Vector3 &corner, uint32 type);
|
||||||
|
WmoLiquid(const WmoLiquid &other);
|
||||||
|
~WmoLiquid();
|
||||||
|
WmoLiquid& operator=(const WmoLiquid &other);
|
||||||
|
bool GetLiquidHeight(const Vector3 &pos, float &liqHeight) const;
|
||||||
|
uint32 GetType() const { return iType; }
|
||||||
|
float *GetHeightStorage() { return iHeight; }
|
||||||
|
uint8 *GetFlagsStorage() { return iFlags; }
|
||||||
|
uint32 GetFileSize();
|
||||||
|
bool writeToFile(FILE *wf);
|
||||||
|
static bool readFromFile(FILE *rf, WmoLiquid *&liquid);
|
||||||
|
private:
|
||||||
|
WmoLiquid(): iHeight(0), iFlags(0) {};
|
||||||
|
uint32 iTilesX; //!< number of tiles in x direction, each
|
||||||
|
uint32 iTilesY;
|
||||||
|
Vector3 iCorner; //!< the lower corner
|
||||||
|
uint32 iType; //!< liquid type
|
||||||
|
float *iHeight; //!< (tilesX + 1)*(tilesY + 1) height values
|
||||||
|
uint8 *iFlags; //!< info if liquid tile is used
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! holding additional info for WMO group files */
|
||||||
|
class GroupModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GroupModel(): iLiquid(0) {}
|
||||||
|
GroupModel(const GroupModel &other);
|
||||||
|
GroupModel(uint32 mogpFlags, uint32 groupWMOID, const AABox &bound):
|
||||||
|
iBound(bound), iMogpFlags(mogpFlags), iGroupWMOID(groupWMOID), iLiquid(0) {}
|
||||||
|
~GroupModel() { delete iLiquid; }
|
||||||
|
|
||||||
|
//! pass mesh data to object and create BIH. Passed vectors get get swapped with old geometry!
|
||||||
|
void setMeshData(std::vector<Vector3> &vert, std::vector<MeshTriangle> &tri);
|
||||||
|
void setLiquidData(WmoLiquid *liquid) { iLiquid = liquid; }
|
||||||
|
bool IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const;
|
||||||
|
bool IsInsideObject(const Vector3 &pos, const Vector3 &down, float &z_dist) const;
|
||||||
|
bool GetLiquidLevel(const Vector3 &pos, float &liqHeight) const;
|
||||||
|
uint32 GetLiquidType() const;
|
||||||
|
bool writeToFile(FILE *wf);
|
||||||
|
bool readFromFile(FILE *rf);
|
||||||
|
const G3D::AABox& GetBound() const { return iBound; }
|
||||||
|
uint32 GetMogpFlags() const { return iMogpFlags; }
|
||||||
|
uint32 GetWmoID() const { return iGroupWMOID; }
|
||||||
|
protected:
|
||||||
|
G3D::AABox iBound;
|
||||||
|
uint32 iMogpFlags;// 0x8 outdor; 0x2000 indoor
|
||||||
|
uint32 iGroupWMOID;
|
||||||
|
std::vector<Vector3> vertices;
|
||||||
|
std::vector<MeshTriangle> triangles;
|
||||||
|
BIH meshTree;
|
||||||
|
WmoLiquid *iLiquid;
|
||||||
|
};
|
||||||
|
/*! Holds a model (converted M2 or WMO) in its original coordinate space */
|
||||||
|
class WorldModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WorldModel(): RootWMOID(0) {}
|
||||||
|
|
||||||
|
//! pass group models to WorldModel and create BIH. Passed vector is swapped with old geometry!
|
||||||
|
void setGroupModels(std::vector<GroupModel> &models);
|
||||||
|
void setRootWmoID(uint32 id) { RootWMOID = id; }
|
||||||
|
bool IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const;
|
||||||
|
bool IntersectPoint(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, AreaInfo &info) const;
|
||||||
|
bool GetLocationInfo(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, LocationInfo &info) const;
|
||||||
|
bool writeFile(const std::string &filename);
|
||||||
|
bool readFile(const std::string &filename);
|
||||||
|
protected:
|
||||||
|
uint32 RootWMOID;
|
||||||
|
std::vector<GroupModel> groupModels;
|
||||||
|
BIH groupTree;
|
||||||
|
};
|
||||||
|
} // namespace VMAP
|
||||||
|
|
||||||
|
#endif // _WORLDMODEL_H
|
||||||
|
|
@ -451,16 +451,13 @@
|
||||||
<ClCompile Include="..\..\src\shared\ServiceWin32.cpp" />
|
<ClCompile Include="..\..\src\shared\ServiceWin32.cpp" />
|
||||||
<ClCompile Include="..\..\src\shared\Threading.cpp" />
|
<ClCompile Include="..\..\src\shared\Threading.cpp" />
|
||||||
<ClCompile Include="..\..\src\shared\Util.cpp" />
|
<ClCompile Include="..\..\src\shared\Util.cpp" />
|
||||||
<ClCompile Include="..\..\src\shared\vmap\BaseModel.cpp" />
|
<ClCompile Include="..\..\src\shared\vmap\BIH.cpp" />
|
||||||
<ClCompile Include="..\..\src\shared\vmap\CoordModelMapping.cpp" />
|
<ClCompile Include="..\..\src\shared\vmap\MapTree.cpp" />
|
||||||
<ClCompile Include="..\..\src\shared\vmap\DebugCmdLogger.cpp" />
|
<ClCompile Include="..\..\src\shared\vmap\ModelInstance.cpp" />
|
||||||
<ClCompile Include="..\..\src\shared\vmap\ManagedModelContainer.cpp" />
|
|
||||||
<ClCompile Include="..\..\src\shared\vmap\ModelContainer.cpp" />
|
|
||||||
<ClCompile Include="..\..\src\shared\vmap\SubModel.cpp" />
|
|
||||||
<ClCompile Include="..\..\src\shared\vmap\TileAssembler.cpp" />
|
<ClCompile Include="..\..\src\shared\vmap\TileAssembler.cpp" />
|
||||||
<ClCompile Include="..\..\src\shared\vmap\TreeNode.cpp" />
|
|
||||||
<ClCompile Include="..\..\src\shared\vmap\VMapFactory.cpp" />
|
<ClCompile Include="..\..\src\shared\vmap\VMapFactory.cpp" />
|
||||||
<ClCompile Include="..\..\src\shared\vmap\VMapManager.cpp" />
|
<ClCompile Include="..\..\src\shared\vmap\VMapManager2.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\shared\vmap\WorldModel.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\dep\include\mersennetwister\MersenneTwister.h" />
|
<ClInclude Include="..\..\dep\include\mersennetwister\MersenneTwister.h" />
|
||||||
|
|
@ -498,23 +495,16 @@
|
||||||
<ClInclude Include="..\..\src\shared\Threading.h" />
|
<ClInclude Include="..\..\src\shared\Threading.h" />
|
||||||
<ClInclude Include="..\..\src\shared\Timer.h" />
|
<ClInclude Include="..\..\src\shared\Timer.h" />
|
||||||
<ClInclude Include="..\..\src\shared\Util.h" />
|
<ClInclude Include="..\..\src\shared\Util.h" />
|
||||||
<ClInclude Include="..\..\src\shared\vmap\AABSPTree.h" />
|
<ClInclude Include="..\..\src\shared\vmap\BIH.h" />
|
||||||
<ClInclude Include="..\..\src\shared\vmap\BaseModel.h" />
|
|
||||||
<ClInclude Include="..\..\src\shared\vmap\CoordModelMapping.h" />
|
|
||||||
<ClInclude Include="..\..\src\shared\vmap\DebugCmdLogger.h" />
|
|
||||||
<ClInclude Include="..\..\src\shared\vmap\IVMapManager.h" />
|
<ClInclude Include="..\..\src\shared\vmap\IVMapManager.h" />
|
||||||
<ClInclude Include="..\..\src\shared\vmap\ManagedModelContainer.h" />
|
<ClInclude Include="..\..\src\shared\vmap\MapTree.h" />
|
||||||
<ClInclude Include="..\..\src\shared\vmap\ModelContainer.h" />
|
<ClInclude Include="..\..\src\shared\vmap\ModelInstance.h" />
|
||||||
<ClInclude Include="..\..\src\shared\vmap\NodeValueAccess.h" />
|
|
||||||
<ClInclude Include="..\..\src\shared\vmap\ShortBox.h" />
|
|
||||||
<ClInclude Include="..\..\src\shared\vmap\ShortVector.h" />
|
|
||||||
<ClInclude Include="..\..\src\shared\vmap\SubModel.h" />
|
|
||||||
<ClInclude Include="..\..\src\shared\vmap\TileAssembler.h" />
|
<ClInclude Include="..\..\src\shared\vmap\TileAssembler.h" />
|
||||||
<ClInclude Include="..\..\src\shared\vmap\TreeNode.h" />
|
|
||||||
<ClInclude Include="..\..\src\shared\vmap\VMapDefinitions.h" />
|
<ClInclude Include="..\..\src\shared\vmap\VMapDefinitions.h" />
|
||||||
<ClInclude Include="..\..\src\shared\vmap\VMapFactory.h" />
|
<ClInclude Include="..\..\src\shared\vmap\VMapFactory.h" />
|
||||||
<ClInclude Include="..\..\src\shared\vmap\VMapManager.h" />
|
<ClInclude Include="..\..\src\shared\vmap\VMapManager2.h" />
|
||||||
<ClInclude Include="..\..\src\shared\vmap\VMapTools.h" />
|
<ClInclude Include="..\..\src\shared\vmap\VMapTools.h" />
|
||||||
|
<ClInclude Include="..\..\src\shared\vmap\WorldModel.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="ACE_vc10.vcxproj">
|
<ProjectReference Include="ACE_vc10.vcxproj">
|
||||||
|
|
|
||||||
|
|
@ -721,31 +721,11 @@
|
||||||
Name="vmaps"
|
Name="vmaps"
|
||||||
>
|
>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\AABSPTree.h"
|
RelativePath="..\..\src\shared\vmap\BIH.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\BaseModel.cpp"
|
RelativePath="..\..\src\shared\vmap\BIH.h"
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\BaseModel.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\CoordModelMapping.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\CoordModelMapping.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\DebugCmdLogger.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\DebugCmdLogger.h"
|
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
|
@ -753,39 +733,19 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\ManagedModelContainer.cpp"
|
RelativePath="..\..\src\shared\vmap\MapTree.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\ManagedModelContainer.h"
|
RelativePath="..\..\src\shared\vmap\MapTree.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\ModelContainer.cpp"
|
RelativePath="..\..\src\shared\vmap\ModelInstance.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\ModelContainer.h"
|
RelativePath="..\..\src\shared\vmap\ModelInstance.h"
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\NodeValueAccess.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\ShortBox.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\ShortVector.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\SubModel.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\SubModel.h"
|
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
|
@ -796,14 +756,6 @@
|
||||||
RelativePath="..\..\src\shared\vmap\TileAssembler.h"
|
RelativePath="..\..\src\shared\vmap\TileAssembler.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\TreeNode.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\TreeNode.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\VMapDefinitions.h"
|
RelativePath="..\..\src\shared\vmap\VMapDefinitions.h"
|
||||||
>
|
>
|
||||||
|
|
@ -817,17 +769,25 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\VMapManager.cpp"
|
RelativePath="..\..\src\shared\vmap\VMapManager2.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\VMapManager.h"
|
RelativePath="..\..\src\shared\vmap\VMapManager2.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\VMapTools.h"
|
RelativePath="..\..\src\shared\vmap\VMapTools.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\shared\vmap\WorldModel.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\shared\vmap\WorldModel.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\Common.cpp"
|
RelativePath="..\..\src\shared\Common.cpp"
|
||||||
|
|
|
||||||
|
|
@ -727,31 +727,11 @@
|
||||||
Name="vmaps"
|
Name="vmaps"
|
||||||
>
|
>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\AABSPTree.h"
|
RelativePath="..\..\src\shared\vmap\BIH.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\BaseModel.cpp"
|
RelativePath="..\..\src\shared\vmap\BIH.h"
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\BaseModel.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\CoordModelMapping.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\CoordModelMapping.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\DebugCmdLogger.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\DebugCmdLogger.h"
|
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
|
@ -759,39 +739,19 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\ManagedModelContainer.cpp"
|
RelativePath="..\..\src\shared\vmap\MapTree.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\ManagedModelContainer.h"
|
RelativePath="..\..\src\shared\vmap\MapTree.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\ModelContainer.cpp"
|
RelativePath="..\..\src\shared\vmap\ModelInstance.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\ModelContainer.h"
|
RelativePath="..\..\src\shared\vmap\ModelInstance.h"
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\NodeValueAccess.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\ShortBox.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\ShortVector.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\SubModel.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\SubModel.h"
|
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
|
@ -802,14 +762,6 @@
|
||||||
RelativePath="..\..\src\shared\vmap\TileAssembler.h"
|
RelativePath="..\..\src\shared\vmap\TileAssembler.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\TreeNode.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\shared\vmap\TreeNode.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\VMapDefinitions.h"
|
RelativePath="..\..\src\shared\vmap\VMapDefinitions.h"
|
||||||
>
|
>
|
||||||
|
|
@ -823,17 +775,25 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\VMapManager.cpp"
|
RelativePath="..\..\src\shared\vmap\VMapManager2.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\VMapManager.h"
|
RelativePath="..\..\src\shared\vmap\VMapManager2.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\vmap\VMapTools.h"
|
RelativePath="..\..\src\shared\vmap\VMapTools.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\shared\vmap\WorldModel.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\shared\vmap\WorldModel.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\shared\Common.cpp"
|
RelativePath="..\..\src\shared\Common.cpp"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue