diff --git a/CMakeLists.txt b/CMakeLists.txt index 494959cbc..ec126b241 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ #EQEMU_BUILD_LUA #EQEMU_SANITIZE_LUA_LIBS #EQEMU_BUILD_CLIENT_FILES +#EQEMU_USE_MAP_MMFS #EQEMU_MAP_DIR #We set a fairly new version (as of 2013) because I found finding perl was a bit... buggy on older ones @@ -275,6 +276,11 @@ IF(EQEMU_BUILD_LUA) ADD_DEFINITIONS(-DLUA_EQEMU) ENDIF(EQEMU_BUILD_LUA) +OPTION(EQEMU_USE_MAP_MMFS "Create and use Zone Map MMF files." OFF) +IF(EQEMU_USE_MAP_MMFS) + ADD_DEFINITIONS(-DUSE_MAP_MMFS) +ENDIF(EQEMU_USE_MAP_MMFS) + SET(EQEMU_MAP_DIR "./Maps" CACHE STRING "The dir that maps, water maps, and paths are located in.") ADD_DEFINITIONS(-DEQDEBUG=${EQEMU_DEBUG_LEVEL}) diff --git a/changelog.txt b/changelog.txt index 7607bcf14..f1af1009a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,18 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- -== 07/25/216 == +== 07/28/2016 == +Uleat: Implemented zone memory-mapped file usage + - Zone map files are converted to pre-loaded binary files, bypassing the (sometimes) time-consuming raw data transform process + - There are three ways to convert files: + -- Do nothing! The zone bootup process will check for a mmf file and load it, if found, or create it after the 'normal' transform process is complete + -- Use the command line option: zone convert_map .map (for singular conversions) + -- Drop the 'convert_maps_to_mmfs.pl' into your server directory and execute it for a batch conversion + -- Note: Any zone maps not pre-converted will be processed once a zone is booted up that does not have one + - To enable this feature, you must have the 'USE_MAP_MMFS' option checked in cmake and have built binaries on that + - To disable this feature, or if you encouter problems, disable the 'USE_MAP_MMFS' option and rebuild your binaries + - This feature will test the validity of your zlib library. If you get errors/crashes upon conversion, then your zlib1.dll is most likely suspect (check our forum for solutions) + +== 07/25/2016 == mackal: Fix up the SpellBuff struct - THERE MAYBE BUGS - there shouldn't though, most of the hackery was from badly named fields causing confusion diff --git a/utils/scripts/convert_maps_to_mmfs.pl b/utils/scripts/convert_maps_to_mmfs.pl new file mode 100644 index 000000000..4c68c7e18 --- /dev/null +++ b/utils/scripts/convert_maps_to_mmfs.pl @@ -0,0 +1,34 @@ +#!/usr/bin/perl + +########################################################### +#::: Automatic (Map-to-MMF) Conversion Script +#::: Author: Uleat +#::: Purpose: To convert existing zone maps to memory-mapped files +########################################################### + +use Config; + +print("\n"); +print("Zone Map-to-MMF Batch convertor\n"); +print("===============================\n"); +print("\n"); + +if($Config{osname}=~/freebsd|linux/i){ $OS = "Linux"; } +if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; } +print("Operating System is: $Config{osname}\n"); +print("\n"); + +opendir(D, "maps") || die "Can't find directory maps: $!\n"; +my @mapfiles = grep { /\.map$/ && !/_lit/ } readdir(D); +closedir(D); + +foreach my $mapfile (@mapfiles) { + my $result = "Unknown action..\n"; + print("processing map: '$mapfile'\n"); + if($OS eq "Windows"){ $result = `zone convert_map $mapfile`; } + if($OS eq "Linux"){ $result = `./zone convert_map $mapfile`; } + print("-- $result"); +} + +print("\n"); +print("Batch processing complete\n") diff --git a/zone/map.cpp b/zone/map.cpp index d266f9834..5ae79e8ef 100644 --- a/zone/map.cpp +++ b/zone/map.cpp @@ -12,6 +12,48 @@ #include #include + +uint32 EstimateDeflateBuffer(uint32_t len) { + z_stream zstream; + memset(&zstream, 0, sizeof(zstream)); + + zstream.zalloc = Z_NULL; + zstream.zfree = Z_NULL; + zstream.opaque = Z_NULL; + if (deflateInit(&zstream, Z_FINISH) != Z_OK) + return 0; + + return deflateBound(&zstream, len); +} + +uint32_t DeflateData(const char *buffer, uint32_t len, char *out_buffer, uint32_t out_len_max) { + z_stream zstream; + memset(&zstream, 0, sizeof(zstream)); + int zerror; + + zstream.next_in = const_cast(reinterpret_cast(buffer)); + zstream.avail_in = len; + zstream.zalloc = Z_NULL; + zstream.zfree = Z_NULL; + zstream.opaque = Z_NULL; + deflateInit(&zstream, Z_FINISH); + + zstream.next_out = reinterpret_cast(out_buffer); + zstream.avail_out = out_len_max; + zerror = deflate(&zstream, Z_FINISH); + + if (zerror == Z_STREAM_END) + { + deflateEnd(&zstream); + return (uint32_t)zstream.total_out; + } + else + { + zerror = deflateEnd(&zstream); + return 0; + } +} + uint32 InflateData(const char* buffer, uint32 len, char* out_buffer, uint32 out_len_max) { z_stream zstream; int zerror = 0; @@ -241,7 +283,16 @@ Map *Map::LoadMapFile(std::string file) { return nullptr; } -bool Map::Load(std::string filename) { +#ifdef USE_MAP_MMFS +bool Map::Load(std::string filename, bool force_mmf_overwrite) +{ + if (LoadMMF(filename, force_mmf_overwrite)) + return true; +#else +bool Map::Load(std::string filename) +{ +#endif /*USE_MAP_MMFS*/ + FILE *f = fopen(filename.c_str(), "rb"); if(f) { uint32 version; @@ -253,10 +304,22 @@ bool Map::Load(std::string filename) { if(version == 0x01000000) { bool v = LoadV1(f); fclose(f); + +#ifdef USE_MAP_MMFS + if (v) + return SaveMMF(filename, force_mmf_overwrite); +#endif /*USE_MAP_MMFS*/ + return v; } else if(version == 0x02000000) { bool v = LoadV2(f); fclose(f); + +#ifdef USE_MAP_MMFS + if (v) + return SaveMMF(filename, force_mmf_overwrite); +#endif /*USE_MAP_MMFS*/ + return v; } else { fclose(f); @@ -897,3 +960,199 @@ void Map::TranslateVertex(glm::vec3 &v, float tx, float ty, float tz) { v.y = v.y + ty; v.z = v.z + tz; } + +#ifdef USE_MAP_MMFS +inline void strip_map_extension(std::string& map_file_name) +{ + auto ext_off = map_file_name.find(".map"); + if (ext_off != std::string::npos) + map_file_name.erase(ext_off, strlen(".map")); +} + +inline bool add_mmf_extension(std::string& mmf_file_name) +{ + if (mmf_file_name.empty()) + return false; + + mmf_file_name.append(".mmf"); + size_t dot_check = std::count(mmf_file_name.begin(), mmf_file_name.end(), '.'); + + return (dot_check == 1); +} + +bool Map::LoadMMF(const std::string& map_file_name, bool force_mmf_overwrite) +{ + if (force_mmf_overwrite) + return false; + + std::string mmf_file_name = map_file_name; + strip_map_extension(mmf_file_name); + if (!add_mmf_extension(mmf_file_name)) { + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s'", mmf_file_name.c_str()); + return false; + } + + FILE *f = fopen(mmf_file_name.c_str(), "rb"); + if (!f) { + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - could not open file", mmf_file_name.c_str()); + return false; + } + + uint32 file_version; + if (fread(&file_version, sizeof(uint32), 1, f) != 1) { + fclose(f); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - f@file_version", mmf_file_name.c_str()); + return false; + } + + uint32 rm_buffer_size; + if (fread(&rm_buffer_size, sizeof(uint32), 1, f) != 1) { + fclose(f); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - f@rm_buffer_size", mmf_file_name.c_str()); + return false; + } + + uint32 rm_buffer_crc32; + if (fread(&rm_buffer_crc32, sizeof(uint32), 1, f) != 1) { + fclose(f); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - f@rm_buffer_crc32", mmf_file_name.c_str()); + return false; + } + if (rm_buffer_crc32 != /*crc32_check*/ 0) { + fclose(f); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - bad rm_buffer checksum", mmf_file_name.c_str()); + return false; + } + + uint32 mmf_buffer_size; + if (fread(&mmf_buffer_size, sizeof(uint32), 1, f) != 1) { + fclose(f); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - f@mmf_buffer_size", mmf_file_name.c_str()); + return false; + } + + std::vector mmf_buffer(mmf_buffer_size); + if (fread(mmf_buffer.data(), mmf_buffer_size, 1, f) != 1) { + fclose(f); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - f@mmf_buffer", mmf_file_name.c_str()); + return false; + } + + fclose(f); + + std::vector rm_buffer(rm_buffer_size); + uint32 v = InflateData(mmf_buffer.data(), mmf_buffer_size, rm_buffer.data(), rm_buffer_size); + + if (imp) { + imp->rm->release(); + imp->rm = nullptr; + } + else { + imp = new impl; + } + + bool load_success = false; + imp->rm = loadRaycastMesh(rm_buffer, load_success); + if (imp->rm && !load_success) { + imp->rm->release(); + imp->rm = nullptr; + } + + if (!imp->rm) { + delete imp; + imp = nullptr; + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - null RaycastMesh", mmf_file_name.c_str()); + return false; + } + + return true; +} + +bool Map::SaveMMF(const std::string& map_file_name, bool force_mmf_overwrite) +{ + if (!imp || !imp->rm) { + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file - No implementation (map_file_name: '%s')", map_file_name.c_str()); + return false; + } + + std::string mmf_file_name = map_file_name; + strip_map_extension(mmf_file_name); + if (!add_mmf_extension(mmf_file_name)) { + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s'", mmf_file_name.c_str()); + return false; + } + + FILE* f = fopen(mmf_file_name.c_str(), "rb"); + if (f) { + fclose(f); + if (!force_mmf_overwrite) + return true; + } + + std::vector rm_buffer; // size set in MyRaycastMesh::serialize() + serializeRaycastMesh(imp->rm, rm_buffer); + if (rm_buffer.empty()) { + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - empty RaycastMesh buffer", mmf_file_name.c_str()); + return false; + } + + uint32 rm_buffer_size = rm_buffer.size(); + uint32 mmf_buffer_size = EstimateDeflateBuffer(rm_buffer.size()); + + std::vector mmf_buffer(mmf_buffer_size); + + mmf_buffer_size = DeflateData(rm_buffer.data(), rm_buffer.size(), mmf_buffer.data(), mmf_buffer.size()); + if (!mmf_buffer_size) { + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - null MMF buffer size", mmf_file_name.c_str()); + return false; + } + + f = fopen(mmf_file_name.c_str(), "wb"); + if (!f) { + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - could not open file", mmf_file_name.c_str()); + return false; + } + + uint32 file_version = 0; + if (fwrite(&file_version, sizeof(uint32), 1, f) != 1) { + fclose(f); + std::remove(mmf_file_name.c_str()); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - f@file_version", mmf_file_name.c_str()); + return false; + } + + if (fwrite(&rm_buffer_size, sizeof(uint32), 1, f) != 1) { + fclose(f); + std::remove(mmf_file_name.c_str()); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - f@rm_buffer_size", mmf_file_name.c_str()); + return false; + } + + uint32 rm_buffer_crc32 = 0; + if (fwrite(&rm_buffer_crc32, sizeof(uint32), 1, f) != 1) { + fclose(f); + std::remove(mmf_file_name.c_str()); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - f@rm_buffer_crc32", mmf_file_name.c_str()); + return false; + } + + if (fwrite(&mmf_buffer_size, sizeof(uint32), 1, f) != 1) { + fclose(f); + std::remove(mmf_file_name.c_str()); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - f@mmf_buffer_size", mmf_file_name.c_str()); + return false; + } + + if (fwrite(mmf_buffer.data(), mmf_buffer_size, 1, f) != 1) { + fclose(f); + std::remove(mmf_file_name.c_str()); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - f@mmf_buffer", mmf_file_name.c_str()); + return false; + } + + fclose(f); + + return true; +} + +#endif /*USE_MAP_MMFS*/ diff --git a/zone/map.h b/zone/map.h index 5d1b08618..35b5baeda 100644 --- a/zone/map.h +++ b/zone/map.h @@ -42,7 +42,13 @@ public: bool LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const; bool LineIntersectsZoneNoZLeaps(glm::vec3 start, glm::vec3 end, float step_mag, glm::vec3 *result) const; bool CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const; + +#ifdef USE_MAP_MMFS + bool Load(std::string filename, bool force_mmf_overwrite = false); +#else bool Load(std::string filename); +#endif + static Map *LoadMapFile(std::string file); private: void RotateVertex(glm::vec3 &v, float rx, float ry, float rz); @@ -51,6 +57,11 @@ private: bool LoadV1(FILE *f); bool LoadV2(FILE *f); +#ifdef USE_MAP_MMFS + bool LoadMMF(const std::string& map_file_name, bool force_mmf_overwrite); + bool SaveMMF(const std::string& map_file_name, bool force_mmf_overwrite); +#endif /*USE_MAP_MMFS*/ + struct impl; impl *imp; }; diff --git a/zone/net.cpp b/zone/net.cpp index 0f6ad0bbe..25d6f65df 100644 --- a/zone/net.cpp +++ b/zone/net.cpp @@ -116,6 +116,27 @@ int main(int argc, char** argv) { Log.LoadLogSettingsDefaults(); set_exception_handler(); + +#ifdef USE_MAP_MMFS + if (argc == 3 && strcasecmp(argv[1], "convert_map") == 0) { + if (!ZoneConfig::LoadConfig()) + return 1; + Config = ZoneConfig::get(); + + std::string mapfile = argv[2]; + std::transform(mapfile.begin(), mapfile.end(), mapfile.begin(), ::tolower); + std::string filename = Config->MapDir; + filename += mapfile; + + auto m = new Map(); + auto success = m->Load(filename, true); + delete m; + std::cout << mapfile.c_str() << " conversion " << (success ? "succeeded" : "failed") << std::endl; + + return 0; + } +#endif /*USE_MAP_MMFS*/ + QServ = new QueryServ; Log.Out(Logs::General, Logs::Zone_Server, "Loading server configuration.."); diff --git a/zone/raycast_mesh.cpp b/zone/raycast_mesh.cpp index e2e88b100..28427339e 100644 --- a/zone/raycast_mesh.cpp +++ b/zone/raycast_mesh.cpp @@ -914,6 +914,11 @@ public: RmUint32 mMaxNodeCount; NodeAABB *mNodes; TriVector mLeafTriangles; + +#ifdef USE_MAP_MMFS + MyRaycastMesh(std::vector& rm_buffer); + void serialize(std::vector& rm_buffer); +#endif /*USE_MAP_MMFS*/ }; }; @@ -936,4 +941,253 @@ RaycastMesh * createRaycastMesh(RmUint32 vcount, // The number of vertices in t return static_cast< RaycastMesh * >(m); } +#ifdef USE_MAP_MMFS +RaycastMesh* loadRaycastMesh(std::vector& rm_buffer, bool& load_success) +{ + if (rm_buffer.empty()) + return nullptr; + auto m = new MyRaycastMesh(rm_buffer); + load_success = (m->mNodes != nullptr); + + return static_cast(m); +} + +void serializeRaycastMesh(RaycastMesh* rm, std::vector& rm_buffer) +{ + if (!rm) { + rm_buffer.clear(); + return; + } + + static_cast(rm)->serialize(rm_buffer); +} + +MyRaycastMesh::MyRaycastMesh(std::vector& rm_buffer) +{ + mVcount = 0; + mVertices = nullptr; + mTcount = 0; + mIndices = nullptr; + mRaycastTriangles = nullptr; + mFaceNormals = nullptr; + mRaycastFrame = 0; + mMaxNodeCount = 0; + mNodeCount = 0; + mNodes = nullptr; + mRoot = nullptr; + + size_t chunk_size = 0; + size_t bytes_read = 0; + size_t rm_buffer_size_ = rm_buffer.size(); + if (!rm_buffer_size_) + return; + + char* buf = rm_buffer.data(); + + chunk_size = sizeof(RmUint32); + memcpy(&mVcount, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = (sizeof(RmReal) * (3 * mVcount)); + mVertices = (RmReal *)::malloc(chunk_size); + memcpy(mVertices, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = sizeof(RmUint32); + memcpy(&mTcount, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = (sizeof(RmUint32) * (3 * mTcount)); + mIndices = (RmUint32 *)::malloc(chunk_size); + memcpy(mIndices, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = (sizeof(RmUint32) * mTcount); + mRaycastTriangles = (RmUint32 *)::malloc(chunk_size); + memcpy(mRaycastTriangles, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = (sizeof(RmReal) * (3 * mTcount)); + mFaceNormals = (RmReal *)::malloc(chunk_size); + memcpy(mFaceNormals, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = sizeof(RmUint32); + memcpy(&mRaycastFrame, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + RmUint32 lt_size; + chunk_size = sizeof(RmUint32); + memcpy(<_size, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + if (lt_size) { + mLeafTriangles.resize(lt_size); + chunk_size = (sizeof(RmUint32) * lt_size); + memcpy(&mLeafTriangles[0], buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + } + + chunk_size = sizeof(RmUint32); + memcpy(&mNodeCount, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + mMaxNodeCount = mNodeCount; + + mNodes = new NodeAABB[mMaxNodeCount]; + mRoot = &mNodes[0]; + + for (int index = 0; index < mNodeCount; ++index) { + chunk_size = (sizeof(RmReal) * 3); + memcpy(&mNodes[index].mBounds.mMin, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = (sizeof(RmReal) * 3); + memcpy(&mNodes[index].mBounds.mMax, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = sizeof(RmUint32); + memcpy(&mNodes[index].mLeafTriangleIndex, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + RmUint32 lNodeIndex; + chunk_size = sizeof(RmUint32); + memcpy(&lNodeIndex, buf, chunk_size); + if (lNodeIndex != TRI_EOF) + mNodes[index].mLeft = &mNodes[lNodeIndex]; + buf += chunk_size; + bytes_read += chunk_size; + + RmUint32 rNodeIndex; + chunk_size = sizeof(RmUint32); + memcpy(&rNodeIndex, buf, chunk_size); + if (rNodeIndex != TRI_EOF) + mNodes[index].mRight = &mNodes[rNodeIndex]; + buf += chunk_size; + bytes_read += chunk_size; + } + + if (bytes_read != rm_buffer_size_) { + delete[] mNodes; + ::free(mVertices); + ::free(mIndices); + ::free(mFaceNormals); + ::free(mRaycastTriangles); + + mVcount = 0; + mVertices = nullptr; + mTcount = 0; + mIndices = nullptr; + mRaycastTriangles = nullptr; + mFaceNormals = nullptr; + mRaycastFrame = 0; + mLeafTriangles.clear(); + mMaxNodeCount = 0; + mNodeCount = 0; + mNodes = nullptr; + mRoot = nullptr; + } +} + +void MyRaycastMesh::serialize(std::vector& rm_buffer) +{ + rm_buffer.clear(); + + size_t rm_buffer_size_ = 0; + + rm_buffer_size_ += sizeof(RmUint32); // mVcount + rm_buffer_size_ += (sizeof(RmReal) * (3 * mVcount)); // mVertices + rm_buffer_size_ += sizeof(RmUint32); // mTcount + rm_buffer_size_ += (sizeof(RmUint32) * (3 * mTcount)); // mIndices + rm_buffer_size_ += (sizeof(RmUint32) * mTcount); // mRaycastTriangles + rm_buffer_size_ += (sizeof(RmReal) * (3 * mTcount)); // mFaceNormals + rm_buffer_size_ += sizeof(RmUint32); // mRaycastFrame + rm_buffer_size_ += sizeof(RmUint32); // mLeafTriangles.size() + rm_buffer_size_ += (sizeof(RmUint32) * (RmUint32)mLeafTriangles.size()); // mLeafTriangles + rm_buffer_size_ += sizeof(RmUint32); // mNodeCount + rm_buffer_size_ += (sizeof(RmReal) * (3 * mNodeCount)); // mNodes.mBounds.mMin + rm_buffer_size_ += (sizeof(RmReal) * (3 * mNodeCount)); // mNodes.mBounds.mMax + rm_buffer_size_ += (sizeof(RmUint32) * mNodeCount); // mNodes.mLeafTriangleIndex + rm_buffer_size_ += (sizeof(RmUint32) * mNodeCount); // mNodes.mLeft[Index] + rm_buffer_size_ += (sizeof(RmUint32) * mNodeCount); // mNodes.mRight[Index] + + rm_buffer.resize(rm_buffer_size_); + + char* buf = rm_buffer.data(); + + memcpy(buf, &mVcount, sizeof(RmUint32)); + buf += sizeof(RmUint32); + + memcpy(buf, mVertices, (sizeof(RmReal) * (3 * mVcount))); + buf += (sizeof(RmReal) * (3 * mVcount)); + + memcpy(buf, &mTcount, sizeof(RmUint32)); + buf += sizeof(RmUint32); + + memcpy(buf, mIndices, (sizeof(RmUint32) * (3 * mTcount))); + buf += (sizeof(RmUint32) * (3 * mTcount)); + + memcpy(buf, mRaycastTriangles, (sizeof(RmUint32) * mTcount)); + buf += (sizeof(RmUint32) * mTcount); + + if (!mFaceNormals) { + RmReal save_face[3]; + getFaceNormal(0, &save_face[0]); + } + + memcpy(buf, mFaceNormals, (sizeof(RmReal) * (3 * mTcount))); + buf += (sizeof(RmReal) * (3 * mTcount)); + + memcpy(buf, &mRaycastFrame, sizeof(RmUint32)); + buf += sizeof(RmUint32); + + RmUint32 lt_size = (RmUint32)mLeafTriangles.size(); + memcpy(buf, <_size, sizeof(RmUint32)); + buf += sizeof(RmUint32); + + if (lt_size) { + memcpy(buf, &mLeafTriangles[0], (sizeof(RmUint32) * lt_size)); + buf += (sizeof(RmUint32) * lt_size); + } + + memcpy(buf, &mNodeCount, sizeof(RmUint32)); + buf += sizeof(RmUint32); + + for (RmUint32 index = 0; index < mNodeCount; ++index) { + memcpy(buf, &mNodes[index].mBounds.mMin, (sizeof(RmReal) * 3)); + buf += (sizeof(RmReal) * 3); + + memcpy(buf, &mNodes[index].mBounds.mMax, (sizeof(RmReal) * 3)); + buf += (sizeof(RmReal) * 3); + + memcpy(buf, &mNodes[index].mLeafTriangleIndex, sizeof(RmUint32)); + buf += sizeof(RmUint32); + + RmUint32 lNodeIndex = TRI_EOF; + if (mNodes[index].mLeft) + lNodeIndex = ((RmUint32)mNodes[index].mLeft - (RmUint32)mNodes) / sizeof(NodeAABB); + memcpy(buf, &lNodeIndex, sizeof(RmUint32)); + buf += sizeof(RmUint32); + + RmUint32 rNodeIndex = TRI_EOF; + if (mNodes[index].mRight) + rNodeIndex = ((RmUint32)mNodes[index].mRight - (RmUint32)mNodes) / sizeof(NodeAABB); + memcpy(buf, &rNodeIndex, sizeof(RmUint32)); + buf += sizeof(RmUint32); + } +} +#endif /*USE_MAP_MMFS*/ diff --git a/zone/raycast_mesh.h b/zone/raycast_mesh.h index eec2e0ba4..1aaa100cb 100644 --- a/zone/raycast_mesh.h +++ b/zone/raycast_mesh.h @@ -56,5 +56,11 @@ RaycastMesh * createRaycastMesh(RmUint32 vcount, // The number of vertices in t RmReal minAxisSize=0.01f // once a particular axis is less than this size, stop sub-dividing. ); +#ifdef USE_MAP_MMFS +#include + +RaycastMesh* loadRaycastMesh(std::vector& rm_buffer, bool& load_success); +void serializeRaycastMesh(RaycastMesh* rm, std::vector& rm_buffer); +#endif /*USE_MAP_MMFS*/ #endif \ No newline at end of file