diff options
author | Subv2112 <s.v.h21@hotmail.com> | 2012-02-03 16:03:52 -0500 |
---|---|---|
committer | Subv <s.v.h21@hotmail.com> | 2012-02-09 13:58:22 -0500 |
commit | 93d199f04382fe3c7f6f08f59fd2ad058568679a (patch) | |
tree | b698029a6cf0649bed6689cd0aa4414d8ad1aa42 /src/server/collision | |
parent | 229d4119e887fa6079a6e0b093860e11b5facb63 (diff) |
Core/Collision: Ported dynamic line of sight patch by Silverice from MaNGOS and
added lots of improvements
Please re-extract vmaps
Diffstat (limited to 'src/server/collision')
-rwxr-xr-x | src/server/collision/BoundingIntervalHierarchy.h | 22 | ||||
-rw-r--r-- | src/server/collision/BoundingIntervalHierarchyWrapper.h | 109 | ||||
-rw-r--r-- | src/server/collision/CMakeLists.txt | 27 | ||||
-rw-r--r-- | src/server/collision/DynamicTree.cpp | 206 | ||||
-rw-r--r-- | src/server/collision/DynamicTree.h | 60 | ||||
-rw-r--r-- | src/server/collision/Maps/TileAssembler.cpp | 388 | ||||
-rwxr-xr-x | src/server/collision/Maps/TileAssembler.h | 29 | ||||
-rw-r--r-- | src/server/collision/Models/GameObjectModel.cpp | 175 | ||||
-rw-r--r-- | src/server/collision/Models/GameObjectModel.h | 69 | ||||
-rwxr-xr-x | src/server/collision/Models/WorldModel.h | 2 | ||||
-rw-r--r-- | src/server/collision/RegularGrid.h | 218 | ||||
-rw-r--r-- | src/server/collision/VMapDefinitions.h | 4 |
12 files changed, 1114 insertions, 195 deletions
diff --git a/src/server/collision/BoundingIntervalHierarchy.h b/src/server/collision/BoundingIntervalHierarchy.h index b0c35237a9d..ea70fc3e322 100755 --- a/src/server/collision/BoundingIntervalHierarchy.h +++ b/src/server/collision/BoundingIntervalHierarchy.h @@ -81,13 +81,25 @@ struct AABound class BIH { + private: + void init_empty() + { + tree.clear(); + objects.clear(); + // create space for the first node + tree.push_back(3 << 30); // dummy leaf + tree.insert(tree.end(), 2, 0); + } public: - BIH() {}; - template< class T, class BoundsFunc > - void build(const std::vector<T> &primitives, BoundsFunc &getBounds, uint32 leafSize = 3, bool printStats=false) + BIH() { init_empty(); } + template< class BoundsFunc, class PrimArray > + void build(const PrimArray &primitives, BoundsFunc &getBounds, uint32 leafSize = 3, bool printStats=false) { - if (primitives.empty()) + if (primitives.size() == 0) + { + init_empty(); return; + } buildData dat; dat.maxPrims = leafSize; @@ -397,4 +409,4 @@ class BIH 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 +#endif // _BIH_H
\ No newline at end of file diff --git a/src/server/collision/BoundingIntervalHierarchyWrapper.h b/src/server/collision/BoundingIntervalHierarchyWrapper.h new file mode 100644 index 00000000000..e54a4e653a1 --- /dev/null +++ b/src/server/collision/BoundingIntervalHierarchyWrapper.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2008-2012 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 _BIH_WRAP +#define _BIH_WRAP + +#include "G3D/Table.h" +#include "G3D/Array.h" +#include "G3D/Set.h" +#include "BoundingIntervalHierarchy.h" + + +template<class T, class BoundsFunc = BoundsTrait<T> > +class BIHWrap +{ + template<class RayCallback> + struct MDLCallback + { + const T* const* objects; + RayCallback& _callback; + + MDLCallback(RayCallback& callback, const T* const* objects_array ) : _callback(callback), objects(objects_array){} + + bool operator() (const Ray& ray, uint32 Idx, float& MaxDist, bool /*stopAtFirst*/) + { + if (const T* obj = objects[Idx]) + return _callback(ray, *obj, MaxDist/*, stopAtFirst*/); + return false; + } + + void operator() (const Vector3& p, uint32 Idx) + { + if (const T* obj = objects[Idx]) + _callback(p, *obj); + } + }; + + typedef G3D::Array<const T*> ObjArray; + + BIH m_tree; + ObjArray m_objects; + G3D::Table<const T*, uint32> m_obj2Idx; + G3D::Set<const T*> m_objects_to_push; + int unbalanced_times; + +public: + BIHWrap() : unbalanced_times(0) {} + + void insert(const T& obj) + { + ++unbalanced_times; + m_objects_to_push.insert(&obj); + } + + void remove(const T& obj) + { + ++unbalanced_times; + uint32 Idx = 0; + const T * temp; + if (m_obj2Idx.getRemove(&obj, temp, Idx)) + m_objects[Idx] = NULL; + else + m_objects_to_push.remove(&obj); + } + + void balance() + { + if (unbalanced_times == 0) + return; + + unbalanced_times = 0; + m_objects.fastClear(); + m_obj2Idx.getKeys(m_objects); + m_objects_to_push.getMembers(m_objects); + + m_tree.build(m_objects, BoundsFunc::getBounds2); + } + + template<typename RayCallback> + void intersectRay(const Ray& ray, RayCallback& intersectCallback, float& maxDist) const + { + MDLCallback<RayCallback> temp_cb(intersectCallback, m_objects.getCArray()); + m_tree.intersectRay(ray, temp_cb, maxDist, true); + } + + template<typename IsectCallback> + void intersectPoint(const Vector3& point, IsectCallback& intersectCallback) const + { + MDLCallback<IsectCallback> callback(intersectCallback, m_objects.getCArray()); + m_tree.intersectPoint(point, callback); + } +}; + +#endif // _BIH_WRAP
\ No newline at end of file diff --git a/src/server/collision/CMakeLists.txt b/src/server/collision/CMakeLists.txt index e2e182626c7..9fc696ab19a 100644 --- a/src/server/collision/CMakeLists.txt +++ b/src/server/collision/CMakeLists.txt @@ -39,9 +39,36 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Database ${CMAKE_SOURCE_DIR}/src/server/shared/Debugging ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic + ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference ${CMAKE_SOURCE_DIR}/src/server/shared/Logging ${CMAKE_SOURCE_DIR}/src/server/shared/Threading + ${CMAKE_SOURCE_DIR}/src/server/shared/Packets + ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities + ${CMAKE_SOURCE_DIR}/src/server/shared/DataStores + ${CMAKE_SOURCE_DIR}/src/server/game/Addons ${CMAKE_SOURCE_DIR}/src/server/game/Conditions + ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Item + ${CMAKE_SOURCE_DIR}/src/server/game/Entities/GameObject + ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Creature + ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object + ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object/Updates + ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Unit + ${CMAKE_SOURCE_DIR}/src/server/game/Combat + ${CMAKE_SOURCE_DIR}/src/server/game/Loot + ${CMAKE_SOURCE_DIR}/src/server/game/Miscellaneous + ${CMAKE_SOURCE_DIR}/src/server/game/Grids + ${CMAKE_SOURCE_DIR}/src/server/game/Grids/Cells + ${CMAKE_SOURCE_DIR}/src/server/game/Grids/Notifiers + ${CMAKE_SOURCE_DIR}/src/server/game/Maps + ${CMAKE_SOURCE_DIR}/src/server/game/DataStores + ${CMAKE_SOURCE_DIR}/src/server/game/Movement/Waypoints + ${CMAKE_SOURCE_DIR}/src/server/game/Movement/Spline + ${CMAKE_SOURCE_DIR}/src/server/game/Movement + ${CMAKE_SOURCE_DIR}/src/server/game/Server + ${CMAKE_SOURCE_DIR}/src/server/game/Server/Protocol + ${CMAKE_SOURCE_DIR}/src/server/game/World + ${CMAKE_SOURCE_DIR}/src/server/game/Spells + ${CMAKE_SOURCE_DIR}/src/server/game/Spells/Auras ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/Management ${CMAKE_CURRENT_SOURCE_DIR}/Maps diff --git a/src/server/collision/DynamicTree.cpp b/src/server/collision/DynamicTree.cpp new file mode 100644 index 00000000000..1d6877d1209 --- /dev/null +++ b/src/server/collision/DynamicTree.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2008-2012 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 "DynamicTree.h" +//#include "QuadTree.h" +//#include "RegularGrid.h" +#include "BoundingIntervalHierarchyWrapper.h" + +#include "Log.h" +#include "RegularGrid.h" +#include "Timer.h" +#include "GameObjectModel.h" +#include "ModelInstance.h" + +using VMAP::ModelInstance; +using G3D::Ray; + +template<> struct HashTrait< GameObjectModel>{ + static size_t hashCode(const GameObjectModel& g) { return (size_t)(void*)&g; } +}; + +template<> struct PositionTrait< GameObjectModel> { + static void getPosition(const GameObjectModel& g, Vector3& p) { p = g.getPosition(); } +}; + +template<> struct BoundsTrait< GameObjectModel> { + static void getBounds(const GameObjectModel& g, G3D::AABox& out) { out = g.getBounds();} + static void getBounds2(const GameObjectModel* g, G3D::AABox& out) { out = g->getBounds();} +}; + +static bool operator == (const GameObjectModel& mdl, const GameObjectModel& mdl2){ + return &mdl == &mdl2; +} + + +int valuesPerNode = 5, numMeanSplits = 3; + +int UNBALANCED_TIMES_LIMIT = 5; +int CHECK_TREE_PERIOD = 200; + +typedef RegularGrid2D<GameObjectModel, BIHWrap<GameObjectModel> > ParentTree; + +struct DynTreeImpl : public ParentTree/*, public Intersectable*/ +{ + typedef GameObjectModel Model; + typedef ParentTree base; + + DynTreeImpl() : + rebalance_timer(CHECK_TREE_PERIOD), + unbalanced_times(0) + { + } + + void insert(const Model& mdl) + { + base::insert(mdl); + ++unbalanced_times; + } + + void remove(const Model& mdl) + { + base::remove(mdl); + ++unbalanced_times; + } + + void balance() + { + base::balance(); + unbalanced_times = 0; + } + + void update(uint32 difftime) + { + if (!size()) + return; + + rebalance_timer.Update(difftime); + if (rebalance_timer.Passed()) + { + rebalance_timer.Reset(CHECK_TREE_PERIOD); + if (unbalanced_times > 0) + balance(); + } + } + + TimeTrackerSmall rebalance_timer; + int unbalanced_times; +}; + +DynamicMapTree::DynamicMapTree() : impl(*new DynTreeImpl()) +{ +} + +DynamicMapTree::~DynamicMapTree() +{ + delete &impl; +} + +void DynamicMapTree::insert(const GameObjectModel& mdl) +{ + impl.insert(mdl); +} + +void DynamicMapTree::remove(const GameObjectModel& mdl) +{ + impl.remove(mdl); +} + +bool DynamicMapTree::contains(const GameObjectModel& mdl) const +{ + return impl.contains(mdl); +} + +void DynamicMapTree::balance() +{ + impl.balance(); +} + +int DynamicMapTree::size() const +{ + return impl.size(); +} + +void DynamicMapTree::update(uint32 t_diff) +{ + impl.update(t_diff); +} + +struct DynamicTreeIntersectionCallback +{ + bool did_hit; + uint32 phase_mask; + DynamicTreeIntersectionCallback(uint32 phasemask) : did_hit(false), phase_mask(phasemask) {} + bool operator()(const Ray& r, const GameObjectModel& obj, float& distance) + { + did_hit = obj.intersectRay(r, distance, true, phase_mask); + return did_hit; + } + bool didHit() const { return did_hit;} +}; + +struct DynamicTreeIntersectionCallback_WithLogger +{ + bool did_hit; + uint32 phase_mask; + DynamicTreeIntersectionCallback_WithLogger(uint32 phasemask) : did_hit(false), phase_mask(phasemask) + { + sLog->outDebug(LOG_FILTER_MAPS, "Dynamic Intersection log"); + } + bool operator()(const Ray& r, const GameObjectModel& obj, float& distance) + { + sLog->outDebug(LOG_FILTER_MAPS, "testing intersection with %s", obj.name.c_str()); + bool hit = obj.intersectRay(r, distance, true, phase_mask); + if (hit) + { + did_hit = true; + sLog->outDebug(LOG_FILTER_MAPS, "result: intersects"); + } + return hit; + } + bool didHit() const { return did_hit;} +}; + +bool DynamicMapTree::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const +{ + Vector3 v1(x1,y1,z1), v2(x2,y2,z2); + + float maxDist = (v2 - v1).magnitude(); + + if (!G3D::fuzzyGt(maxDist, 0) ) + return true; + + Ray r(v1, (v2-v1) / maxDist); + DynamicTreeIntersectionCallback callback(phasemask); + impl.intersectRay(r, callback, maxDist, v2); + + return !callback.did_hit; +} + +float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist, uint32 phasemask) const +{ + Vector3 v(x,y,z); + Ray r(v, Vector3(0,0,-1)); + DynamicTreeIntersectionCallback callback(phasemask); + impl.intersectZAllignedRay(r, callback, maxSearchDist); + + if (callback.didHit()) + return v.z - maxSearchDist; + else + return -G3D::inf(); +}
\ No newline at end of file diff --git a/src/server/collision/DynamicTree.h b/src/server/collision/DynamicTree.h new file mode 100644 index 00000000000..ab28641b6ad --- /dev/null +++ b/src/server/collision/DynamicTree.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008-2012 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 _DYNTREE_H +#define _DYNTREE_H + +#include <G3D/Matrix3.h> +#include <G3D/Vector3.h> +#include <G3D/AABox.h> +#include <G3D/Ray.h> + +//#include "ModelInstance.h" +#include "Define.h" +//#include "GameObjectModel.h" + +namespace G3D +{ + class Vector3; +} + +using G3D::Vector3; +class GameObjectModel; + +class DynamicMapTree +{ + struct DynTreeImpl& impl; +public: + + DynamicMapTree(); + ~DynamicMapTree(); + + bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const; + float getHeight(float x, float y, float z, float maxSearchDist, uint32 phasemask) const; + + void insert(const GameObjectModel&); + void remove(const GameObjectModel&); + bool contains(const GameObjectModel&) const; + int size() const; + + void balance(); + void update(uint32 diff); +}; + +#endif // _DYNTREE_H diff --git a/src/server/collision/Maps/TileAssembler.cpp b/src/server/collision/Maps/TileAssembler.cpp index 355ef6b1944..62968e4dedd 100644 --- a/src/server/collision/Maps/TileAssembler.cpp +++ b/src/server/collision/Maps/TileAssembler.cpp @@ -16,7 +16,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "WorldModel.h" #include "TileAssembler.h" #include "MapTree.h" #include "BoundingIntervalHierarchy.h" @@ -71,7 +70,6 @@ namespace VMAP bool TileAssembler::convertWorld2() { - std::set<std::string> spawnedModelFiles; bool success = readMapSpawns(); if (!success) return false; @@ -178,6 +176,8 @@ namespace VMAP // break; //test, extract only first map; TODO: remvoe this line } + // add an object models, listed in temp_gameobject_models file + exportGameobjectModels(); // export objects std::cout << "\nConverting Model Files" << std::endl; for (std::set<std::string>::iterator mfile = spawnedModelFiles.begin(); mfile != spawnedModelFiles.end(); ++mfile) @@ -251,99 +251,40 @@ namespace VMAP 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()); + WorldModel_Raw raw_model; + if (!raw_model.Read(modelFilename.c_str())) return false; - } + uint32 groups = raw_model.groupsArray.size(); + if (groups != 1) + printf("Warning: '%s' does not seem to be a M2 model!\n", modelFilename.c_str()); + 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++; - // only use this for array deletes - #define READ_OR_RETURN_WITH_DELETE(V, S) if (fread((V), (S), 1, rf) != 1) { \ - fclose(rf); printf("readfail, op = %i\n", readOperation); delete[] V; 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)); + std::vector<Vector3>& vertices = raw_model.groupsArray[g].vertexArray; - if (nvectors >0) - { - vectorarray = new float[nvectors*3]; - READ_OR_RETURN_WITH_DELETE(vectorarray, nvectors*sizeof(float)*3); - } - else + if (vertices.empty()) { std::cout << "error: model '" << spawn.name << "' has no geometry!" << std::endl; - fclose(rf); - return false; + continue; } - for (uint32 i=0, indexNo=0; indexNo<nvectors; indexNo++, i+=3) + uint32 nvectors = vertices.size(); + for (uint32 i = 0; i < nvectors; ++i) { - Vector3 v = Vector3(vectorarray[i+0], vectorarray[i+1], vectorarray[i+2]); - v = modelPosition.transform(v); + Vector3 v = modelPosition.transform(vertices[i]); if (boundEmpty) modelBound = AABox(v, v), boundEmpty=false; else modelBound.merge(v); } - delete[] vectorarray; - // drop of temporary use defines - #undef READ_OR_RETURN - #undef READ_OR_RETURN_WITH_DELETE - #undef CMP_OR_RETURN } spawn.iBound = modelBound + spawn.iPos; spawn.flags |= MOD_HAS_BOUND; - fclose(rf); return true; } @@ -363,150 +304,221 @@ namespace VMAP if (filename.length() >0) filename.push_back('/'); filename.append(pModelFilename); - FILE* rf = fopen(filename.c_str(), "rb"); - if (!rf) - { - printf("ERROR: Can't open model file in form: %s", pModelFilename.c_str()); - printf("... or form: %s", filename.c_str() ); + WorldModel_Raw raw_model; + if (!raw_model.Read(filename.c_str())) return false; + + // write WorldModel + WorldModel model; + model.setRootWmoID(raw_model.RootWMOID); + if (raw_model.groupsArray.size()) + { + std::vector<GroupModel> groupsArray; + + uint32 groups = raw_model.groupsArray.size(); + for (uint32 g = 0; g < groups; ++g) + { + GroupModel_Raw& raw_group = raw_model.groupsArray[g]; + groupsArray.push_back(GroupModel(raw_group.mogpflags, raw_group.GroupWMOID, raw_group.bounds )); + groupsArray.back().setMeshData(raw_group.vertexArray, raw_group.triangles); + groupsArray.back().setLiquidData(raw_group.liquid); + } + + model.setGroupModels(groupsArray); } + + success = model.writeFile(iDestDir + "/" + pModelFilename + ".vmo"); + //std::cout << "readRawFile2: '" << pModelFilename << "' tris: " << nElements << " nodes: " << nNodes << std::endl; + return success; + } + + void TileAssembler::exportGameobjectModels() + { + FILE* model_list = fopen((iSrcDir + "/" + GAMEOBJECT_MODELS).c_str(), "rb"); + FILE* model_list_copy = fopen((iDestDir + "/" + GAMEOBJECT_MODELS).c_str(), "wb"); + if (!model_list || !model_list_copy) + return; + + uint32 name_length, displayId; + char buff[500]; + while (!feof(model_list)) + { + fread(&displayId,sizeof(uint32),1,model_list); + fread(&name_length,sizeof(uint32),1,model_list); - char ident[8]; + if (name_length >= sizeof(buff)) + { + std::cout << "\nFile 'temp_gameobject_models' seems to be corrupted" << std::endl; + break; + } + + fread(&buff,sizeof(char),name_length,model_list); + std::string model_name(buff, name_length); + + WorldModel_Raw raw_model; + if ( !raw_model.Read((iSrcDir + "/" + model_name).c_str()) ) + continue; - int readOperation = 1; + spawnedModelFiles.insert(model_name); + AABox bounds; + bool boundEmpty = true; + for (uint32 g = 0; g < raw_model.groupsArray.size(); ++g) + { + std::vector<Vector3>& vertices = raw_model.groupsArray[g].vertexArray; + + uint32 nvectors = vertices.size(); + for (uint32 i = 0; i < nvectors; ++i) + { + Vector3& v = vertices[i]; + if (boundEmpty) + bounds = AABox(v, v), boundEmpty = false; + else + bounds.merge(v); + } + } + + fwrite(&displayId,sizeof(uint32),1,model_list_copy); + fwrite(&name_length,sizeof(uint32),1,model_list_copy); + fwrite(&buff,sizeof(char),name_length,model_list_copy); + fwrite(&bounds.low(),sizeof(Vector3),1,model_list_copy); + fwrite(&bounds.high(),sizeof(Vector3),1,model_list_copy); + } + fclose(model_list); + fclose(model_list_copy); + } // 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++; + fclose(rf); printf("readfail, op = %i\n", readOperation); return(false); } #define READ_OR_RETURN_WITH_DELETE(V, S) if (fread((V), (S), 1, rf) != 1) { \ - fclose(rf); printf("readfail, op = %i\n", readOperation); delete[] V; return(false); }readOperation++; + fclose(rf); printf("readfail, op = %i\n", readOperation); delete[] V; return(false); }; #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; - uint32 RootWMOID; + bool GroupModel_Raw::Read(FILE* rf) + { char blockId[5]; blockId[4] = 0; int blocksize; - - READ_OR_RETURN(&groups, sizeof(uint32)); - READ_OR_RETURN(&RootWMOID, sizeof(uint32)); - - std::vector<GroupModel> groupsArray; - - for (uint32 g=0; g<groups; ++g) + int readOperation = 0; + + READ_OR_RETURN(&mogpflags, sizeof(uint32)); + READ_OR_RETURN(&GroupWMOID, sizeof(uint32)); + + + Vector3 vec1, vec2; + READ_OR_RETURN(&vec1, sizeof(Vector3)); + + READ_OR_RETURN(&vec2, sizeof(Vector3)); + bounds.set(vec1, vec2); + + READ_OR_RETURN(&liquidflags, sizeof(uint32)); + + // 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(uint32)); + for (uint32 b=0; b<branches; ++b) { - std::vector<MeshTriangle> triangles; - std::vector<Vector3> vertexArray; + uint32 indexes; + // indexes for each branch (not used jet) + READ_OR_RETURN(&indexes, sizeof(uint32)); + } - uint32 mogpflags, GroupWMOID; - READ_OR_RETURN(&mogpflags, sizeof(uint32)); - READ_OR_RETURN(&GroupWMOID, sizeof(uint32)); + // ---- indexes + READ_OR_RETURN(&blockId, 4); + CMP_OR_RETURN(blockId, "INDX"); + READ_OR_RETURN(&blocksize, sizeof(int)); + uint32 nindexes; + READ_OR_RETURN(&nindexes, sizeof(uint32)); + if (nindexes >0) + { + uint16 *indexarray = new uint16[nindexes]; + READ_OR_RETURN_WITH_DELETE(indexarray, nindexes*sizeof(uint16)); + triangles.reserve(nindexes / 3); + for (uint32 i=0; i<nindexes; i+=3) + triangles.push_back(MeshTriangle(indexarray[i], indexarray[i+1], indexarray[i+2])); - float bbox1[3], bbox2[3]; - READ_OR_RETURN(bbox1, sizeof(float)*3); - READ_OR_RETURN(bbox2, sizeof(float)*3); + delete[] indexarray; + } - uint32 liquidflags; - READ_OR_RETURN(&liquidflags, sizeof(uint32)); + // ---- 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)); - // 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(uint32)); - for (uint32 b=0; b<branches; ++b) - { - uint32 indexes; - // indexes for each branch (not used jet) - READ_OR_RETURN(&indexes, sizeof(uint32)); - } - - // ---- indexes - READ_OR_RETURN(&blockId, 4); - CMP_OR_RETURN(blockId, "INDX"); - READ_OR_RETURN(&blocksize, sizeof(int)); - uint32 nindexes; - READ_OR_RETURN(&nindexes, sizeof(uint32)); - if (nindexes >0) - { - uint16 *indexarray = new uint16[nindexes]; - READ_OR_RETURN_WITH_DELETE(indexarray, nindexes*sizeof(uint16)); - for (uint32 i=0; i<nindexes; i+=3) - { - triangles.push_back(MeshTriangle(indexarray[i], indexarray[i+1], indexarray[i+2])); - } - delete[] indexarray; - } + if (nvectors >0) + { + float *vectorarray = new float[nvectors*3]; + READ_OR_RETURN_WITH_DELETE(vectorarray, nvectors*sizeof(float)*3); + for (uint32 i=0; i<nvectors; ++i) + vertexArray.push_back( Vector3(vectorarray + 3*i) ); - // ---- vectors + delete[] vectorarray; + } + // ----- liquid + liquid = 0; + if (liquidflags& 1) + { + WMOLiquidHeader hlq; READ_OR_RETURN(&blockId, 4); - CMP_OR_RETURN(blockId, "VERT"); + CMP_OR_RETURN(blockId, "LIQU"); READ_OR_RETURN(&blocksize, sizeof(int)); - uint32 nvectors; - READ_OR_RETURN(&nvectors, sizeof(uint32)); + 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); + } + + return true; + } - if (nvectors >0) - { - float *vectorarray = new float[nvectors*3]; - READ_OR_RETURN_WITH_DELETE(vectorarray, nvectors*sizeof(float)*3); - for (uint32 i=0; i<nvectors; ++i) - { - 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)); - READ_OR_RETURN(&hlq, sizeof(WMOLiquidHeader)); - liquid = new WmoLiquid(hlq.xtiles, hlq.ytiles, Vector3(hlq.pos_x, hlq.pos_y, hlq.pos_z), hlq.type); - uint32 size = hlq.xverts*hlq.yverts; - READ_OR_RETURN(liquid->GetHeightStorage(), size*sizeof(float)); - size = hlq.xtiles*hlq.ytiles; - READ_OR_RETURN(liquid->GetFlagsStorage(), size); - } - groupsArray.push_back(GroupModel(mogpflags, GroupWMOID, AABox(Vector3(bbox1), Vector3(bbox2)))); - groupsArray.back().setMeshData(vertexArray, triangles); - groupsArray.back().setLiquidData(liquid); + GroupModel_Raw::~GroupModel_Raw() + { + delete liquid; + } + + bool WorldModel_Raw::Read(const char * path) + { + FILE* rf = fopen(path, "rb"); + if (!rf) + { + printf("ERROR: Can't open raw model file: %s\n", path); + return false; + } + + char ident[8]; + int readOperation = 0; - // drop of temporary use defines - #undef READ_OR_RETURN - #undef READ_OR_RETURN_WITH_DELETE - #undef CMP_OR_RETURN + READ_OR_RETURN(&ident, 8); + CMP_OR_RETURN(ident, RAW_VMAP_MAGIC); - } - fclose(rf); + // 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)); - // write WorldModel - WorldModel model; - model.setRootWmoID(RootWMOID); - if (!groupsArray.empty()) - { - model.setGroupModels(groupsArray); + uint32 groups; + READ_OR_RETURN(&groups, sizeof(uint32)); + READ_OR_RETURN(&RootWMOID, sizeof(uint32)); - std::string worldModelFileName(iDestDir); - worldModelFileName.push_back('/'); - worldModelFileName.append(pModelFilename).append(".vmo"); - success = model.writeFile(worldModelFileName); - } + groupsArray.resize(groups); + bool succeed = true; + for (uint32 g = 0; g < groups && succeed; ++g) + succeed = groupsArray[g].Read(rf); - //std::cout << "readRawFile2: '" << pModelFilename << "' tris: " << nElements << " nodes: " << nNodes << std::endl; - return success; + fclose(rf); + return succeed; } + + // drop of temporary use defines + #undef READ_OR_RETURN + #undef CMP_OR_RETURN } diff --git a/src/server/collision/Maps/TileAssembler.h b/src/server/collision/Maps/TileAssembler.h index 6128a0d2a53..554940a4663 100755 --- a/src/server/collision/Maps/TileAssembler.h +++ b/src/server/collision/Maps/TileAssembler.h @@ -22,8 +22,10 @@ #include <G3D/Vector3.h> #include <G3D/Matrix3.h> #include <map> +#include <set> #include "ModelInstance.h" +#include "WorldModel.h" namespace VMAP { @@ -61,6 +63,31 @@ namespace VMAP typedef std::map<uint32, MapSpawns*> MapData; //=============================================== + struct GroupModel_Raw + { + uint32 mogpflags; + uint32 GroupWMOID; + + G3D::AABox bounds; + uint32 liquidflags; + std::vector<MeshTriangle> triangles; + std::vector<G3D::Vector3> vertexArray; + class WmoLiquid *liquid; + + GroupModel_Raw() : liquid(0) {} + ~GroupModel_Raw(); + + bool Read(FILE * f); + }; + + struct WorldModel_Raw + { + uint32 RootWMOID; + std::vector<GroupModel_Raw> groupsArray; + + bool Read(const char * path); + }; + class TileAssembler { private: @@ -70,6 +97,7 @@ namespace VMAP G3D::Table<std::string, unsigned int > iUniqueNameIds; unsigned int iCurrentUniqueNameId; MapData mapData; + std::set<std::string> spawnedModelFiles; public: TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName); @@ -78,6 +106,7 @@ namespace VMAP bool convertWorld2(); bool readMapSpawns(); bool calculateTransformedBound(ModelSpawn &spawn); + void exportGameobjectModels(); bool convertRawFile(const std::string& pModelFilename); void setModelNameFilterMethod(bool (*pFilterMethod)(char *pName)) { iFilterMethod = pFilterMethod; } diff --git a/src/server/collision/Models/GameObjectModel.cpp b/src/server/collision/Models/GameObjectModel.cpp new file mode 100644 index 00000000000..5ad984fcb4b --- /dev/null +++ b/src/server/collision/Models/GameObjectModel.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2008-2012 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 "GameObject.h" +#include "Creature.h" +#include "TemporarySummon.h" +#include "Object.h" +#include "DBCStores.h" + +using G3D::Vector3; +using G3D::Ray; +using G3D::AABox; + +struct GameobjectModelData +{ + GameobjectModelData(const std::string& name_, const AABox& box) : + name(name_), bound(box) {} + + AABox bound; + std::string name; +}; + +typedef UNORDERED_MAP<uint32, GameobjectModelData> ModelList; +ModelList model_list; + +void LoadGameObjectModelList() +{ + FILE* model_list_file = fopen((sWorld->GetDataPath() + "vmaps/" + VMAP::GAMEOBJECT_MODELS).c_str(), "rb"); + if (!model_list_file) + return; + + uint32 name_length, displayId; + char buff[500]; + while (!feof(model_list_file)) + { + fread(&displayId,sizeof(uint32),1,model_list_file); + fread(&name_length,sizeof(uint32),1,model_list_file); + + if (name_length >= sizeof(buff)) + { + printf("\nFile '%s' seems to be corrupted", VMAP::GAMEOBJECT_MODELS); + break; + } + + fread(&buff, sizeof(char), name_length,model_list_file); + Vector3 v1, v2; + fread(&v1, sizeof(Vector3), 1, model_list_file); + fread(&v2, sizeof(Vector3), 1, model_list_file); + + model_list.insert + ( + ModelList::value_type( displayId, GameobjectModelData(std::string(buff,name_length),AABox(v1,v2)) ) + ); + } + fclose(model_list_file); +} + +GameObjectModel::~GameObjectModel() +{ + if (iModel) + ((VMAP::VMapManager2*)VMAP::VMapFactory::createOrGetVMapManager())->releaseModelInstance(name); +} + +bool GameObjectModel::initialize(const GameObject& go, const GameObjectDisplayInfoEntry& info) +{ + ModelList::const_iterator it = model_list.find(info.Displayid); + 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()) + { + std::cout << "Model " << it->second.name << " has zero bounds, loading skipped" << std::endl; + return false; + } + + iModel = ((VMAP::VMapManager2*)VMAP::VMapFactory::createOrGetVMapManager())->acquireModelInstance(sWorld->GetDataPath() + "vmaps/", it->second.name); + + if (!iModel) + return false; + + name = it->second.name; + //flags = VMAP::MOD_M2; + //adtId = 0; + //ID = 0; + iPos = Vector3(go.GetPositionX(), go.GetPositionY(), go.GetPositionZ()); + phasemask = go.GetPhaseMask(); + iScale = go.GetFloatValue(OBJECT_FIELD_SCALE_X); + iInvScale = 1.f / iScale; + + G3D::Matrix3 iRotation = G3D::Matrix3::fromEulerAnglesZYX(go.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)); + + this->iBound = rotated_bounds + iPos; +#ifdef SPAWN_CORNERS + // test: + for (int i = 0; i < 8; ++i) + { + Vector3 pos(iBound.corner(i)); + if (Creature* c = const_cast<GameObject&>(go).SummonCreature(24440, pos.x, pos.y, pos.z, 0, TEMPSUMMON_MANUAL_DESPAWN)) + { + c->setFaction(35); + c->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.1f); + } + } +#endif + + return true; +} + +GameObjectModel* GameObjectModel::Create(const GameObject& go) +{ + const GameObjectDisplayInfoEntry* info = sGameObjectDisplayInfoStore.LookupEntry(go.GetGOInfo()->displayId); + if (!info) + return NULL; + + GameObjectModel* mdl = new GameObjectModel(); + if (!mdl->initialize(go, *info)) + { + 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)) + return false; + + float time = ray.intersectionTime(iBound); + if (time == G3D::inf()) + 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; +}
\ No newline at end of file diff --git a/src/server/collision/Models/GameObjectModel.h b/src/server/collision/Models/GameObjectModel.h new file mode 100644 index 00000000000..413061c0de0 --- /dev/null +++ b/src/server/collision/Models/GameObjectModel.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008-2012 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" + +namespace VMAP +{ + class WorldModel; +} + +class GameObject; +struct GameObjectDisplayInfoEntry; + +class GameObjectModel /*, public Intersectable*/ +{ + uint32 phasemask; + G3D::AABox iBound; + G3D::Matrix3 iInvRot; + G3D::Vector3 iPos; + //G3D::Vector3 iRot; + float iInvScale; + float iScale; + VMAP::WorldModel* iModel; + + GameObjectModel() : phasemask(0), iModel(NULL) {} + bool initialize(const GameObject& go, const GameObjectDisplayInfoEntry& info); + +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 intersectRay(const G3D::Ray& Ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask) const; + + static GameObjectModel* Create(const GameObject& go); +}; + +#endif // _GAMEOBJECT_MODEL_H
\ No newline at end of file diff --git a/src/server/collision/Models/WorldModel.h b/src/server/collision/Models/WorldModel.h index 52ecf498700..ebf828e4935 100755 --- a/src/server/collision/Models/WorldModel.h +++ b/src/server/collision/Models/WorldModel.h @@ -80,7 +80,7 @@ namespace VMAP //! 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; } + void setLiquidData(WmoLiquid*& liquid) { iLiquid = liquid; liquid = NULL; } 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; diff --git a/src/server/collision/RegularGrid.h b/src/server/collision/RegularGrid.h new file mode 100644 index 00000000000..be61504bc65 --- /dev/null +++ b/src/server/collision/RegularGrid.h @@ -0,0 +1,218 @@ +#ifndef _REGULAR_GRID_H +#define _REGULAR_GRID_H + + +#include <G3D/Ray.h> +#include <G3D/AABox.h> +#include <G3D/Table.h> +#include <G3D/BoundsTrait.h> +#include <G3D/PositionTrait.h> + +#include "Errors.h" + +using G3D::Vector2; +using G3D::Vector3; +using G3D::AABox; +using G3D::Ray; + +template<class Node> +struct NodeCreator{ + static Node * makeNode(int x, int y) { return new Node();} +}; + +template<class T, +class Node, +class NodeCreatorFunc = NodeCreator<Node>, + /*class BoundsFunc = BoundsTrait<T>,*/ +class PositionFunc = PositionTrait<T> +> +class RegularGrid2D +{ +public: + + enum{ + CELL_NUMBER = 64, + }; + + #define HGRID_MAP_SIZE (533.33333f * 64.f) // shouldn't be changed + #define CELL_SIZE float(HGRID_MAP_SIZE/(float)CELL_NUMBER) + + typedef G3D::Table<const T*, Node*> MemberTable; + + MemberTable memberTable; + Node* nodes[CELL_NUMBER][CELL_NUMBER]; + + RegularGrid2D(){ + memset(nodes, 0, sizeof(nodes)); + } + + ~RegularGrid2D(){ + for (int x = 0; x < CELL_NUMBER; ++x) + for (int y = 0; y < CELL_NUMBER; ++y) + delete nodes[x][y]; + } + + void insert(const T& value) + { + Vector3 pos; + PositionFunc::getPosition(value, pos); + Node& node = getGridFor(pos.x, pos.y); + node.insert(value); + memberTable.set(&value, &node); + } + + void remove(const T& value) + { + memberTable[&value]->remove(value); + // Remove the member + memberTable.remove(&value); + } + + void balance() + { + for (int x = 0; x < CELL_NUMBER; ++x) + for (int y = 0; y < CELL_NUMBER; ++y) + if (Node* n = nodes[x][y]) + n->balance(); + } + + bool contains(const T& value) const { return memberTable.containsKey(&value); } + int size() const { return memberTable.size(); } + + struct Cell + { + int x, y; + bool operator == (const Cell& c2) const { return x == c2.x && y == c2.y;} + + static Cell ComputeCell(float fx, float fy) + { + Cell c = {fx * (1.f/CELL_SIZE) + (CELL_NUMBER/2), fy * (1.f/CELL_SIZE) + (CELL_NUMBER/2)}; + return c; + } + + bool isValid() const { return x >= 0 && x < CELL_NUMBER && y >= 0 && y < CELL_NUMBER;} + }; + + + Node& getGridFor(float fx, float fy) + { + Cell c = Cell::ComputeCell(fx, fy); + return getGrid(c.x, c.y); + } + + Node& getGrid(int x, int y) + { + ASSERT(x < CELL_NUMBER && y < CELL_NUMBER); + if (!nodes[x][y]) + nodes[x][y] = NodeCreatorFunc::makeNode(x,y); + return *nodes[x][y]; + } + + template<typename RayCallback> + void intersectRay(const Ray& ray, RayCallback& intersectCallback, float max_dist) + { + intersectRay(ray, intersectCallback, max_dist, ray.origin() + ray.direction() * max_dist); + } + + template<typename RayCallback> + void intersectRay(const Ray& ray, RayCallback& intersectCallback, float& max_dist, const Vector3& end) + { + Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y); + if (!cell.isValid()) + return; + + Cell last_cell = Cell::ComputeCell(end.x, end.y); + + if (cell == last_cell) + { + if (Node* node = nodes[cell.x][cell.y]) + node->intersectRay(ray, intersectCallback, max_dist); + return; + } + + float voxel = (float)CELL_SIZE; + float kx_inv = ray.invDirection().x, bx = ray.origin().x; + float ky_inv = ray.invDirection().y, by = ray.origin().y; + + int stepX, stepY; + float tMaxX, tMaxY; + if (kx_inv >= 0) + { + stepX = 1; + float x_border = (cell.x+1) * voxel; + tMaxX = (x_border - bx) * kx_inv; + } + else + { + stepX = -1; + float x_border = (cell.x-1) * voxel; + tMaxX = (x_border - bx) * kx_inv; + } + + if (ky_inv >= 0) + { + stepY = 1; + float y_border = (cell.y+1) * voxel; + tMaxY = (y_border - by) * ky_inv; + } + else + { + stepY = -1; + float y_border = (cell.y-1) * voxel; + tMaxY = (y_border - by) * ky_inv; + } + + //int Cycles = std::max((int)ceilf(max_dist/tMaxX),(int)ceilf(max_dist/tMaxY)); + //int i = 0; + + float tDeltaX = voxel * fabs(kx_inv); + float tDeltaY = voxel * fabs(ky_inv); + do + { + if (Node* node = nodes[cell.x][cell.y]) + { + //float enterdist = max_dist; + node->intersectRay(ray, intersectCallback, max_dist); + } + if (cell == last_cell) + break; + if(tMaxX < tMaxY) + { + tMaxX += tDeltaX; + cell.x += stepX; + } + else + { + tMaxY += tDeltaY; + cell.y += stepY; + } + //++i; + } while (cell.isValid()); + } + + template<typename IsectCallback> + void intersectPoint(const Vector3& point, IsectCallback& intersectCallback) + { + Cell cell = Cell::ComputeCell(point.x, point.y); + if (!cell.isValid()) + return; + if (Node* node = nodes[cell.x][cell.y]) + node->intersectPoint(point, intersectCallback); + } + + // Optimized verson of intersectRay function for rays with vertical directions + template<typename RayCallback> + void intersectZAllignedRay(const Ray& ray, RayCallback& intersectCallback, float& max_dist) + { + Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y); + if (!cell.isValid()) + return; + if (Node* node = nodes[cell.x][cell.y]) + node->intersectRay(ray, intersectCallback, max_dist); + } +}; + +#undef CELL_SIZE +#undef HGRID_MAP_SIZE + +#endif
\ No newline at end of file diff --git a/src/server/collision/VMapDefinitions.h b/src/server/collision/VMapDefinitions.h index f7d6f0ddaa1..72a62807b4c 100644 --- a/src/server/collision/VMapDefinitions.h +++ b/src/server/collision/VMapDefinitions.h @@ -24,7 +24,9 @@ namespace VMAP { - const char VMAP_MAGIC[] = "VMAP_3.0"; + const char VMAP_MAGIC[] = "VMAP_4.0"; + const char RAW_VMAP_MAGIC[] = "VMAP004"; // used in extracted vmap files with raw data + const char GAMEOBJECT_MODELS[] = "temp_gameobject_models"; // defined in TileAssembler.cpp currently... bool readChunk(FILE* rf, char *dest, const char *compare, uint32 len); |