diff options
Diffstat (limited to 'src/server/collision/Models')
| -rw-r--r-- | src/server/collision/Models/GameObjectModel.cpp | 216 | ||||
| -rw-r--r-- | src/server/collision/Models/GameObjectModel.h | 87 | ||||
| -rw-r--r-- | src/server/collision/Models/ModelInstance.cpp | 223 | ||||
| -rw-r--r-- | src/server/collision/Models/ModelInstance.h | 82 | ||||
| -rw-r--r-- | src/server/collision/Models/WorldModel.cpp | 586 | ||||
| -rw-r--r-- | src/server/collision/Models/WorldModel.h | 129 |
6 files changed, 0 insertions, 1323 deletions
diff --git a/src/server/collision/Models/GameObjectModel.cpp b/src/server/collision/Models/GameObjectModel.cpp deleted file mode 100644 index dbdc0554e06..00000000000 --- a/src/server/collision/Models/GameObjectModel.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 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, see <http://www.gnu.org/licenses/>. - */ - -#include "VMapFactory.h" -#include "VMapManager2.h" -#include "VMapDefinitions.h" -#include "WorldModel.h" -#include "GameObjectModel.h" -#include "Log.h" -#include "Timer.h" - -using G3D::Vector3; -using G3D::Ray; -using G3D::AABox; - -struct GameobjectModelData -{ - GameobjectModelData(const std::string& name_, const AABox& box) : - bound(box), name(name_) { } - - AABox bound; - std::string name; -}; - -typedef std::unordered_map<uint32, GameobjectModelData> ModelList; -ModelList model_list; - -void LoadGameObjectModelList(std::string const& dataPath) -{ -#ifndef NO_CORE_FUNCS - uint32 oldMSTime = getMSTime(); -#endif - - FILE* model_list_file = fopen((dataPath + "vmaps/" + VMAP::GAMEOBJECT_MODELS).c_str(), "rb"); - if (!model_list_file) - { - VMAP_ERROR_LOG("misc", "Unable to open '%s' file.", VMAP::GAMEOBJECT_MODELS); - return; - } - - uint32 name_length, displayId; - char buff[500]; - while (true) - { - Vector3 v1, v2; - if (fread(&displayId, sizeof(uint32), 1, model_list_file) != 1) - if (feof(model_list_file)) // EOF flag is only set after failed reading attempt - break; - - if (fread(&name_length, sizeof(uint32), 1, model_list_file) != 1 - || name_length >= sizeof(buff) - || fread(&buff, sizeof(char), name_length, model_list_file) != name_length - || fread(&v1, sizeof(Vector3), 1, model_list_file) != 1 - || fread(&v2, sizeof(Vector3), 1, model_list_file) != 1) - { - VMAP_ERROR_LOG("misc", "File '%s' seems to be corrupted!", VMAP::GAMEOBJECT_MODELS); - break; - } - - if (v1.isNaN() || v2.isNaN()) - { - VMAP_ERROR_LOG("misc", "File '%s' Model '%s' has invalid v1%s v2%s values!", VMAP::GAMEOBJECT_MODELS, std::string(buff, name_length).c_str(), v1.toString().c_str(), v2.toString().c_str()); - continue; - } - - model_list.insert - ( - ModelList::value_type(displayId, GameobjectModelData(std::string(buff, name_length), AABox(v1, v2))) - ); - } - - fclose(model_list_file); - VMAP_INFO_LOG("server.loading", ">> Loaded %u GameObject models in %u ms", uint32(model_list.size()), GetMSTimeDiffToNow(oldMSTime)); -} - -GameObjectModel::~GameObjectModel() -{ - if (iModel) - ((VMAP::VMapManager2*)VMAP::VMapFactory::createOrGetVMapManager())->releaseModelInstance(name); -} - -bool GameObjectModel::initialize(std::unique_ptr<GameObjectModelOwnerBase> modelOwner, std::string const& dataPath) -{ - ModelList::const_iterator it = model_list.find(modelOwner->GetDisplayId()); - if (it == model_list.end()) - return false; - - G3D::AABox mdl_box(it->second.bound); - // ignore models with no bounds - if (mdl_box == G3D::AABox::zero()) - { - VMAP_ERROR_LOG("misc", "GameObject model %s has zero bounds, loading skipped", it->second.name.c_str()); - return false; - } - - iModel = ((VMAP::VMapManager2*)VMAP::VMapFactory::createOrGetVMapManager())->acquireModelInstance(dataPath + "vmaps/", it->second.name); - - if (!iModel) - return false; - - name = it->second.name; - iPos = modelOwner->GetPosition(); - phasemask = modelOwner->GetPhaseMask(); - iScale = modelOwner->GetScale(); - iInvScale = 1.f / iScale; - - G3D::Matrix3 iRotation = G3D::Matrix3::fromEulerAnglesZYX(modelOwner->GetOrientation(), 0, 0); - iInvRot = iRotation.inverse(); - // transform bounding box: - mdl_box = AABox(mdl_box.low() * iScale, mdl_box.high() * iScale); - AABox rotated_bounds; - for (int i = 0; i < 8; ++i) - rotated_bounds.merge(iRotation * mdl_box.corner(i)); - - iBound = rotated_bounds + iPos; -#ifdef SPAWN_CORNERS - // test: - for (int i = 0; i < 8; ++i) - { - Vector3 pos(iBound.corner(i)); - modelOwner->DebugVisualizeCorner(pos); - } -#endif - - owner = std::move(modelOwner); - return true; -} - -GameObjectModel* GameObjectModel::Create(std::unique_ptr<GameObjectModelOwnerBase> modelOwner, std::string const& dataPath) -{ - GameObjectModel* mdl = new GameObjectModel(); - if (!mdl->initialize(std::move(modelOwner), dataPath)) - { - delete mdl; - return NULL; - } - - return mdl; -} - -bool GameObjectModel::intersectRay(const G3D::Ray& ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask) const -{ - if (!(phasemask & ph_mask) || !owner->IsSpawned()) - return false; - - float time = ray.intersectionTime(iBound); - if (time == G3D::finf()) - return false; - - // child bounds are defined in object space: - Vector3 p = iInvRot * (ray.origin() - iPos) * iInvScale; - Ray modRay(p, iInvRot * ray.direction()); - float distance = MaxDist * iInvScale; - bool hit = iModel->IntersectRay(modRay, distance, StopAtFirstHit); - if (hit) - { - distance *= iScale; - MaxDist = distance; - } - return hit; -} - -bool GameObjectModel::UpdatePosition() -{ - if (!iModel) - return false; - - ModelList::const_iterator it = model_list.find(owner->GetDisplayId()); - if (it == model_list.end()) - return false; - - G3D::AABox mdl_box(it->second.bound); - // ignore models with no bounds - if (mdl_box == G3D::AABox::zero()) - { - VMAP_ERROR_LOG("misc", "GameObject model %s has zero bounds, loading skipped", it->second.name.c_str()); - return false; - } - - iPos = owner->GetPosition(); - - G3D::Matrix3 iRotation = G3D::Matrix3::fromEulerAnglesZYX(owner->GetOrientation(), 0, 0); - iInvRot = iRotation.inverse(); - // transform bounding box: - mdl_box = AABox(mdl_box.low() * iScale, mdl_box.high() * iScale); - AABox rotated_bounds; - for (int i = 0; i < 8; ++i) - rotated_bounds.merge(iRotation * mdl_box.corner(i)); - - iBound = rotated_bounds + iPos; -#ifdef SPAWN_CORNERS - // test: - for (int i = 0; i < 8; ++i) - { - Vector3 pos(iBound.corner(i)); - owner->DebugVisualizeCorner(pos); - } -#endif - - return true; -} diff --git a/src/server/collision/Models/GameObjectModel.h b/src/server/collision/Models/GameObjectModel.h deleted file mode 100644 index 17669189af5..00000000000 --- a/src/server/collision/Models/GameObjectModel.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 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, see <http://www.gnu.org/licenses/>. - */ - -#ifndef _GAMEOBJECT_MODEL_H -#define _GAMEOBJECT_MODEL_H - -#include <G3D/Matrix3.h> -#include <G3D/Vector3.h> -#include <G3D/AABox.h> -#include <G3D/Ray.h> - -#include "Define.h" -#include <memory> - -namespace VMAP -{ - class WorldModel; -} - -class GameObject; -struct GameObjectDisplayInfoEntry; - -class GameObjectModelOwnerBase -{ -public: - virtual bool IsSpawned() const { return false; } - virtual uint32 GetDisplayId() const { return 0; } - virtual uint32 GetPhaseMask() const { return 0; } - virtual G3D::Vector3 GetPosition() const { return G3D::Vector3::zero(); } - virtual float GetOrientation() const { return 0.0f; } - virtual float GetScale() const { return 1.0f; } - virtual void DebugVisualizeCorner(G3D::Vector3 const& /*corner*/) const { } -}; - -class GameObjectModel /*, public Intersectable*/ -{ - GameObjectModel() : phasemask(0), iInvScale(0), iScale(0), iModel(NULL) { } -public: - std::string name; - - const G3D::AABox& getBounds() const { return iBound; } - - ~GameObjectModel(); - - const G3D::Vector3& getPosition() const { return iPos;} - - /** Enables\disables collision. */ - void disable() { phasemask = 0;} - void enable(uint32 ph_mask) { phasemask = ph_mask;} - - bool isEnabled() const {return phasemask != 0;} - - bool intersectRay(const G3D::Ray& Ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask) const; - - static GameObjectModel* Create(std::unique_ptr<GameObjectModelOwnerBase> modelOwner, std::string const& dataPath); - - bool UpdatePosition(); - -private: - bool initialize(std::unique_ptr<GameObjectModelOwnerBase> modelOwner, std::string const& dataPath); - - uint32 phasemask; - G3D::AABox iBound; - G3D::Matrix3 iInvRot; - G3D::Vector3 iPos; - float iInvScale; - float iScale; - VMAP::WorldModel* iModel; - std::unique_ptr<GameObjectModelOwnerBase> owner; -}; - -#endif // _GAMEOBJECT_MODEL_H diff --git a/src/server/collision/Models/ModelInstance.cpp b/src/server/collision/Models/ModelInstance.cpp deleted file mode 100644 index 025352eeb58..00000000000 --- a/src/server/collision/Models/ModelInstance.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * 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, see <http://www.gnu.org/licenses/>. - */ - -#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::pif()*iRot.y/180.f, G3D::pif()*iRot.x/180.f, G3D::pif()*iRot.z/180.f).inverse(); - iInvScale = 1.f/iScale; - } - - bool ModelInstance::intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit) const - { - if (!iModel) - { - //std::cout << "<object not loaded>\n"; - return false; - } - float time = pRay.intersectionTime(iBound); - if (time == G3D::finf()) - { -// std::cout << "Ray does not hit '" << name << "'\n"; - - return false; - } -// std::cout << "Ray crosses bound of '" << name << "'\n"; -/* std::cout << "ray from:" << pRay.origin().x << ", " << pRay.origin().y << ", " << pRay.origin().z - << " dir:" << pRay.direction().x << ", " << pRay.direction().y << ", " << pRay.direction().z - << " t/tmax:" << time << '/' << pMaxDist; - std::cout << "\nBound lo:" << iBound.low().x << ", " << iBound.low().y << ", " << iBound.low().z << " hi: " - << iBound.high().x << ", " << iBound.high().y << ", " << iBound.high().z << std::endl; */ - // 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); - if (hit) - { - distance *= iScale; - pMaxDist = distance; - } - return hit; - } - - void ModelInstance::intersectPoint(const G3D::Vector3& p, AreaInfo &info) const - { - if (!iModel) - { -#ifdef VMAP_DEBUG - std::cout << "<object not loaded>\n"; -#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 - std::cout << "<object not loaded>\n"; -#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)) - std::cout << "Error reading ModelSpawn!\n"; - 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) != 0; - 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 != uint32(has_bound ? 17 : 11)) - { - std::cout << "Error reading ModelSpawn!\n"; - return false; - } - char nameBuff[500]; - if (nameLen > 500) // file names should never be that long, must be file error - { - std::cout << "Error reading ModelSpawn, file name too long!\n"; - return false; - } - check = fread(nameBuff, sizeof(char), nameLen, rf); - if (check != nameLen) - { - std::cout << "Error reading ModelSpawn!\n"; - 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) != 0; - 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 != uint32(has_bound ? 17 : 11)) return false; - check = fwrite(spawn.name.c_str(), sizeof(char), nameLen, wf); - if (check != nameLen) return false; - return true; - } - -} diff --git a/src/server/collision/Models/ModelInstance.h b/src/server/collision/Models/ModelInstance.h deleted file mode 100644 index dfdb001db0a..00000000000 --- a/src/server/collision/Models/ModelInstance.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * 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, see <http://www.gnu.org/licenses/>. - */ - -#ifndef _MODELINSTANCE_H_ -#define _MODELINSTANCE_H_ - -#include <G3D/Matrix3.h> -#include <G3D/Vector3.h> -#include <G3D/AABox.h> -#include <G3D/Ray.h> - -#include "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(): iInvScale(0.0f), iModel(nullptr) { } - ModelInstance(const ModelSpawn &spawn, WorldModel* model); - void setUnloaded() { iModel = nullptr; } - 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; - public: - WorldModel* getWorldModel(); - }; -} // namespace VMAP - -#endif // _MODELINSTANCE diff --git a/src/server/collision/Models/WorldModel.cpp b/src/server/collision/Models/WorldModel.cpp deleted file mode 100644 index 3af120045cb..00000000000 --- a/src/server/collision/Models/WorldModel.cpp +++ /dev/null @@ -1,586 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * 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, see <http://www.gnu.org/licenses/>. - */ - -#include "WorldModel.h" -#include "ModelInstance.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 (std::fabs(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(nullptr), iFlags(nullptr) - { - *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 = nullptr; - if (other.iFlags) - { - iFlags = new uint8[iTilesX * iTilesY]; - memcpy(iFlags, other.iFlags, iTilesX * iTilesY); - } - else - iFlags = nullptr; - 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_f < 0.0f || tx >= iTilesX) - return false; - float ty_f = (pos.y - iCorner.y)/LIQUID_TILE_SIZE; - uint32 ty = uint32(ty_f); - if (ty_f < 0.0f || 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 = false; - if (fwrite(&iTilesX, sizeof(uint32), 1, wf) == 1 && - fwrite(&iTilesY, sizeof(uint32), 1, wf) == 1 && - fwrite(&iCorner, sizeof(Vector3), 1, wf) == 1 && - fwrite(&iType, sizeof(uint32), 1, wf) == 1) - { - uint32 size = (iTilesX + 1) * (iTilesY + 1); - if (fwrite(iHeight, sizeof(float), size, wf) == size) - { - size = iTilesX*iTilesY; - result = fwrite(iFlags, sizeof(uint8), size, wf) == size; - } - } - - return result; - } - - bool WmoLiquid::readFromFile(FILE* rf, WmoLiquid* &out) - { - bool result = false; - WmoLiquid* liquid = new WmoLiquid(); - - if (fread(&liquid->iTilesX, sizeof(uint32), 1, rf) == 1 && - fread(&liquid->iTilesY, sizeof(uint32), 1, rf) == 1 && - fread(&liquid->iCorner, sizeof(Vector3), 1, rf) == 1 && - fread(&liquid->iType, sizeof(uint32), 1, rf) == 1) - { - uint32 size = (liquid->iTilesX + 1) * (liquid->iTilesY + 1); - liquid->iHeight = new float[size]; - if (fread(liquid->iHeight, sizeof(float), size, rf) == size) - { - size = liquid->iTilesX * liquid->iTilesY; - liquid->iFlags = new uint8[size]; - result = fread(liquid->iFlags, sizeof(uint8), size, rf) == size; - } - } - - if (!result) - delete liquid; - else - 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(nullptr) - { - 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 = 0; - uint32 count = 0; - triangles.clear(); - vertices.clear(); - delete iLiquid; - iLiquid = NULL; - - 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.empty()) - 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.empty() || !iBound.contains(pos)) - return false; - GModelRayCallback callback(triangles, vertices); - Vector3 rPos = pos - 0.1f * down; - float dist = G3D::finf(); - 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 - { - if (iLiquid) - return 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::finf()), zDist(G3D::finf()), 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.empty()) - 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.empty()) - 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; - - uint32 chunkSize, count; - bool 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 = 0; - uint32 count = 0; - 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; - } -} diff --git a/src/server/collision/Models/WorldModel.h b/src/server/collision/Models/WorldModel.h deleted file mode 100644 index 6a901a59fdf..00000000000 --- a/src/server/collision/Models/WorldModel.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * 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, see <http://www.gnu.org/licenses/>. - */ - -#ifndef _WORLDMODEL_H -#define _WORLDMODEL_H - -#include <G3D/HashTrait.h> -#include <G3D/Vector3.h> -#include <G3D/AABox.h> -#include <G3D/Ray.h> -#include "BoundingIntervalHierarchy.h" - -#include "Define.h" - -namespace VMAP -{ - class TreeNode; - struct AreaInfo; - struct LocationInfo; - - class MeshTriangle - { - public: - MeshTriangle() : idx0(0), idx1(0), idx2(0) { } - 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 G3D::Vector3 &corner, uint32 type); - WmoLiquid(const WmoLiquid &other); - ~WmoLiquid(); - WmoLiquid& operator=(const WmoLiquid &other); - bool GetLiquidHeight(const G3D::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() : iTilesX(0), iTilesY(0), iCorner(), iType(0), iHeight(NULL), iFlags(NULL) { } - uint32 iTilesX; //!< number of tiles in x direction, each - uint32 iTilesY; - G3D::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 - public: - void getPosInfo(uint32 &tilesX, uint32 &tilesY, G3D::Vector3 &corner) const; - }; - - /*! holding additional info for WMO group files */ - class GroupModel - { - public: - GroupModel() : iBound(), iMogpFlags(0), iGroupWMOID(0), iLiquid(NULL) { } - GroupModel(const GroupModel &other); - GroupModel(uint32 mogpFlags, uint32 groupWMOID, const G3D::AABox &bound): - iBound(bound), iMogpFlags(mogpFlags), iGroupWMOID(groupWMOID), iLiquid(NULL) { } - ~GroupModel() { delete iLiquid; } - - //! pass mesh data to object and create BIH. Passed vectors get get swapped with old geometry! - void setMeshData(std::vector<G3D::Vector3> &vert, std::vector<MeshTriangle> &tri); - void setLiquidData(WmoLiquid*& liquid) { iLiquid = liquid; liquid = NULL; } - bool IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const; - bool IsInsideObject(const G3D::Vector3 &pos, const G3D::Vector3 &down, float &z_dist) const; - bool GetLiquidLevel(const G3D::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<G3D::Vector3> vertices; - std::vector<MeshTriangle> triangles; - BIH meshTree; - WmoLiquid* iLiquid; - public: - void getMeshData(std::vector<G3D::Vector3> &vertices, std::vector<MeshTriangle> &triangles, WmoLiquid* &liquid); - }; - /*! 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; - public: - void getGroupModels(std::vector<GroupModel> &groupModels); - }; -} // namespace VMAP - -#endif // _WORLDMODEL_H |
