mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 10: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_UNK8 = 0x00800000, // Westguard Inn, Acherus: The Ebon Hold, Valgarde
|
||||
AREA_FLAG_OUTDOOR_PVP = 0x01000000, // Wintergrasp and it's subzones
|
||||
AREA_FLAG_UNK9 = 0x02000000, // unknown
|
||||
AREA_FLAG_UNK10 = 0x04000000, // unknown
|
||||
AREA_FLAG_INSIDE = 0x02000000, // used for determinating spell related inside/outside questions in Map::IsOutdoors
|
||||
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
|
||||
// 0x20000000 not flyable?
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,11 +30,32 @@
|
|||
typedef std::map<uint16,uint32> AreaFlagByAreaID;
|
||||
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 <AreaGroupEntry> sAreaGroupStore(AreaGroupEntryfmt);
|
||||
static AreaFlagByAreaID sAreaFlagByAreaID;
|
||||
static AreaFlagByMapID sAreaFlagByMapID; // for instances without generated *.map files
|
||||
|
||||
static WMOAreaInfoByTripple sWMOAreaInfoByTripple;
|
||||
|
||||
DBCStorage <AchievementEntry> sAchievementStore(Achievementfmt);
|
||||
DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore(AchievementCriteriafmt);
|
||||
DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt);
|
||||
|
|
@ -157,6 +178,7 @@ static DBCStorage <TaxiPathNodeEntry> sTaxiPathNodeStore(TaxiPathNodeEntryfmt);
|
|||
DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt);
|
||||
DBCStorage <VehicleEntry> sVehicleStore(VehicleEntryfmt);
|
||||
DBCStorage <VehicleSeatEntry> sVehicleSeatStore(VehicleSeatEntryfmt);
|
||||
DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore(WMOAreaTableEntryfmt);
|
||||
DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreaEntryfmt);
|
||||
DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore(WorldMapOverlayEntryfmt);
|
||||
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,sVehicleSeatStore, dbcPath,"VehicleSeat.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,sWorldSafeLocsStore, dbcPath,"WorldSafeLocs.dbc");
|
||||
|
||||
|
|
@ -702,6 +732,15 @@ int32 GetAreaFlagByAreaID(uint32 area_id)
|
|||
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)
|
||||
{
|
||||
int32 areaflag = GetAreaFlagByAreaID(area_id);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ TalentSpellPos const* GetTalentSpellPos(uint32 spellId);
|
|||
int32 GetAreaFlagByAreaID(uint32 area_id); // -1 if not found
|
||||
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* GetAreaEntryByAreaFlagAndMap(uint32 area_flag,uint32 map_id);
|
||||
|
||||
|
|
@ -161,6 +163,7 @@ extern TaxiPathNodesByPath sTaxiPathNodesByPath;
|
|||
extern DBCStorage <TotemCategoryEntry> sTotemCategoryStore;
|
||||
extern DBCStorage <VehicleEntry> sVehicleStore;
|
||||
extern DBCStorage <VehicleSeatEntry> sVehicleSeatStore;
|
||||
extern DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore;
|
||||
//extern DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates
|
||||
extern DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore;
|
||||
extern DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore;
|
||||
|
|
|
|||
|
|
@ -1781,6 +1781,23 @@ struct VehicleSeatEntry
|
|||
// 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
|
||||
{
|
||||
//uint32 ID; // 0
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ const char TaxiPathNodeEntryfmt[]="diiifffiiii";
|
|||
const char TotemCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxii";
|
||||
const char VehicleEntryfmt[]="niffffiiiiiiiifffffffffffffffssssfifixxx";
|
||||
const char VehicleSeatEntryfmt[]="niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiixxxxxxxxxxxx";
|
||||
const char WMOAreaTableEntryfmt[]="niiixxxxxiixxxxxxxxxxxxxxxxx";
|
||||
const char WorldMapAreaEntryfmt[]="xinxffffixx";
|
||||
const char WorldMapOverlayEntryfmt[]="nxiiiixxxxxxxxxxx";
|
||||
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_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,
|
||||
obj->GetMapId(), (mapEntry ? mapEntry->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;
|
||||
if (atEntry)
|
||||
areaflag = atEntry->exploreFlag;
|
||||
else
|
||||
{
|
||||
if(GridMap *gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||
areaflag = gmap->getArea(x, y);
|
||||
// this used while not all *.map files generated (instances)
|
||||
else
|
||||
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 ((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))
|
||||
if (isOutdoors)
|
||||
{
|
||||
// need exclude 2 shop rooms
|
||||
if (((x-5862.26f)*(x-5862.26f)+(y-554.76f)*(y-554.76f) > 335.85f/*310.64f*/ || z > 671.12f) &&
|
||||
((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
|
||||
if (haveAreaInfo)
|
||||
*isOutdoors = IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
|
||||
else
|
||||
{
|
||||
if (x > 1299.0f && x < 1839.0f && y > 10.0f && y < 440.0f) areaflag = 685;
|
||||
*isOutdoors = true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -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 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))
|
||||
return gmap->getLiquidStatus(x, y, z, ReqLiquidType, data);
|
||||
else
|
||||
return LIQUID_MAP_NO_WATER;
|
||||
{
|
||||
GridMapLiquidData map_data;
|
||||
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
|
||||
|
|
@ -1373,15 +1270,16 @@ void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 area
|
|||
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
|
||||
if (const_cast<Map*>(this)->GetGrid(x, y))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// 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;
|
||||
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;
|
||||
|
||||
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;
|
||||
float GetWaterLevel(float x, float y ) 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
|
||||
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:
|
||||
void LoadMapAndVMap(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);
|
||||
if (m_MirrorTimerFlags&UNDERWATER_INLAVA)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -6050,7 +6052,7 @@ bool Player::SetPosition(float x, float y, float z, float orientation, bool tele
|
|||
// code block for underwater state update
|
||||
UpdateUnderwaterState(m, x, y, z);
|
||||
|
||||
CheckExploreSystem();
|
||||
CheckAreaExploreAndOutdoor();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -6112,7 +6114,7 @@ void Player::SendMovieStart(uint32 MovieId)
|
|||
SendDirectMessage(&data);
|
||||
}
|
||||
|
||||
void Player::CheckExploreSystem()
|
||||
void Player::CheckAreaExploreAndOutdoor()
|
||||
{
|
||||
if (!isAlive())
|
||||
return;
|
||||
|
|
@ -6120,12 +6122,17 @@ void Player::CheckExploreSystem()
|
|||
if (isInFlight())
|
||||
return;
|
||||
|
||||
uint16 areaFlag = GetBaseMap()->GetAreaFlag(GetPositionX(),GetPositionY(),GetPositionZ());
|
||||
if(areaFlag==0xffff)
|
||||
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)
|
||||
return;
|
||||
int offset = areaFlag / 32;
|
||||
|
||||
if(offset >= PLAYER_EXPLORED_ZONES_SIZE)
|
||||
if (offset >= PLAYER_EXPLORED_ZONES_SIZE)
|
||||
{
|
||||
sLog.outError("Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < %u ).",areaFlag,GetPositionX(),GetPositionY(),offset,offset, PLAYER_EXPLORED_ZONES_SIZE);
|
||||
return;
|
||||
|
|
@ -6134,7 +6141,7 @@ void Player::CheckExploreSystem()
|
|||
uint32 val = (uint32)(1 << (areaFlag % 32));
|
||||
uint32 currFields = GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);
|
||||
|
||||
if( !(currFields & val) )
|
||||
if (!(currFields & val))
|
||||
{
|
||||
SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields | val));
|
||||
|
||||
|
|
@ -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);
|
||||
// Small hack for enable breath in WMO
|
||||
if (IsInWater())
|
||||
m_MirrorTimerFlags|=UNDERWATER_INWATER;
|
||||
/* if (IsInWater())
|
||||
m_MirrorTimerFlags|=UNDERWATER_INWATER; */
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1951,7 +1951,7 @@ class MANGOS_DLL_SPEC Player : public Unit
|
|||
void SetSemaphoreTeleportFar(bool semphsetting) { mSemaphoreTeleport_Far = semphsetting; }
|
||||
void ProcessDelayedOperations();
|
||||
|
||||
void CheckExploreSystem(void);
|
||||
void CheckAreaExploreAndOutdoor(void);
|
||||
|
||||
static uint32 TeamForRace(uint8 race);
|
||||
uint32 GetTeam() const { return m_team; }
|
||||
|
|
|
|||
|
|
@ -4189,6 +4189,16 @@ SpellCastResult Spell::CheckCast(bool strict)
|
|||
if(bg->GetStatus() == STATUS_WAIT_LEAVE)
|
||||
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
|
||||
// for now, ignore triggered spells
|
||||
if( strict && !m_IsTriggeredSpell)
|
||||
|
|
|
|||
|
|
@ -46,9 +46,9 @@
|
|||
#include "BattleGround.h"
|
||||
#include "BattleGroundEY.h"
|
||||
#include "BattleGroundWS.h"
|
||||
#include "VMapFactory.h"
|
||||
#include "Language.h"
|
||||
#include "SocialMgr.h"
|
||||
#include "VMapFactory.h"
|
||||
#include "Util.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "ScriptCalls.h"
|
||||
|
|
@ -7505,7 +7505,8 @@ void Spell::EffectTransmitted(SpellEffectIndex eff_idx)
|
|||
|
||||
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
|
||||
SendCastResult(SPELL_FAILED_NOT_HERE);
|
||||
SendChannelUpdate(0);
|
||||
|
|
@ -7513,7 +7514,8 @@ void Spell::EffectTransmitted(SpellEffectIndex eff_idx)
|
|||
}
|
||||
|
||||
// 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
|
||||
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)
|
||||
{
|
||||
// single target auras from other casters
|
||||
|
|
|
|||
|
|
@ -1526,6 +1526,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
|
|||
void RemoveRankAurasDueToSpell(uint32 spellId);
|
||||
bool RemoveNoStackAurasDueToAuraHolder(SpellAuraHolder *holder);
|
||||
void RemoveAurasWithInterruptFlags(uint32 flags);
|
||||
void RemoveAurasWithAttribute(uint32 flags);
|
||||
void RemoveAurasWithDispelType( DispelType type );
|
||||
void RemoveAllAuras(AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);
|
||||
void RemoveArenaAuras(bool onleave = false);
|
||||
|
|
|
|||
|
|
@ -848,6 +848,7 @@ void World::LoadConfigSettings(bool reload)
|
|||
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 enableHeight = sConfig.GetBoolDefault("vmap.enableHeight", false);
|
||||
std::string ignoreMapIds = sConfig.GetStringDefault("vmap.ignoreMapIds", "");
|
||||
|
|
@ -887,7 +888,7 @@ void World::SetInitialWorldSettings()
|
|||
||m_configUint32Values[CONFIG_UINT32_EXPANSION] && (
|
||||
!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();
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -314,6 +314,7 @@ enum eConfigBoolValues
|
|||
CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET,
|
||||
CONFIG_BOOL_STATS_SAVE_ONLY_ON_LOGOUT,
|
||||
CONFIG_BOOL_CLEAN_CHARACTER_DB,
|
||||
CONFIG_BOOL_VMAP_INDOOR_CHECK,
|
||||
CONFIG_BOOL_VALUE_COUNT
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -144,6 +144,13 @@ BindIP = "0.0.0.0"
|
|||
# These spells are ignored for LoS calculation
|
||||
# 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
|
||||
# Check final move position, summon position, etc for visible collision with other objects or
|
||||
# wall (wall only if vmaps are enabled)
|
||||
|
|
@ -194,8 +201,9 @@ PlayerSave.Stats.MinLevel = 0
|
|||
PlayerSave.Stats.SaveOnlyOnLogout = 1
|
||||
vmap.enableLOS = 0
|
||||
vmap.enableHeight = 0
|
||||
vmap.ignoreMapIds = "369"
|
||||
vmap.ignoreMapIds = ""
|
||||
vmap.ignoreSpellIds = "7720"
|
||||
vmap.enableIndoorCheck = 1
|
||||
DetectPosCollision = 1
|
||||
TargetPosRecalculateRange = 1.5
|
||||
UpdateUptimeInterval = 10
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef __REVISION_NR_H__
|
||||
#define __REVISION_NR_H__
|
||||
#define REVISION_NR "10164"
|
||||
#define REVISION_NR "10165"
|
||||
#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
|
||||
|
||||
#include<string>
|
||||
#include <Platform/Define.h>
|
||||
|
||||
//===========================================================
|
||||
|
||||
|
|
@ -93,6 +94,12 @@ namespace VMAP
|
|||
e.g.: "0,1,530"
|
||||
*/
|
||||
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
|
||||
|
||||
libmangosvmaps_a_SOURCES = \
|
||||
AABSPTree.h \
|
||||
BaseModel.cpp \
|
||||
BaseModel.h \
|
||||
CoordModelMapping.cpp \
|
||||
CoordModelMapping.h \
|
||||
DebugCmdLogger.cpp \
|
||||
DebugCmdLogger.h \
|
||||
BIH.h \
|
||||
BIH.cpp \
|
||||
IVMapManager.h \
|
||||
ManagedModelContainer.cpp \
|
||||
ManagedModelContainer.h \
|
||||
ModelContainer.cpp \
|
||||
ModelContainer.h \
|
||||
NodeValueAccess.h \
|
||||
ShortBox.h \
|
||||
ShortVector.h \
|
||||
SubModel.cpp \
|
||||
SubModel.h \
|
||||
MapTree.cpp \
|
||||
MapTree.h \
|
||||
ModelInstance.cpp \
|
||||
ModelInstance.h \
|
||||
TileAssembler.cpp \
|
||||
TileAssembler.h \
|
||||
TreeNode.cpp \
|
||||
TreeNode.h \
|
||||
VMapDefinitions.h \
|
||||
VMapFactory.cpp \
|
||||
VMapFactory.h \
|
||||
VMapManager.cpp \
|
||||
VMapManager.h \
|
||||
VMapTools.h
|
||||
VMapManager2.cpp \
|
||||
VMapManager2.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
|
||||
*/
|
||||
|
||||
#include <G3D/Vector3.h>
|
||||
#include <G3D/Triangle.h>
|
||||
|
||||
#include "WorldModel.h"
|
||||
#include "TileAssembler.h"
|
||||
#include "CoordModelMapping.h"
|
||||
#include "ModelContainer.h"
|
||||
#include "MapTree.h"
|
||||
#include "BIH.h"
|
||||
#include "VMapDefinitions.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <set>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#ifdef _ASSEMBLER_DEBUG
|
||||
FILE *g_df = NULL;
|
||||
#endif
|
||||
using G3D::Vector3;
|
||||
using G3D::AABox;
|
||||
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
|
||||
{
|
||||
//=================================================================
|
||||
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
|
||||
{
|
||||
//return(pIn);
|
||||
Vector3 out = pIn * iScale;
|
||||
out = izMatrix * out;
|
||||
out = ixMatrix * out;
|
||||
out = iyMatrix * out;
|
||||
out = iRotation * out;
|
||||
return(out);
|
||||
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
|
||||
TileAssembler::TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName)
|
||||
|
|
@ -55,320 +61,302 @@ namespace VMAP
|
|||
iSrcDir = pSrcDirName;
|
||||
iDestDir = pDestDirName;
|
||||
//mkdir(iDestDir);
|
||||
init();
|
||||
//init();
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
|
||||
TileAssembler::~TileAssembler()
|
||||
{
|
||||
delete iCoordModelMapping;
|
||||
//delete iCoordModelMapping;
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
|
||||
void TileAssembler::init()
|
||||
bool TileAssembler::convertWorld2()
|
||||
{
|
||||
iCoordModelMapping = new CoordModelMapping();
|
||||
addWorldAreaMapId(0); //Azeroth
|
||||
addWorldAreaMapId(1); //Kalimdor
|
||||
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))
|
||||
std::set<std::string> spawnedModelFiles;
|
||||
bool success = readMapSpawns();
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
Array<unsigned int> mapIds = iCoordModelMapping->getMaps();
|
||||
if(mapIds.size() == 0)
|
||||
// export Map data
|
||||
for (MapData::iterator map_iter = mapData.begin(); map_iter != mapData.end() && success; ++map_iter)
|
||||
{
|
||||
printf("Fatal error: empty map list!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i=0; i<mapIds.size(); ++i)
|
||||
// build global map tree
|
||||
std::vector<ModelSpawn*> mapSpawns;
|
||||
UniqueEntryMap::iterator entry;
|
||||
printf("Calculating model bounds for map %u...\n", map_iter->first);
|
||||
for (entry = map_iter->second->UniqueEntries.begin(); entry != map_iter->second->UniqueEntries.end(); ++entry)
|
||||
{
|
||||
unsigned int mapId = mapIds[i];
|
||||
|
||||
#ifdef _ASSEMBLER_DEBUG
|
||||
if(mapId == 0) // "Azeroth" just for debug
|
||||
// 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)
|
||||
{
|
||||
for(int x=28; x<29; ++x) //debug
|
||||
{
|
||||
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;
|
||||
if (!calculateTransformedBound(entry->second))
|
||||
break;
|
||||
}
|
||||
++pos;
|
||||
}
|
||||
if(result && mainTree->size() > 0)
|
||||
else if (entry->second.flags & MOD_WORLDSPAWN) // WMO maps and terrain maps use different origin, so we need to adapt :/
|
||||
{
|
||||
mainTree->balance();
|
||||
modelContainer = new ModelContainer(mainTree);
|
||||
modelContainer->writeFile(pDestFileName);
|
||||
// TODO: remove extractor hack and uncomment below line:
|
||||
//entry->second.iPos += Vector3(533.33333f*32, 533.33333f*32, 0.f);
|
||||
entry->second.iBound = entry->second.iBound + Vector3(533.33333f*32, 533.33333f*32, 0.f);
|
||||
}
|
||||
removeEntriesFromTree(mainTree);
|
||||
|
||||
delete mainTree;
|
||||
|
||||
return(modelContainer);
|
||||
mapSpawns.push_back(&(entry->second));
|
||||
spawnedModelFiles.insert(entry->second.name);
|
||||
}
|
||||
|
||||
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;
|
||||
if(filename.length() >0)
|
||||
if (filename.length() >0)
|
||||
filename.append("/");
|
||||
filename.append(pModelFilename);
|
||||
FILE *rf = fopen(filename.c_str(), "rb");
|
||||
if(!rf)
|
||||
{
|
||||
// depending on the extractor version, the data could be located in the root dir
|
||||
std::string baseModelFilename = pModelFilename.substr((pModelFilename.find_first_of("/")+1),pModelFilename.length());
|
||||
filename = iSrcDir;
|
||||
if(filename.length() >0)
|
||||
filename.append("/");
|
||||
filename.append(baseModelFilename);
|
||||
rf = fopen(filename.c_str(), "rb");
|
||||
}
|
||||
|
||||
if(!rf)
|
||||
if (!rf)
|
||||
{
|
||||
printf("ERROR: Can't open model file in form: %s",pModelFilename.c_str());
|
||||
printf("... or form: %s",filename.c_str() );
|
||||
|
|
@ -377,95 +365,74 @@ namespace VMAP
|
|||
|
||||
char ident[8];
|
||||
|
||||
int trianglecount =0;
|
||||
|
||||
#ifdef _ASSEMBLER_DEBUG
|
||||
int startgroup = 0; //2;
|
||||
int endgroup = INT_MAX; //2;
|
||||
fprintf(::g_df,"-------------------------------------------------\n");
|
||||
fprintf(::g_df,"%s\n", pModelFilename.c_str());
|
||||
fprintf(::g_df,"-------------------------------------------------\n");
|
||||
#else
|
||||
int startgroup = 0;
|
||||
int endgroup = INT_MAX;
|
||||
#endif
|
||||
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); return(false); }
|
||||
fclose(rf); printf("readfail, op = %i\n", readOperation); return(false); }readOperation++;
|
||||
#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);
|
||||
if(strcmp(ident, "VMAP001") == 0)
|
||||
{
|
||||
// OK, do nothing
|
||||
}
|
||||
else if(strcmp(ident, "VMAP002") == 0)
|
||||
{
|
||||
// we have to read one int. This is needed during the export and we have to skip it here
|
||||
int tempNVectors;
|
||||
READ_OR_RETURN(&tempNVectors, sizeof(int));
|
||||
CMP_OR_RETURN(ident, "VMAP003");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// wrong version
|
||||
fclose(rf);
|
||||
return(false);
|
||||
}
|
||||
G3D::uint32 groups;
|
||||
// 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;
|
||||
uint32 RootWMOID;
|
||||
char blockId[5];
|
||||
blockId[4] = 0;
|
||||
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 ...)
|
||||
Array<int> tempIndexArray;
|
||||
Array<Vector3> tempVertexArray;
|
||||
std::vector<MeshTriangle> triangles;
|
||||
std::vector<Vector3> vertexArray;
|
||||
|
||||
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
|
||||
#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; return(false); }
|
||||
#define CMP_OR_RETURN(V,S) if(strcmp((V),(S)) != 0) { \
|
||||
fclose(rf); delete gtree; return(false); }
|
||||
float bbox1[3], bbox2[3];
|
||||
READ_OR_RETURN(bbox1, sizeof(float)*3);
|
||||
READ_OR_RETURN(bbox2, sizeof(float)*3);
|
||||
|
||||
G3D::uint32 flags;
|
||||
READ_OR_RETURN(&flags, sizeof(G3D::uint32));
|
||||
uint32 liquidflags;
|
||||
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);
|
||||
CMP_OR_RETURN(blockId, "GRP ");
|
||||
READ_OR_RETURN(&blocksize, sizeof(int));
|
||||
READ_OR_RETURN(&branches, sizeof(G3D::uint32));
|
||||
for(int b=0;b<(int)branches; b++)
|
||||
READ_OR_RETURN(&branches, sizeof(uint32));
|
||||
for (uint32 b=0; b<branches; ++b)
|
||||
{
|
||||
G3D::uint32 indexes;
|
||||
uint32 indexes;
|
||||
// indexes for each branch (not used jet)
|
||||
READ_OR_RETURN(&indexes, sizeof(G3D::uint32));
|
||||
READ_OR_RETURN(&indexes, sizeof(uint32));
|
||||
}
|
||||
|
||||
// ---- indexes
|
||||
READ_OR_RETURN(&blockId, 4);
|
||||
CMP_OR_RETURN(blockId, "INDX");
|
||||
READ_OR_RETURN(&blocksize, sizeof(int));
|
||||
unsigned int nindexes;
|
||||
READ_OR_RETURN(&nindexes, sizeof(G3D::uint32));
|
||||
if(nindexes >0)
|
||||
uint32 nindexes;
|
||||
READ_OR_RETURN(&nindexes, sizeof(uint32));
|
||||
if (nindexes >0)
|
||||
{
|
||||
unsigned short *indexarray = new unsigned short[nindexes*sizeof(unsigned short)];
|
||||
READ_OR_RETURN(indexarray, nindexes*sizeof(unsigned short));
|
||||
for(int i=0;i<(int)nindexes; i++)
|
||||
uint16 *indexarray = new uint16[nindexes];
|
||||
READ_OR_RETURN(indexarray, nindexes*sizeof(uint16));
|
||||
for (uint32 i=0; i<nindexes; i+=3)
|
||||
{
|
||||
unsigned short val = indexarray[i];
|
||||
tempIndexArray.append(val);
|
||||
triangles.push_back(MeshTriangle(indexarray[i], indexarray[i+1], indexarray[i+2]));
|
||||
}
|
||||
delete[] indexarray;
|
||||
}
|
||||
|
|
@ -474,128 +441,56 @@ namespace VMAP
|
|||
READ_OR_RETURN(&blockId, 4);
|
||||
CMP_OR_RETURN(blockId, "VERT");
|
||||
READ_OR_RETURN(&blocksize, sizeof(int));
|
||||
unsigned int nvectors;
|
||||
READ_OR_RETURN(&nvectors, sizeof(int));
|
||||
uint32 nvectors;
|
||||
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);
|
||||
}
|
||||
// ----- liquit
|
||||
if(flags & 1)
|
||||
for (uint32 i=0; i<nvectors; ++i)
|
||||
{
|
||||
// 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);
|
||||
CMP_OR_RETURN(blockId, "LIQU");
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
for(unsigned int i=0, indexNo=0; indexNo<nvectors; indexNo++)
|
||||
{
|
||||
Vector3 v = Vector3(vectorarray[i+2], vectorarray[i+1], vectorarray[i+0]);
|
||||
i+=3;
|
||||
v = pModelPosition.transform(v);
|
||||
|
||||
float swapy = v.y;
|
||||
v.y = v.x;
|
||||
v.x = swapy;
|
||||
|
||||
tempVertexArray.append(v);
|
||||
}
|
||||
|
||||
// ---- calculate triangles
|
||||
int rest = nindexes%3;
|
||||
if(rest != 0)
|
||||
{
|
||||
nindexes -= rest;
|
||||
}
|
||||
|
||||
for(unsigned int i=0;i<(nindexes);)
|
||||
{
|
||||
Triangle t = Triangle(tempVertexArray[tempIndexArray[i+2]], tempVertexArray[tempIndexArray[i+1]], tempVertexArray[tempIndexArray[i+0]] );
|
||||
i+=3;
|
||||
++trianglecount;
|
||||
if(g>= startgroup && g <= endgroup)
|
||||
{
|
||||
gtree->insert(t);
|
||||
}
|
||||
}
|
||||
groupsArray.push_back(GroupModel(mogpflags, GroupWMOID, AABox(Vector3(bbox1), Vector3(bbox2))));
|
||||
groupsArray.back().setMeshData(vertexArray, triangles);
|
||||
groupsArray.back().setLiquidData(liquid);
|
||||
|
||||
// drop of temporary use defines
|
||||
#undef READ_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);
|
||||
return true;
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
|
||||
bool TileAssembler::fillModelIntoTree(AABSPTree<SubModel *> *pMainTree, const Vector3& pBasePos, std::string& pPos, std::string& pModelFilename)
|
||||
// write WorldModel
|
||||
WorldModel model;
|
||||
model.setRootWmoID(RootWMOID);
|
||||
if (groupsArray.size())
|
||||
{
|
||||
ModelPosition modelPosition;
|
||||
getModelPosition(pPos, modelPosition);
|
||||
// all should be relative to object base position
|
||||
modelPosition.moveToBasePos(pBasePos);
|
||||
|
||||
modelPosition.init();
|
||||
|
||||
return readRawFile(pModelFilename, modelPosition, pMainTree);
|
||||
model.setGroupModels(groupsArray);
|
||||
success = model.writeFile(iDestDir + "/" + pModelFilename + ".vmo");
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
void TileAssembler::getModelPosition(std::string& pPosString, ModelPosition& pModelPosition)
|
||||
{
|
||||
float vposarray[3];
|
||||
float vdirarray[3];
|
||||
float scale;
|
||||
|
||||
size_t spos = pPosString.find_first_of('#');
|
||||
std::string stripedPosString = pPosString.substr(spos+1,pPosString.length());
|
||||
|
||||
sscanf(stripedPosString.c_str(), "%f,%f,%f_%f,%f,%f_%f",
|
||||
&vposarray[0],&vposarray[1],&vposarray[2],
|
||||
&vdirarray[0],&vdirarray[1],&vdirarray[2],
|
||||
&scale);
|
||||
|
||||
pModelPosition.iPos = Vector3(vposarray[0], vposarray[1], vposarray[2]);
|
||||
pModelPosition.iDir = Vector3(vdirarray[0], vdirarray[1], vdirarray[2]);
|
||||
pModelPosition.iScale = scale;
|
||||
|
||||
//std::cout << "readRawFile2: '" << pModelFilename << "' tris: " << nElements << " nodes: " << nNodes << std::endl;
|
||||
return success;
|
||||
}
|
||||
//==========================================
|
||||
} // VMAP
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,14 +19,11 @@
|
|||
#ifndef _TILEASSEMBLER_H_
|
||||
#define _TILEASSEMBLER_H_
|
||||
|
||||
// load our modified version first !!
|
||||
#include "AABSPTree.h"
|
||||
|
||||
#include <G3D/Vector3.h>
|
||||
#include <G3D/Matrix3.h>
|
||||
#include <map>
|
||||
|
||||
#include "CoordModelMapping.h"
|
||||
#include "SubModel.h"
|
||||
#include "ModelContainer.h"
|
||||
#include "ModelInstance.h"
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
|
|
@ -39,55 +36,54 @@ namespace VMAP
|
|||
class ModelPosition
|
||||
{
|
||||
private:
|
||||
G3D::Matrix3 ixMatrix;
|
||||
G3D::Matrix3 iyMatrix;
|
||||
G3D::Matrix3 izMatrix;
|
||||
G3D::Matrix3 iRotation;
|
||||
public:
|
||||
G3D::Vector3 iPos;
|
||||
G3D::Vector3 iDir;
|
||||
float iScale;
|
||||
void init()
|
||||
{
|
||||
|
||||
// Swap x and y the raw data uses the axis differently
|
||||
ixMatrix = G3D::Matrix3::fromAxisAngle(G3D::Vector3::unitY(),-(G3D::pi()*iDir.x/180.0));
|
||||
iyMatrix = G3D::Matrix3::fromAxisAngle(G3D::Vector3::unitX(),-(G3D::pi()*iDir.y/180.0));
|
||||
izMatrix = G3D::Matrix3::fromAxisAngle(G3D::Vector3::unitZ(),-(G3D::pi()*iDir.z/180.0));
|
||||
|
||||
iRotation = G3D::Matrix3::fromEulerAnglesZYX(G3D::pi()*iDir.y/180.f, G3D::pi()*iDir.x/180.f, G3D::pi()*iDir.z/180.f);
|
||||
}
|
||||
G3D::Vector3 transform(const G3D::Vector3& pIn) const;
|
||||
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
|
||||
{
|
||||
private:
|
||||
CoordModelMapping *iCoordModelMapping;
|
||||
std::string iDestDir;
|
||||
std::string iSrcDir;
|
||||
bool (*iFilterMethod)(char *pName);
|
||||
G3D::Table<std::string, unsigned int > iUniqueNameIds;
|
||||
unsigned int iCurrentUniqueNameId;
|
||||
MapData mapData;
|
||||
|
||||
public:
|
||||
TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName);
|
||||
virtual ~TileAssembler();
|
||||
|
||||
bool fillModelContainerArray(const std::string& pDirFileName, unsigned int pMapId, int pXPos, int pYPos, G3D::Array<ModelContainer*>& pMC);
|
||||
ModelContainer* processNames(const G3D::Array<std::string>& pPosFileNames, const char* pDestFileName);
|
||||
bool convertWorld2();
|
||||
bool readMapSpawns();
|
||||
bool calculateTransformedBound(ModelSpawn &spawn);
|
||||
|
||||
void init();
|
||||
bool convertWorld();
|
||||
|
||||
bool fillModelIntoTree(G3D::AABSPTree<SubModel *> *pMainTree, const G3D::Vector3& pBasePos, std::string& pPosFilename, std::string& pModelFilename);
|
||||
void getModelPosition(std::string& pPosString, ModelPosition& pModelPosition);
|
||||
bool readRawFile(std::string& pModelFilename, ModelPosition& pModelPosition, G3D::AABSPTree<SubModel *> *pMainTree);
|
||||
void addWorldAreaMapId(unsigned int pMapId) { iCoordModelMapping->addWorldAreaMap(pMapId); }
|
||||
bool convertRawFile(const std::string& pModelFilename);
|
||||
void setModelNameFilterMethod(bool (*pFilterMethod)(char *pName)) { iFilterMethod = pFilterMethod; }
|
||||
std::string getDirEntryNameFromModName(unsigned int pMapId, const std::string& pModPosName);
|
||||
unsigned int getUniqueNameId(const std::string pName);
|
||||
};
|
||||
//===============================================
|
||||
|
||||
} // VMAP
|
||||
#endif /*_TILEASSEMBLER_H_*/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#include <cstring>
|
||||
|
||||
#define LIQUID_TILE_SIZE (533.333f / 128.f)
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
//=====================================
|
||||
#define MAX_CAN_FALL_DISTANCE 10.0f
|
||||
const char VMAP_MAGIC[] = "VMAP_2.0";
|
||||
const char VMAP_MAGIC[] = "VMAP_3.0";
|
||||
|
||||
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 // _VMAPDEFINITIONS_H
|
||||
|
|
|
|||
|
|
@ -18,15 +18,41 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
#include "VMapFactory.h"
|
||||
#include "VMapManager.h"
|
||||
#include "VMapManager2.h"
|
||||
|
||||
using namespace G3D;
|
||||
|
||||
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;
|
||||
|
||||
//===============================================
|
||||
|
|
@ -88,7 +114,7 @@ namespace VMAP
|
|||
IVMapManager* VMapFactory::createOrGetVMapManager()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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\Threading.cpp" />
|
||||
<ClCompile Include="..\..\src\shared\Util.cpp" />
|
||||
<ClCompile Include="..\..\src\shared\vmap\BaseModel.cpp" />
|
||||
<ClCompile Include="..\..\src\shared\vmap\CoordModelMapping.cpp" />
|
||||
<ClCompile Include="..\..\src\shared\vmap\DebugCmdLogger.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\BIH.cpp" />
|
||||
<ClCompile Include="..\..\src\shared\vmap\MapTree.cpp" />
|
||||
<ClCompile Include="..\..\src\shared\vmap\ModelInstance.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\VMapManager.cpp" />
|
||||
<ClCompile Include="..\..\src\shared\vmap\VMapManager2.cpp" />
|
||||
<ClCompile Include="..\..\src\shared\vmap\WorldModel.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\dep\include\mersennetwister\MersenneTwister.h" />
|
||||
|
|
@ -498,23 +495,16 @@
|
|||
<ClInclude Include="..\..\src\shared\Threading.h" />
|
||||
<ClInclude Include="..\..\src\shared\Timer.h" />
|
||||
<ClInclude Include="..\..\src\shared\Util.h" />
|
||||
<ClInclude Include="..\..\src\shared\vmap\AABSPTree.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\BIH.h" />
|
||||
<ClInclude Include="..\..\src\shared\vmap\IVMapManager.h" />
|
||||
<ClInclude Include="..\..\src\shared\vmap\ManagedModelContainer.h" />
|
||||
<ClInclude Include="..\..\src\shared\vmap\ModelContainer.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\MapTree.h" />
|
||||
<ClInclude Include="..\..\src\shared\vmap\ModelInstance.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\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\WorldModel.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="ACE_vc10.vcxproj">
|
||||
|
|
|
|||
|
|
@ -721,31 +721,11 @@
|
|||
Name="vmaps"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\AABSPTree.h"
|
||||
RelativePath="..\..\src\shared\vmap\BIH.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\BaseModel.cpp"
|
||||
>
|
||||
</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"
|
||||
RelativePath="..\..\src\shared\vmap\BIH.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
|
@ -753,39 +733,19 @@
|
|||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\ManagedModelContainer.cpp"
|
||||
RelativePath="..\..\src\shared\vmap\MapTree.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\ManagedModelContainer.h"
|
||||
RelativePath="..\..\src\shared\vmap\MapTree.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\ModelContainer.cpp"
|
||||
RelativePath="..\..\src\shared\vmap\ModelInstance.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\ModelContainer.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"
|
||||
RelativePath="..\..\src\shared\vmap\ModelInstance.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
|
@ -796,14 +756,6 @@
|
|||
RelativePath="..\..\src\shared\vmap\TileAssembler.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\TreeNode.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\TreeNode.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\VMapDefinitions.h"
|
||||
>
|
||||
|
|
@ -817,17 +769,25 @@
|
|||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\VMapManager.cpp"
|
||||
RelativePath="..\..\src\shared\vmap\VMapManager2.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\VMapManager.h"
|
||||
RelativePath="..\..\src\shared\vmap\VMapManager2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\VMapTools.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\WorldModel.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\WorldModel.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\Common.cpp"
|
||||
|
|
|
|||
|
|
@ -727,31 +727,11 @@
|
|||
Name="vmaps"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\AABSPTree.h"
|
||||
RelativePath="..\..\src\shared\vmap\BIH.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\BaseModel.cpp"
|
||||
>
|
||||
</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"
|
||||
RelativePath="..\..\src\shared\vmap\BIH.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
|
@ -759,39 +739,19 @@
|
|||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\ManagedModelContainer.cpp"
|
||||
RelativePath="..\..\src\shared\vmap\MapTree.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\ManagedModelContainer.h"
|
||||
RelativePath="..\..\src\shared\vmap\MapTree.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\ModelContainer.cpp"
|
||||
RelativePath="..\..\src\shared\vmap\ModelInstance.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\ModelContainer.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"
|
||||
RelativePath="..\..\src\shared\vmap\ModelInstance.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
|
@ -802,14 +762,6 @@
|
|||
RelativePath="..\..\src\shared\vmap\TileAssembler.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\TreeNode.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\TreeNode.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\VMapDefinitions.h"
|
||||
>
|
||||
|
|
@ -823,17 +775,25 @@
|
|||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\VMapManager.cpp"
|
||||
RelativePath="..\..\src\shared\vmap\VMapManager2.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\VMapManager.h"
|
||||
RelativePath="..\..\src\shared\vmap\VMapManager2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\VMapTools.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\WorldModel.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\vmap\WorldModel.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath="..\..\src\shared\Common.cpp"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue