From cda38d9370ba8f4cddd412e38e11d91504306a2b Mon Sep 17 00:00:00 2001 From: Lynx3d Date: Thu, 8 Jul 2010 23:08:38 +0200 Subject: [PATCH] [10163] Update vmap_extractor to support new vmap implementation. Note: This is not compatible with current assembler, wait for upcoming commits * Now also supports Linux (CMake) and Visual Studio 2010, see README for build and use instructions * Uses libmpq for now, since at project start stormlib did not work properly on 64bit linux. * Should be a lot faster, a few badly written lines ate most CPU time for nothing... Special thanks to arrai and faramir118 for additional code and fixes --- .../vmapExtractor3.exe | Bin 0 -> 121344 bytes contrib/vmap_extractor_v2/.gitignore | 12 +- contrib/vmap_extractor_v2/CMakeLists.txt | 25 + contrib/vmap_extractor_v2/README | 42 + .../vmap_extractor_v2/vmapExtractor_VC80.sln | 19 - .../vmapExtractor_VC80.vcproj | 1000 ----------------- .../vmap_extractor_v2/vmapExtractor_VC90.sln | 19 - .../vmapExtractor_VC90.vcproj | 999 ---------------- .../vmap_extractor_v2/vmapextract/.gitignore | 18 + .../vmapextract/CMakeLists.txt | 16 + .../vmap_extractor_v2/vmapextract/adtfile.cpp | 70 +- .../vmap_extractor_v2/vmapextract/adtfile.h | 10 +- .../vmap_extractor_v2/vmapextract/dbcfile.cpp | 8 +- .../vmap_extractor_v2/vmapextract/dbcfile.h | 4 +- .../vmapextract/loadlib/loadlib.h | 59 + .../vmap_extractor_v2/vmapextract/model.cpp | 75 +- contrib/vmap_extractor_v2/vmapextract/model.h | 8 +- .../vmapextract/modelheaders.h | 4 +- contrib/vmap_extractor_v2/vmapextract/mpq.cpp | 143 --- contrib/vmap_extractor_v2/vmapextract/mpq.h | 80 -- .../vmapextract/mpq_libmpq.cpp | 111 ++ .../vmapextract/mpq_libmpq04.h | 91 ++ contrib/vmap_extractor_v2/vmapextract/vec3d.h | 6 + .../vmapextract/vmapexport.cpp | 440 ++++---- .../vmapextract/vmapexport.h | 13 + .../vmap_extractor_v2/vmapextract/wdtfile.cpp | 16 +- .../vmap_extractor_v2/vmapextract/wdtfile.h | 9 +- contrib/vmap_extractor_v2/vmapextract/wmo.cpp | 369 +++--- contrib/vmap_extractor_v2/vmapextract/wmo.h | 112 +- contrib/vmap_extractor_v2/win/.gitignore | 6 + .../vmap_extractor_v2/win/VC100/.gitignore | 2 + .../win/VC100/vmapExtractor3.vcxproj | 106 ++ contrib/vmap_extractor_v2/win/VC90/.gitignore | 2 + .../win/VC90/vmapExtractor3.vcproj | 246 ++++ .../win/vmapExtractor3_VC100.sln | 42 + .../win/vmapExtractor3_VC90.sln | 42 + src/shared/revision_nr.h | 2 +- 37 files changed, 1357 insertions(+), 2869 deletions(-) create mode 100644 contrib/vmap_extract_assembler_bin/vmapExtractor3.exe create mode 100644 contrib/vmap_extractor_v2/CMakeLists.txt create mode 100644 contrib/vmap_extractor_v2/README delete mode 100644 contrib/vmap_extractor_v2/vmapExtractor_VC80.sln delete mode 100644 contrib/vmap_extractor_v2/vmapExtractor_VC80.vcproj delete mode 100644 contrib/vmap_extractor_v2/vmapExtractor_VC90.sln delete mode 100644 contrib/vmap_extractor_v2/vmapExtractor_VC90.vcproj create mode 100644 contrib/vmap_extractor_v2/vmapextract/.gitignore create mode 100644 contrib/vmap_extractor_v2/vmapextract/CMakeLists.txt create mode 100644 contrib/vmap_extractor_v2/vmapextract/loadlib/loadlib.h delete mode 100644 contrib/vmap_extractor_v2/vmapextract/mpq.cpp delete mode 100644 contrib/vmap_extractor_v2/vmapextract/mpq.h create mode 100644 contrib/vmap_extractor_v2/vmapextract/mpq_libmpq.cpp create mode 100644 contrib/vmap_extractor_v2/vmapextract/mpq_libmpq04.h create mode 100644 contrib/vmap_extractor_v2/vmapextract/vmapexport.h create mode 100644 contrib/vmap_extractor_v2/win/.gitignore create mode 100644 contrib/vmap_extractor_v2/win/VC100/.gitignore create mode 100644 contrib/vmap_extractor_v2/win/VC100/vmapExtractor3.vcxproj create mode 100644 contrib/vmap_extractor_v2/win/VC90/.gitignore create mode 100644 contrib/vmap_extractor_v2/win/VC90/vmapExtractor3.vcproj create mode 100644 contrib/vmap_extractor_v2/win/vmapExtractor3_VC100.sln create mode 100644 contrib/vmap_extractor_v2/win/vmapExtractor3_VC90.sln diff --git a/contrib/vmap_extract_assembler_bin/vmapExtractor3.exe b/contrib/vmap_extract_assembler_bin/vmapExtractor3.exe new file mode 100644 index 0000000000000000000000000000000000000000..db9552732f3d0b9d2de43012dc3f752dc06c4a83 GIT binary patch literal 121344 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 +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +cmake_minimum_required (VERSION 2.6) +project (MANGOS_VMAP_EXTRACT_IO) + + +# uncomment next line to disable debug mode +ADD_DEFINITIONS("-DIOMAP_DEBUG") +# build setup currently only supports libmpq 0.4.x +ADD_DEFINITIONS("-DUSE_LIBMPQ04") +ADD_DEFINITIONS("-Wall") +ADD_DEFINITIONS("-ggdb") +ADD_DEFINITIONS("-O3") + +include_directories(../../dep/libmpq) + +add_subdirectory(vmapextract) diff --git a/contrib/vmap_extractor_v2/README b/contrib/vmap_extractor_v2/README new file mode 100644 index 000000000..696657d05 --- /dev/null +++ b/contrib/vmap_extractor_v2/README @@ -0,0 +1,42 @@ +Linux: + +1. Building + + Because vmap_extractor depends on libmpq for reading mpq files, you will have + to build libmpq prior to vmap_extractor. Therefore cd to dep/libmpq and execute: + + $ ./autogen.sh + $ ./configure + $ make + + After that, cd to contrib/vmap_extractor_v2/ and execute: + + $ cmake . + $ make + + You should now have an executable file at vmapextract/vmapextractor + +2. Extracting + + Use the created executable to extract model information. Change the data path if + needed. + + $ vmapextract/vmapextractor -d /mnt/windows/games/wow/Data/ + + Resulting files will be in ./Buildings + +########################### +Windows: + +1. Building + + Just buid the solution in contrib\vmap_extractor_v2\win + Resulting binaries will be in contrib\vmap_extractor_v2\bin\$(PlatformName)_$(ConfigurationName) + +2. Extracting + + Use the created executable (from command prompt) to extract model information. + It should find the data path for your client installation through the windows registry, + but the data path can be specified with the -d option. + + Resulting files will be in .\Buildings diff --git a/contrib/vmap_extractor_v2/vmapExtractor_VC80.sln b/contrib/vmap_extractor_v2/vmapExtractor_VC80.sln deleted file mode 100644 index cc24730b1..000000000 --- a/contrib/vmap_extractor_v2/vmapExtractor_VC80.sln +++ /dev/null @@ -1,19 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual C++ Express 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmapExtractor", "vmapExtractor_VC80.vcproj", "{87335BBF-5DA8-4FEC-A51E-1FB948F2FFE9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug Ansi Static|Win32 = Debug Ansi Static|Win32 - Release Ansi Static|Win32 = Release Ansi Static|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {87335BBF-5DA8-4FEC-A51E-1FB948F2FFE9}.Debug Ansi Static|Win32.ActiveCfg = Debug Ansi Static|Win32 - {87335BBF-5DA8-4FEC-A51E-1FB948F2FFE9}.Debug Ansi Static|Win32.Build.0 = Debug Ansi Static|Win32 - {87335BBF-5DA8-4FEC-A51E-1FB948F2FFE9}.Release Ansi Static|Win32.ActiveCfg = Release Ansi Static|Win32 - {87335BBF-5DA8-4FEC-A51E-1FB948F2FFE9}.Release Ansi Static|Win32.Build.0 = Release Ansi Static|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/contrib/vmap_extractor_v2/vmapExtractor_VC80.vcproj b/contrib/vmap_extractor_v2/vmapExtractor_VC80.vcproj deleted file mode 100644 index 5d8cdea90..000000000 --- a/contrib/vmap_extractor_v2/vmapExtractor_VC80.vcproj +++ /dev/null @@ -1,1000 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/contrib/vmap_extractor_v2/vmapExtractor_VC90.sln b/contrib/vmap_extractor_v2/vmapExtractor_VC90.sln deleted file mode 100644 index 82d3e1509..000000000 --- a/contrib/vmap_extractor_v2/vmapExtractor_VC90.sln +++ /dev/null @@ -1,19 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmapExtractor", "vmapExtractor_VC90.vcproj", "{87335BBF-5DA8-4FEC-A51E-1FB948F2FFE9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug Ansi Static|Win32 = Debug Ansi Static|Win32 - Release Ansi Static|Win32 = Release Ansi Static|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {87335BBF-5DA8-4FEC-A51E-1FB948F2FFE9}.Debug Ansi Static|Win32.ActiveCfg = Debug Ansi Static|Win32 - {87335BBF-5DA8-4FEC-A51E-1FB948F2FFE9}.Debug Ansi Static|Win32.Build.0 = Debug Ansi Static|Win32 - {87335BBF-5DA8-4FEC-A51E-1FB948F2FFE9}.Release Ansi Static|Win32.ActiveCfg = Release Ansi Static|Win32 - {87335BBF-5DA8-4FEC-A51E-1FB948F2FFE9}.Release Ansi Static|Win32.Build.0 = Release Ansi Static|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/contrib/vmap_extractor_v2/vmapExtractor_VC90.vcproj b/contrib/vmap_extractor_v2/vmapExtractor_VC90.vcproj deleted file mode 100644 index ed75735c4..000000000 --- a/contrib/vmap_extractor_v2/vmapExtractor_VC90.vcproj +++ /dev/null @@ -1,999 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/contrib/vmap_extractor_v2/vmapextract/.gitignore b/contrib/vmap_extractor_v2/vmapextract/.gitignore new file mode 100644 index 000000000..79b30acc5 --- /dev/null +++ b/contrib/vmap_extractor_v2/vmapextract/.gitignore @@ -0,0 +1,18 @@ +# +# NOTE! Don't add files that are generated in specific +# subdirectories here. Add them in the ".gitignore" file +# in that subdirectory instead. +# +# NOTE! Please use 'git-ls-files -i --exclude-standard' +# command after changing this file, to see if there are +# any tracked files which get ignored after the change. +# +# MaNGOS generated files at Windows build +# + +# CMake files + +CMakeFiles +CMakeCache.txt +cmake_install.cmake + diff --git a/contrib/vmap_extractor_v2/vmapextract/CMakeLists.txt b/contrib/vmap_extractor_v2/vmapextract/CMakeLists.txt new file mode 100644 index 000000000..473bd5085 --- /dev/null +++ b/contrib/vmap_extractor_v2/vmapextract/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (C) 2005-2009 MaNGOS project +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +cmake_minimum_required (VERSION 2.6) +project (MANGOS_IOMAP_EXTRACTOR) + +LINK_DIRECTORIES( ${LINK_DIRECTORIES} ../../../dep/libmpq/libmpq/.libs/ ) +add_executable(vmapextractor adtfile.cpp dbcfile.cpp model.cpp mpq_libmpq.cpp vmapexport.cpp wdtfile.cpp wmo.cpp) +target_link_libraries(vmapextractor libmpq.a bz2 z) diff --git a/contrib/vmap_extractor_v2/vmapextract/adtfile.cpp b/contrib/vmap_extractor_v2/vmapextract/adtfile.cpp index 49717c047..314255d3a 100644 --- a/contrib/vmap_extractor_v2/vmapextract/adtfile.cpp +++ b/contrib/vmap_extractor_v2/vmapextract/adtfile.cpp @@ -1,6 +1,12 @@ +#include "vmapexport.h" #include "adtfile.h" #include +#include + +#ifdef WIN32 +#define snprintf _snprintf +#endif char * GetPlainName(char * FileName) { @@ -23,6 +29,9 @@ void fixnamen(char *name, size_t len) name[i] &= ~0x20; } } + //extension in lowercase + for(size_t i=len-3; i= 3.1.0 ADT MMDX section store filename.m2 filenames for corresponded .m2 file // nothing do - char szLocalFile[MAX_PATH]; - sprintf(szLocalFile, ".\\buildings\\%s", s); + char szLocalFile[1024]; + snprintf(szLocalFile, 1024, "%s/%s", szWorkDirWmo, s); FILE * output = fopen(szLocalFile,"rb"); if(!output) { - Model * m2 = new Model(path); - if(m2->open()) - m2->ConvertToVMAPModel(szLocalFile); - delete m2; + Model m2(path); + if(m2.open()) + m2.ConvertToVMAPModel(szLocalFile); } else fclose(output); @@ -161,9 +169,9 @@ bool ADTFile::init(char *map_id) nMDX = (int)size / 36; for (int i=0; i DBCFile::DBCFile(const std::string &filename) : filename(filename) { diff --git a/contrib/vmap_extractor_v2/vmapextract/dbcfile.h b/contrib/vmap_extractor_v2/vmapextract/dbcfile.h index 002e7eeeb..7d23f2d1e 100644 --- a/contrib/vmap_extractor_v2/vmapextract/dbcfile.h +++ b/contrib/vmap_extractor_v2/vmapextract/dbcfile.h @@ -1,10 +1,8 @@ #ifndef DBCFILE_H #define DBCFILE_H -#define __STORMLIB_SELF__ #include #include -#include "Stormlib.h" class DBCFile { @@ -80,8 +78,8 @@ public: } private: Record(DBCFile &file, unsigned char *offset): file(file), offset(offset) {} - unsigned char *offset; DBCFile &file; + unsigned char *offset; friend class DBCFile; friend class Iterator; diff --git a/contrib/vmap_extractor_v2/vmapextract/loadlib/loadlib.h b/contrib/vmap_extractor_v2/vmapextract/loadlib/loadlib.h new file mode 100644 index 000000000..537317534 --- /dev/null +++ b/contrib/vmap_extractor_v2/vmapextract/loadlib/loadlib.h @@ -0,0 +1,59 @@ +#ifndef LOAD_LIB_H +#define LOAD_LIB_H + +#ifdef WIN32 +typedef __int64 int64; +typedef __int32 int32; +typedef __int16 int16; +typedef __int8 int8; +typedef unsigned __int64 uint64; +typedef unsigned __int32 uint32; +typedef unsigned __int16 uint16; +typedef unsigned __int8 uint8; +#else +#include +#ifndef uint64_t +#ifdef __linux__ +#include +#endif +#endif +typedef int64_t int64; +typedef int32_t int32; +typedef int16_t int16; +typedef int8_t int8; +typedef uint64_t uint64; +typedef uint32_t uint32; +typedef uint16_t uint16; +typedef uint8_t uint8; +#endif + +#define FILE_FORMAT_VERSION 18 + +// +// File version chunk +// +struct file_MVER +{ + union{ + uint32 fcc; + char fcc_txt[4]; + }; + uint32 size; + uint32 ver; +}; + +class FileLoader{ + uint8 *data; + uint32 data_size; +public: + virtual bool prepareLoadedData(); + uint8 *GetData() {return data;} + uint32 GetDataSize() {return data_size;} + + file_MVER *version; + FileLoader(); + ~FileLoader(); + bool loadFile(char *filename, bool log = true); + virtual void free(); +}; +#endif diff --git a/contrib/vmap_extractor_v2/vmapextract/model.cpp b/contrib/vmap_extractor_v2/vmapextract/model.cpp index 9605e3320..a2493f7e5 100644 --- a/contrib/vmap_extractor_v2/vmapextract/model.cpp +++ b/contrib/vmap_extractor_v2/vmapextract/model.cpp @@ -1,6 +1,10 @@ +#include "vmapexport.h" #include "model.h" +#include "wmo.h" +#include "mpq_libmpq04.h" #include #include +#include Model::Model(std::string &filename) : filename(filename) { @@ -35,8 +39,8 @@ bool Model::open() indices = new uint16[header.nBoundingTriangles]; f.read(indices,header.nBoundingTriangles*2); f.close(); - } - else + } + else { //printf("not included %s\n", filename.c_str()); f.close(); @@ -47,20 +51,22 @@ bool Model::open() bool Model::ConvertToVMAPModel(char * outfilename) { - int N[] = {0x00000000}; + int N[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; FILE * output=fopen(outfilename,"wb"); if(!output) { printf("Can't create the output file '%s'\n",outfilename); return false; } - fwrite("VMAP002",8,1,output); + fwrite("VMAP003",8,1,output); uint32 nVertices = 0; nVertices = header.nBoundingVertices; fwrite(&nVertices, sizeof(int), 1, output); uint32 nofgroups = 1; fwrite(&nofgroups,sizeof(uint32), 1, output); - fwrite(N,4,1,output); + fwrite(N,4*3,1,output);// rootwmoid, flags, groupid + fwrite(N,sizeof(float),3*2,output);//bbox, only needed for WMO currently + fwrite(N,4,1,output);// liquidflags fwrite("GRP ",4,1,output); uint32 branches = 1; int wsize; @@ -115,12 +121,12 @@ Vec3D fixCoordSystem2(Vec3D v) return Vec3D(v.x, v.z, v.y); } -ModelInstance::ModelInstance(MPQFile &f,const char* ModelInstName,const char*MapName, FILE *pDirfile) +ModelInstance::ModelInstance(MPQFile &f,const char* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE *pDirfile) { float ff[3]; - f.read(&d1, 4); + f.read(&id, 4); f.read(ff,12); - pos = Vec3D(ff[0],ff[1],ff[2]); + pos = fixCoords(Vec3D(ff[0],ff[1],ff[2])); f.read(ff,12); rot = Vec3D(ff[0],ff[1],ff[2]); f.read(&scale,4); @@ -128,12 +134,15 @@ ModelInstance::ModelInstance(MPQFile &f,const char* ModelInstName,const char*Map sc = scale / 1024.0f; char tempname[512]; - sprintf(tempname, ".\\buildings\\%s", ModelInstName); + sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName); FILE *input; input = fopen(tempname, "r+b"); if(!input) + { + //printf("ModelInstance::ModelInstance couldn't open %s\n", tempname); return; + } fseek(input, 8, SEEK_SET); // get the correct no of vertices int nVertices; @@ -143,22 +152,36 @@ ModelInstance::ModelInstance(MPQFile &f,const char* ModelInstName,const char*Map if(nVertices == 0) return; - if(pDirfile) - { - int realx1 = (int) ((float) pos.x / 533.333333f); - int realy1 = (int) ((float) pos.z / 533.333333f); - int realx2 = (int) ((float) pos.x / 533.333333f); - int realy2 = (int) ((float) pos.z / 533.333333f); + uint16 adtId = 0;// not used for models + uint32 flags = MOD_M2; + if(tileX == 65 && tileY == 65) flags |= MOD_WORLDSPAWN; + //write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, name + fwrite(&mapID, sizeof(uint32), 1, pDirfile); + fwrite(&tileX, sizeof(uint32), 1, pDirfile); + fwrite(&tileY, sizeof(uint32), 1, pDirfile); + fwrite(&flags, sizeof(uint32), 1, pDirfile); + fwrite(&adtId, sizeof(uint16), 1, pDirfile); + fwrite(&id, sizeof(uint32), 1, pDirfile); + fwrite(&pos, sizeof(float), 3, pDirfile); + fwrite(&rot, sizeof(float), 3, pDirfile); + fwrite(&sc, sizeof(float), 1, pDirfile); + uint32 nlen=strlen(ModelInstName); + fwrite(&nlen, sizeof(uint32), 1, pDirfile); + fwrite(ModelInstName, sizeof(char), nlen, pDirfile); - fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f %f %d %d %d,%d %d\n", - MapName, - ModelInstName, - (float) pos.x, (float) pos.y, (float) pos.z, - (float) rot.x, (float) rot.y, (float) rot.z, - sc, - nVertices, - realx1, realy1, - realx2, realy2 - ); - } + /* int realx1 = (int) ((float) pos.x / 533.333333f); + int realy1 = (int) ((float) pos.z / 533.333333f); + int realx2 = (int) ((float) pos.x / 533.333333f); + int realy2 = (int) ((float) pos.z / 533.333333f); + + fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f %f %d %d %d,%d %d\n", + MapName, + ModelInstName, + (float) pos.x, (float) pos.y, (float) pos.z, + (float) rot.x, (float) rot.y, (float) rot.z, + sc, + nVertices, + realx1, realy1, + realx2, realy2 + ); */ } diff --git a/contrib/vmap_extractor_v2/vmapextract/model.h b/contrib/vmap_extractor_v2/vmapextract/model.h index 2bcb20b11..d1be46f3c 100644 --- a/contrib/vmap_extractor_v2/vmapextract/model.h +++ b/contrib/vmap_extractor_v2/vmapextract/model.h @@ -1,13 +1,15 @@ #ifndef MODEL_H #define MODEL_H +#include "loadlib/loadlib.h" #include "vec3d.h" -#include "mpq.h" +//#include "mpq.h" #include "modelheaders.h" #include class Model; class WMOInstance; +class MPQFile; Vec3D fixCoordSystem(Vec3D v); @@ -38,13 +40,13 @@ class ModelInstance public: Model *model; - int id; + uint32 id; Vec3D pos, rot; unsigned int d1, scale; float w,sc; ModelInstance() {} - ModelInstance(MPQFile &f,const char* ModelInstName,const char*MapName, FILE *pDirfile); + ModelInstance(MPQFile &f,const char* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE *pDirfile); }; diff --git a/contrib/vmap_extractor_v2/vmapextract/modelheaders.h b/contrib/vmap_extractor_v2/vmapextract/modelheaders.h index 445ab3843..776a981eb 100644 --- a/contrib/vmap_extractor_v2/vmapextract/modelheaders.h +++ b/contrib/vmap_extractor_v2/vmapextract/modelheaders.h @@ -1,12 +1,12 @@ #ifndef MODELHEADERS_H #define MODELHEADERS_H -typedef unsigned char uint8; +/* typedef unsigned char uint8; typedef char int8; typedef unsigned short uint16; typedef short int16; typedef unsigned int uint32; -typedef int int32; +typedef int int32; */ #pragma pack(push,1) diff --git a/contrib/vmap_extractor_v2/vmapextract/mpq.cpp b/contrib/vmap_extractor_v2/vmapextract/mpq.cpp deleted file mode 100644 index 0d72f06a7..000000000 --- a/contrib/vmap_extractor_v2/vmapextract/mpq.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "mpq.h" -//#include -#include "Stormlib.h" -#define __STORMLIB_SELF__ - -MPQArchiveSet gOpenArchives; - -//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -MPQArchive::MPQArchive(const char* filename) -{ - BOOL succ = SFileOpenArchive(filename, 0, 0,&hMPQ); - if (succ) - printf("Opening %s\n", filename); - else - printf("Error!!!Not open archive %s\n", filename); -} - -void MPQArchive::close() -{ - SFileCloseArchive(hMPQ); -} - -bool MPQArchiveSet::Open( std::vector const& archiveNames ) -{ - for (size_t i=0; i < archiveNames.size(); ++i) - { - MPQArchive mpqarch(archiveNames[i].c_str()); - if(mpqarch.isOpen()) - archives.push_back(mpqarch); - } - - return !archives.empty(); -} - -MPQArchiveSet::~MPQArchiveSet() -{ - // close archives - for (ArchiveSet::iterator ar_itr = archives.begin(); ar_itr != archives.end(); ++ar_itr) - ar_itr->close(); -} - -MPQFile::MPQFile(const char* filename): - eof(false), - buffer(0), - pointer(0), - size(0) -{ - for(ArchiveSet::const_iterator i=gOpenArchives.archives.begin(); i!=gOpenArchives.archives.end();++i) - { - HANDLE hFile = ""; - hMPQ = i->hMPQ; - BOOL succ = SFileOpenFileEx(hMPQ,filename,0, &hFile); - if (succ) - { - DWORD s = SFileGetFileSize(hFile, 0); - if (!s) - { - eof = true; - buffer = 0; - return; - } - size = (size_t)s; - buffer = new char[s]; - SFileReadFile(hFile, buffer, s, 0, 0); - SFileCloseFile(hFile); - - eof = false; - return; - } - } - - eof = true; - buffer = 0; -} - -MPQFile::~MPQFile() -{ - close(); -} - -size_t MPQFile::read(void* dest, size_t bytes) -{ - if (eof) - return 0; - - size_t rpos = pointer + bytes; - if (rpos > size) - { - bytes = size - pointer; - eof = true; - } - - memcpy(dest, &(buffer[pointer]), bytes); - - pointer = rpos; - - return bytes; -} - -bool MPQFile::isEof() -{ - return eof; -} - -void MPQFile::seek(int offset) -{ - pointer = offset; - eof = (pointer >= size); -} - -void MPQFile::seekRelative(int offset) -{ - pointer += offset; - eof = (pointer >= size); -} - -void MPQFile::close() -{ - if (buffer) - delete[] buffer; - buffer = 0; - eof = true; -} - -size_t MPQFile::getSize() -{ - return size; -} - -size_t MPQFile::getPos() -{ - return pointer; -} - -char* MPQFile::getBuffer() -{ - return buffer; -} - -char* MPQFile::getPointer() -{ - return buffer + pointer; -} diff --git a/contrib/vmap_extractor_v2/vmapextract/mpq.h b/contrib/vmap_extractor_v2/vmapextract/mpq.h deleted file mode 100644 index 0d1d14851..000000000 --- a/contrib/vmap_extractor_v2/vmapextract/mpq.h +++ /dev/null @@ -1,80 +0,0 @@ -#define _CRT_SECURE_NO_DEPRECATE - -#ifndef MPQ_H -#define MPQ_H - -#define __STORMLIB_SELF__ - -#include -#include -#include -#include -#include "Stormlib.h" - -using namespace std; - -typedef unsigned int uint32; - -class MPQArchive -{ - public: - HANDLE hMPQ; - MPQArchive(const char* filename); - void close(); - bool isOpen() const { return hMPQ != 0; } -}; - -typedef std::vector ArchiveSet; - -class MPQArchiveSet -{ - public: - MPQArchiveSet() {} - ~MPQArchiveSet(); - - bool Open(std::vector const& archiveNames); - - ArchiveSet archives; -}; - -extern MPQArchiveSet gOpenArchives; - -class MPQFile -{ - HANDLE hFile; - HANDLE hMPQ; - bool eof; - char *buffer; - size_t pointer, - size; - - // disable copying - //MPQFile(const MPQFile &f) {} - //void operator=(const MPQFile &f) {} - -public: - MPQFile(const char* filename); - ~MPQFile(); - size_t read(void* dest, size_t bytes); - size_t getSize(); - size_t getPos(); - char* getBuffer(); - char* getPointer(); - bool isEof(); - void seek(int offset); - void seekRelative(int offset); - void close(); -}; - -inline void flipcc(char *fcc) -{ - char t; - t=fcc[0]; - fcc[0]=fcc[3]; - fcc[3]=t; - t=fcc[1]; - fcc[1]=fcc[2]; - fcc[2]=t; -} - -#endif diff --git a/contrib/vmap_extractor_v2/vmapextract/mpq_libmpq.cpp b/contrib/vmap_extractor_v2/vmapextract/mpq_libmpq.cpp new file mode 100644 index 000000000..528b9679a --- /dev/null +++ b/contrib/vmap_extractor_v2/vmapextract/mpq_libmpq.cpp @@ -0,0 +1,111 @@ +#include "mpq_libmpq04.h" +#include +#include + +ArchiveSet gOpenArchives; + +MPQArchive::MPQArchive(const char* filename) +{ + int result = libmpq__archive_open(&mpq_a, filename, -1); + printf("Opening %s\n", filename); + if(result) { + switch(result) { + case LIBMPQ_ERROR_OPEN : + printf("Error opening archive '%s': Does file really exist?\n", filename); + break; + case LIBMPQ_ERROR_FORMAT : /* bad file format */ + printf("Error opening archive '%s': Bad file format\n", filename); + break; + case LIBMPQ_ERROR_SEEK : /* seeking in file failed */ + printf("Error opening archive '%s': Seeking in file failed\n", filename); + break; + case LIBMPQ_ERROR_READ : /* Read error in archive */ + printf("Error opening archive '%s': Read error in archive\n", filename); + break; + case LIBMPQ_ERROR_MALLOC : /* maybe not enough memory? :) */ + printf("Error opening archive '%s': Maybe not enough memory\n", filename); + break; + default: + printf("Error opening archive '%s': Unknown error\n", filename); + break; + } + return; + } + gOpenArchives.push_front(this); +} + +void MPQArchive::close() +{ + //gOpenArchives.erase(erase(&mpq_a); + libmpq__archive_close(mpq_a); +} + +MPQFile::MPQFile(const char* filename): + eof(false), + buffer(0), + pointer(0), + size(0) +{ + for(ArchiveSet::iterator i=gOpenArchives.begin(); i!=gOpenArchives.end();++i) + { + mpq_archive *mpq_a = (*i)->mpq_a; + + uint32 filenum; + if(libmpq__file_number(mpq_a, filename, &filenum)) continue; + libmpq__off_t transferred; + libmpq__file_unpacked_size(mpq_a, filenum, &size); + + // HACK: in patch.mpq some files don't want to open and give 1 for filesize + if (size<=1) { + // printf("info: file %s has size %d; considered dummy file.\n", filename, size); + eof = true; + buffer = 0; + return; + } + buffer = new char[size]; + + //libmpq_file_getdata + libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred); + /*libmpq_file_getdata(&mpq_a, hash, fileno, (unsigned char*)buffer);*/ + return; + + } + eof = true; + buffer = 0; +} + +size_t MPQFile::read(void* dest, size_t bytes) +{ + if (eof) return 0; + + size_t rpos = pointer + bytes; + if (rpos > size) { + bytes = size - pointer; + eof = true; + } + + memcpy(dest, &(buffer[pointer]), bytes); + + pointer = rpos; + + return bytes; +} + +void MPQFile::seek(int offset) +{ + pointer = offset; + eof = (pointer >= size); +} + +void MPQFile::seekRelative(int offset) +{ + pointer += offset; + eof = (pointer >= size); +} + +void MPQFile::close() +{ + if (buffer) delete[] buffer; + buffer = 0; + eof = true; +} diff --git a/contrib/vmap_extractor_v2/vmapextract/mpq_libmpq04.h b/contrib/vmap_extractor_v2/vmapextract/mpq_libmpq04.h new file mode 100644 index 000000000..ccbfe37cb --- /dev/null +++ b/contrib/vmap_extractor_v2/vmapextract/mpq_libmpq04.h @@ -0,0 +1,91 @@ +#define _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_WARNINGS + +#ifndef MPQ_H +#define MPQ_H + +#include "loadlib/loadlib.h" +#include "libmpq/mpq.h" +#include +#include +#include +#include +#include + +using namespace std; + +class MPQArchive +{ + +public: + mpq_archive_s *mpq_a; + + MPQArchive(const char* filename); + void close(); + + void GetFileListTo(vector& filelist) { + uint32 filenum; + if(libmpq__file_number(mpq_a, "(listfile)", &filenum)) return; + libmpq__off_t size, transferred; + libmpq__file_unpacked_size(mpq_a, filenum, &size); + + char *buffer = new char[size]; + + libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred); + + char seps[] = "\n"; + char *token; + + token = strtok( buffer, seps ); + uint32 counter = 0; + while ((token != NULL) && (counter < size)) { + //cout << token << endl; + token[strlen(token) - 1] = 0; + string s = token; + filelist.push_back(s); + counter += strlen(token) + 2; + token = strtok(NULL, seps); + } + + delete[] buffer; + } +}; +typedef std::deque ArchiveSet; + +class MPQFile +{ + //MPQHANDLE handle; + bool eof; + char *buffer; + libmpq__off_t pointer,size; + + // disable copying + MPQFile(const MPQFile &f) {} + void operator=(const MPQFile &f) {} + +public: + MPQFile(const char* filename); // filenames are not case sensitive + ~MPQFile() { close(); } + size_t read(void* dest, size_t bytes); + size_t getSize() { return size; } + size_t getPos() { return pointer; } + char* getBuffer() { return buffer; } + char* getPointer() { return buffer + pointer; } + bool isEof() { return eof; } + void seek(int offset); + void seekRelative(int offset); + void close(); +}; + +inline void flipcc(char *fcc) +{ + char t; + t=fcc[0]; + fcc[0]=fcc[3]; + fcc[3]=t; + t=fcc[1]; + fcc[1]=fcc[2]; + fcc[2]=t; +} + +#endif diff --git a/contrib/vmap_extractor_v2/vmapextract/vec3d.h b/contrib/vmap_extractor_v2/vmapextract/vec3d.h index 405135521..d2569bc13 100644 --- a/contrib/vmap_extractor_v2/vmapextract/vec3d.h +++ b/contrib/vmap_extractor_v2/vmapextract/vec3d.h @@ -106,6 +106,12 @@ public: in >> v.x >> v.y >> v.z; return in; } + + friend std::ostream& operator<<(std::ostream& out, const Vec3D& v) + { + out << v.x << " " << v.y << " " << v.z; + return out; + } operator float*() { diff --git a/contrib/vmap_extractor_v2/vmapextract/vmapexport.cpp b/contrib/vmap_extractor_v2/vmapextract/vmapexport.cpp index a96a404f6..a11d05e37 100644 --- a/contrib/vmap_extractor_v2/vmapextract/vmapexport.cpp +++ b/contrib/vmap_extractor_v2/vmapextract/vmapexport.cpp @@ -1,38 +1,33 @@ -/*****************************************************************************/ -/* StormLibTest.cpp Copyright (c) Ladislav Zezula 2003 */ -/*---------------------------------------------------------------------------*/ -/* This module uses very brutal test methods for StormLib. It extracts all */ -/* files from the archive with Storm.dll and with stormlib and compares them,*/ -/* then tries to build a copy of the entire archive, then removes a few files*/ -/* from the archive and adds them back, then compares the two archives, ... */ -/*---------------------------------------------------------------------------*/ -/* Date Ver Who Comment */ -/* -------- ---- --- ------- */ -/* 25.03.03 1.00 Lad The first version of StormLibTest.cpp */ -/*****************************************************************************/ - #define _CRT_SECURE_NO_DEPRECATE -#include -#include -#include -#include -#include +#include +#include #include #include +#include +#ifdef WIN32 + #include + #include + #include + #define mkdir _mkdir +#else + #include +#endif -#define __STORMLIB_SELF__ // Don't use StormLib.lib -#include "StormLib.h" +#undef min +#undef max -#pragma warning(disable : 4505) -#pragma comment(lib, "Winmm.lib") +//#pragma warning(disable : 4505) +//#pragma comment(lib, "Winmm.lib") + +#include //From Extractor #include "adtfile.h" #include "wdtfile.h" #include "dbcfile.h" -#include "mpq.h" #include "wmo.h" +#include "mpq_libmpq04.h" //------------------------------------------------------------------------------ // Defines @@ -40,10 +35,9 @@ #define MPQ_BLOCK_SIZE 0x1000 //----------------------------------------------------------------------------- -// from extractor -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; + +extern ArchiveSet gOpenArchives; + typedef struct { char name[64]; @@ -51,26 +45,17 @@ typedef struct }map_id; map_id * map_ids; -uint16 * areas; -uint16 *areamax; +uint16 *LiqType = 0; uint32 map_count; char output_path[128]="."; char input_path[1024]="."; bool hasInputPathParam = false; -char tmp[512]; bool preciseVectorData = false; -//char gamepath[1024]; - -//Convert function -//bool ConvertADT(char*,char*); // Constants //static const char * szWorkDirMaps = ".\\Maps"; -static const char * szWorkDirWmo = ".\\buildings"; - -//static LPBYTE pbBuffer1 = NULL; -//static LPBYTE pbBuffer2 = NULL; +const char * szWorkDirWmo = "./Buildings"; // Local testing functions @@ -79,6 +64,15 @@ static void clreol() printf("\r \r"); } +void strToLower(char* str) +{ + while(*str) + { + *str=tolower(*str); + ++str; + } +} + static const char * GetPlainName(const char * szFileName) { const char * szTemp; @@ -88,56 +82,55 @@ static const char * GetPlainName(const char * szFileName) return szFileName; } -static void ShowProcessedFile(const char * szFileName) +// copied from contrib/extractor/System.cpp +void ReadLiquidTypeTableDBC() { -/* not truncate file names in output - char szLine[80]; - size_t nLength = strlen(szFileName); + printf("Read LiquidType.dbc file..."); + DBCFile dbc("DBFilesClient\\LiquidType.dbc"); + if(!dbc.open()) + { + printf("Fatal error: Invalid LiquidType.dbc file format!\n"); + exit(1); + } - memset(szLine, 0x20, sizeof(szLine)); - szLine[sizeof(szLine)-1] = 0; + size_t LiqType_count = dbc.getRecordCount(); + size_t LiqType_maxid = dbc.getRecord(LiqType_count - 1).getUInt(0); + LiqType = new uint16[LiqType_maxid + 1]; + memset(LiqType, 0xff, (LiqType_maxid + 1) * sizeof(uint16)); - if(nLength > sizeof(szLine)-1) - nLength = sizeof(szLine)-1; - memcpy(szLine, szFileName, nLength); - printf("\r%s\n", szLine); -*/ - printf("\r%s\n", szFileName); + for(uint32 x = 0; x < LiqType_count; ++x) + LiqType[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3); + + printf("Done! (%u LiqTypes loaded)\n", (unsigned int)LiqType_count); } int ExtractWmo() { - char* szListFile = ""; - char szLocalFile[MAX_PATH] = ""; - BOOL bResult = FALSE; + char szLocalFile[1024] = ""; + bool success=true; //const char* ParsArchiveNames[] = {"patch-2.MPQ", "patch.MPQ", "common.MPQ", "expansion.MPQ"}; - int nError = ERROR_SUCCESS; - if(szListFile == NULL || *szListFile == 0) - szListFile = NULL; - - for (ArchiveSet::const_iterator ar_itr = gOpenArchives.archives.begin(); ar_itr != gOpenArchives.archives.end(); ++ar_itr) + for (ArchiveSet::const_iterator ar_itr = gOpenArchives.begin(); ar_itr != gOpenArchives.end() && success; ++ar_itr) { - // Copy files from archive - if(nError == ERROR_SUCCESS) - { - SFILE_FIND_DATA wf; - HANDLE hFind = SFileFindFirstFile(ar_itr->hMPQ,"*.wmo*", &wf, szListFile); - bResult = TRUE; + vector filelist; - while(hFind != NULL && bResult == TRUE) + (*ar_itr)->GetFileListTo(filelist); + for (vector::iterator fname=filelist.begin(); fname != filelist.end() && success; ++fname) + { + bool file_ok=true; + if (fname->find(".wmo") != string::npos) { - ShowProcessedFile(wf.cFileName); - SFileSetLocale(wf.lcLocale); - sprintf(szLocalFile, "%s\\%s", szWorkDirWmo, GetPlainName(wf.cFileName)); + // Copy files from archive + //std::cout << "found *.wmo file " << *fname << std::endl; + sprintf(szLocalFile, "%s/%s", szWorkDirWmo, GetPlainName(fname->c_str())); fixnamen(szLocalFile,strlen(szLocalFile)); FILE * n; if ((n = fopen(szLocalFile, "rb"))== NULL) { int p = 0; //Select root wmo files - const char * rchr = strrchr(GetPlainName(wf.cFileName),0x5f); + const char * rchr = strrchr(GetPlainName(fname->c_str()),0x5f); if(rchr != NULL) { char cpy[4]; @@ -151,67 +144,67 @@ int ExtractWmo() } if(p != 3) { - //printf("RootWmo!\n"); - string s = wf.cFileName; - WMORoot * froot = new WMORoot(s); + std::cout << "Extracting " << *fname << std::endl; + WMORoot * froot = new WMORoot(*fname); if(!froot->open()) { - printf("Not open RootWmo!!!\n"); - bResult = SFileFindNextFile(hFind, &wf); + printf("Couldn't open RootWmo!!!\n"); + delete froot; continue; } FILE *output=fopen(szLocalFile,"wb"); + if(!output) + { + printf("couldn't open %s for writing!\n", szLocalFile); + success=false; + } froot->ConvertToVMAPRootWmo(output); int Wmo_nVertices = 0; + //printf("root has %d groups\n", froot->nGroups); if(froot->nGroups !=0) { - for (int i=0; inGroups; ++i) + for (uint32 i=0; inGroups; ++i) { - char temp[MAX_PATH]; - strcpy(temp, wf.cFileName); - temp[strlen(wf.cFileName)-4] = 0; - char groupFileName[MAX_PATH]; + char temp[1024]; + strcpy(temp, fname->c_str()); + temp[fname->length()-4] = 0; + char groupFileName[1024]; sprintf(groupFileName,"%s_%03d.wmo",temp, i); - printf("%s\n",groupFileName); - //printf("GroupWmo!\n"); + //printf("Trying to open groupfile %s\n",groupFileName); string s = groupFileName; WMOGroup * fgroup = new WMOGroup(s); if(!fgroup->open()) { - printf("Not all open Group file for: %s\n",GetPlainName(wf.cFileName)); - bResult = SFileFindNextFile(hFind, &wf); + printf("Could not open all Group file for: %s\n",GetPlainName(fname->c_str())); + file_ok=false; break; } - Wmo_nVertices += fgroup->ConvertToVMAPGroupWmo(output, preciseVectorData); + + Wmo_nVertices += fgroup->ConvertToVMAPGroupWmo(output, froot, preciseVectorData); + delete fgroup; } } fseek(output, 8, SEEK_SET); // store the correct no of vertices fwrite(&Wmo_nVertices,sizeof(int),1,output); fclose(output); + delete froot; } } else { fclose(n); } - wf.dwFileFlags &= ~MPQ_FILE_HAS_EXTRA; - wf.dwFileFlags &= ~MPQ_FILE_EXISTS; - // Find the next file - bResult = SFileFindNextFile(hFind, &wf); } // Delete the extracted file in the case of an error - if(nError != ERROR_SUCCESS) - DeleteFile(szLocalFile); - // Close the search handle - if(hFind != NULL) - SFileFindClose(hFind); + if(!file_ok) + remove(szLocalFile); } } - if(nError == ERROR_SUCCESS) - printf("\nExtract wmo complete (No errors)\n"); + if(success) + printf("\nExtract wmo complete (No (fatal) errors)\n"); - return nError; + return success; } void ExtractMapsFromMpq() @@ -221,55 +214,34 @@ void ExtractMapsFromMpq() void ParsMapFiles() { char fn[512]; - char id_filename[64]; + //char id_filename[64]; char id[10]; for (unsigned int i=0; iinit(id_filename); + //sprintf(id_filename,"%02u %02u %03u",x,y,map_ids[i].id);//!!!!!!!!! + ADT->init(map_ids[i].id, x, y); delete ADT; } } + printf("#"); + fflush(stdout); } + printf("]\n"); } } } -#if 0 -void ParsMapFiles() -{ - char fn[512]; - for (unsigned int i=0; iinit(); - delete ADT; - } - } - } - } - } -} -#endif void getGamePath() { @@ -289,7 +261,7 @@ void getGamePath() } strcat(input_path,"Data\\"); #else - strcpy(input_path,"data/"); + strcpy(input_path,"Data/"); #endif } @@ -297,38 +269,29 @@ bool scan_patches(char* scanmatch, std::vector& pArchiveNames) { int i; char path[512]; - std::list matches; - - WIN32_FIND_DATA ffData; - HANDLE hFind; for (i = 1; i <= 99; i++) { if (i != 1) { - sprintf(path, "%s-%d.mpq", scanmatch, i); + sprintf(path, "%s-%d.MPQ", scanmatch, i); } else { - sprintf(path, "%s.mpq", scanmatch); + sprintf(path, "%s.MPQ", scanmatch); + } +#ifdef __linux__ + if(FILE* h = fopen64(path, "rb")) +#else + if(FILE* h = fopen(path, "rb")) +#endif + { + fclose(h); + //matches.push_back(path); + pArchiveNames.push_back(path); } - - hFind = INVALID_HANDLE_VALUE; - hFind = FindFirstFile(path, &ffData); - if (hFind == INVALID_HANDLE_VALUE) break; - FindClose(hFind); - - matches.push_back(path); } - matches.reverse(); - for (std::list::iterator i = matches.begin(); i != matches.end(); ++i) - { - pArchiveNames.push_back(i->c_str()); - } - - printf("\n"); - return(true); } @@ -340,96 +303,75 @@ bool fillArchiveNameVector(std::vector& pArchiveNames) printf("\nGame path: %s\n", input_path); char path[512]; - std::vector locales; + string in_path(input_path); + std::vector locales, searchLocales; - // scan game directories - WIN32_FIND_DATA ffData; - HANDLE hFind; - DWORD dwError; + searchLocales.push_back("enGB"); + searchLocales.push_back("enUS"); + searchLocales.push_back("deDE"); + searchLocales.push_back("esES"); + searchLocales.push_back("frFR"); + searchLocales.push_back("koKR"); + searchLocales.push_back("ruRU"); - // first, scan for locales (4-letter directories) - printf("Scanning for locales.\n"); - sprintf(path, "%s*.*", input_path); - hFind = INVALID_HANDLE_VALUE; - hFind = FindFirstFile(path, &ffData); - if (hFind == INVALID_HANDLE_VALUE) + for (std::vector::iterator i = searchLocales.begin(); i != searchLocales.end(); ++i) { - printf("\nCould not open data directory for reading. Aborting.\n"); - return(false); - } - do - { - if (ffData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - if (ffData.cFileName[0] != '.') - { - if (strlen(ffData.cFileName) == 4) - { - printf("Found locale: %s\n", ffData.cFileName); - locales.push_back(ffData.cFileName); - } - } - } - } while (FindNextFile(hFind, &ffData) != 0); - dwError = GetLastError(); - FindClose(hFind); - if (dwError != ERROR_NO_MORE_FILES) - { - printf("\nError reading data directory while scanning locales. Aborting.\n"); - return(false); + std::string localePath = in_path + *i; + // check if locale exists: + struct stat status; + if (stat(localePath.c_str(), &status)) + continue; + if ((status.st_mode & S_IFDIR) == 0) + continue; + printf("Found locale '%s'\n", i->c_str()); + locales.push_back(*i); } printf("\n"); - if (locales.size() == 0) + // open locale expansion and common files + printf("Adding data files from locale directories.\n"); + for (std::vector::iterator i = locales.begin(); i != locales.end(); ++i) { - printf("Sorry, no locales found. Aborting.\n"); - return(false); + pArchiveNames.push_back(in_path + *i + "/locale-" + *i + ".MPQ"); + pArchiveNames.push_back(in_path + *i + "/expansion-locale-" + *i + ".MPQ"); + pArchiveNames.push_back(in_path + *i + "/lichking-locale-" + *i + ".MPQ"); } + // open expansion and common files + pArchiveNames.push_back(input_path + string("common.MPQ")); + pArchiveNames.push_back(input_path + string("common-2.MPQ")); + pArchiveNames.push_back(input_path + string("expansion.MPQ")); + pArchiveNames.push_back(input_path + string("lichking.MPQ")); + // now, scan for the patch levels in the core dir - printf("Loading patch levels from data directory.\n"); + printf("Scanning patch levels from data directory.\n"); sprintf(path, "%spatch", input_path); if (!scan_patches(path, pArchiveNames)) return(false); // now, scan for the patch levels in locale dirs - printf("Loading patch levels from locale directories.\n"); + printf("Scanning patch levels from locale directories.\n"); + bool foundOne = false; for (std::vector::iterator i = locales.begin(); i != locales.end(); ++i) { printf("Locale: %s\n", i->c_str()); - sprintf(path, "%s%s\\patch-%s", input_path, i->c_str(), i->c_str()); - if (!scan_patches(path, pArchiveNames)) return(false); + sprintf(path, "%s%s/patch-%s", input_path, i->c_str(), i->c_str()); + if(scan_patches(path, pArchiveNames)) + foundOne = true; } - // open expansion and common files - printf("Opening data files from data directory.\n"); - sprintf(path, "%slichking.mpq", input_path); - pArchiveNames.push_back(path); - sprintf(path, "%scommon-2.mpq", input_path); - pArchiveNames.push_back(path); - sprintf(path, "%sexpansion.mpq", input_path); - pArchiveNames.push_back(path); - sprintf(path, "%scommon.mpq", input_path); - pArchiveNames.push_back(path); printf("\n"); - // open locale expansion and common files - printf("Opening data files from locale directories.\n"); - for (std::vector::iterator i = locales.begin(); i != locales.end(); ++i) + if(!foundOne) { - printf("Locale: %s\n", i->c_str()); - sprintf(path, "%s%s\\lichking-locale-%s.mpq", input_path, i->c_str(), i->c_str()); - pArchiveNames.push_back(path); - sprintf(path, "%s%s\\expansion-locale-%s.mpq", input_path, i->c_str(), i->c_str()); - pArchiveNames.push_back(path); - sprintf(path, "%s%s\\locale-%s.mpq", input_path, i->c_str(), i->c_str()); - pArchiveNames.push_back(path); - printf("\n"); + printf("no locale found\n"); + return false; } + return true; } -bool processArgv(int argc, char ** argv, char*versionString) +bool processArgv(int argc, char ** argv, const char *versionString) { bool result = true; hasInputPathParam = false; @@ -448,7 +390,7 @@ bool processArgv(int argc, char ** argv, char*versionString) hasInputPathParam = true; strcpy(input_path, argv[i+1]); if (input_path[strlen(input_path) - 1] != '\\' || input_path[strlen(input_path) - 1] != '/') - strcat(input_path, "\\"); + strcat(input_path, "/"); ++i; } else @@ -484,7 +426,7 @@ bool processArgv(int argc, char ** argv, char*versionString) //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // Main -// +// // The program must be run with two command line arguments // // Arg1 - The source MPQ name (for testing reading and file find) @@ -493,52 +435,63 @@ bool processArgv(int argc, char ** argv, char*versionString) int main(int argc, char ** argv) { - //char tmp[512]; -// FILE* pDatei; -// char tmp[512]; -// char tmp1[512]; - //char tmp2[512]; -// char tmp3[512]; -// char tmp4[512]; -// char szMpqName[MAX_PATH] = ""; -// char szListFile[MAX_PATH] = ""; - int nError = ERROR_SUCCESS; - char *versionString = "V2.4 2007_07_12"; + bool success=true; + const char *versionString = "V2.90 2010_05"; // Use command line arguments, when some if(!processArgv(argc, argv, versionString)) return 1; + // some simple check if working dir is dirty + else + { + std::string sdir = std::string(szWorkDirWmo) + "/dir"; + std::string sdir_bin = std::string(szWorkDirWmo) + "/dir_bin"; + struct stat status; + if (!stat(sdir.c_str(), &status) || !stat(sdir_bin.c_str(), &status)) + { + printf("Your output directory seems to be polluted, please use an empty directory!\n"); + printf(""); + char garbage[2]; + scanf("%c", garbage); + return 1; + } + } + printf("Extract %s. Beginning work ....\n",versionString); - // Set the lowest priority to allow running in the background - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // Create the working directory - if(nError == ERROR_SUCCESS) - { - //if(!CreateDirectory(szWorkDirMaps, NULL)) - // nError = GetLastError(); - if(!CreateDirectory(szWorkDirWmo, NULL)) - nError = GetLastError(); - if(nError == ERROR_ALREADY_EXISTS) - nError = ERROR_SUCCESS; - } + if(mkdir(szWorkDirWmo +#ifdef __linux__ + , 0711 +#endif + )) + success = (errno == EEXIST); // prepare archive name list std::vector archiveNames; fillArchiveNameVector(archiveNames); - if(!gOpenArchives.Open(archiveNames)) + for (size_t i=0; i < archiveNames.size(); ++i) + { + MPQArchive *archive = new MPQArchive(archiveNames[i].c_str()); + if(!gOpenArchives.size() || gOpenArchives.front() != archive) + delete archive; + } + + if(gOpenArchives.empty()) { printf("FATAL ERROR: None MPQ archive found by path '%s'. Use -d option with proper path.\n",input_path); return 1; } + ReadLiquidTypeTableDBC(); // extract data - ExtractWmo(); + if(success) + success = ExtractWmo(); //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx //map.dbc - if(nError == ERROR_SUCCESS) + if(success) { DBCFile * dbc = new DBCFile("DBFilesClient\\Map.dbc"); if(!dbc->open()) @@ -556,18 +509,21 @@ int main(int argc, char ** argv) printf("Map - %s\n",map_ids[x].name); } + delete dbc; ParsMapFiles(); delete [] map_ids; - nError = ERROR_SUCCESS; + //nError = ERROR_SUCCESS; } clreol(); - if(nError != ERROR_SUCCESS) + if(!success) { printf("ERROR: Extract %s. Work NOT complete.\n Precise vector data=%d.\nPress any key.\n",versionString, preciseVectorData); - _getch(); + getchar(); } - printf("Extract %s. Work complete. No errors.",versionString); + printf("Extract %s. Work complete. No errors.\n",versionString); + delete [] LiqType; + return 0; } diff --git a/contrib/vmap_extractor_v2/vmapextract/vmapexport.h b/contrib/vmap_extractor_v2/vmapextract/vmapexport.h new file mode 100644 index 000000000..fa9a609ab --- /dev/null +++ b/contrib/vmap_extractor_v2/vmapextract/vmapexport.h @@ -0,0 +1,13 @@ +#ifndef VMAPEXPORT_H +#define VMAPEXPORT_H + +enum ModelFlags +{ + MOD_M2 = 1, + MOD_WORLDSPAWN = 1<<1, + MOD_HAS_BOUND = 1<<2 +}; + +extern const char * szWorkDirWmo; + +#endif diff --git a/contrib/vmap_extractor_v2/vmapextract/wdtfile.cpp b/contrib/vmap_extractor_v2/vmapextract/wdtfile.cpp index 697f9b33b..cd24ef034 100644 --- a/contrib/vmap_extractor_v2/vmapextract/wdtfile.cpp +++ b/contrib/vmap_extractor_v2/vmapextract/wdtfile.cpp @@ -1,7 +1,7 @@ -#define __STORMLIB_SELF__ - +#include "vmapexport.h" #include "wdtfile.h" #include "adtfile.h" +#include char * wdtGetPlainName(char * FileName) { @@ -17,7 +17,7 @@ WDTFile::WDTFile(char* file_name, char* file_name1):WDT(file_name) filename.append(file_name1,strlen(file_name1)); } -bool WDTFile::init(char *map_id) +bool WDTFile::init(char *map_id, unsigned int mapID) { if (WDT.isEof()) { @@ -26,14 +26,14 @@ bool WDTFile::init(char *map_id) } char fourcc[5]; - size_t size; + uint32 size; - const char dirname[] = "buildings\\dir"; + std::string dirname = std::string(szWorkDirWmo) + "/dir_bin"; FILE *dirfile; - dirfile = fopen(dirname, "ab"); + dirfile = fopen(dirname.c_str(), "ab"); if(!dirfile) { - printf("Can't open dirfile!'%s'\n"); + printf("Can't open dirfile!'%s'\n", dirname.c_str()); return false; } @@ -86,7 +86,7 @@ bool WDTFile::init(char *map_id) { int id; WDT.read(&id, 4); - WMOInstance inst(WDT,gWmoInstansName[id].c_str(),gWMO_mapname.c_str(), dirfile); + WMOInstance inst(WDT,gWmoInstansName[id].c_str(),mapID, 65, 65, dirfile); } delete[] gWmoInstansName; } diff --git a/contrib/vmap_extractor_v2/vmapextract/wdtfile.h b/contrib/vmap_extractor_v2/vmapextract/wdtfile.h index 0baef22f1..f3d71c417 100644 --- a/contrib/vmap_extractor_v2/vmapextract/wdtfile.h +++ b/contrib/vmap_extractor_v2/vmapextract/wdtfile.h @@ -1,20 +1,19 @@ #ifndef WDTFILE_H #define WDTFILE_H -#define __STORMLIB_SELF__ - -#include "mpq.h" -#include "adtfile.h" +#include "mpq_libmpq04.h" #include "wmo.h" #include #include "stdlib.h" +class ADTFile; + class WDTFile { public: WDTFile(char* file_name, char* file_name1); ~WDTFile(void); - bool init(char *map_id); + bool init(char *map_id, unsigned int mapID); string* gWmoInstansName; int gnWMO, nMaps; diff --git a/contrib/vmap_extractor_v2/vmapextract/wmo.cpp b/contrib/vmap_extractor_v2/vmapextract/wmo.cpp index 4817e14c8..03cc2c16c 100644 --- a/contrib/vmap_extractor_v2/vmapextract/wmo.cpp +++ b/contrib/vmap_extractor_v2/vmapextract/wmo.cpp @@ -1,10 +1,18 @@ -#define __STORMLIB_SELF__ +#include "vmapexport.h" #include "wmo.h" -#include "Stormlib.h" -#include "mpq.h" +#include "vec3d.h" +#include +#include +#include +#include +#include +#undef min +#undef max +#include "mpq_libmpq04.h" using namespace std; +extern uint16 *LiqType; WMORoot::WMORoot(std::string &filename) : filename(filename) { @@ -19,10 +27,8 @@ bool WMORoot::open() return false; } - size_t size; + uint32 size; char fourcc[5]; - bbcorn1[3] = 0; - bbcorn2[3]= 0; while (!f.isEof()) { @@ -44,9 +50,10 @@ bool WMORoot::open() f.read(&nDoodads, 4); f.read(&nDoodadSets, 4); f.read(&col, 4); - f.read(&RootID, 4); + f.read(&RootWMOID, 4); f.read(bbcorn1,12); f.read(bbcorn2,12); + f.read(&liquidType, 4); break; } /* @@ -100,10 +107,11 @@ bool WMORoot::ConvertToVMAPRootWmo(FILE *pOutfile) { //printf("Convert RootWmo...\n"); - fwrite("VMAP002",1,8,pOutfile); + fwrite("VMAP003",1,8,pOutfile); unsigned int nVectors = 0; fwrite(&nVectors,sizeof(nVectors),1,pOutfile); // will be filled later fwrite(&nGroups,4,1,pOutfile); + fwrite(&RootWMOID,4,1,pOutfile); return true; } @@ -111,7 +119,8 @@ WMORoot::~WMORoot() { } -WMOGroup::WMOGroup(std::string &filename) : filename(filename) +WMOGroup::WMOGroup(std::string &filename) : filename(filename), + MOPY(0), MOVI(0), MoviEx(0), MOVT(0), MOBA(0), MobaEx(0), hlq(0), LiquEx(0), LiquBytes(0) { } @@ -123,10 +132,8 @@ bool WMOGroup::open() printf("No such file.\n"); return false; } - size_t size; + uint32 size; char fourcc[5]; - bbcorn1[3] = 0; - bbcorn2[3] = 0; while (!f.isEof()) { f.read(fourcc,4); @@ -143,19 +150,20 @@ bool WMOGroup::open() if (!strcmp(fourcc,"MOGP"))//header { - f.seekRelative(-4); - f.read(&offsize, 4); - f.read(&flag, 4); - f.read(&flag1, 4); - f.read(&Xid, 4); + f.read(&groupName, 4); + f.read(&descGroupName, 4); + f.read(&mogpFlags, 4); f.read(bbcorn1, 12); f.read(bbcorn2, 12); - f.read(&Xid2, 4); - f.read(&Xid3, 4); - f.read(&zero1, 4); - f.read(&Xflag, 4); - f.read(&nTexture,4); - f.read(&GroupID,4); + f.read(&moprIdx, 2); + f.read(&moprNItems, 2); + f.read(&nBatchA, 2); + f.read(&nBatchB, 2); + f.read(&nBatchC, 4); + f.read(&fogIdx, 4); + f.read(&liquidType, 4); + f.read(&groupWMOID,4); + } else if (!strcmp(fourcc,"MOPY")) { @@ -190,26 +198,21 @@ bool WMOGroup::open() else if (!strcmp(fourcc,"MLIQ")) { liquflags |= 1; - WMOLiquidHeader hlq; - f.read(&hlq, 0x1E); - float ydir = -1.0f; - hlq_xverts = hlq.xverts; - hlq_yverts = hlq.yverts; - int noVer = hlq.xverts * hlq.yverts; - float tilesize = CHUNKSIZE / 8.0f; - LiquEx_size = sizeof(float) * 3 * noVer; - LiquEx = new float[sizeof(float) * 3 * noVer]; - int p = 0; + hlq = new WMOLiquidHeader; + f.read(hlq, 0x1E); + LiquEx_size = sizeof(WMOLiquidVert) * hlq->xverts * hlq->yverts; + LiquEx = new WMOLiquidVert[hlq->xverts * hlq->yverts]; + f.read(LiquEx, LiquEx_size); + int nLiquBytes = hlq->xtiles * hlq->ytiles; + LiquBytes = new char[nLiquBytes]; + f.read(LiquBytes, nLiquBytes); - for (int j=0; jpos_x << ", " << hlq->pos_y << ", " << hlq->pos_z; + llog << "\nx-/yvert: " << hlq->xverts << "/" << hlq->yverts << " size: " << size << " expected size: " << 30 + hlq->xverts*hlq->yverts*8 + hlq->xtiles*hlq->ytiles << std::endl; + llog.close(); */ } f.seek((int)nextpos); } @@ -217,11 +220,17 @@ bool WMOGroup::open() return true; } -int WMOGroup::ConvertToVMAPGroupWmo(FILE *output, bool pPreciseVectorData) +int WMOGroup::ConvertToVMAPGroupWmo(FILE *output, WMORoot *rootWMO, bool pPreciseVectorData) { + fwrite(&mogpFlags,sizeof(uint32),1,output); + fwrite(&groupWMOID,sizeof(uint32),1,output); + // group bound + fwrite(bbcorn1, sizeof(float), 3, output); + fwrite(bbcorn2, sizeof(float), 3, output); + fwrite(&liquflags,sizeof(uint32),1,output); + int nColTriangles = 0; if(pPreciseVectorData) { - fwrite(&liquflags,sizeof(uint32),1,output); char GRP[] = "GRP "; fwrite(GRP,1,4,output); @@ -232,7 +241,6 @@ int WMOGroup::ConvertToVMAPGroupWmo(FILE *output, bool pPreciseVectorData) { MobaEx[k++] = MOBA[i]; } - delete [] MOBA; int moba_size_grp = moba_batch*4+4; fwrite(&moba_size_grp,4,1,output); fwrite(&moba_batch,4,1,output); @@ -291,21 +299,10 @@ int WMOGroup::ConvertToVMAPGroupWmo(FILE *output, bool pPreciseVectorData) } } - if(LiquEx_size != 0) - { - int LIQU_h[] = {0x5551494C,LiquEx_size+8,hlq_xverts,hlq_yverts};// "LIQU" - fwrite(LIQU_h,4,4,output); - fwrite(LiquEx,4,LiquEx_size/4,output); - delete [] LiquEx; - } - - return nTriangles; + nColTriangles = nTriangles; } else { - //printf("Convert GroupWmo...\n"); - //-------GRP ------------------------------------- - fwrite(&liquflags,sizeof(uint32),1,output); char GRP[] = "GRP "; fwrite(GRP,1,4,output); int k = 0; @@ -315,7 +312,7 @@ int WMOGroup::ConvertToVMAPGroupWmo(FILE *output, bool pPreciseVectorData) { MobaEx[k++] = MOBA[i]; } - delete [] MOBA; + int moba_size_grp = moba_batch*4+4; fwrite(&moba_size_grp,4,1,output); fwrite(&moba_batch,4,1,output); @@ -324,146 +321,106 @@ int WMOGroup::ConvertToVMAPGroupWmo(FILE *output, bool pPreciseVectorData) //-------INDX------------------------------------ //-------MOPY-------- - int n = 0; - int j = 0; - MopyEx = new char[mopy_size]; - IndexExTr = new int[mopy_size]; - for (int i=0; i MoviExSort[i+1]) - { - hold = MoviExSort[i]; - MoviExSort[i] = MoviExSort[i+1]; - MoviExSort[i+1] = hold; - } - //double = 65535 - else - if (MoviExSort[i] == MoviExSort[i+1]) - MoviExSort[i+1] = 65535; + IndexRenum[i] = nColVertices; + ++nColVertices; } } - // double delet - uint16 s = 0; - for (int i=0; i < IndexExTr_size*3; ++i) - { - if (MoviExSort[i]!=65535) - { - MoviExSort[s] = MoviExSort[i]; - s++; - } - } - MovtExSort = new uint16[s]; - for (int i=0; i < s; ++i) - { - MovtExSort[i] = MoviExSort[i]; - } - for (int i=0; i < IndexExTr_size*3; ++i) + // translate triangle indices to new numbers + for (int i=0; i<3*nColTriangles; ++i) { - uint16 b = MoviEx[i]; - for (uint16 x = 0; x < s; ++x) - { - if(MoviExSort[x] == b) - { - MoviEx[i] = x; - break; - } - } + assert(MoviEx[i] < nVertices); + MoviEx[i] = IndexRenum[MoviEx[i]]; } - int INDX[] = {0x58444E49,IndexExTr_size*6+4,IndexExTr_size*3}; + + // write triangle indices + int INDX[] = {0x58444E49, nColTriangles*6+4, nColTriangles*3}; fwrite(INDX,4,3,output); - fwrite(MoviEx,2,IndexExTr_size*3,output); + fwrite(MoviEx,2,nColTriangles*3,output); + + // write vertices + int VERT[] = {0x54524556, nColVertices*3*sizeof(float)+4, nColVertices};// "VERT" + int check = 3*nColVertices; + fwrite(VERT,4,3,output); + for (uint32 i=0; i= 0) + check -= fwrite(MOVT+3*i, sizeof(float), 3, output); + + assert(check==0); delete [] MoviEx; - delete [] MoviExSort; - delete [] IndexExTr; - - //----------VERT--------- - //-----MOVT---------- - int d = 0; - MovtEx = new float[s*3]; - for (uint16 i=0; ixtiles*hlq->ytiles};// "LIQU" + fwrite(LIQU_h, 4, 2, output); + + // according to WoW.Dev Wiki: + uint32 liquidEntry; + if (rootWMO->liquidType & 4) + liquidEntry = liquidType; + else if (liquidType == 15) + liquidEntry = 1; // first entry, generic "Water" + else + liquidEntry = liquidType + 1; + // overwrite material type in header... + hlq->type = LiqType[liquidEntry]; + + /* std::ofstream llog("Buildings/liquid.log", ios_base::out | ios_base::app); + llog << filename; + llog << ":\nliquidEntry: " << liquidEntry << " type: " << hlq->type << " (root:" << rootWMO->liquidType << " group:" << liquidType << ")\n"; + llog.close(); */ + + fwrite(hlq, sizeof(WMOLiquidHeader), 1, output); + // only need height values, the other values are unknown anyway + for (uint32 i = 0; ixtiles*hlq->ytiles, output); + } + + return nColTriangles; } WMOGroup::~WMOGroup() { + delete [] MOPY; + delete [] MOVI; + delete [] MOVT; + delete [] MOBA; + delete hlq; + delete [] LiquEx; + delete [] LiquBytes; } -WMOInstance::WMOInstance(MPQFile &f,const char* WmoInstName,const char*MapName, FILE *pDirfile) +WMOInstance::WMOInstance(MPQFile &f,const char* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE *pDirfile) { pos = Vec3D(0,0,0); @@ -478,35 +435,23 @@ WMOInstance::WMOInstance(MPQFile &f,const char* WmoInstName,const char*MapName, f.read(ff,12); pos3 = Vec3D(ff[0],ff[1],ff[2]); f.read(&d2,4); - f.read(&d3,4); - doodadset = (d2 & 0xFFFF0000) >> 16; - - int realx1 = (int) ((float) pos2.x / 533.333333f); - int realy1 = (int) ((float) pos2.z / 533.333333f); - int realx2 = (int) ((float) pos3.x / 533.333333f); - int realy2 = (int) ((float) pos3.z / 533.333333f); - - if(realx1 < 0) - { - realx1 +=20; realx2+=20; - } - if(realy1 < 0) - { - realy1 +=20; realy2+=20; - } // hack to prevent neg. values + uint16 trash,adtId; + f.read(&adtId,2); + f.read(&trash,2); //-----------add_in _dir_file---------------- char tempname[512]; - // const char dirname[] = "buildings\\dir"; - - sprintf(tempname, "buildings\\%s", WmoInstName); + sprintf(tempname, "%s/%s", szWorkDirWmo, WmoInstName); FILE *input; input = fopen(tempname, "r+b"); if(!input) + { + printf("WMOInstance::WMOInstance: couldn't open %s\n", tempname); return; + } fseek(input, 8, SEEK_SET); // get the correct no of vertices int nVertices; @@ -516,24 +461,38 @@ WMOInstance::WMOInstance(MPQFile &f,const char* WmoInstName,const char*MapName, if(nVertices == 0) return; - /* FILE *dirfile; - dirfile = fopen(dirname, "ab"); - if(!dirfile) - { - printf("Can't open dirfile!'%s'\n"); - return; - } - */ float x,z; x = pos.x; z = pos.z; if(x==0 && z == 0) { - x = 533.33333f*32; - z = 533.33333f*32; + pos.x = 533.33333f*32; + pos.z = 533.33333f*32; } + pos = fixCoords(pos); + pos2 = fixCoords(pos2); + pos3 = fixCoords(pos3); - fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f 1.0 %d %d %d,%d %d\n", + float scale = 1.0f; + uint32 flags = MOD_HAS_BOUND; + if(tileX == 65 && tileY == 65) flags |= MOD_WORLDSPAWN; + //write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name + fwrite(&mapID, sizeof(uint32), 1, pDirfile); + fwrite(&tileX, sizeof(uint32), 1, pDirfile); + fwrite(&tileY, sizeof(uint32), 1, pDirfile); + fwrite(&flags, sizeof(uint32), 1, pDirfile); + fwrite(&adtId, sizeof(uint16), 1, pDirfile); + fwrite(&id, sizeof(uint32), 1, pDirfile); + fwrite(&pos, sizeof(float), 3, pDirfile); + fwrite(&rot, sizeof(float), 3, pDirfile); + fwrite(&scale, sizeof(float), 1, pDirfile); + fwrite(&pos2, sizeof(float), 3, pDirfile); + fwrite(&pos3, sizeof(float), 3, pDirfile); + uint32 nlen=strlen(WmoInstName); + fwrite(&nlen, sizeof(uint32), 1, pDirfile); + fwrite(WmoInstName, sizeof(char), nlen, pDirfile); + + /* fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f 1.0 %d %d %d,%d %d\n", MapName, WmoInstName, (float) x, (float) pos.y, (float) z, @@ -541,7 +500,7 @@ WMOInstance::WMOInstance(MPQFile &f,const char* WmoInstName,const char*MapName, nVertices, realx1, realy1, realx2, realy2 - ); + ); */ // fclose(dirfile); } diff --git a/contrib/vmap_extractor_v2/vmapextract/wmo.h b/contrib/vmap_extractor_v2/vmapextract/wmo.h index 3000050c1..12979bc13 100644 --- a/contrib/vmap_extractor_v2/vmapextract/wmo.h +++ b/contrib/vmap_extractor_v2/vmapextract/wmo.h @@ -1,14 +1,12 @@ #ifndef WMO_H #define WMO_H -#define __STORMLIB_SELF__ #define TILESIZE (533.33333f) #define CHUNKSIZE ((TILESIZE) / 16.0f) -#include "Stormlib.h" #include -#include "vec3d.h" #include -#include "mpq.h" +#include "vec3d.h" +#include "loadlib/loadlib.h" // MOPY flags #define WMO_MATERIAL_NOCAMCOLLIDE 0x01 @@ -21,19 +19,18 @@ class WMOInstance; class WMOManager; +class MPQFile; -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; - +/* for whatever reason a certain company just can't stick to one coordinate system... */ +static inline Vec3D fixCoords(const Vec3D &v){ return Vec3D(v.z, v.x, v.y); } class WMORoot { public: - int nTextures, nGroups, nP, nLights, nModels, nDoodads, nDoodadSets, RootID; + uint32 nTextures, nGroups, nP, nLights, nModels, nDoodads, nDoodadSets, RootWMOID, liquidType; unsigned int col; - int bbcorn1[3]; - int bbcorn2[3]; + float bbcorn1[3]; + float bbcorn2[3]; WMORoot(std::string &filename); ~WMORoot(); @@ -45,44 +42,7 @@ private: char outfilename; }; -class WMOGroup -{ -public: - int offsize,flag,flag1,Xid,Xid2,Xid3,zero1,Xflag,nTexture,GroupID; - int mopy_size,moba_size,hlq_xverts,hlq_yverts; - int MopyEx_size,IndexExTr_size,LiquEx_size; - unsigned int nVertices; // number when loaded - int nTriangles; // number when loaded - int bbcorn1[3]; - int bbcorn2[3]; - int * IndexExTr; - char* MOPY; - char* MopyEx; - uint16* MOVI; - uint16* MoviEx; - uint16* MoviExSort; - float* MOVT; - float* MovtEx; - uint16* MovtExSort; - float* MONR; - float* MonrEx; - uint16* MOBA; - int* MobaEx; - float* LiquEx; - uint32 liquflags; - - WMOGroup(std::string &filename); - ~WMOGroup(); - - bool open(); - int ConvertToVMAPGroupWmo(FILE *output, bool pPreciseVectorData); - -private: - std::string filename; - char outfilename; -}; - -struct WMOLiquidHeader +struct WMOLiquidHeader { int xverts, yverts, xtiles, ytiles; float pos_x; @@ -91,20 +51,66 @@ struct WMOLiquidHeader short type; }; -class WMOInstance +struct WMOLiquidVert +{ + uint16 unk1; + uint16 unk2; + float height; +}; + +class WMOGroup +{ +public: + // MOGP + int groupName, descGroupName, mogpFlags; + float bbcorn1[3]; + float bbcorn2[3]; + uint16 moprIdx; + uint16 moprNItems; + uint16 nBatchA; + uint16 nBatchB; + uint32 nBatchC, fogIdx, liquidType, groupWMOID; + + int mopy_size,moba_size; + int LiquEx_size; + unsigned int nVertices; // number when loaded + int nTriangles; // number when loaded + char *MOPY; + uint16 *MOVI; + uint16 *MoviEx; + float *MOVT; + uint16 *MOBA; + int *MobaEx; + WMOLiquidHeader *hlq; + WMOLiquidVert *LiquEx; + char *LiquBytes; + uint32 liquflags; + + WMOGroup(std::string &filename); + ~WMOGroup(); + + bool open(); + int ConvertToVMAPGroupWmo(FILE *output, WMORoot *rootWMO, bool pPreciseVectorData); + +private: + std::string filename; + char outfilename; +}; + +class WMOInstance { static std::set ids; public: - string MapName; + std::string MapName; int currx; int curry; WMOGroup *wmo; Vec3D pos; Vec3D pos2, pos3, rot; - int indx,id, d2, d3; + uint32 indx,id, d2, d3; int doodadset; - WMOInstance(MPQFile &f,const char* WmoInstName,const char*MapName, FILE *pDirfile); + WMOInstance(MPQFile &f,const char* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE *pDirfile); static void reset(); }; diff --git a/contrib/vmap_extractor_v2/win/.gitignore b/contrib/vmap_extractor_v2/win/.gitignore new file mode 100644 index 000000000..52fa31bb7 --- /dev/null +++ b/contrib/vmap_extractor_v2/win/.gitignore @@ -0,0 +1,6 @@ + +*.opensdf +*.sdf +*.suo +bin +ipch \ No newline at end of file diff --git a/contrib/vmap_extractor_v2/win/VC100/.gitignore b/contrib/vmap_extractor_v2/win/VC100/.gitignore new file mode 100644 index 000000000..4fb7be5e4 --- /dev/null +++ b/contrib/vmap_extractor_v2/win/VC100/.gitignore @@ -0,0 +1,2 @@ + +*.user \ No newline at end of file diff --git a/contrib/vmap_extractor_v2/win/VC100/vmapExtractor3.vcxproj b/contrib/vmap_extractor_v2/win/VC100/vmapExtractor3.vcxproj new file mode 100644 index 000000000..78e8c8765 --- /dev/null +++ b/contrib/vmap_extractor_v2/win/VC100/vmapExtractor3.vcxproj @@ -0,0 +1,106 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393} + vmapExtractor3 + + + + Application + MultiByte + true + + + Application + MultiByte + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\$(Platform)_$(Configuration)\ + ..\bin\$(ProjectName)__$(Platform)_$(Configuration)\ + ..\..\bin\$(Platform)_$(Configuration)\ + ..\bin\$(ProjectName)__$(Platform)_$(Configuration)\ + + + + Disabled + ..\..\..\..\dep\libmpq;%(AdditionalIncludeDirectories) + WIN32;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Level3 + EditAndContinue + + + libmpq.lib;%(AdditionalDependencies) + ..\..\..\..\dep\libmpq\bin\$(Platform)_$(Configuration);%(AdditionalLibraryDirectories) + true + MachineX86 + + + + + MaxSpeed + true + ..\..\..\..\dep\libmpq;%(AdditionalIncludeDirectories) + WIN32;%(PreprocessorDefinitions) + MultiThreadedDLL + true + Level3 + ProgramDatabase + + + libmpq.lib;%(AdditionalDependencies) + ..\..\..\..\dep\libmpq\bin\$(Platform)_$(Configuration);%(AdditionalLibraryDirectories) + false + true + true + MachineX86 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/vmap_extractor_v2/win/VC90/.gitignore b/contrib/vmap_extractor_v2/win/VC90/.gitignore new file mode 100644 index 000000000..4fb7be5e4 --- /dev/null +++ b/contrib/vmap_extractor_v2/win/VC90/.gitignore @@ -0,0 +1,2 @@ + +*.user \ No newline at end of file diff --git a/contrib/vmap_extractor_v2/win/VC90/vmapExtractor3.vcproj b/contrib/vmap_extractor_v2/win/VC90/vmapExtractor3.vcproj new file mode 100644 index 000000000..83801906a --- /dev/null +++ b/contrib/vmap_extractor_v2/win/VC90/vmapExtractor3.vcproj @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/vmap_extractor_v2/win/vmapExtractor3_VC100.sln b/contrib/vmap_extractor_v2/win/vmapExtractor3_VC100.sln new file mode 100644 index 000000000..7fed404d0 --- /dev/null +++ b/contrib/vmap_extractor_v2/win/vmapExtractor3_VC100.sln @@ -0,0 +1,42 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmapExtractor3", "VC100\vmapExtractor3.vcxproj", "{D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}" + ProjectSection(ProjectDependencies) = postProject + {B96F612A-C91D-43B3-A4C3-D4294817EC6C} = {B96F612A-C91D-43B3-A4C3-D4294817EC6C} + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2} = {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2} + {03AB0F44-628E-4855-99A0-C98A1EB52C50} = {03AB0F44-628E-4855-99A0-C98A1EB52C50} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmpq", "..\..\..\dep\libmpq\win\VC100\libmpq.vcxproj", "{03AB0F44-628E-4855-99A0-C98A1EB52C50}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\..\..\win\VC100\zlib.vcxproj", "{8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bzip2", "..\..\..\win\VC100\bzip2.vcxproj", "{B96F612A-C91D-43B3-A4C3-D4294817EC6C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}.Debug|Win32.ActiveCfg = Debug|Win32 + {D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}.Debug|Win32.Build.0 = Debug|Win32 + {D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}.Release|Win32.ActiveCfg = Release|Win32 + {D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}.Release|Win32.Build.0 = Release|Win32 + {03AB0F44-628E-4855-99A0-C98A1EB52C50}.Debug|Win32.ActiveCfg = Debug|Win32 + {03AB0F44-628E-4855-99A0-C98A1EB52C50}.Debug|Win32.Build.0 = Debug|Win32 + {03AB0F44-628E-4855-99A0-C98A1EB52C50}.Release|Win32.ActiveCfg = Release|Win32 + {03AB0F44-628E-4855-99A0-C98A1EB52C50}.Release|Win32.Build.0 = Release|Win32 + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Debug|Win32.ActiveCfg = Debug|Win32 + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Debug|Win32.Build.0 = Debug|Win32 + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Release|Win32.ActiveCfg = Release|Win32 + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Release|Win32.Build.0 = Release|Win32 + {B96F612A-C91D-43B3-A4C3-D4294817EC6C}.Debug|Win32.ActiveCfg = Debug|Win32 + {B96F612A-C91D-43B3-A4C3-D4294817EC6C}.Debug|Win32.Build.0 = Debug|Win32 + {B96F612A-C91D-43B3-A4C3-D4294817EC6C}.Release|Win32.ActiveCfg = Release|Win32 + {B96F612A-C91D-43B3-A4C3-D4294817EC6C}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/contrib/vmap_extractor_v2/win/vmapExtractor3_VC90.sln b/contrib/vmap_extractor_v2/win/vmapExtractor3_VC90.sln new file mode 100644 index 000000000..f353a972b --- /dev/null +++ b/contrib/vmap_extractor_v2/win/vmapExtractor3_VC90.sln @@ -0,0 +1,42 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmapExtractor3", "VC90\vmapExtractor3.vcproj", "{D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}" + ProjectSection(ProjectDependencies) = postProject + {B96F612A-C91D-43B3-A4C3-D4294817EC6C} = {B96F612A-C91D-43B3-A4C3-D4294817EC6C} + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2} = {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2} + {03AB0F44-628E-4855-99A0-C98A1EB52C50} = {03AB0F44-628E-4855-99A0-C98A1EB52C50} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmpq", "..\..\..\dep\libmpq\win\VC90\libmpq.vcproj", "{03AB0F44-628E-4855-99A0-C98A1EB52C50}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\..\..\win\VC90\zlib.vcproj", "{8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bzip2", "..\..\..\win\VC90\bzip2.vcproj", "{B96F612A-C91D-43B3-A4C3-D4294817EC6C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}.Debug|Win32.ActiveCfg = Debug|Win32 + {D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}.Debug|Win32.Build.0 = Debug|Win32 + {D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}.Release|Win32.ActiveCfg = Release|Win32 + {D4624B20-AC1E-4EE9-8C9C-0FB65EEE3393}.Release|Win32.Build.0 = Release|Win32 + {03AB0F44-628E-4855-99A0-C98A1EB52C50}.Debug|Win32.ActiveCfg = Debug|Win32 + {03AB0F44-628E-4855-99A0-C98A1EB52C50}.Debug|Win32.Build.0 = Debug|Win32 + {03AB0F44-628E-4855-99A0-C98A1EB52C50}.Release|Win32.ActiveCfg = Release|Win32 + {03AB0F44-628E-4855-99A0-C98A1EB52C50}.Release|Win32.Build.0 = Release|Win32 + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Debug|Win32.ActiveCfg = Debug|Win32 + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Debug|Win32.Build.0 = Debug|Win32 + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Release|Win32.ActiveCfg = Release|Win32 + {8F1DEA42-6A5B-4B62-839D-C141A7BFACF2}.Release|Win32.Build.0 = Release|Win32 + {B96F612A-C91D-43B3-A4C3-D4294817EC6C}.Debug|Win32.ActiveCfg = Debug|Win32 + {B96F612A-C91D-43B3-A4C3-D4294817EC6C}.Debug|Win32.Build.0 = Debug|Win32 + {B96F612A-C91D-43B3-A4C3-D4294817EC6C}.Release|Win32.ActiveCfg = Release|Win32 + {B96F612A-C91D-43B3-A4C3-D4294817EC6C}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 97e285422..c78fbf752 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "10162" + #define REVISION_NR "10163" #endif // __REVISION_NR_H__