diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..ee01f0d --- /dev/null +++ b/.clang-format @@ -0,0 +1,27 @@ +BasedOnStyle: LLVM +AccessModifierOffset: -8 +AlignEscapedNewlinesLeft: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +AlwaysBreakTemplateDeclarations: false +BinPackParameters: true +ColumnLimit: 0 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +DerivePointerBinding: false +IndentCaseLabels: true +MaxEmptyLinesToKeep: 2 +ObjCSpaceBeforeProtocolList: true +PenaltyBreakComment: 45 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 75 +PointerBindsToType: true +PointerAlignment: Left +SpacesBeforeTrailingComments: 1 +Standard: Auto +IndentWidth: 8 +UseTab: Always +BreakBeforeBraces: Linux +BreakConstructorInitializersBeforeComma: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ab6702 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +/CMakeFiles +/CMakeCache.txt +/Makefile +/cmake_install.cmake + +*.swp +*.so +*.a +*.exe +*~ +/mapcompile +/mapdecompile +/.ninja_deps +/.ninja_log +/build.ninja +/rules.ninja + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6fe840b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: cpp +dist: trusty +sudo: required +compiler: + - gcc + - clang +before_script: + - sudo apt-get install libdevil-dev + - cmake . +script: + - make + diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e757cf..6627d16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,32 +1,42 @@ project(SpringMapConvNG) -cmake_minimum_required(VERSION 2.6) -#find_package(Qt4 REQUIRED) -if (NOT MINGW ) - include_directories(${CMAKE_CURRENT_BINARY_DIR}) -else ( NOT MINGW ) - include_directories(${CMAKE_CURRENT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/winlibs/Devil_${ARCH}/include ) - link_directories( ${PROJECT_SOURCE_DIR}/winlibs/Devil_${ARCH}/lib ${PROJECT_SOURCE_DIR}/winlibs/Devil_${ARCH} ) - -endif ( NOT MINGW ) - -#qt4_automoc(${springMapConvNG_SRCS}) - -find_package(DevIL REQUIRED) - -add_library(mapconv SHARED CRC.cpp Image.cpp SMFMap.cpp TileStorage.cpp ) -add_library(mapconv_static STATIC CRC.cpp Image.cpp SMFMap.cpp TileStorage.cpp ) -add_executable(springMapConvNG main.cpp) -add_executable(smfdecompiler decompiler.cpp) -if (NOT MINGW ) -target_link_libraries(springMapConvNG IL ILU mapconv_static ) -target_link_libraries(mapconv IL ILU ) -target_link_libraries(smfdecompiler IL ILU mapconv_static ) -else ( NOT MINGW ) -target_link_libraries(springMapConvNG DevIL ILU mapconv ) -target_link_libraries(mapconv DevIL ILU ) -target_link_libraries(smfdecompiler DevIL ILU mapconv ) -endif ( NOT MINGW ) - -install(TARGETS springMapConvNG smfdecompiler RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin ) -install(TARGETS mapconv_static ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) -install(TARGETS mapconv LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) +cmake_minimum_required(VERSION 3.3) + +set (CMAKE_CXX_STANDARD 11) +find_package(PkgConfig REQUIRED) +pkg_check_modules(ILU REQUIRED ILU) + + +set(MAPCONV_FILES + src/CRC.cpp + src/Image.cpp + src/SMFMap.cpp + src/TileStorage.cpp +) + + +add_executable(mapcompile src/mapcompile.cpp ${MAPCONV_FILES}) +add_executable(mapdecompile src/mapdecompile.cpp ${MAPCONV_FILES}) + +foreach(target mapcompile mapdecompile) + if(PREFER_STATIC_LIBS) # inside spring build + target_compile_definitions(${target} PRIVATE IL_STATIC_LIB) + set_target_properties(${target} PROPERTIES LINK_FLAGS "-static" ) + endif () + + target_link_libraries(${target} + PRIVATE + ${ILU_LINK_LIBRARIES} + ) + target_include_directories(${target} + PRIVATE + ${ILU_INCLUDE_DIRS} + ) +endforeach() + + +if (DEFINED BINDIR) + install(TARGETS mapcompile mapdecompile RUNTIME DESTINATION ${BINDIR}) +else () + install(TARGETS mapcompile mapcompile RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) +endif () + diff --git a/CRC.h b/CRC.h deleted file mode 100644 index e5af8cd..0000000 --- a/CRC.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef CRC_H -#define CRC_H - -#include - -class Crc32 -{ -public: - Crc32() ; - ~Crc32(); - void Reset(); - void AddData(const uint8_t* pData, const uint32_t length); - - const uint32_t GetCrc32(); - -private: - uint32_t _crc; -}; - -#endif // CRC_H diff --git a/Image.cpp b/Image.cpp deleted file mode 100644 index 9bb0446..0000000 --- a/Image.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - - Copyright (C) 2011 Tiziano - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - - -#include "Image.h" - -CannotLoadImageException::CannotLoadImageException(std::string path) : runtime_error(path) -{ - -} - -Image::Image() -{ - ilGenImages(1,&image); - - - -} -void Image::GetRect(int x, int y, int w, int h,ILenum format, void * dest) -{ - ilBindImage(image); - ilCopyPixels(x,y,0,w,h,1,format,IL_UNSIGNED_BYTE,dest); -} -void Image::GetRect(int x, int y, int w, int h, ILenum format, ILenum type, void* dest) -{ - ilBindImage(image); - ilCopyPixels(x,y,0,w,h,1,format,type,dest); -} -void Image::FlipVertical() -{ - ilBindImage(image); - iluFlipImage(); -} - -Image::Image(const char* filename, bool hdrlum ) -{ - - ilGenImages(1,&image); - ilBindImage(image); - if ( ! ilLoadImage(filename) ) - { - throw CannotLoadImageException(std::string(filename)); - - } - if (!hdrlum) - { - ConvertToRGBA(); - }else if ( ilGetInteger( IL_IMAGE_BYTES_PER_PIXEL ) != 2 || ilGetInteger(IL_IMAGE_FORMAT) != IL_LUMINANCE ) { - ConvertToLUMHDR(); - } - w = ilGetInteger(IL_IMAGE_WIDTH); - h = ilGetInteger(IL_IMAGE_HEIGHT); - d = ilGetInteger(IL_IMAGE_DEPTH); - datapointer = ilGetData(); - -} -void Image::Save(const char* filename) -{ - ilBindImage(image); - ilSaveImage(filename); -} -void Image::AllocateLUM(int x, int y, char* data) -{ - ilBindImage(image); - ilTexImage(x,y,1,1,IL_LUMINANCE,IL_UNSIGNED_BYTE,data); - datapointer = ilGetData(); - w = ilGetInteger(IL_IMAGE_WIDTH); - h = ilGetInteger(IL_IMAGE_HEIGHT); - d = ilGetInteger(IL_IMAGE_DEPTH); -} - -void Image::AllocateRGBA(int x, int y, char* data) -{ - ilBindImage(image); - ilTexImage(x,y,1,4,IL_RGBA,IL_UNSIGNED_BYTE,data); - datapointer = ilGetData(); - w = ilGetInteger(IL_IMAGE_WIDTH); - h = ilGetInteger(IL_IMAGE_HEIGHT); - d = ilGetInteger(IL_IMAGE_DEPTH); -} -void Image::Rescale(int x, int y) -{ - ilBindImage(image); - iluScale(x,y,1); - datapointer = ilGetData(); - w = ilGetInteger(IL_IMAGE_WIDTH); - h = ilGetInteger(IL_IMAGE_HEIGHT); - d = ilGetInteger(IL_IMAGE_DEPTH); -} - -void Image::GetPixelRGBA(int x_, int y_, unsigned char* pix) -{ - - int x = x_ % w; - int y = h -(y_ % h); - - if ( datapointer ) - { - pix[0] = datapointer[w*y*4+x*4]; - pix[1] = datapointer[w*y*4+x*4+1]; - pix[2] = datapointer[w*y*4+x*4+2]; - pix[3] = datapointer[w*y*4+x*4+3]; - } else { - printf("GetPixelRGBA(%i,%i): datapointer is NULL\n",x_,y_); - } - //printf("%i %i %i\n",(int)pix[0],(int)pix[1],int(pix[2])); -} - - - -void Image::SetPixelRGBA(int x_, int y_, char r, char g, char b, char a) -{ - int x = (x_ % w); - int y = h - (y_ % h) - 1; - datapointer[w*y*3+x*3] = r; - datapointer[w*y*3+x*3+1] = g; - datapointer[w*y*3+x*3+2] = b; - datapointer[w*y*4+x*4+3] = a; - -} - -void Image::SetPixelLUM(int x_, int y_, char val) -{ - int x = x_ % w; - int y = y_ % h; - datapointer[y*w+x] = val; - - -} -void Image::GetPixelLUM(int x_, int y_, unsigned char* p) -{ - //printf("GetPixelLUM(%i,%i)\n",x_,y_); - int x = x_ % w; - int y = y_ % h; - p[0] = datapointer[y*w+x]; - -} -void Image::ConvertToLUM() -{ - ilBindImage(image); - ilConvertImage(IL_LUMINANCE,IL_UNSIGNED_BYTE); - datapointer = ilGetData(); - -} -void Image::ConvertToLUMHDR() -{ - ilBindImage(image); - ilConvertImage(IL_LUMINANCE,IL_UNSIGNED_SHORT); - datapointer = ilGetData(); -} - -void Image::ConvertToRGBA() -{ - ilBindImage(image); - ilConvertImage(IL_RGBA,IL_UNSIGNED_BYTE); - datapointer = ilGetData(); -} -Image::~Image() -{ - ilDeleteImages(1,&image); -} - - diff --git a/Image.h b/Image.h deleted file mode 100644 index 00dc9c1..0000000 --- a/Image.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - - Copyright (C) 2011 Tiziano - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - - -#ifndef IMAGE_H -#define IMAGE_H -#include -#include -#include -#include -class CannotLoadImageException : public std::runtime_error -{ -public: - CannotLoadImageException(std::string path); -}; -class Image{ - public: - ILuint image; - int w; - int h; - int d; - unsigned char * datapointer; - Image(); - - Image(const char* filename, bool hdrlum = false); - - void Save(const char * filename); - - void AllocateLUM(int x, int y,char * data=NULL); - - void AllocateRGBA(int x, int y,char * data=NULL); - - void Rescale(int x , int y); - - void GetPixelRGBA(int x_,int y_,unsigned char * pix); - - void SetPixelRGBA(int x_, int y_,char r, char g, char b, char a); - - void SetPixelLUM(int x_, int y_, char val); - - void GetPixelLUM(int x_, int y_,unsigned char * p); - - void ConvertToLUM(); - - void ConvertToLUMHDR(); - - void ConvertToRGBA(); - - void FlipVertical(); - void GetRect(int x, int y, int w, int h, ILenum format, void* dest); - void GetRect(int x, int y, int w, int h, ILenum format , ILenum type, void* dest); - ~Image(); - -}; - -#endif // IMAGE_H diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..ea1388e --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# SpringMapConvNG + +SpringMapConvNG is a map compiler for the spring rts engine. + +it also contains a decompiler, smfdecompiler. + +for details see https://springrts.com/wiki/MapConvNG + +# compile + +to compile install g++/clang, cmake, DevIL-dev. then run + + cmake . + make diff --git a/SMFMap.cpp b/SMFMap.cpp deleted file mode 100644 index 6960b2b..0000000 --- a/SMFMap.cpp +++ /dev/null @@ -1,750 +0,0 @@ -/* - - Copyright (C) 2011 Tiziano - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - - -#include "SMFMap.h" -#include -#include -#include -#include -#include -#ifndef bzero -#define bzero(ptr,len) memset(ptr,0,len) - -#endif -SMFMap::SMFMap(std::string name,std::string texturepath) -{ - - m_tiles = new TileStorage(); - metalmap = NULL; - heightmap = NULL; - typemap = NULL; - minimap = NULL; - vegetationmap = NULL; - texture = new Image(texturepath.c_str()); - - if ( texture->w < 1 ) - throw CannotLoadTextureException(); - if ( texture->w % 1024 != 0 || texture->h % 1024 != 0) - { - throw InvalidMapSizeException(); - - } - mapx = ( texture->w / 1024 ) * 128; - mapy = ( texture->h / 1024 ) * 128; - m_minh = 0.0; - m_maxh = 1.0; - m_name = name; - m_doclamp = true; - m_th = 0; - m_comptype = COMPRESS_REASONABLE; - m_smooth = false; - texpath = texturepath; -} -SMFMap::SMFMap(std::string smfname) -{ - std::vector tiles_images; - std::vector tile_files; - metalmap = NULL; - heightmap = NULL; - typemap = NULL; - minimap = NULL; - vegetationmap = NULL; - FILE * smffile = fopen(smfname.c_str(),"rb"); - if ( !smffile ) - { - throw CannotLoadSmfFileException(); - - } - SMFHeader hdr; - fread(&hdr,sizeof(hdr),1,smffile); - if ( strncmp(hdr.magic,"spring map file",15) > 0 ) - { - fclose(smffile); - throw InvalidSmfFileException(); - } - mapx = hdr.mapx; - mapy = hdr.mapy; - m_minh = hdr.minHeight; - m_maxh = hdr.maxHeight; - m_smfname = smfname; - m_doclamp = true; - m_th = 0; - m_comptype = COMPRESS_REASONABLE; - m_smooth = false; - texture = new Image(); - texture->AllocateRGBA((mapx/128)*1024,(mapy/128)*1024); - std::cout << "Loading metal map..." << std::endl; - metalmap = new Image(); - metalmap->AllocateLUM(mapx/2,mapy/2); - fseek(smffile,hdr.metalmapPtr,SEEK_SET); - fread(metalmap->datapointer,mapx/2*mapy/2,1,smffile); - - - std::cout << "Loading heightmap..." << std::endl; - heightmap = new Image(); - heightmap->AllocateLUM(mapx+1,mapy+1); - heightmap->ConvertToLUMHDR();//TODO: Allocate directly HDR - fseek(smffile,hdr.heightmapPtr,SEEK_SET); - fread(heightmap->datapointer,(mapx+1)*(mapy+1)*2,1,smffile); - heightmap->FlipVertical(); - - std::cout << "Loading type map..." << std::endl; - typemap = new Image(); - typemap->AllocateLUM(mapx/2,mapy/2); - fseek(smffile,hdr.typeMapPtr,SEEK_SET); - fread(typemap->datapointer,mapx/2*mapy/2,1,smffile); - typemap->FlipVertical(); - - std::cout << "Loading minimap..." << std::endl; - minimap = new Image(); - uint8_t * dxt1data = new uint8_t[699064]; - fseek(smffile,hdr.minimapPtr,SEEK_SET); - fread(dxt1data,699064,1,smffile); - ilBindImage(minimap->image); - ilTexImageDxtc(1024,1024,1,IL_DXT1,dxt1data); - ilDxtcDataToImage(); - std::cout << "Extracting main texture..." << std::endl; - int *tilematrix = new int[mapx/4 * mapy/4]; - - fseek(smffile,hdr.tilesPtr,SEEK_SET); - MapTileHeader thdr; - fread(&thdr,sizeof(thdr),1,smffile); - while ( tile_files.size() < thdr.numTileFiles ) - { - tile_files.push_back(""); - char byte; - int numtiles; - fread(&numtiles,4,1,smffile); - fread(&byte,1,1,smffile); - while ( byte != 0 ) - { - tile_files[tile_files.size()-1].append(1,byte); - fread(&byte,1,1,smffile); - } - } - for ( std::vector::iterator it = tile_files.begin(); it != tile_files.end(); it++ ) - { - std::cout << "Opening " << *it << std::endl; - FILE* smtfile = fopen((*it).c_str(),"rb"); - if ( !smtfile ) - { - fclose(smffile); - delete [] tilematrix; - throw CannotOpenSmtFileException(); - } - TileFileHeader smthdr; - fread(&smthdr,sizeof(smthdr),1,smtfile); - if ( strncmp(smthdr.magic,"spring tilefile",14) ) - { - fclose(smffile); - fclose(smtfile); - delete [] tilematrix; - throw InvalidSmtFileException(); - } - for ( int i = 0; i < smthdr.numTiles; i++ ) - { - ILuint tile = ilGenImage(); - fread(dxt1data,680,1,smtfile); - ilBindImage(tile); - ilTexImageDxtc(32,32,1,IL_DXT1,dxt1data); - ilDxtcDataToImage(); - tiles_images.push_back(tile); - } - fclose(smtfile); - - - } - std::cout << "Tiles @ " << ftell(smffile) << std::endl; - fread(tilematrix,mapx/4 * mapy/4 * 4,1,smffile); - ilBindImage(texture->image); - unsigned int * texdata = (unsigned int *)ilGetData(); - std::cout << "Blitting tiles..." << std::endl; - for ( int y = 0; y < mapy/4; y++ ) - { - std::cout << "Row " << y << " of " << mapy/4 << std::endl; - for ( int x = 0; x < mapx/4; x++ ) - { - if ( tilematrix[y*(mapx/4)+x] >= tiles_images.size() ) - { - std::cerr << "Warning: tile " << tilematrix[y*(mapx/4)+x] << " out of range" << std::endl; - continue; - } - //ilBlit(tiles_images[tilematrix[y*(mapx/4)+x]],x*32,y*32,0,0,0,0,32,32,1); - ilBindImage(tiles_images[tilematrix[y*(mapx/4)+x]]); - unsigned int * data = (unsigned int *)ilGetData(); - int r2 = 0; - for ( int y2 = y*32; y2 < y*32+32; y2++ )//FAST blitting - { - /*for ( int x2 = y*32; x2 < y*32+32; x2++ ) - { - - - }*/ - memcpy(&texdata[y2*texture->w+x*32],&data[r2*32],32*4); - r2++; - } - } - - } - texture->FlipVertical(); - - - std::cout << "Loading features..." << std::endl; - - fseek(smffile,hdr.featurePtr,SEEK_SET); - MapFeatureHeader mfhdr; - fread(&mfhdr,sizeof(mfhdr),1,smffile); - //-32767.0f+f->rotation/65535.0f*360 - - std::vector feature_types; - while ( feature_types.size() < mfhdr.numFeatureType ) - { - feature_types.push_back(""); - char byte; - fread(&byte,1,1,smffile); - while ( byte != 0 ) - { - feature_types[feature_types.size()-1].append(1,byte); - fread(&byte,1,1,smffile); - } - } - for ( int i = 0; i < mfhdr.numFeatures; i++ ) - { - MapFeatureStruct f; - fread(&f,sizeof(f),1,smffile); - if ( f.featureType >= feature_types.size() ) - { - std::cerr << "Warning: invalid feature type " << f.featureType << std::endl; - continue; - } - AddFeature(feature_types[f.featureType],f.xpos,f.ypos,f.zpos,-32767.0f+f.rotation/65535.0f*360); - - } - fclose(smffile); - delete [] dxt1data; - - -} - -void SMFMap::SetClamping(bool b) -{ - m_doclamp = b; -} -void SMFMap::SaveSourceFiles() -{ - if ( metalmap ) - { - metalmap->Save("metalmap.png"); - } - if ( typemap ) - { - typemap->Save("typemap.png"); - } - if ( heightmap ) - { - heightmap->Save("heightmap.png"); - //heightmap->Save("heightmap.exr"); Not needed , png already supports 16 bit and DevIL too - - } - if ( texture ) - { - texture->Save("texture.png"); - } - if ( minimap ) - { - minimap->Save("minimap.png"); - } - FILE * featurefile = fopen("features.txt","w"); - for ( std::map * >::iterator it = features.begin(); it != features.end(); it++ ) - { - for ( std::list::iterator it2 = (*it).second->begin(); it2 != (*it).second->end(); it2++ ) - { - MapFeatureStruct* f = (*it2); - float degrot = -32767.0f+f->rotation/65535.0f*360; // 32767.0f-((orientation/360.0)*65535.0f); - - fprintf(featurefile,"%s %f %f %f %f\n",(*it).first.c_str(),f->xpos,f->ypos,f->zpos,degrot); - - - } - - - } - fclose(featurefile); - - const char* compileCmd = "springMapConvNG -t texture.png -h heightmap.png -z typemap.png -m metalmap.png -maxh %f -minh %f -th 0.8 -ct 4 -features features.txt -minimap minimap.png -o \"%s\""; - FILE * makefile = fopen("Makefile","w"); - fprintf(makefile,"%s: texture.png heightmap.png typemap.png metalmap.png minimap.png features.txt\n",m_smfname.c_str()); - std::string smfbasename = m_smfname.substr(0,m_smfname.find(".")); - fprintf(makefile, "\t"); - fprintf(makefile, compileCmd, m_maxh, m_minh, smfbasename.c_str()); - fprintf(makefile, "\n"); - fclose(makefile); - - FILE * batchfile = fopen("make.bat","w"); - fprintf(batchfile, compileCmd, m_maxh, m_minh, smfbasename.c_str()); - fprintf(batchfile,"\r\npause\r\n"); - fclose(batchfile); -} - -void SMFMap::SetVegetationMap(std::string path) -{ - Image * img = new Image(path.c_str()); - if ( img->w > 0 ) - { - if ( vegetationmap ) - delete vegetationmap; - vegetationmap = img; - vegetationmap->ConvertToLUM(); - if ( img->w != mapx/4 || img->h != mapy/4 ) - { - std::cerr << "Warning: Vegetation map has wrong size , rescaling!" << std::endl; - vegetationmap->Rescale(mapx/4,mapy/4); - - } - } -} -void SMFMap::AddFeature(std::string name, float x, float y, float z, float orientation) -{ - if ( features.find(name) == features.end() )//Allocate new vector - { - features[name] = new std::list(); - } - MapFeatureStruct * feat = (MapFeatureStruct*)malloc(sizeof(MapFeatureStruct)); - feat->xpos = x; - feat->ypos = y; - feat->zpos = z; - feat->rotation = 32767.0f-((orientation/360.0)*65535.0f); - feat->relativeSize = 1; - features[name]->push_back(feat); -} - -void SMFMap::SetHeightRange(float minh, float maxh) -{ - m_minh = minh; - m_maxh = maxh; -} - -SMFMap::~SMFMap() -{ - delete m_tiles; - if ( metalmap ) - delete metalmap; - if ( heightmap ) - delete heightmap; - if ( typemap ) - delete typemap; - if ( minimap ) - delete minimap; - if ( texture ) - delete texture; - if ( vegetationmap ) - delete vegetationmap; -} -void SMFMap::SetMiniMap(std::string path) -{ - delete texture; - std::cout << "Loading minimap " << path << std::endl; - Image * img = new Image(path.c_str()); - if ( img->w > 0 ) - { - if ( minimap ) - delete minimap; - minimap = img; - minimap->ConvertToRGBA(); - minimap->FlipVertical(); - if ( img->w != 1024 || img->h != 1024 ) - { - std::cerr << "Warning: Minimap has wrong size , rescaling!" << std::endl; - minimap->Rescale(1024,1024); - - } - texture = new Image(texpath.c_str()); - return; - } - std::cout << "Failed " << path << std::endl; - texture = new Image(texpath.c_str()); -} - -/*void SMFMap::SetFeatureMap(std::string path) -{ - Image * img = new Image(path.c_str()); - if ( img->w > 0 ) - { - if ( featuremap ) - delete featuremap; - featuremap = img; - featuremap->ConvertToLUM(); - } - if ( img->w != mapx/2 || img->h != mapy/2 ) - { - std::cerr << "Warning: Feature map has wrong size , rescaling!" << std::endl; - heightmap->Rescale(mapx+1,mapy+1); - - } -}*/ -void SMFMap::SetHeightMap(std::string path) -{ - Image * img = new Image(path.c_str(),true); - if ( img->w > 0 ) - { - if ( heightmap ) - delete heightmap; - heightmap = img; - // heightmap->ConvertToLUMHDR(); - if ( img->w != mapx+1 || img->h != mapy+1 ) - { - std::cerr << "Warning: Height map has wrong size , rescaling! (" << img->w << "," << img->h << ") instead of (" << mapx+1 << "," << mapy+1 << ")" << std::endl; - heightmap->Rescale(mapx+1,mapy+1); - - } - //Clamp heightmap before blurring - if ( m_doclamp ) - { - float _min = 65537.0f; - float _max = -65337.0f; - unsigned short * pixels = (unsigned short*)heightmap->datapointer; - for ( int i = 0; i < heightmap->w*heightmap->h; i++ ) - { - if ( _min > pixels[i] ) - _min = pixels[i]; - if ( _max < pixels[i] ) - _max = pixels[i]; - - } - std::cout << "Range : " << _min << " -> " << _max << std::endl; - float range = _max-_min; - for ( int i = 0; i < heightmap->w*heightmap->h; i++ ) - { - pixels[i] = (unsigned short)((((pixels[i]-_min)/range)*65535.0f)); - - } - } - if ( m_smooth ) - { - std::cout << "Blurring heightmap..." << std::endl; - /*ilBindImage(heightmap->image); // Seems broken with 16 bit image - iluBlurAvg(5); - heightmap->datapointer = ilGetData();*/ - unsigned short * tempdata = new unsigned short[img->h*img->w]; - for ( int pass = 0; pass < 3; pass++ ) - { - std::cout << "Blurring heightmap pass " << pass+1 << "..." << std::endl; - memcpy(tempdata,img->datapointer,img->h*img->w*2); - for ( int y = 1; y < img->h-1; y++ ) - { - for ( int x = 1; x < img->w-1; x++ ) - { - float sum = 0.0f; - sum += ((unsigned short*)img->datapointer)[y*img->w+x]; - sum += ((unsigned short*)img->datapointer)[(y-1)*img->w+(x-1)]; - sum += ((unsigned short*)img->datapointer)[(y-1)*img->w+(x-0)]; - sum += ((unsigned short*)img->datapointer)[(y-1)*img->w+(x+1)]; - sum += ((unsigned short*)img->datapointer)[(y-0)*img->w+(x-1)]; - sum += ((unsigned short*)img->datapointer)[(y-0)*img->w+(x+1)]; - sum += ((unsigned short*)img->datapointer)[(y+1)*img->w+(x-1)]; - sum += ((unsigned short*)img->datapointer)[(y+1)*img->w+(x-0)]; - sum += ((unsigned short*)img->datapointer)[(y+1)*img->w+(x+1)]; - sum /= 9.0f; - tempdata[y*img->w+x] = (unsigned short)(sum); - } - - } - memcpy(img->datapointer,tempdata,img->h*img->w*2); - } - delete [] tempdata; - } - } - -} -void SMFMap::SetBlur(bool b) -{ - m_smooth = b; -} -void SMFMap::SetCompareTileCount(uint32_t count) -{ - m_tiles->SetDictSize(count); -} - -void SMFMap::SetMetalMap(std::string path) -{ - Image * img = new Image(path.c_str()); - if ( img->w > 0 ) - { - if ( metalmap ) - delete metalmap; - metalmap = img; - metalmap->ConvertToLUM(); - - if ( img->w != mapx/2 || img->h != mapy/2 ) - { - std::cerr << "Warning: Metal map has wrong size , rescaling! (" << img->w << "," << img->h << ") instead of (" << mapx/2 << "," << mapy/2 << ")" << std::endl; - metalmap->Rescale( mapx/2,mapy/2); - - } - } -} -void SMFMap::SetTypeMap(std::string path) -{ - Image * img = new Image(path.c_str()); - if ( img->w > 0 ) - { - if ( typemap ) - delete typemap; - typemap = img; - typemap->ConvertToLUM(); - if ( img->w != mapx/2 || img->h != mapy/2 ) - { - std::cerr << "Warning: Type map has wrong size , rescaling! (" << img->w << "," << img->h << ") instead of (" << mapx/2 << "," << mapy/2 << ")" << std::endl; - typemap->Rescale(mapx/2,mapy/2); - - } - - } - -} - -void SMFMap::Compile() -{ - SMFHeader hdr; - strcpy(hdr.magic,"spring map file"); - hdr.version = 1; - hdr.mapid = rand(); - hdr.mapx = (texture->w / 1024)*128; - hdr.mapy = (texture->h / 1024)*128; - hdr.squareSize = 8; - hdr.texelPerSquare = 8; - hdr.tilesize = 32; - hdr.minHeight = m_minh; - hdr.maxHeight = m_maxh; - - - short int * hmap = new short int[(mapy+1)*(mapx+1)];bzero(hmap,((mapy+1)*(mapx+1))*2); - if ( heightmap ) - { - //heightmap->GetRect(0,0,heightmap->w,heightmap->h,IL_LUMINANCE,IL_SHORT,hmap); : IL seems to fail to convert from unsigned short to signed - /*for ( int k = 0; k < (mapy+1)*(mapx+1); k++ ) - { - int pix = ((unsigned short*)heightmap->datapointer)[k]; - hmap[k] = short(int(pix)-int(32767)); - - */ - memcpy(hmap,heightmap->datapointer,((mapy+1)*(mapx+1))*2); - } - unsigned char * typedata = new unsigned char[mapy/2 * mapx/2];bzero(typedata,(mapy/2 * mapx/2)); - if ( typemap ) - { - typemap->GetRect(0,0,typemap->w,typemap->h,IL_LUMINANCE,IL_UNSIGNED_BYTE,typedata); - - } - uint8_t * minimap_data = new uint8_t[699064]; - bzero(minimap_data,699064); - if ( minimap ) - { - int p = 0; - int s = 1024; - - Image * im2 = new Image(); - im2->AllocateRGBA(1024,1024,(char*)minimap->datapointer); - for ( int i = 0; i < 9; i++ ) - { - //std::cout << ">Mipmap " << i << std::endl; - im2->Rescale(s,s); - //std::cout << "datapointer,s,s,1,IL_DXT1,&ss); - //std::cout << ss << " " << s; - memcpy(&minimap_data[p],dxtdata,ss); - free(dxtdata); - p += ss; - - s = s >> 1; - - } - delete im2; - - } - unsigned char * metalmap_data = new unsigned char[mapx/2 * mapy/2];bzero(metalmap_data,(mapy/2 * mapx/2)); - if ( metalmap ) - { - metalmap->GetRect(0,0,metalmap->w,metalmap->h,IL_LUMINANCE,IL_UNSIGNED_BYTE,metalmap_data); - - } - /*hdr.heightmapPtr = sizeof(hdr); - hdr.typeMapPtr = hdr.heightmapPtr + ((mapy+1)*(mapx+1))*2; - hdr.minimapPtr = hdr.typeMapPtr + (mapy/2 * mapx/2); - hdr.metalmapPtr = hdr.minimapPtr + 699048; - hdr.featurePtr = hdr.metalmapPtr + (mapy/2 * mapx/2);*/ - MapFeatureHeader mfhdr; - - hdr.tilesPtr = hdr.featurePtr + sizeof(mfhdr); - hdr.numExtraHeaders = 1; - ExtraHeader grassHeader; - grassHeader.size = 4; - grassHeader.type = 1; - MapTileHeader mthdr; - mthdr.numTileFiles = 1; - unsigned char * grass_data = new unsigned char[mapx/4 * mapy/4];bzero(grass_data,mapx/4 * mapy/4); - if ( vegetationmap ) - { - vegetationmap->GetRect(0,0,vegetationmap->w,vegetationmap->h,IL_LUMINANCE,IL_UNSIGNED_BYTE,grass_data); - - } - int * tiles = new int[mapx/4 * mapy/4]; - std::vector order; - DoCompress(tiles,order); - /* for ( int y = 0; y < mapy/4; y++ ) - { - for ( int x = 0; x < mapx/4; x++ ) - { - printf("%5d,",tiles[(mapx/4)*y+x]); - } - printf("\n"); - }*/ - - FILE * tilefile = fopen((m_name+std::string(".smt")).c_str(),"wb"); - delete texture; //Temporarily delete texture from memory to reduce mem usage - m_tiles->WriteToFile(tilefile,order); - texture = new Image(texpath.c_str()); - - fclose(tilefile); - FILE * smffile = fopen((m_name+std::string(".smf")).c_str(),"wb"); - fwrite(&hdr,sizeof(hdr),1,smffile); - fwrite(&grassHeader,sizeof(grassHeader),1,smffile); - int _ofs = ftell(smffile)+4; - fwrite(&_ofs,4,1,smffile); - fwrite(grass_data,mapx/4 * mapy/4,1,smffile); - - hdr.minimapPtr = ftell(smffile); - fwrite(minimap_data,699064,1,smffile); - hdr.heightmapPtr = ftell(smffile); - fwrite(hmap,((mapy+1)*(mapx+1))*2,1,smffile); - hdr.typeMapPtr = ftell(smffile); - fwrite(typedata,mapy/2 * mapx/2,1,smffile); - - hdr.metalmapPtr = ftell(smffile); - fwrite(metalmap_data,mapy/2 * mapx/2,1,smffile); - hdr.featurePtr = ftell(smffile); - - - mfhdr.numFeatures = 0; - for ( std::map * >::iterator it = features.begin(); it != features.end(); it++ )//Enumerate features - mfhdr.numFeatures += (*it).second->size(); - mfhdr.numFeatureType = features.size(); - fwrite(&mfhdr,sizeof(mfhdr),1,smffile); - { - std::map featureTypes; - unsigned int z = 0; - for ( std::map * >::iterator it = features.begin(); it != features.end(); it++ )//Write feature types - { - fwrite((*it).first.c_str(),(*it).first.size()+1,1,smffile); - featureTypes[(*it).first] = z++; - } - for ( std::map * >::iterator it = features.begin(); it != features.end(); it++ )//Write feature types - { - for ( std::list::iterator it2 = (*it).second->begin(); it2 != (*it).second->end(); it2++ ) - { - (*it2)->featureType = featureTypes[(*it).first]; - if ( (*it2)->ypos < 490000.0f ) // Align on terrain - { - unsigned int hmapx = ((*it2)->xpos/float((mapx/128)*1024))*heightmap->w; - unsigned int hmapy = ((*it2)->zpos/float((mapy/128)*1024))*heightmap->h; - (*it2)->ypos = hdr.minHeight+(float(hmap[hmapy*(mapx+1)+hmapx])/32767.0)*(hdr.maxHeight-hdr.minHeight); - std::cout << "Feature " << (*it).first << " Instance " << (*it2) << " Terrain height: " << (*it2)->ypos << std::endl; - } - - fwrite((*it2),sizeof(MapFeatureStruct),1,smffile); - } - - } - - - - } - - hdr.tilesPtr = ftell(smffile); - uint32_t tc = m_tiles->GetTileCount(); - mthdr.numTiles = tc; - fwrite(&mthdr,sizeof(mthdr),1,smffile); - fwrite(&tc,4,1,smffile); - fwrite((m_name+std::string(".smt")).c_str(),(m_name+std::string(".smt")).length()+1,1,smffile); - fwrite(tiles,(mapx/4 * mapy/4)*4,1,smffile); - fseek(smffile,0,SEEK_SET); - fwrite(&hdr,sizeof(hdr),1,smffile); - fclose(smffile); - delete [] metalmap_data; - delete [] hmap; - delete [] typedata; - delete [] tiles; - delete [] minimap_data; - delete [] grass_data; -} - -void SMFMap::DoCompress(int* indices, std::vector< uint64_t >& order) -{ - order.clear(); - - uint8_t tiledata[32*32*4]; - std::map existingtiles; - int c = 0; - for ( int y = 0; y < mapy/4; y++ ) - { - for ( int x = 0; x < mapx/4; x++ ) - { - if ( c % 50 == 0 ) - printf("\rCompressing %8d/%8d - %6d tiles ",c,mapy/4*mapx/4,m_tiles->GetTileCount()); - c++; - texture->GetRect(x*32,y*32,32,32,IL_RGBA,IL_UNSIGNED_BYTE,tiledata); - for ( int yy = 0; yy < 16; yy++ )//Flip vertically - { - char tmprow[32*4]; - memcpy(tmprow,&tiledata[(31-yy)*32*4],32*4); - memcpy(&tiledata[(31-yy)*32*4],&tiledata[yy*32*4],32*4); - memcpy(&tiledata[yy*32*4],tmprow,32*4); - } - // std::cout << "Compressing (" << x << "," << y << ")" << std::endl; - uint64_t uid = m_tiles->AddTileOrGetSimiliar(tiledata,m_th,m_comptype); - if ( existingtiles.find(uid) == existingtiles.end() ) - { - indices[(mapx/4)*y+x] = order.size(); - existingtiles[uid] = order.size(); - order.push_back(uid); - }else{ - indices[(mapx/4)*y+x] = existingtiles[uid]; - - } - - - } - - - - } - printf("\n"); - std::cout << "Compress done , ratio: " << float(existingtiles.size())/float(mapy/4 * mapx/4)*100.0 << std::endl; - -} -void SMFMap::SetCompressionTol(float th) -{ - m_th = th; -} -void SMFMap::SetCompressionType(int c) -{ - m_comptype = c; -} - diff --git a/SMFMap.h b/SMFMap.h deleted file mode 100644 index e386777..0000000 --- a/SMFMap.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - - Copyright (C) 2011 Tiziano - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - - -#ifndef SMFMAP_H -#define SMFMAP_H -#include "TileStorage.h" -#include "Image.h" -#include - -typedef struct { - char magic[16]; ///< "spring map file\0" - int version; ///< Must be 1 for now - int mapid; ///< Sort of a GUID of the file, just set to a random value when writing a map - - int mapx; ///< Must be divisible by 128 - int mapy; ///< Must be divisible by 128 - int squareSize; ///< Distance between vertices. Must be 8 - int texelPerSquare; ///< Number of texels per square, must be 8 for now - int tilesize; ///< Number of texels in a tile, must be 32 for now - float minHeight; ///< Height value that 0 in the heightmap corresponds to - float maxHeight; ///< Height value that 0xffff in the heightmap corresponds to - - int heightmapPtr; ///< File offset to elevation data (short int[(mapy+1)*(mapx+1)]) - int typeMapPtr; ///< File offset to typedata (unsigned char[mapy/2 * mapx/2]) - int tilesPtr; ///< File offset to tile data (see MapTileHeader) - int minimapPtr; ///< File offset to minimap (always 1024*1024 dxt1 compresed data plus 8 mipmap sublevels) - int metalmapPtr; ///< File offset to metalmap (unsigned char[mapx/2 * mapy/2]) - int featurePtr; ///< File offset to feature data (see MapFeatureHeader) - - int numExtraHeaders; ///< Numbers of extra headers following main header -} SMFHeader ; -typedef struct -{ - int numFeatureType; - int numFeatures; -}MapFeatureHeader ; -typedef struct -{ - int numTileFiles; ///< Number of tile files to read in (usually 1) - int numTiles; ///< Total number of tiles -} MapTileHeader; -typedef struct{ - int size; ///< Size of extra header - int type; ///< Type of extra header -} ExtraHeader; -typedef struct -{ - int featureType; ///< Index to one of the strings above - float xpos; ///< X coordinate of the feature - float ypos; ///< Y coordinate of the feature (height) - float zpos; ///< Z coordinate of the feature - - float rotation; ///< Orientation of this feature (-32768..32767 for full circle) - float relativeSize; ///< Not used at the moment keep 1 -} MapFeatureStruct; -typedef struct -{ - char magic[16]; ///< "spring tilefile\0" - int version; ///< Must be 1 for now - - int numTiles; ///< Total number of tiles in this file - int tileSize; ///< Must be 32 for now - int compressionType; ///< Must be 1 (= dxt1) for now -} TileFileHeader; -class InvalidMapSizeException -{ - -}; -class CannotLoadTextureException -{ - -}; -class CannotLoadSmfFileException -{ - - -}; -class InvalidSmfFileException -{ - -}; -class CannotOpenSmtFileException -{ - -}; -class InvalidSmtFileException -{ - -}; -class SMFMap -{ - -public: - SMFMap(std::string name,std::string texturepath); - SMFMap(std::string smfname); //Decompile - virtual ~SMFMap(); - void SetMetalMap(std::string path); - void SetTypeMap(std::string path); - //void SetFeatureMap(std::string path); - void SetHeightMap(std::string path); - void SetVegetationMap(std::string path); - void SetMiniMap(std::string path); - void Compile(); - void SetHeightRange(float minh,float maxh); - void SetCompressionTol(float th); - void SetCompressionType(int c); - void SetCompareTileCount(uint32_t count); - void SetClamping(bool b); - void SetBlur(bool b); - void SaveSourceFiles(); - void AddFeature(std::string name,float x, float y , float z,float orientation); - -private: - void DoCompress(int * indices , std::vector& order); - TileStorage * m_tiles; - Image * metalmap; - //Image * featuremap; - Image * heightmap; - Image * typemap; - Image * texture; - Image * minimap; - Image * vegetationmap; - int mapx,mapy; - std::string m_name; - float m_minh; - float m_maxh; - float m_th; - bool m_doclamp; - bool m_smooth; - int m_comptype; - std::string texpath; - std::string m_smfname; - std::map * > features; -}; - -#endif // SMFMAP_H diff --git a/SpringMapConvNG.kdev4 b/SpringMapConvNG.kdev4 deleted file mode 100644 index 1966f2e..0000000 --- a/SpringMapConvNG.kdev4 +++ /dev/null @@ -1,4 +0,0 @@ -[Project] -Name=SpringMapConvNG -Manager=KDevCMakeManager -VersionControl= diff --git a/TileStorage.cpp b/TileStorage.cpp deleted file mode 100644 index 2be0454..0000000 --- a/TileStorage.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* - - Copyright (C) 2011 Tiziano - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - - -#include "TileStorage.h" -#include -#include -#include -#include -#include -#include -#include -inline float tilediff(uint8_t * t1,uint8_t * t2) -{ - float diff = 0.0; - for ( int i = 0; i < 32*32*4; i++ ) - { - float d1 = fabs(float(t1[i])-float(t2[i])); - if ( d1 < 30 ) - diff += d1; - else - diff += 255.0f;//If it has a point that is VERY different , it must not be reused - - - } - diff /= 32.0*32.0*4.0f*10.0f; - return diff; -} - -TileStorage::TileStorage() -{ - Reset(); - m_dictcount = 64; -} - -TileStorage::~TileStorage() -{ - Reset(); -} -void TileStorage::Reset() -{ - for ( std::map::iterator it = m_tiles.begin(); it != m_tiles.end(); it++ ) - { - if ( m_tiles_compressed.find((*it).first) != m_tiles_compressed.end() ) - { - delete m_tiles_compressed[(*it).first]; - - } - delete (*it).second; - } - m_tiles.clear(); - m_lasttiles.clear(); - m_tiles_compressed.clear(); -} - -uint64_t TileStorage::AddTile(uint8_t* data) -{ - uint64_t checksum = tilechecksum(data); - if ( m_tiles.find(checksum) != m_tiles.end() ) - { - std::cerr << "Duplicate tile detected, dropping!" << std::endl; - return checksum; - } - uint8_t* data_copy = new uint8_t[32*32*4]; - memcpy(data_copy,data,32*32*4); - m_tiles.insert(std::pair(checksum,data_copy)); - m_lasttiles.push_back(checksum); - if ( m_lasttiles.size() > m_dictcount ) - m_lasttiles.pop_front(); - return checksum; -} -void TileStorage::CompressAll() -{ - for ( std::map::iterator it = m_tiles.begin(); it != m_tiles.end(); it++ ) - { - if ( m_tiles_compressed.find((*it).first) == m_tiles_compressed.end() ) - { - CompressTile((*it).first); - - - } - - - } - -} -void TileStorage::SetDictSize(uint32_t s) -{ - m_dictcount = s; -} - -void TileStorage::CompressTile(uint64_t uid) -{ - uint8_t * m0; - uint8_t * m1; - uint8_t * m2; - uint8_t * m3; - uint8_t * dataptr = m_tiles[uid]; - uint8_t * compressedmipmaps = new uint8_t[680]; - if ( !dataptr ) - { - delete [] compressedmipmaps; - throw InvalidTileDataPointerException(); - - } - uint32_t s; - uint32_t s2 = 0; - ILuint mip1 = ilGenImage(); - ilBindImage(mip1); - ilTexImage(32,32,1,4,IL_RGBA,IL_UNSIGNED_BYTE,dataptr); - /*std::stringstream ss; - ss << "Tile" << uid << ".png"; - ilSaveImage(ss.str().c_str());*/ - m0 = ilCompressDXT(ilGetData(),32,32,1,IL_DXT1,&s); - memcpy(&compressedmipmaps[s2],m0,s); - s2 += s; - iluScale(16,16,1); - m1 = ilCompressDXT(ilGetData(),16,16,1,IL_DXT1,&s); - memcpy(&compressedmipmaps[s2],m1,s); - s2 += s; - iluScale(8,8,1); - m2 = ilCompressDXT(ilGetData(),8,8,1,IL_DXT1,&s); - memcpy(&compressedmipmaps[s2],m2,s); - s2 += s; - iluScale(4,4,1); - m3 = ilCompressDXT(ilGetData(),4,4,1,IL_DXT1,&s); - memcpy(&compressedmipmaps[s2],m3,s); - s2 += s; - ilDeleteImage(mip1); - - /*squish::CompressImage(dataptr,32,32,m0,squish::kDxt1); - squish::CompressImage(dataptr,16,16,m1,squish::kDxt1); - squish::CompressImage(dataptr,8,8,m2,squish::kDxt1); - squish::CompressImage(dataptr,4,4,m3,squish::kDxt1);*/ - - - - - free(m0); - free(m1); - free(m2); - free(m3); - - m_tiles_compressed[uid] = compressedmipmaps; - //std::cout << "Tile " << uid << " compressed!" << std::endl; - -} - -void TileStorage::WriteToFile(FILE* f, std::vector< uint64_t >& tile_order) -{ - char magic[16]; - strcpy(magic,"spring tilefile"); - int version = 1; - int numtiles = m_tiles_compressed.size(); - int tileSize = 32; - int compressionType = 1; - fwrite(magic,16,1,f); - fwrite(&version,4,1,f); - fwrite(&numtiles,4,1,f); - fwrite(&tileSize,4,1,f); - fwrite(&compressionType,4,1,f); - for ( std::vector< uint64_t >::const_iterator it = tile_order.begin(); it != tile_order.end(); it++ ) - { - if ( m_tiles_compressed.find(*it) == m_tiles_compressed.end() ) - { - CompressAll(); - - - } - if ( m_tiles_compressed.find(*it) == m_tiles_compressed.end() ) - { - throw InvalidTileIndexException(); - } - fwrite(m_tiles_compressed[*it],680,1,f); - } - fflush(f); -} -uint64_t TileStorage::AddTileOrGetSimiliar(uint8_t* data, float th, int compresslevel) -{ - uint64_t checksum = tilechecksum(data); - if ( m_tiles.find(checksum) != m_tiles.end() ) - { - //std::cout << "Debug(AddTileOrGetSimiliar): " << checksum << " already exists" << std::endl; - return checksum; - - } - if ( compresslevel == COMPRESS_INSANE ) - { - for ( std::map::iterator it = m_tiles.begin(); it != m_tiles.end(); it++ ) - { - if ( tilediff(data,(*it).second) < th ) - { - return (*it).first; - - } - - - } - }else if ( compresslevel == COMPRESS_REASONABLE ) - { - for ( std::list::iterator it = m_lasttiles.begin(); it != m_lasttiles.end(); it++ ) - { - if ( tilediff(data,m_tiles[(*it)]) < th ) - { - return (*it); - - } - } - - - }else if ( compresslevel == COMPRESS_SHITTY ) - { - //do nothing... - - }else if ( compresslevel == COMPRESS_REASONABLE_BESTQUALITY ) - { - float mindiff = 9999999.0f; - uint64_t besttile; - for ( std::list::iterator it = m_lasttiles.begin(); it != m_lasttiles.end(); it++ ) - { - float diff = tilediff(data,m_tiles[(*it)]); - if ( diff < mindiff ) - { - besttile = (*it); - mindiff = diff; - - } - } - if ( mindiff <= th ) - return besttile; - - - } - return AddTile(data); -} -uint32_t TileStorage::GetTileCount() -{ - return std::max(m_tiles_compressed.size(),m_tiles.size()); -} diff --git a/TileStorage.h b/TileStorage.h deleted file mode 100644 index 113dee6..0000000 --- a/TileStorage.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - Copyright (C) 2011 Tiziano - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - - -#ifndef TILESTORAGE_H -#define TILESTORAGE_H -#include -#include -#include -#include -#include -#include "CRC.h" -inline uint64_t tilechecksum( uint8_t * data ) -{ - uint64_t r = 0; - for ( int x = 0; x < 32*32*4; x++ ) - { - r += data[x]*63018038201L*x*x; - r ^= 13091204281L; - r *= 13091204281L*x; - r *= 226673591177742970257407LL*data[x]; - } - Crc32 c; - c.AddData(data,32*32*4); - r *= c.GetCrc32(); - return r; - -} -class InvalidTileIndexException -{ - - -}; -class InvalidTileDataPointerException -{ - - -}; -enum CompressLevels -{ - COMPRESS_SHITTY = 1, - COMPRESS_REASONABLE = 2, - COMPRESS_INSANE = 3, - COMPRESS_REASONABLE_BESTQUALITY = 4 - - -}; -class TileStorage -{ - -public: - TileStorage(); - virtual ~TileStorage(); - uint64_t AddTile( uint8_t * data ); // 32x32 RGBA - void WriteToFile( FILE * f , std::vector& tile_order); - uint64_t AddTileOrGetSimiliar( uint8_t* data, float th, int compresslevel ); - uint32_t GetTileCount(); - void SetDictSize(uint32_t s); - void Reset(); -private: - void CompressAll(); - void CompressTile(uint64_t uid); - std::map m_tiles; - std::map m_tiles_compressed; - std::list m_lasttiles; - unsigned int m_dictcount; -}; - -#endif // TILESTORAGE_H diff --git a/decompiler.cpp b/decompiler.cpp deleted file mode 100644 index 107d52c..0000000 --- a/decompiler.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include -#include -#include "SMFMap.h" - -#include -#ifdef WIN32 -#include -#include -#include -#endif -void help(char ** argv) -{ - std::cout << "Usage: " << argv[0] << " -directory [directory where .smt files are] -mapfile [name of the smf file , NOT path ]" << std::endl; - -} -int main(int argc, char** argv) -{ - ilInit(); - if ( argc == 1 ) - { - - help(argv); - return 1; - }else{ - std::string mapdirectory; - std::string mapfile; - bool valid1=false,valid2=false; - for ( int i = 1; i < argc; i++ ) - { - if ( strlen(argv[i]) > 1 ) - { - if ( argv[i][0] == '-' ) - { - if ( strcmp(&argv[i][1],"directory") == 0 ) - { - valid1 = true; - if ( i+1 < argc ) - { - mapdirectory = argv[++i]; - }else{ - goto error; - } - }else if ( strcmp(&argv[i][1],"mapfile") == 0 ) - { - if ( i+1 < argc ) - { - mapfile = argv[++i]; - }else{ - goto error; - } - valid2 = true; - - } - else if ( strncmp(&argv[i][1],"h",1) == 0 )//Help - { - goto error; - } - - - - - - - } - - } - - } - - if ( valid1 && valid2 ) - goto success; - error: - help(argv); - return 1; - success: -#ifndef WIN32 - if ( chdir(mapdirectory.c_str()) ) -#else - if ( _chdir(mapdirectory.c_str()) ) -#endif - { - std::cerr << "Cannot change working directory to " << mapdirectory << std::endl; - return 1; - } - SMFMap * m = new SMFMap(mapfile); - m->SaveSourceFiles(); - } -} - diff --git a/main.cpp b/main.cpp deleted file mode 100644 index 39aa554..0000000 --- a/main.cpp +++ /dev/null @@ -1,244 +0,0 @@ - - -#include -#include -#include -#include "SMFMap.h" - -#include -void help(char ** argv) -{ - std::cout << "Usage: " << argv[0] << " -t [maintexture] -m [metalmap] -z [typemap] -h [heightmap] -maxh [white height value] -minh [black height value] -o [outputsuffix] -minimap [minimap_image]" << std::endl; - std::cout << " -ct [compression_type] -ccount [compare_tilecount] -th [compression_level] -features [featurefile]" << std::endl; - std::cout << " -noclamp disables heightmap clamping to max - min values , you should avoid using that , cause you lose precision, if you want less high landscape use maxh and minh" << std::endl; - std::cout << "Compression types:\n\t1: No compression \n\t2: Fast compression , compare tile with last -ccount tiles , take first which difference is below -th\n\t3: Insane Compression: compare each tile with whole map , it is very SLOW, not recomended\n\t4: High quality Fast compression: Slightly slower than 2 , it searchs for less different tile in last -ccount tiles" << std::endl; - std::cout << "Feature file: Each line is a feature instance and has the fields in the following order [tdfname] [xpos] [ypos] [zpos] [rotation yaxis] , please do not leave whitespaces at the end or it\n will give errors." << std::endl; - std::cout << "If you specify less than -490000 as ypos , it will calculate ypos depending on terrain height" << std::endl; - -} -int main(int argc, char** argv) -{ - ilInit(); - if ( argc == 1 ) - { - - help(argv); - return 1; - }else{ - bool valid2 = false; - bool valid1 = false; - std::string outputname; - std::string texture; - std::string minimap; - std::string metalmap; - std::string typemap; - std::string heightmap; - std::string vegmap; - std::string featurefile; - bool smooth = false; - int tcount = 64; - float minh = 0.0f; - bool clamping = true; - float maxh = 1.0f; - int ct = COMPRESS_REASONABLE; - float th = 0.8; - for ( int i = 1; i < argc; i++ ) - { - if ( strlen(argv[i]) > 1 ) - { - if ( argv[i][0] == '-' ) - { - if ( strcmp(&argv[i][1],"t") == 0 ) - { - valid1 = true; - if ( i+1 < argc ) - { - texture = argv[++i]; - }else{ - goto error; - } - }else if ( strcmp(&argv[i][1],"m") == 0 )//Metal - { - if ( i+1 < argc ) - { - metalmap = argv[++i]; - }else{ - goto error; - } - - }else if ( strcmp(&argv[i][1],"z") == 0 )//Type - { - if ( i+1 < argc ) - { - typemap = argv[++i]; - }else{ - goto error; - } - - }else if ( strcmp(&argv[i][1],"h") == 0 )//Height - { - if ( i+1 < argc ) - { - heightmap = argv[++i]; - }else{ - goto error; - } - - }else if ( strcmp(&argv[i][1],"maxh") == 0 )//Max Height - { - if ( i+1 < argc ) - { - maxh = atof(argv[++i]); - }else{ - goto error; - } - - }else if ( strcmp(&argv[i][1],"minh") == 0 )//Min Height - { - if ( i+1 < argc ) - { - minh = atof(argv[++i]); - }else{ - goto error; - } - - }else if ( strcmp(&argv[i][1],"o") == 0 )//Output name - { - if ( i+1 < argc ) - { - outputname = argv[++i]; - }else{ - goto error; - } - valid2 = true; - - }else if ( strcmp(&argv[i][1],"minimap") == 0 )//Minimap - { - if ( i+1 < argc ) - { - minimap = argv[++i]; - }else{ - goto error; - } - - }else if ( strcmp(&argv[i][1],"th") == 0 )//Compression level - { - if ( i+1 < argc ) - { - th = atof(argv[++i]); - }else{ - goto error; - } - - } - else if ( strcmp(&argv[i][1],"ct") == 0 )//Compression mode - { - if ( i+1 < argc ) - { - ct = atoi(argv[++i]); - }else{ - goto error; - } - - }else if ( strcmp(&argv[i][1],"ccount") == 0 )//Compression , count of tiles to comapre in mode 2 and 4 - { - if ( i+1 < argc ) - { - tcount = atoi(argv[++i]); - }else{ - goto error; - } - - } - else if ( strcmp(&argv[i][1],"v") == 0 )//Vegetation map - { - if ( i+1 < argc ) - { - vegmap = argv[++i]; - }else{ - goto error; - } - - }else if ( strcmp(&argv[i][1],"noclamp") == 0 )//No heightmap clamp - { - clamping = false; - - }else if ( strcmp(&argv[i][1],"features") == 0 )//features file - { - - if ( i+1 < argc ) - { - featurefile = argv[++i]; - }else{ - goto error; - } - - } - else if ( strcmp(&argv[i][1],"smooth") == 0 )//Smooth - { - smooth = true; - - } - else if ( strncmp(&argv[i][1],"h",1) == 0 )//Help - { - goto error; - } - - - - - - - } - - } - - } - - if ( valid1 && valid2 ) - goto success; - error: - help(argv); - return 1; - success: - SMFMap * m = new SMFMap(outputname,texture); - m->SetBlur(smooth); - if ( heightmap.length() > 0 ) m->SetHeightMap(heightmap); - if ( metalmap.length() > 0 ) m->SetMetalMap(metalmap); - if ( typemap.length() > 0 ) m->SetTypeMap(typemap); - if ( minimap.length() > 0 ) m->SetMiniMap(minimap); - if ( vegmap.length() > 0 ) m->SetVegetationMap(vegmap); - m->SetCompareTileCount(tcount); - m->SetHeightRange(minh,maxh); - m->SetCompressionTol(th); - m->SetCompressionType(ct); - m->SetClamping(clamping); - if ( featurefile.length() > 0 ) - { - FILE * ff = fopen(featurefile.c_str(),"r"); - if (!ff) - { - std::cerr << "Cannot open feature file for reading!" <AddFeature(name,x,y,z,o); - } - fclose(ff); - - } - m->Compile(); - } -} - diff --git a/CRC.cpp b/src/CRC.cpp similarity index 92% rename from CRC.cpp rename to src/CRC.cpp index 65a6707..0d49e8a 100644 --- a/CRC.cpp +++ b/src/CRC.cpp @@ -1,3 +1,5 @@ +/* This file is part of SpringMapConvNG (GPL v2 or later), see the LICENSE file */ + #include "CRC.h" static const uint32_t kCrc32Table[256] = { @@ -68,27 +70,23 @@ static const uint32_t kCrc32Table[256] = { }; // kCrc32Table void Crc32::AddData(const uint8_t* pData, const uint32_t length) { - uint8_t* pCur = (uint8_t*)pData; - uint32_t remaining = length; - for (; remaining--; ++pCur) - _crc = ( _crc >> 8 ) ^ kCrc32Table[(_crc ^ *pCur) & 0xff]; + uint8_t* pCur = (uint8_t*)pData; + uint32_t remaining = length; + for (; remaining--; ++pCur) + _crc = (_crc >> 8) ^ kCrc32Table[(_crc ^ *pCur) & 0xff]; } void Crc32::Reset() { - _crc = (uint32_t)~0; + _crc = (uint32_t)~0; } const uint32_t Crc32::GetCrc32() { - return ~_crc; + return ~_crc; } Crc32::Crc32() { - Reset(); + Reset(); } Crc32::~Crc32() { - } - - - diff --git a/src/CRC.h b/src/CRC.h new file mode 100644 index 0000000..4b1b69d --- /dev/null +++ b/src/CRC.h @@ -0,0 +1,22 @@ +/* This file is part of SpringMapConvNG (GPL v2 or later), see the LICENSE file */ + +#ifndef CRC_H +#define CRC_H + +#include + +class Crc32 +{ +public: + Crc32(); + ~Crc32(); + void Reset(); + void AddData(const uint8_t* pData, const uint32_t length); + + const uint32_t GetCrc32(); + +private: + uint32_t _crc; +}; + +#endif // CRC_H diff --git a/src/Image.cpp b/src/Image.cpp new file mode 100644 index 0000000..00ca9e5 --- /dev/null +++ b/src/Image.cpp @@ -0,0 +1,148 @@ +/* This file is part of SpringMapConvNG (GPL v2 or later), see the LICENSE file */ + +#include "Image.h" + +CannotLoadImageException::CannotLoadImageException(std::string path) + : runtime_error(path) +{ +} + +Image::Image() +{ + ilGenImages(1, &image); + w = 0; + h = 0; + d = 0; +} +void Image::GetRect(int x, int y, int w, int h, ILenum format, void* dest) +{ + ilBindImage(image); + ilCopyPixels(x, y, 0, w, h, 1, format, IL_UNSIGNED_BYTE, dest); +} +void Image::GetRect(int x, int y, int w, int h, ILenum format, ILenum type, void* dest) +{ + ilBindImage(image); + ilCopyPixels(x, y, 0, w, h, 1, format, type, dest); +} +void Image::FlipVertical() +{ + ilBindImage(image); + iluFlipImage(); +} + +Image::Image(const char* filename, bool hdrlum) +{ + + ilGenImages(1, &image); + ilBindImage(image); + if (!ilLoadImage(filename)) { + throw CannotLoadImageException(std::string(filename)); + } + if (!hdrlum) { + ConvertToRGBA(); + } else if (ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL) != 2 || ilGetInteger(IL_IMAGE_FORMAT) != IL_LUMINANCE) { + ConvertToLUMHDR(); + } + w = ilGetInteger(IL_IMAGE_WIDTH); + h = ilGetInteger(IL_IMAGE_HEIGHT); + d = ilGetInteger(IL_IMAGE_DEPTH); + datapointer = ilGetData(); +} +void Image::Save(const char* filename) +{ + ilBindImage(image); + ilSaveImage(filename); +} +void Image::AllocateLUM(int x, int y, char* data) +{ + ilBindImage(image); + ilTexImage(x, y, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, data); + datapointer = ilGetData(); + w = ilGetInteger(IL_IMAGE_WIDTH); + h = ilGetInteger(IL_IMAGE_HEIGHT); + d = ilGetInteger(IL_IMAGE_DEPTH); +} + +void Image::AllocateRGBA(int x, int y, char* data) +{ + ilBindImage(image); + ilTexImage(x, y, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, data); + datapointer = ilGetData(); + w = ilGetInteger(IL_IMAGE_WIDTH); + h = ilGetInteger(IL_IMAGE_HEIGHT); + d = ilGetInteger(IL_IMAGE_DEPTH); +} +void Image::Rescale(int x, int y) +{ + ilBindImage(image); + iluScale(x, y, 1); + datapointer = ilGetData(); + w = ilGetInteger(IL_IMAGE_WIDTH); + h = ilGetInteger(IL_IMAGE_HEIGHT); + d = ilGetInteger(IL_IMAGE_DEPTH); +} + +void Image::GetPixelRGBA(int x_, int y_, unsigned char* pix) +{ + + int x = x_ % w; + int y = h - (y_ % h); + + if (datapointer) { + pix[0] = datapointer[w * y * 4 + x * 4]; + pix[1] = datapointer[w * y * 4 + x * 4 + 1]; + pix[2] = datapointer[w * y * 4 + x * 4 + 2]; + pix[3] = datapointer[w * y * 4 + x * 4 + 3]; + } else { + printf("GetPixelRGBA(%i,%i): datapointer is NULL\n", x_, y_); + } + //printf("%i %i %i\n",(int)pix[0],(int)pix[1],int(pix[2])); +} + + +void Image::SetPixelRGBA(int x_, int y_, char r, char g, char b, char a) +{ + int x = (x_ % w); + int y = h - (y_ % h) - 1; + datapointer[w * y * 3 + x * 3] = r; + datapointer[w * y * 3 + x * 3 + 1] = g; + datapointer[w * y * 3 + x * 3 + 2] = b; + datapointer[w * y * 4 + x * 4 + 3] = a; +} + +void Image::SetPixelLUM(int x_, int y_, char val) +{ + int x = x_ % w; + int y = y_ % h; + datapointer[y * w + x] = val; +} +void Image::GetPixelLUM(int x_, int y_, unsigned char* p) +{ + //printf("GetPixelLUM(%i,%i)\n",x_,y_); + int x = x_ % w; + int y = y_ % h; + p[0] = datapointer[y * w + x]; +} +void Image::ConvertToLUM() +{ + ilBindImage(image); + ilConvertImage(IL_LUMINANCE, IL_UNSIGNED_BYTE); + datapointer = ilGetData(); +} +void Image::ConvertToLUMHDR() +{ + ilBindImage(image); + ilConvertImage(IL_LUMINANCE, IL_UNSIGNED_SHORT); + datapointer = ilGetData(); +} + +void Image::ConvertToRGBA() +{ + ilBindImage(image); + ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE); + datapointer = ilGetData(); +} +Image::~Image() +{ + ilDeleteImages(1, &image); +} diff --git a/src/Image.h b/src/Image.h new file mode 100644 index 0000000..621338e --- /dev/null +++ b/src/Image.h @@ -0,0 +1,59 @@ +/* This file is part of SpringMapConvNG (GPL v2 or later), see the LICENSE file */ + +#ifndef IMAGE_H +#define IMAGE_H +#include +#include +#include +#include + +#ifdef SetPixelRGBA +#undef SetPixelRGBA +#endif + +class CannotLoadImageException : public std::runtime_error +{ +public: + CannotLoadImageException(std::string path); +}; +class Image +{ +public: + ILuint image; + int w; + int h; + int d; + unsigned char* datapointer; + Image(); + + Image(const char* filename, bool hdrlum = false); + + void Save(const char* filename); + + void AllocateLUM(int x, int y, char* data = NULL); + + void AllocateRGBA(int x, int y, char* data = NULL); + + void Rescale(int x, int y); + + void GetPixelRGBA(int x_, int y_, unsigned char* pix); + + void SetPixelRGBA(int x_, int y_, char r, char g, char b, char a); + + void SetPixelLUM(int x_, int y_, char val); + + void GetPixelLUM(int x_, int y_, unsigned char* p); + + void ConvertToLUM(); + + void ConvertToLUMHDR(); + + void ConvertToRGBA(); + + void FlipVertical(); + void GetRect(int x, int y, int w, int h, ILenum format, void* dest); + void GetRect(int x, int y, int w, int h, ILenum format, ILenum type, void* dest); + ~Image(); +}; + +#endif // IMAGE_H diff --git a/src/SMFMap.cpp b/src/SMFMap.cpp new file mode 100644 index 0000000..28c6432 --- /dev/null +++ b/src/SMFMap.cpp @@ -0,0 +1,652 @@ +/* This file is part of SpringMapConvNG (GPL v2 or later), see the LICENSE file */ + +#include "SMFMap.h" +#include "Image.h" +#include "TileStorage.h" +#include +#include +#include +#include +#include + + +#ifndef bzero +#define bzero(ptr, len) memset(ptr, 0, len) + +#endif +SMFMap::SMFMap(std::string name, std::string texturepath) +{ + + m_tiles = new TileStorage(); + metalmap = NULL; + heightmap = NULL; + typemap = NULL; + minimap = NULL; + vegetationmap = NULL; + texture = new Image(texturepath.c_str()); + + if (texture->w < 1) + throw CannotLoadTextureException(); + if (texture->w % 1024 != 0 || texture->h % 1024 != 0) { + throw InvalidMapSizeException(); + } + mapx = (texture->w / 1024) * 128; + mapy = (texture->h / 1024) * 128; + m_minh = 0.0; + m_maxh = 1.0; + m_name = name; + m_doclamp = true; + m_th = 0; + m_comptype = COMPRESS_REASONABLE; + m_smooth = false; + texpath = texturepath; +} +SMFMap::SMFMap(std::string smfname) +{ + std::vector tiles_images; + std::vector tile_files; + metalmap = NULL; + heightmap = NULL; + typemap = NULL; + minimap = NULL; + vegetationmap = NULL; + m_tiles = NULL; + FILE* smffile = fopen(smfname.c_str(), "rb"); + if (!smffile) { + throw CannotLoadSmfFileException(); + } + SMFHeader hdr; + fread(&hdr, sizeof(hdr), 1, smffile); + if (strncmp(hdr.magic, "spring map file", 15) > 0) { + fclose(smffile); + throw InvalidSmfFileException(); + } + mapx = hdr.mapx; + mapy = hdr.mapy; + m_minh = hdr.minHeight; + m_maxh = hdr.maxHeight; + m_smfname = smfname; + m_doclamp = true; + m_th = 0; + m_comptype = COMPRESS_REASONABLE; + m_smooth = false; + texture = new Image(); + texture->AllocateRGBA((mapx / 128) * 1024, (mapy / 128) * 1024); + std::cout << "Loading metal map..." << std::endl; + metalmap = new Image(); + metalmap->AllocateLUM(mapx / 2, mapy / 2); + fseek(smffile, hdr.metalmapPtr, SEEK_SET); + fread(metalmap->datapointer, mapx / 2 * mapy / 2, 1, smffile); + + + std::cout << "Loading heightmap..." << std::endl; + heightmap = new Image(); + heightmap->AllocateLUM(mapx + 1, mapy + 1); + heightmap->ConvertToLUMHDR(); //TODO: Allocate directly HDR + fseek(smffile, hdr.heightmapPtr, SEEK_SET); + fread(heightmap->datapointer, (mapx + 1) * (mapy + 1) * 2, 1, smffile); + heightmap->FlipVertical(); + + std::cout << "Loading type map..." << std::endl; + typemap = new Image(); + typemap->AllocateLUM(mapx / 2, mapy / 2); + fseek(smffile, hdr.typeMapPtr, SEEK_SET); + fread(typemap->datapointer, mapx / 2 * mapy / 2, 1, smffile); + typemap->FlipVertical(); + + std::cout << "Loading minimap..." << std::endl; + minimap = new Image(); + uint8_t* dxt1data = new uint8_t[699064]; + fseek(smffile, hdr.minimapPtr, SEEK_SET); + fread(dxt1data, 699064, 1, smffile); + ilBindImage(minimap->image); + ilTexImageDxtc(1024, 1024, 1, IL_DXT1, dxt1data); + ilDxtcDataToImage(); + std::cout << "Extracting main texture..." << std::endl; + int* tilematrix = new int[mapx / 4 * mapy / 4]; + + fseek(smffile, hdr.tilesPtr, SEEK_SET); + MapTileHeader thdr; + fread(&thdr, sizeof(thdr), 1, smffile); + while (tile_files.size() < thdr.numTileFiles) { + tile_files.push_back(""); + char byte; + int numtiles; + fread(&numtiles, 4, 1, smffile); + fread(&byte, 1, 1, smffile); + while (byte != 0) { + tile_files[tile_files.size() - 1].append(1, byte); + fread(&byte, 1, 1, smffile); + } + } + for (std::vector::iterator it = tile_files.begin(); it != tile_files.end(); it++) { + std::cout << "Opening " << *it << std::endl; + FILE* smtfile = fopen((*it).c_str(), "rb"); + if (!smtfile) { + fclose(smffile); + delete[] tilematrix; + throw CannotOpenSmtFileException(); + } + TileFileHeader smthdr; + fread(&smthdr, sizeof(smthdr), 1, smtfile); + if (strncmp(smthdr.magic, "spring tilefile", 14)) { + fclose(smffile); + fclose(smtfile); + delete[] tilematrix; + throw InvalidSmtFileException(); + } + for (int i = 0; i < smthdr.numTiles; i++) { + ILuint tile = ilGenImage(); + fread(dxt1data, 680, 1, smtfile); + ilBindImage(tile); + ilTexImageDxtc(32, 32, 1, IL_DXT1, dxt1data); + ilDxtcDataToImage(); + tiles_images.push_back(tile); + } + fclose(smtfile); + } + std::cout << "Tiles @ " << ftell(smffile) << std::endl; + fread(tilematrix, mapx / 4 * mapy / 4 * 4, 1, smffile); + ilBindImage(texture->image); + unsigned int* texdata = (unsigned int*)ilGetData(); + std::cout << "Blitting tiles..." << std::endl; + for (int y = 0; y < mapy / 4; y++) { + std::cout << "Row " << y << " of " << mapy / 4 << std::endl; + for (int x = 0; x < mapx / 4; x++) { + if (tilematrix[y * (mapx / 4) + x] >= tiles_images.size()) { + std::cerr << "Warning: tile " << tilematrix[y * (mapx / 4) + x] << " out of range" << std::endl; + continue; + } + //ilBlit(tiles_images[tilematrix[y*(mapx/4)+x]],x*32,y*32,0,0,0,0,32,32,1); + ilBindImage(tiles_images[tilematrix[y * (mapx / 4) + x]]); + unsigned int* data = (unsigned int*)ilGetData(); + int r2 = 0; + for (int y2 = y * 32; y2 < y * 32 + 32; y2++) //FAST blitting + { + /*for ( int x2 = y*32; x2 < y*32+32; x2++ ) + { + + + }*/ + memcpy(&texdata[y2 * texture->w + x * 32], &data[r2 * 32], 32 * 4); + r2++; + } + } + } + texture->FlipVertical(); + + + std::cout << "Loading features..." << std::endl; + + fseek(smffile, hdr.featurePtr, SEEK_SET); + MapFeatureHeader mfhdr; + fread(&mfhdr, sizeof(mfhdr), 1, smffile); + //-32767.0f+f->rotation/65535.0f*360 + + std::vector feature_types; + while (feature_types.size() < mfhdr.numFeatureType) { + feature_types.push_back(""); + char byte; + fread(&byte, 1, 1, smffile); + while (byte != 0) { + feature_types[feature_types.size() - 1].append(1, byte); + fread(&byte, 1, 1, smffile); + } + } + for (int i = 0; i < mfhdr.numFeatures; i++) { + MapFeatureStruct f; + fread(&f, sizeof(f), 1, smffile); + if (f.featureType >= feature_types.size()) { + std::cerr << "Warning: invalid feature type " << f.featureType << std::endl; + continue; + } + AddFeature(feature_types[f.featureType], f.xpos, f.ypos, f.zpos, -32767.0f + f.rotation / 65535.0f * 360); + } + fclose(smffile); + delete[] dxt1data; + delete[] tilematrix; +} + +void SMFMap::SetClamping(bool b) +{ + m_doclamp = b; +} +void SMFMap::SaveSourceFiles() +{ + if (metalmap) { + metalmap->Save("metalmap.png"); + } + if (typemap) { + typemap->Save("typemap.png"); + } + if (heightmap) { + heightmap->Save("heightmap.png"); + //heightmap->Save("heightmap.exr"); Not needed , png already supports 16 bit and DevIL too + } + if (texture) { + texture->Save("texture.png"); + } + if (minimap) { + minimap->Save("minimap.png"); + } + FILE* featurefile = fopen("features.txt", "w"); + for (std::map*>::iterator it = features.begin(); it != features.end(); it++) { + for (std::list::iterator it2 = (*it).second->begin(); it2 != (*it).second->end(); it2++) { + MapFeatureStruct* f = (*it2); + float degrot = -32767.0f + f->rotation / 65535.0f * 360; // 32767.0f-((orientation/360.0)*65535.0f); + + fprintf(featurefile, "%s %f %f %f %f\n", (*it).first.c_str(), f->xpos, f->ypos, f->zpos, degrot); + } + } + fclose(featurefile); + + const char* compileCmd = "springMapConvNG -t texture.png -h heightmap.png -z typemap.png -m metalmap.png -maxh %f -minh %f -th 0.8 -ct 4 -features features.txt -minimap minimap.png -o \"%s\""; + FILE* makefile = fopen("Makefile", "w"); + fprintf(makefile, "%s: texture.png heightmap.png typemap.png metalmap.png minimap.png features.txt\n", m_smfname.c_str()); + std::string smfbasename = m_smfname.substr(0, m_smfname.find(".")); + fprintf(makefile, "\t"); + fprintf(makefile, compileCmd, m_maxh, m_minh, smfbasename.c_str()); + fprintf(makefile, "\n"); + fclose(makefile); + + FILE* batchfile = fopen("make.bat", "w"); + fprintf(batchfile, compileCmd, m_maxh, m_minh, smfbasename.c_str()); + fprintf(batchfile, "\r\npause\r\n"); + fclose(batchfile); +} + +void SMFMap::SetVegetationMap(std::string path) +{ + Image* img = new Image(path.c_str()); + if (img->w > 0) { + if (vegetationmap) + delete vegetationmap; + vegetationmap = img; + vegetationmap->ConvertToLUM(); + if (img->w != mapx / 4 || img->h != mapy / 4) { + std::cerr << "Warning: Vegetation map has wrong size , rescaling!" << std::endl; + vegetationmap->Rescale(mapx / 4, mapy / 4); + } + } +} +void SMFMap::AddFeature(std::string name, float x, float y, float z, float orientation) +{ + if (features.find(name) == features.end()) //Allocate new vector + { + features[name] = new std::list(); + } + MapFeatureStruct* feat = (MapFeatureStruct*)malloc(sizeof(MapFeatureStruct)); + feat->xpos = x; + feat->ypos = y; + feat->zpos = z; + feat->rotation = 32767.0f - ((orientation / 360.0) * 65535.0f); + feat->relativeSize = 1; + features[name]->push_back(feat); +} + +void SMFMap::SetHeightRange(float minh, float maxh) +{ + m_minh = minh; + m_maxh = maxh; +} + +SMFMap::~SMFMap() +{ + delete m_tiles; + if (metalmap) + delete metalmap; + if (heightmap) + delete heightmap; + if (typemap) + delete typemap; + if (minimap) + delete minimap; + if (texture) + delete texture; + if (vegetationmap) + delete vegetationmap; +} +void SMFMap::SetMiniMap(std::string path) +{ + delete texture; + std::cout << "Loading minimap " << path << std::endl; + Image* img = new Image(path.c_str()); + if (img->w > 0) { + if (minimap) + delete minimap; + minimap = img; + minimap->ConvertToRGBA(); + minimap->FlipVertical(); + if (img->w != 1024 || img->h != 1024) { + std::cerr << "Warning: Minimap has wrong size , rescaling!" << std::endl; + minimap->Rescale(1024, 1024); + } + texture = new Image(texpath.c_str()); + return; + } + std::cout << "Failed " << path << std::endl; + texture = new Image(texpath.c_str()); +} + +/*void SMFMap::SetFeatureMap(std::string path) +{ + Image * img = new Image(path.c_str()); + if ( img->w > 0 ) + { + if ( featuremap ) + delete featuremap; + featuremap = img; + featuremap->ConvertToLUM(); + } + if ( img->w != mapx/2 || img->h != mapy/2 ) + { + std::cerr << "Warning: Feature map has wrong size , rescaling!" << std::endl; + heightmap->Rescale(mapx+1,mapy+1); + + } +}*/ +void SMFMap::SetHeightMap(std::string path) +{ + Image* img = new Image(path.c_str(), true); + if (img->w > 0) { + if (heightmap) + delete heightmap; + heightmap = img; + // heightmap->ConvertToLUMHDR(); + if (img->w != mapx + 1 || img->h != mapy + 1) { + std::cerr << "Warning: Height map has wrong size , rescaling! (" << img->w << "," << img->h << ") instead of (" << mapx + 1 << "," << mapy + 1 << ")" << std::endl; + heightmap->Rescale(mapx + 1, mapy + 1); + } + //Clamp heightmap before blurring + if (m_doclamp) { + float _min = 65537.0f; + float _max = -65337.0f; + unsigned short* pixels = (unsigned short*)heightmap->datapointer; + for (int i = 0; i < heightmap->w * heightmap->h; i++) { + if (_min > pixels[i]) + _min = pixels[i]; + if (_max < pixels[i]) + _max = pixels[i]; + } + std::cout << "Range : " << _min << " -> " << _max << std::endl; + float range = _max - _min; + for (int i = 0; i < heightmap->w * heightmap->h; i++) { + pixels[i] = (unsigned short)((((pixels[i] - _min) / range) * 65535.0f)); + } + } + if (m_smooth) { + std::cout << "Blurring heightmap..." << std::endl; + /*ilBindImage(heightmap->image); // Seems broken with 16 bit image + iluBlurAvg(5); + heightmap->datapointer = ilGetData();*/ + unsigned short* tempdata = new unsigned short[img->h * img->w]; + for (int pass = 0; pass < 3; pass++) { + std::cout << "Blurring heightmap pass " << pass + 1 << "..." << std::endl; + memcpy(tempdata, img->datapointer, img->h * img->w * 2); + for (int y = 1; y < img->h - 1; y++) { + for (int x = 1; x < img->w - 1; x++) { + float sum = 0.0f; + sum += ((unsigned short*)img->datapointer)[y * img->w + x]; + sum += ((unsigned short*)img->datapointer)[(y - 1) * img->w + (x - 1)]; + sum += ((unsigned short*)img->datapointer)[(y - 1) * img->w + (x - 0)]; + sum += ((unsigned short*)img->datapointer)[(y - 1) * img->w + (x + 1)]; + sum += ((unsigned short*)img->datapointer)[(y - 0) * img->w + (x - 1)]; + sum += ((unsigned short*)img->datapointer)[(y - 0) * img->w + (x + 1)]; + sum += ((unsigned short*)img->datapointer)[(y + 1) * img->w + (x - 1)]; + sum += ((unsigned short*)img->datapointer)[(y + 1) * img->w + (x - 0)]; + sum += ((unsigned short*)img->datapointer)[(y + 1) * img->w + (x + 1)]; + sum /= 9.0f; + tempdata[y * img->w + x] = (unsigned short)(sum); + } + } + memcpy(img->datapointer, tempdata, img->h * img->w * 2); + } + delete[] tempdata; + } + } +} +void SMFMap::SetBlur(bool b) +{ + m_smooth = b; +} +void SMFMap::SetCompareTileCount(uint32_t count) +{ + m_tiles->SetDictSize(count); +} + +void SMFMap::SetMetalMap(std::string path) +{ + Image* img = new Image(path.c_str()); + if (img->w > 0) { + if (metalmap) + delete metalmap; + metalmap = img; + metalmap->ConvertToLUM(); + + if (img->w != mapx / 2 || img->h != mapy / 2) { + std::cerr << "Warning: Metal map has wrong size , rescaling! (" << img->w << "," << img->h << ") instead of (" << mapx / 2 << "," << mapy / 2 << ")" << std::endl; + metalmap->Rescale(mapx / 2, mapy / 2); + } + } +} +void SMFMap::SetTypeMap(std::string path) +{ + Image* img = new Image(path.c_str()); + if (img->w > 0) { + if (typemap) + delete typemap; + typemap = img; + typemap->ConvertToLUM(); + if (img->w != mapx / 2 || img->h != mapy / 2) { + std::cerr << "Warning: Type map has wrong size , rescaling! (" << img->w << "," << img->h << ") instead of (" << mapx / 2 << "," << mapy / 2 << ")" << std::endl; + typemap->Rescale(mapx / 2, mapy / 2); + } + } +} + +void SMFMap::Compile() +{ + SMFHeader hdr; + strcpy(hdr.magic, "spring map file"); + hdr.version = 1; + hdr.mapid = rand(); + hdr.mapx = (texture->w / 1024) * 128; + hdr.mapy = (texture->h / 1024) * 128; + hdr.squareSize = 8; + hdr.texelPerSquare = 8; + hdr.tilesize = 32; + hdr.minHeight = m_minh; + hdr.maxHeight = m_maxh; + + + short int* hmap = new short int[(mapy + 1) * (mapx + 1)]; + bzero(hmap, ((mapy + 1) * (mapx + 1)) * 2); + if (heightmap) { + //heightmap->GetRect(0,0,heightmap->w,heightmap->h,IL_LUMINANCE,IL_SHORT,hmap); : IL seems to fail to convert from unsigned short to signed + /*for ( int k = 0; k < (mapy+1)*(mapx+1); k++ ) + { + int pix = ((unsigned short*)heightmap->datapointer)[k]; + hmap[k] = short(int(pix)-int(32767)); + + */ + memcpy(hmap, heightmap->datapointer, ((mapy + 1) * (mapx + 1)) * 2); + } + unsigned char* typedata = new unsigned char[mapy / 2 * mapx / 2]; + bzero(typedata, (mapy / 2 * mapx / 2)); + if (typemap) { + typemap->GetRect(0, 0, typemap->w, typemap->h, IL_LUMINANCE, IL_UNSIGNED_BYTE, typedata); + } + uint8_t* minimap_data = new uint8_t[699064]; + bzero(minimap_data, 699064); + if (minimap) { + int p = 0; + int s = 1024; + + Image* im2 = new Image(); + im2->AllocateRGBA(1024, 1024, (char*)minimap->datapointer); + for (int i = 0; i < 9; i++) { + //std::cout << ">Mipmap " << i << std::endl; + im2->Rescale(s, s); + //std::cout << "datapointer, s, s, 1, IL_DXT1, &ss); + //std::cout << ss << " " << s; + memcpy(&minimap_data[p], dxtdata, ss); + free(dxtdata); + p += ss; + + s = s >> 1; + } + delete im2; + } + unsigned char* metalmap_data = new unsigned char[mapx / 2 * mapy / 2]; + bzero(metalmap_data, (mapy / 2 * mapx / 2)); + if (metalmap) { + metalmap->GetRect(0, 0, metalmap->w, metalmap->h, IL_LUMINANCE, IL_UNSIGNED_BYTE, metalmap_data); + } + /*hdr.heightmapPtr = sizeof(hdr); + hdr.typeMapPtr = hdr.heightmapPtr + ((mapy+1)*(mapx+1))*2; + hdr.minimapPtr = hdr.typeMapPtr + (mapy/2 * mapx/2); + hdr.metalmapPtr = hdr.minimapPtr + 699048; + hdr.featurePtr = hdr.metalmapPtr + (mapy/2 * mapx/2);*/ + MapFeatureHeader mfhdr; + + hdr.tilesPtr = hdr.featurePtr + sizeof(mfhdr); + hdr.numExtraHeaders = 1; + ExtraHeader grassHeader; + grassHeader.size = 4; + grassHeader.type = 1; + MapTileHeader mthdr; + mthdr.numTileFiles = 1; + unsigned char* grass_data = new unsigned char[mapx / 4 * mapy / 4]; + bzero(grass_data, mapx / 4 * mapy / 4); + if (vegetationmap) { + vegetationmap->GetRect(0, 0, vegetationmap->w, vegetationmap->h, IL_LUMINANCE, IL_UNSIGNED_BYTE, grass_data); + } + int* tiles = new int[mapx / 4 * mapy / 4]; + std::vector order; + DoCompress(tiles, order); + /* for ( int y = 0; y < mapy/4; y++ ) + { + for ( int x = 0; x < mapx/4; x++ ) + { + printf("%5d,",tiles[(mapx/4)*y+x]); + } + printf("\n"); + }*/ + + FILE* tilefile = fopen((m_name + std::string(".smt")).c_str(), "wb"); + delete texture; //Temporarily delete texture from memory to reduce mem usage + m_tiles->WriteToFile(tilefile, order); + texture = new Image(texpath.c_str()); + + fclose(tilefile); + FILE* smffile = fopen((m_name + std::string(".smf")).c_str(), "wb"); + fwrite(&hdr, sizeof(hdr), 1, smffile); + fwrite(&grassHeader, sizeof(grassHeader), 1, smffile); + int _ofs = ftell(smffile) + 4; + fwrite(&_ofs, 4, 1, smffile); + fwrite(grass_data, mapx / 4 * mapy / 4, 1, smffile); + + hdr.minimapPtr = ftell(smffile); + fwrite(minimap_data, 699064, 1, smffile); + hdr.heightmapPtr = ftell(smffile); + fwrite(hmap, ((mapy + 1) * (mapx + 1)) * 2, 1, smffile); + hdr.typeMapPtr = ftell(smffile); + fwrite(typedata, mapy / 2 * mapx / 2, 1, smffile); + + hdr.metalmapPtr = ftell(smffile); + fwrite(metalmap_data, mapy / 2 * mapx / 2, 1, smffile); + hdr.featurePtr = ftell(smffile); + + + mfhdr.numFeatures = 0; + for (std::map*>::iterator it = features.begin(); it != features.end(); it++) //Enumerate features + mfhdr.numFeatures += (*it).second->size(); + mfhdr.numFeatureType = features.size(); + fwrite(&mfhdr, sizeof(mfhdr), 1, smffile); + { + std::map featureTypes; + unsigned int z = 0; + for (std::map*>::iterator it = features.begin(); it != features.end(); it++) //Write feature types + { + fwrite((*it).first.c_str(), (*it).first.size() + 1, 1, smffile); + featureTypes[(*it).first] = z++; + } + for (std::map*>::iterator it = features.begin(); it != features.end(); it++) //Write feature types + { + for (std::list::iterator it2 = (*it).second->begin(); it2 != (*it).second->end(); it2++) { + (*it2)->featureType = featureTypes[(*it).first]; + if ((*it2)->ypos < 490000.0f) // Align on terrain + { + unsigned int hmapx = ((*it2)->xpos / float((mapx / 128) * 1024)) * heightmap->w; + unsigned int hmapy = ((*it2)->zpos / float((mapy / 128) * 1024)) * heightmap->h; + (*it2)->ypos = hdr.minHeight + (float(hmap[hmapy * (mapx + 1) + hmapx]) / 32767.0) * (hdr.maxHeight - hdr.minHeight); + std::cout << "Feature " << (*it).first << " Instance " << (*it2) << " Terrain height: " << (*it2)->ypos << std::endl; + } + + fwrite((*it2), sizeof(MapFeatureStruct), 1, smffile); + } + } + } + + hdr.tilesPtr = ftell(smffile); + uint32_t tc = m_tiles->GetTileCount(); + mthdr.numTiles = tc; + fwrite(&mthdr, sizeof(mthdr), 1, smffile); + fwrite(&tc, 4, 1, smffile); + fwrite((m_name + std::string(".smt")).c_str(), (m_name + std::string(".smt")).length() + 1, 1, smffile); + fwrite(tiles, (mapx / 4 * mapy / 4) * 4, 1, smffile); + fseek(smffile, 0, SEEK_SET); + fwrite(&hdr, sizeof(hdr), 1, smffile); + fclose(smffile); + delete[] metalmap_data; + delete[] hmap; + delete[] typedata; + delete[] tiles; + delete[] minimap_data; + delete[] grass_data; +} + +void SMFMap::DoCompress(int* indices, std::vector& order) +{ + order.clear(); + + uint8_t tiledata[32 * 32 * 4]; + std::map existingtiles; + int c = 0; + for (int y = 0; y < mapy / 4; y++) { + for (int x = 0; x < mapx / 4; x++) { + if (c % 50 == 0) + printf("\rCompressing %8d/%8d - %6d tiles ", c, mapy / 4 * mapx / 4, m_tiles->GetTileCount()); + c++; + texture->GetRect(x * 32, y * 32, 32, 32, IL_RGBA, IL_UNSIGNED_BYTE, tiledata); + for (int yy = 0; yy < 16; yy++) //Flip vertically + { + char tmprow[32 * 4]; + memcpy(tmprow, &tiledata[(31 - yy) * 32 * 4], 32 * 4); + memcpy(&tiledata[(31 - yy) * 32 * 4], &tiledata[yy * 32 * 4], 32 * 4); + memcpy(&tiledata[yy * 32 * 4], tmprow, 32 * 4); + } + // std::cout << "Compressing (" << x << "," << y << ")" << std::endl; + uint64_t uid = m_tiles->AddTileOrGetSimiliar(tiledata, m_th, m_comptype); + if (existingtiles.find(uid) == existingtiles.end()) { + indices[(mapx / 4) * y + x] = order.size(); + existingtiles[uid] = order.size(); + order.push_back(uid); + } else { + indices[(mapx / 4) * y + x] = existingtiles[uid]; + } + } + } + printf("\n"); + std::cout << "Compress done , ratio: " << float(existingtiles.size()) / float(mapy / 4 * mapx / 4) * 100.0 << std::endl; +} +void SMFMap::SetCompressionTol(float th) +{ + m_th = th; +} +void SMFMap::SetCompressionType(int c) +{ + m_comptype = c; +} diff --git a/src/SMFMap.h b/src/SMFMap.h new file mode 100644 index 0000000..cef12d1 --- /dev/null +++ b/src/SMFMap.h @@ -0,0 +1,133 @@ +/* This file is part of SpringMapConvNG (GPL v2 or later), see the LICENSE file */ + +#ifndef SMFMAP_H +#define SMFMAP_H +#include +#include +#include +#include +#include + +class Image; +class TileStorage; + +typedef struct { + char magic[16]; ///< "spring map file\0" + int version; ///< Must be 1 for now + int mapid; ///< Sort of a GUID of the file, just set to a random value when writing a map + + int mapx; ///< Must be divisible by 128 + int mapy; ///< Must be divisible by 128 + int squareSize; ///< Distance between vertices. Must be 8 + int texelPerSquare; ///< Number of texels per square, must be 8 for now + int tilesize; ///< Number of texels in a tile, must be 32 for now + float minHeight; ///< Height value that 0 in the heightmap corresponds to + float maxHeight; ///< Height value that 0xffff in the heightmap corresponds to + + int heightmapPtr; ///< File offset to elevation data (short int[(mapy+1)*(mapx+1)]) + int typeMapPtr; ///< File offset to typedata (unsigned char[mapy/2 * mapx/2]) + int tilesPtr; ///< File offset to tile data (see MapTileHeader) + int minimapPtr; ///< File offset to minimap (always 1024*1024 dxt1 compresed data plus 8 mipmap sublevels) + int metalmapPtr; ///< File offset to metalmap (unsigned char[mapx/2 * mapy/2]) + int featurePtr; ///< File offset to feature data (see MapFeatureHeader) + + int numExtraHeaders; ///< Numbers of extra headers following main header +} SMFHeader; +typedef struct +{ + int numFeatureType; + int numFeatures; +} MapFeatureHeader; +typedef struct +{ + int numTileFiles; ///< Number of tile files to read in (usually 1) + int numTiles; ///< Total number of tiles +} MapTileHeader; +typedef struct { + int size; ///< Size of extra header + int type; ///< Type of extra header +} ExtraHeader; +typedef struct +{ + int featureType; ///< Index to one of the strings above + float xpos; ///< X coordinate of the feature + float ypos; ///< Y coordinate of the feature (height) + float zpos; ///< Z coordinate of the feature + + float rotation; ///< Orientation of this feature (-32768..32767 for full circle) + float relativeSize; ///< Not used at the moment keep 1 +} MapFeatureStruct; +typedef struct +{ + char magic[16]; ///< "spring tilefile\0" + int version; ///< Must be 1 for now + + int numTiles; ///< Total number of tiles in this file + int tileSize; ///< Must be 32 for now + int compressionType; ///< Must be 1 (= dxt1) for now +} TileFileHeader; +class InvalidMapSizeException +{ +}; +class CannotLoadTextureException +{ +}; +class CannotLoadSmfFileException +{ +}; +class InvalidSmfFileException +{ +}; +class CannotOpenSmtFileException +{ +}; +class InvalidSmtFileException +{ +}; +class SMFMap +{ + +public: + SMFMap(std::string name, std::string texturepath); + SMFMap(std::string smfname); //Decompile + virtual ~SMFMap(); + void SetMetalMap(std::string path); + void SetTypeMap(std::string path); + //void SetFeatureMap(std::string path); + void SetHeightMap(std::string path); + void SetVegetationMap(std::string path); + void SetMiniMap(std::string path); + void Compile(); + void SetHeightRange(float minh, float maxh); + void SetCompressionTol(float th); + void SetCompressionType(int c); + void SetCompareTileCount(uint32_t count); + void SetClamping(bool b); + void SetBlur(bool b); + void SaveSourceFiles(); + void AddFeature(std::string name, float x, float y, float z, float orientation); + +private: + void DoCompress(int* indices, std::vector& order); + TileStorage* m_tiles; + Image* metalmap; + //Image * featuremap; + Image* heightmap; + Image* typemap; + Image* texture; + Image* minimap; + Image* vegetationmap; + int mapx, mapy; + std::string m_name; + float m_minh; + float m_maxh; + float m_th; + bool m_doclamp; + bool m_smooth; + int m_comptype; + std::string texpath; + std::string m_smfname; + std::map*> features; +}; + +#endif // SMFMAP_H diff --git a/src/TileStorage.cpp b/src/TileStorage.cpp new file mode 100644 index 0000000..f6c85ab --- /dev/null +++ b/src/TileStorage.cpp @@ -0,0 +1,212 @@ +/* This file is part of SpringMapConvNG (GPL v2 or later), see the LICENSE file */ + +#include "TileStorage.h" +#include "CRC.h" + +#include +#include +#include +#include +#include +#include +#include + +inline uint64_t tilechecksum(uint8_t* data) +{ + uint64_t r = 0; + for (int x = 0; x < 32 * 32 * 4; x++) { + r += data[x] * 63018038201L * x * x; + r ^= 13091204281L; + r *= 13091204281L * x; + r *= 108086391056891903ULL * data[x]; + } + Crc32 c; + c.AddData(data, 32 * 32 * 4); + r *= c.GetCrc32(); + return r; +} + +inline float tilediff(uint8_t* t1, uint8_t* t2) +{ + float diff = 0.0; + for (int i = 0; i < 32 * 32 * 4; i++) { + float d1 = fabs(float(t1[i]) - float(t2[i])); + if (d1 < 30) + diff += d1; + else + diff += 255.0f; //If it has a point that is VERY different , it must not be reused + } + diff /= 32.0 * 32.0 * 4.0f * 10.0f; + return diff; +} + +TileStorage::TileStorage() +{ + Reset(); + m_dictcount = 64; +} + +TileStorage::~TileStorage() +{ + Reset(); +} +void TileStorage::Reset() +{ + for (std::map::iterator it = m_tiles.begin(); it != m_tiles.end(); it++) { + if (m_tiles_compressed.find((*it).first) != m_tiles_compressed.end()) { + delete[] m_tiles_compressed[(*it).first]; + } + delete[](*it).second; + } + m_tiles.clear(); + m_lasttiles.clear(); + m_tiles_compressed.clear(); +} + +uint64_t TileStorage::AddTile(uint8_t* data) +{ + uint64_t checksum = tilechecksum(data); + if (m_tiles.find(checksum) != m_tiles.end()) { + std::cerr << "Duplicate tile detected, dropping!" << std::endl; + return checksum; + } + uint8_t* data_copy = new uint8_t[32 * 32 * 4]; + memcpy(data_copy, data, 32 * 32 * 4); + m_tiles.insert(std::pair(checksum, data_copy)); + m_lasttiles.push_back(checksum); + if (m_lasttiles.size() > m_dictcount) + m_lasttiles.pop_front(); + return checksum; +} +void TileStorage::CompressAll() +{ + for (std::map::iterator it = m_tiles.begin(); it != m_tiles.end(); it++) { + if (m_tiles_compressed.find((*it).first) == m_tiles_compressed.end()) { + CompressTile((*it).first); + } + } +} +void TileStorage::SetDictSize(uint32_t s) +{ + m_dictcount = s; +} + +void TileStorage::CompressTile(uint64_t uid) +{ + uint8_t* m0; + uint8_t* m1; + uint8_t* m2; + uint8_t* m3; + uint8_t* dataptr = m_tiles[uid]; + uint8_t* compressedmipmaps = new uint8_t[680]; + if (!dataptr) { + delete[] compressedmipmaps; + throw InvalidTileDataPointerException(); + } + uint32_t s; + uint32_t s2 = 0; + ILuint mip1 = ilGenImage(); + ilBindImage(mip1); + ilTexImage(32, 32, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, dataptr); + /*std::stringstream ss; + ss << "Tile" << uid << ".png"; + ilSaveImage(ss.str().c_str());*/ + m0 = ilCompressDXT(ilGetData(), 32, 32, 1, IL_DXT1, &s); + memcpy(&compressedmipmaps[s2], m0, s); + s2 += s; + iluScale(16, 16, 1); + m1 = ilCompressDXT(ilGetData(), 16, 16, 1, IL_DXT1, &s); + memcpy(&compressedmipmaps[s2], m1, s); + s2 += s; + iluScale(8, 8, 1); + m2 = ilCompressDXT(ilGetData(), 8, 8, 1, IL_DXT1, &s); + memcpy(&compressedmipmaps[s2], m2, s); + s2 += s; + iluScale(4, 4, 1); + m3 = ilCompressDXT(ilGetData(), 4, 4, 1, IL_DXT1, &s); + memcpy(&compressedmipmaps[s2], m3, s); + s2 += s; + ilDeleteImage(mip1); + + /*squish::CompressImage(dataptr,32,32,m0,squish::kDxt1); + squish::CompressImage(dataptr,16,16,m1,squish::kDxt1); + squish::CompressImage(dataptr,8,8,m2,squish::kDxt1); + squish::CompressImage(dataptr,4,4,m3,squish::kDxt1);*/ + + + free(m0); + free(m1); + free(m2); + free(m3); + + m_tiles_compressed[uid] = compressedmipmaps; + //std::cout << "Tile " << uid << " compressed!" << std::endl; +} + +void TileStorage::WriteToFile(FILE* f, std::vector& tile_order) +{ + char magic[16]; + strcpy(magic, "spring tilefile"); + int version = 1; + int numtiles = m_tiles_compressed.size(); + int tileSize = 32; + int compressionType = 1; + fwrite(magic, 16, 1, f); + fwrite(&version, 4, 1, f); + fwrite(&numtiles, 4, 1, f); + fwrite(&tileSize, 4, 1, f); + fwrite(&compressionType, 4, 1, f); + for (std::vector::const_iterator it = tile_order.begin(); it != tile_order.end(); it++) { + if (m_tiles_compressed.find(*it) == m_tiles_compressed.end()) { + CompressAll(); + } + if (m_tiles_compressed.find(*it) == m_tiles_compressed.end()) { + throw InvalidTileIndexException(); + } + fwrite(m_tiles_compressed[*it], 680, 1, f); + } + fflush(f); +} +uint64_t TileStorage::AddTileOrGetSimiliar(uint8_t* data, float th, int compresslevel) +{ + uint64_t checksum = tilechecksum(data); + if (m_tiles.find(checksum) != m_tiles.end()) { + //std::cout << "Debug(AddTileOrGetSimiliar): " << checksum << " already exists" << std::endl; + return checksum; + } + if (compresslevel == COMPRESS_INSANE) { + for (std::map::iterator it = m_tiles.begin(); it != m_tiles.end(); it++) { + if (tilediff(data, (*it).second) < th) { + return (*it).first; + } + } + } else if (compresslevel == COMPRESS_REASONABLE) { + for (std::list::iterator it = m_lasttiles.begin(); it != m_lasttiles.end(); it++) { + if (tilediff(data, m_tiles[(*it)]) < th) { + return (*it); + } + } + + + } else if (compresslevel == COMPRESS_SHITTY) { + //do nothing... + + } else if (compresslevel == COMPRESS_REASONABLE_BESTQUALITY) { + float mindiff = 9999999.0f; + uint64_t besttile = 0; + for (std::list::iterator it = m_lasttiles.begin(); it != m_lasttiles.end(); it++) { + float diff = tilediff(data, m_tiles[(*it)]); + if (diff < mindiff) { + besttile = (*it); + mindiff = diff; + } + } + if (mindiff <= th) + return besttile; + } + return AddTile(data); +} +uint32_t TileStorage::GetTileCount() +{ + return std::max(m_tiles_compressed.size(), m_tiles.size()); +} diff --git a/src/TileStorage.h b/src/TileStorage.h new file mode 100644 index 0000000..5d0c4e5 --- /dev/null +++ b/src/TileStorage.h @@ -0,0 +1,47 @@ +/* This file is part of SpringMapConvNG (GPL v2 or later), see the LICENSE file */ + +#ifndef TILESTORAGE_H +#define TILESTORAGE_H +#include +#include +#include +#include +#include + +class InvalidTileIndexException +{ +}; +class InvalidTileDataPointerException +{ +}; +enum CompressLevels { + COMPRESS_SHITTY = 1, + COMPRESS_REASONABLE = 2, + COMPRESS_INSANE = 3, + COMPRESS_REASONABLE_BESTQUALITY = 4 + + +}; +class TileStorage +{ + +public: + TileStorage(); + virtual ~TileStorage(); + uint64_t AddTile(uint8_t* data); // 32x32 RGBA + void WriteToFile(FILE* f, std::vector& tile_order); + uint64_t AddTileOrGetSimiliar(uint8_t* data, float th, int compresslevel); + uint32_t GetTileCount(); + void SetDictSize(uint32_t s); + void Reset(); + +private: + void CompressAll(); + void CompressTile(uint64_t uid); + std::map m_tiles; + std::map m_tiles_compressed; + std::list m_lasttiles; + unsigned int m_dictcount; +}; + +#endif // TILESTORAGE_H diff --git a/src/mapcompile.cpp b/src/mapcompile.cpp new file mode 100644 index 0000000..21196fb --- /dev/null +++ b/src/mapcompile.cpp @@ -0,0 +1,215 @@ +/* This file is part of SpringMapConvNG (GPL v2 or later), see the LICENSE file */ + +#include "SMFMap.h" +#include "TileStorage.h" +#include +#include +#include + +#include +void help(char** argv) +{ + std::cout << "Usage: " << argv[0] << " -t [maintexture] -m [metalmap] -z [typemap] -h [heightmap] -maxh [white height value] -minh [black height value] -o [outputsuffix] -minimap [minimap_image]" << std::endl; + std::cout << " -ct [compression_type] -ccount [compare_tilecount] -th [compression_level] -features [featurefile]" << std::endl; + std::cout << " -noclamp disables heightmap clamping to max - min values , you should avoid using that , cause you lose precision, if you want less high landscape use maxh and minh" << std::endl; + std::cout << "Compression types:\n\t1: No compression \n\t2: Fast compression , compare tile with last -ccount tiles , take first which difference is below -th\n\t3: Insane Compression: compare each tile with whole map , it is very SLOW, not recomended\n\t4: High quality Fast compression: Slightly slower than 2 , it searchs for less different tile in last -ccount tiles" << std::endl; + std::cout << "Feature file: Each line is a feature instance and has the fields in the following order [tdfname] [xpos] [ypos] [zpos] [rotation yaxis] , please do not leave whitespaces at the end or it\n will give errors." << std::endl; + std::cout << "If you specify less than -490000 as ypos , it will calculate ypos depending on terrain height" << std::endl; +} + +int main(int argc, char** argv) +{ + ilInit(); + if (argc == 1) { + + help(argv); + return 1; + } else { + bool valid2 = false; + bool valid1 = false; + std::string outputname; + std::string texture; + std::string minimap; + std::string metalmap; + std::string typemap; + std::string heightmap; + std::string vegmap; + std::string featurefile; + bool smooth = false; + int tcount = 64; + float minh = 0.0f; + bool clamping = true; + float maxh = 1.0f; + int ct = COMPRESS_REASONABLE; + float th = 0.8; + for (int i = 1; i < argc; i++) { + if (strlen(argv[i]) > 1) { + if (argv[i][0] == '-') { + if (strcmp(&argv[i][1], "t") == 0) { + valid1 = true; + if (i + 1 < argc) { + texture = argv[++i]; + } else { + goto error; + } + } else if (strcmp(&argv[i][1], "m") == 0) //Metal + { + if (i + 1 < argc) { + metalmap = argv[++i]; + } else { + goto error; + } + + } else if (strcmp(&argv[i][1], "z") == 0) //Type + { + if (i + 1 < argc) { + typemap = argv[++i]; + } else { + goto error; + } + + } else if (strcmp(&argv[i][1], "h") == 0) //Height + { + if (i + 1 < argc) { + heightmap = argv[++i]; + } else { + goto error; + } + + } else if (strcmp(&argv[i][1], "maxh") == 0) //Max Height + { + if (i + 1 < argc) { + maxh = atof(argv[++i]); + } else { + goto error; + } + + } else if (strcmp(&argv[i][1], "minh") == 0) //Min Height + { + if (i + 1 < argc) { + minh = atof(argv[++i]); + } else { + goto error; + } + + } else if (strcmp(&argv[i][1], "o") == 0) //Output name + { + if (i + 1 < argc) { + outputname = argv[++i]; + } else { + goto error; + } + valid2 = true; + + } else if (strcmp(&argv[i][1], "minimap") == 0) //Minimap + { + if (i + 1 < argc) { + minimap = argv[++i]; + } else { + goto error; + } + + } else if (strcmp(&argv[i][1], "th") == 0) //Compression level + { + if (i + 1 < argc) { + th = atof(argv[++i]); + } else { + goto error; + } + + } else if (strcmp(&argv[i][1], "ct") == 0) //Compression mode + { + if (i + 1 < argc) { + ct = atoi(argv[++i]); + } else { + goto error; + } + + } else if (strcmp(&argv[i][1], "ccount") == 0) //Compression , count of tiles to comapre in mode 2 and 4 + { + if (i + 1 < argc) { + tcount = atoi(argv[++i]); + } else { + goto error; + } + + } else if (strcmp(&argv[i][1], "v") == 0) //Vegetation map + { + if (i + 1 < argc) { + vegmap = argv[++i]; + } else { + goto error; + } + + } else if (strcmp(&argv[i][1], "noclamp") == 0) //No heightmap clamp + { + clamping = false; + + } else if (strcmp(&argv[i][1], "features") == 0) //features file + { + + if (i + 1 < argc) { + featurefile = argv[++i]; + } else { + goto error; + } + + } else if (strcmp(&argv[i][1], "smooth") == 0) //Smooth + { + smooth = true; + + } else if (strncmp(&argv[i][1], "h", 1) == 0) //Help + { + goto error; + } + } + } + } + + if (valid1 && valid2) + goto success; + error: + help(argv); + return 1; + success: + SMFMap* m = new SMFMap(outputname, texture); + m->SetBlur(smooth); + if (heightmap.length() > 0) + m->SetHeightMap(heightmap); + if (metalmap.length() > 0) + m->SetMetalMap(metalmap); + if (typemap.length() > 0) + m->SetTypeMap(typemap); + if (minimap.length() > 0) + m->SetMiniMap(minimap); + if (vegmap.length() > 0) + m->SetVegetationMap(vegmap); + m->SetCompareTileCount(tcount); + m->SetHeightRange(minh, maxh); + m->SetCompressionTol(th); + m->SetCompressionType(ct); + m->SetClamping(clamping); + if (featurefile.length() > 0) { + FILE* ff = fopen(featurefile.c_str(), "r"); + if (!ff) { + std::cerr << "Cannot open feature file for reading!" << std::endl; + return 1; + } + char line[512]; + while (fgets(line, 511, ff)) { + float x, y, z, o; + char name[512]; + if (strlen(line) < 1) + continue; + if (sscanf(line, "%s %f %f %f %f", name, &x, &y, &z, &o) != 5) { + std::cerr << "Parse error @ '" << line << "'" << std::endl; + return 1; + } + m->AddFeature(name, x, y, z, o); + } + fclose(ff); + } + m->Compile(); + delete m; + } +} diff --git a/src/mapdecompile.cpp b/src/mapdecompile.cpp new file mode 100644 index 0000000..71b99c5 --- /dev/null +++ b/src/mapdecompile.cpp @@ -0,0 +1,76 @@ +/* This file is part of SpringMapConvNG (GPL v2 or later), see the LICENSE file */ + +#include "SMFMap.h" +#include +#include +#include + +#include +#ifdef WIN32 +#include +#include +#include +#else +#include +#endif +void help(char** argv) +{ + std::cout << "Usage: " << argv[0] << " -directory [directory where .smt files are] -mapfile [name of the smf file , NOT path ]" << std::endl; +} +int main(int argc, char** argv) +{ + ilInit(); + if (argc == 1) { + + help(argv); + return 1; + } else { + std::string mapdirectory; + std::string mapfile; + bool valid1 = false, valid2 = false; + for (int i = 1; i < argc; i++) { + if (strlen(argv[i]) > 1) { + if (argv[i][0] == '-') { + if (strcmp(&argv[i][1], "directory") == 0) { + valid1 = true; + if (i + 1 < argc) { + mapdirectory = argv[++i]; + } else { + goto error; + } + } else if (strcmp(&argv[i][1], "mapfile") == 0) { + if (i + 1 < argc) { + mapfile = argv[++i]; + } else { + goto error; + } + valid2 = true; + + } else if (strncmp(&argv[i][1], "h", 1) == 0) //Help + { + goto error; + } + } + } + } + + if (valid1 && valid2) + goto success; + error: + help(argv); + return 1; + success: +#ifndef WIN32 + if (chdir(mapdirectory.c_str())) +#else + if (_chdir(mapdirectory.c_str())) +#endif + { + std::cerr << "Cannot change working directory to " << mapdirectory << std::endl; + return 1; + } + SMFMap* m = new SMFMap(mapfile); + m->SaveSourceFiles(); + delete m; + } +}