aboutsummaryrefslogtreecommitdiff
path: root/src/server/collision
diff options
context:
space:
mode:
authorSubv2112 <s.v.h21@hotmail.com>2012-02-03 16:03:52 -0500
committerSubv <s.v.h21@hotmail.com>2012-02-09 13:58:22 -0500
commit93d199f04382fe3c7f6f08f59fd2ad058568679a (patch)
treeb698029a6cf0649bed6689cd0aa4414d8ad1aa42 /src/server/collision
parent229d4119e887fa6079a6e0b093860e11b5facb63 (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-xsrc/server/collision/BoundingIntervalHierarchy.h22
-rw-r--r--src/server/collision/BoundingIntervalHierarchyWrapper.h109
-rw-r--r--src/server/collision/CMakeLists.txt27
-rw-r--r--src/server/collision/DynamicTree.cpp206
-rw-r--r--src/server/collision/DynamicTree.h60
-rw-r--r--src/server/collision/Maps/TileAssembler.cpp388
-rwxr-xr-xsrc/server/collision/Maps/TileAssembler.h29
-rw-r--r--src/server/collision/Models/GameObjectModel.cpp175
-rw-r--r--src/server/collision/Models/GameObjectModel.h69
-rwxr-xr-xsrc/server/collision/Models/WorldModel.h2
-rw-r--r--src/server/collision/RegularGrid.h218
-rw-r--r--src/server/collision/VMapDefinitions.h4
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);