├── .gitignore ├── .gitmodules ├── AUTHORS ├── ChangeLog ├── Makefile.am ├── NEWS ├── README ├── autogen.sh ├── configure.ac ├── license.txt └── src ├── dlditool └── dlditool.c ├── nds_texcompress ├── compress_texture.cpp ├── compress_texture.h ├── image.h └── nds_texcompress.cpp └── r4denc └── r4denc.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | COPYING 2 | INSTALL 3 | Makefile 4 | Makefile.in 5 | aclocal.m4 6 | autom4te.cache 7 | config.guess 8 | config.sub 9 | config.log 10 | config.status 11 | configure 12 | depcomp 13 | install-sh 14 | missing 15 | .deps 16 | *.exe 17 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/dslink"] 2 | path = src/dslink 3 | url = git@github.com:devkitPro/dslink-host.git 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devkitPro/dstools/807da5d15033790f9cd15b7cc1172a79cb5ac4bc/AUTHORS -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devkitPro/dstools/807da5d15033790f9cd15b7cc1172a79cb5ac4bc/ChangeLog -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Makefile.am -- Process this file with automake to produce Makefile.in 2 | 3 | bin_PROGRAMS = r4denc dlditool dslink nds_texcompress 4 | 5 | r4denc_SOURCES = src/r4denc/r4denc.cpp 6 | 7 | dlditool_SOURCES = src/dlditool/dlditool.c 8 | 9 | dslink_SOURCES = src/dslink/little.h src/dslink/ndsheader.h src/dslink/main.cpp 10 | 11 | nds_texcompress_SOURCES = src/nds_texcompress/nds_texcompress.cpp src/nds_texcompress/image.h \ 12 | src/nds_texcompress/compress_texture.cpp src/nds_texcompress/compress_texture.h 13 | 14 | nds_texcompress_LDADD = $(FREEIMAGE_LIBS) 15 | 16 | EXTRA_DIST = autogen.sh 17 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devkitPro/dstools/807da5d15033790f9cd15b7cc1172a79cb5ac4bc/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devkitPro/dstools/807da5d15033790f9cd15b7cc1172a79cb5ac4bc/README -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | aclocal 2 | autoconf 3 | automake --add-missing -c 4 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ(2.61) 5 | AC_INIT([dstools],[1.3.3],[https://github.com/devkitPro/dstools/issues]) 6 | AC_CONFIG_SRCDIR([src/r4denc/r4denc.cpp]) 7 | AM_INIT_AUTOMAKE([subdir-objects]) 8 | 9 | AC_CANONICAL_BUILD 10 | AC_CANONICAL_HOST 11 | 12 | AC_PROG_CC 13 | AC_PROG_CXX 14 | 15 | case "$host" in 16 | *-*-mingw*) 17 | LIBS="$LIBS -lws2_32" 18 | ;; 19 | 20 | esac 21 | 22 | case "$host" in 23 | x86_64-apple-darwin* | aarch64-apple-darwin* ) 24 | STDCPP_LIBS="-lc++" 25 | ;; 26 | 27 | *) 28 | STDCPP_LIBS="-lstdc++" 29 | ;; 30 | 31 | esac 32 | 33 | AC_CHECK_HEADER([FreeImage.h]) 34 | 35 | AC_MSG_CHECKING([for libfreeimage]) 36 | save_LIBS="$LIBS" 37 | LIBS="-lfreeimage ${LIBS} ${STDCPP_LIBS} -lm" 38 | AC_LINK_IFELSE( 39 | [AC_LANG_PROGRAM([[#include ]], 40 | [[FreeImage_DeInitialise()]])], 41 | [freeimage_result=yes], 42 | [freeimage_result=no]) 43 | AC_MSG_RESULT([$freeimage_result]) 44 | LIBS="$save_LIBS" 45 | if test "x$freeimage_result" = "xyes"; then 46 | FREEIMAGE_LIBS="-lfreeimage ${STDCPP_LIBS} -lm" 47 | else 48 | AC_MSG_ERROR(['libfreeimage' not found]) 49 | fi 50 | 51 | AC_SUBST([FREEIMAGE_LIBS], [${FREEIMAGE_LIBS}]) 52 | 53 | 54 | AC_CONFIG_FILES([Makefile]) 55 | AC_OUTPUT 56 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /src/dlditool/dlditool.c: -------------------------------------------------------------------------------- 1 | /* 2 | dlditool - Dynamically Linked Disk Interface patch tool 3 | Copyright (C) 2006 Michael Chisholm (Chishm) 4 | 5 | Send all queries to chishm@hotmail.com 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License along 18 | with this program; if not, write to the Free Software Foundation, Inc., 19 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | 21 | * v1.25 - 2017-01-18 - ichfly 22 | * Made not enough space for patch a warning 23 | 24 | * v1.24 - 2007-08-02 - SmileyDude 25 | * Now using EXIT_SUCCESS and EXIT_FAILURE at the suggestion of MachinShin. 26 | * Defined EXIT_NO_DLDI_SECTION for when there is no DLDI section in a file. 27 | * Added cast to strcmp() call to appease the compiler. 28 | 29 | * v1.23 - 2007-01-23 - Chishm 30 | * Fixed bug when DLDI section doesn't exist 31 | * addr_t is now a signed int 32 | 33 | * v1.22 - 2007-01-12 - WinterMute 34 | * add search paths for dldi files 35 | 36 | * v1.21 - 2007-01-12 - Chishm 37 | * Improved error messages 38 | 39 | * v1.20 - 2007-01-11 - Chishm 40 | * Changed offset calculation method 41 | 42 | * v1.10 - 2007-01-07 - Chishm 43 | * Removed assumptions about endianess of computer 44 | * Word size shouldn't matter now either, except that an int type must be at least 32 bits long 45 | * Added *.sc.nds and *.gba.nds file extensions 46 | * Improved command line argument parsing 47 | 48 | * v1.01 - 2006-12-30 - Chishm 49 | * Minor bugfix parsing 3 arguments 50 | 51 | * v1.00 - 2006-12-25 - Chishm 52 | * Original release 53 | */ 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | 62 | #define DLDITOOL_VERSION "1.25" 63 | 64 | #ifndef _MSC_VER 65 | #include 66 | #include 67 | #else 68 | #define MAXPATHLEN 1024 69 | #endif 70 | 71 | #include 72 | 73 | #ifndef bool 74 | typedef enum {false = 0, true = !0} bool; 75 | #endif 76 | 77 | typedef int32_t addr_t; 78 | typedef unsigned char data_t; 79 | 80 | #define FEATURE_MEDIUM_CANREAD 0x00000001 81 | #define FEATURE_MEDIUM_CANWRITE 0x00000002 82 | #define FEATURE_SLOT_GBA 0x00000010 83 | #define FEATURE_SLOT_NDS 0x00000020 84 | 85 | #define MAGIC_TOKEN 0xBF8DA5ED 86 | 87 | #define FIX_ALL 0x01 88 | #define FIX_GLUE 0x02 89 | #define FIX_GOT 0x04 90 | #define FIX_BSS 0x08 91 | 92 | #define DLDI_VERSION 1 93 | 94 | #define EXIT_NO_DLDI_SECTION 2 95 | 96 | enum DldiOffsets { 97 | DO_magicString = 0x00, // "\xED\xA5\x8D\xBF Chishm" 98 | DO_magicToken = 0x00, // 0xBF8DA5ED 99 | DO_magicShortString = 0x04, // " Chishm" 100 | DO_version = 0x0C, 101 | DO_driverSize = 0x0D, 102 | DO_fixSections = 0x0E, 103 | DO_allocatedSpace = 0x0F, 104 | 105 | DO_friendlyName = 0x10, 106 | 107 | DO_text_start = 0x40, // Data start 108 | DO_data_end = 0x44, // Data end 109 | DO_glue_start = 0x48, // Interworking glue start -- Needs address fixing 110 | DO_glue_end = 0x4C, // Interworking glue end 111 | DO_got_start = 0x50, // GOT start -- Needs address fixing 112 | DO_got_end = 0x54, // GOT end 113 | DO_bss_start = 0x58, // bss start -- Needs setting to zero 114 | DO_bss_end = 0x5C, // bss end 115 | 116 | // IO_INTERFACE data 117 | DO_ioType = 0x60, 118 | DO_features = 0x64, 119 | DO_startup = 0x68, 120 | DO_isInserted = 0x6C, 121 | DO_readSectors = 0x70, 122 | DO_writeSectors = 0x74, 123 | DO_clearStatus = 0x78, 124 | DO_shutdown = 0x7C, 125 | DO_code = 0x80 126 | }; 127 | 128 | const data_t dldiMagicString[] = "\xED\xA5\x8D\xBF Chishm"; 129 | const char dldiFileExtension[] = ".dldi"; 130 | 131 | 132 | void printUsage (char* programName) { 133 | printf ("Usage:\n"); 134 | printf ("%s \n", programName); 135 | printf (" the dldi patch file to apply\n"); 136 | printf (" the application binary to apply the patch to\n"); 137 | return; 138 | } 139 | 140 | addr_t readAddr (data_t *mem, addr_t offset) { 141 | return (addr_t)( 142 | (mem[offset + 0] << 0) | 143 | (mem[offset + 1] << 8) | 144 | (mem[offset + 2] << 16) | 145 | (mem[offset + 3] << 24) 146 | ); 147 | } 148 | 149 | void writeAddr (data_t *mem, addr_t offset, addr_t value) { 150 | mem[offset + 0] = (data_t)(value >> 0); 151 | mem[offset + 1] = (data_t)(value >> 8); 152 | mem[offset + 2] = (data_t)(value >> 16); 153 | mem[offset + 3] = (data_t)(value >> 24); 154 | } 155 | 156 | int stringCaseInsensitiveCompare (const char *str1, const char *str2) { 157 | while (tolower(*str1) == tolower(*str2)) { 158 | if (*str1 == '\0') { 159 | return 0; 160 | } 161 | str1++; 162 | str2++; 163 | } 164 | return (tolower(*str1) - tolower(*str2)); 165 | } 166 | 167 | bool stringEndsWith (const char *str, const char *end) { 168 | const char* strEnd; 169 | if (strlen (str) < strlen(end)) { 170 | return false; 171 | } 172 | strEnd = &str[strlen (str) - strlen(end)]; 173 | return (stringCaseInsensitiveCompare (strEnd, end) == 0); 174 | } 175 | 176 | bool stringStartsWith (const char *str, const char *start) { 177 | return (strstr (str, start) == str); 178 | } 179 | 180 | addr_t quickFind (const data_t* data, const data_t* search, size_t dataLen, size_t searchLen) { 181 | const int32_t* dataChunk = (const int32_t*) data; 182 | int searchChunk = ((const int32_t*)search)[0]; 183 | addr_t i; 184 | addr_t dataChunkEnd = (addr_t)(dataLen / sizeof(int32_t)); 185 | 186 | for ( i = 0; i < dataChunkEnd; i++) { 187 | if (dataChunk[i] == searchChunk) { 188 | if ((i*sizeof(int32_t) + searchLen) > dataLen) { 189 | return -1; 190 | } 191 | if (memcmp (&data[i*sizeof(int32_t)], search, searchLen) == 0) { 192 | return i*sizeof(int32_t); 193 | } 194 | } 195 | } 196 | 197 | return -1; 198 | } 199 | 200 | FILE *openDLDIFile(const char *argv0, char *dldiFileName ) { 201 | 202 | 203 | FILE *dldiFile; 204 | char *dldiPATH; 205 | char appPath[MAXPATHLEN]; 206 | char appName[MAXPATHLEN]; 207 | char appPathName[MAXPATHLEN]; 208 | 209 | char *ptr, *lastSlash; 210 | struct stat buf; 211 | 212 | // add .dldi extension to filename 213 | if (!stringEndsWith (dldiFileName, dldiFileExtension)) { 214 | strcat (dldiFileName, dldiFileExtension); 215 | } 216 | 217 | printf ("Trying \"%s\"\n", dldiFileName); 218 | // try opening from current directory 219 | dldiFile = fopen(dldiFileName,"rb"); 220 | 221 | if ( NULL != dldiFile ) return dldiFile; 222 | 223 | // check if the filename has a path component 224 | // check both slash varieties, win32 understands both 225 | // if we have a directory separator don't bother with search paths 226 | if ( NULL != strstr(dldiFileName,"\\") ) return NULL; 227 | if ( NULL != strstr(dldiFileName,"/") ) return NULL; 228 | 229 | // check for DLDIPATH in environment 230 | dldiPATH = getenv("DLDIPATH"); 231 | 232 | 233 | if ( NULL != dldiPATH ) { 234 | strcpy(appPath,dldiPATH); 235 | if ( appPath[strlen(appPath)] != '\\' && appPath[strlen(appPath)] != '/' ) 236 | strcat(appPath,"/"); 237 | strcat ( appPath, dldiFileName ); 238 | 239 | printf ("Trying \"%s\"\n", appPath); 240 | dldiFile = fopen(appPath,"rb"); 241 | 242 | if ( NULL != dldiFile ) return dldiFile; 243 | 244 | } 245 | 246 | 247 | lastSlash = NULL; 248 | ptr = (char *)argv0; 249 | 250 | while ( *(ptr++) != 0 ) { 251 | if ( *ptr == '\\' || * ptr == '/' ) 252 | lastSlash = ptr; 253 | } 254 | 255 | if ( NULL != lastSlash ) { 256 | *(lastSlash++) = '\0'; 257 | strcpy(appPath, argv0); 258 | strcpy(appName, lastSlash); 259 | strcat(appPath, "/"); 260 | } else { 261 | strcpy(appPath, ""); 262 | strcpy(appName, argv0); 263 | } 264 | 265 | 266 | // finally try in the application path 267 | // if argv0 contains a directory separator we have a path component 268 | 269 | if ( NULL == strstr(appPath,"\\") && NULL == strstr(appPath,"/") ) { 270 | 271 | // no path in argv0 so search system path 272 | char *sysPATH = getenv("PATH"); 273 | char *nextPATH; 274 | char *thisPATH = sysPATH; 275 | printf("Searching system path\n%s\n",sysPATH); 276 | 277 | while(1) { 278 | nextPATH = strstr(thisPATH, ":" ); // find next PATH separator 279 | 280 | if ( NULL != nextPATH ) 281 | *(nextPATH++) = '\0'; // terminate string, point to next component 282 | 283 | strcpy(appPath,thisPATH); 284 | strcat(appPath,"/"); 285 | strcpy(appPathName,appPath); 286 | strcat(appPathName,appName); // add application name 287 | 288 | if ( stat(appPathName,&buf) == 0 ) // if it exists we found the path 289 | break; 290 | 291 | thisPATH = nextPATH; 292 | strcpy(appPath,""); // empty path 293 | if ( thisPATH == NULL) break; 294 | } 295 | } 296 | 297 | strcat(appPath,"dldi/"); // add dldi folder 298 | strcat(appPath,dldiFileName); // add dldi filename to path 299 | printf ("Trying \"%s\"\n", appPath); 300 | 301 | return fopen(appPath,"rb"); // no more places to check, just return this handle 302 | } 303 | 304 | int main(int argc, char* argv[]) 305 | { 306 | 307 | char *dldiFileName = NULL; 308 | char *appFileName = NULL; 309 | 310 | addr_t memOffset; // Offset of DLDI after the file is loaded into memory 311 | addr_t patchOffset; // Position of patch destination in the file 312 | addr_t relocationOffset; // Value added to all offsets within the patch to fix it properly 313 | addr_t ddmemOffset; // Original offset used in the DLDI file 314 | addr_t ddmemStart; // Start of range that offsets can be in the DLDI file 315 | addr_t ddmemEnd; // End of range that offsets can be in the DLDI file 316 | addr_t ddmemSize; // Size of range that offsets can be in the DLDI file 317 | 318 | addr_t addrIter; 319 | 320 | FILE* dldiFile; 321 | FILE* appFile; 322 | 323 | data_t *pDH; 324 | data_t *pAH; 325 | 326 | data_t *appFileData = NULL; 327 | size_t appFileSize = 0; 328 | data_t *dldiFileData = NULL; 329 | size_t dldiFileSize = 0; 330 | 331 | int i; 332 | 333 | printf ("Dynamically Linked Disk Interface patch tool " DLDITOOL_VERSION " by Michael Chisholm (Chishm)\n\n"); 334 | 335 | for (i = 1; i < argc; i++) { 336 | if (dldiFileName == NULL) { 337 | dldiFileName = (char*) malloc (strlen (argv[i]) + 1 + sizeof(dldiFileExtension)); 338 | if (!dldiFileName) { 339 | return EXIT_FAILURE; 340 | } 341 | strcpy (dldiFileName, argv[i]); 342 | } else if (appFileName == NULL) { 343 | appFileName = (char*) malloc (strlen (argv[i]) + 1); 344 | if (!appFileName) { 345 | return EXIT_FAILURE; 346 | } 347 | strcpy (appFileName, argv[i]); 348 | } else { 349 | printUsage (argv[0]); 350 | return EXIT_FAILURE; 351 | } 352 | } 353 | 354 | if ((dldiFileName == NULL) || (appFileName == NULL)) { 355 | printUsage (argv[0]); 356 | return EXIT_FAILURE; 357 | } 358 | 359 | if (!(dldiFile = openDLDIFile(argv[0],dldiFileName))) { 360 | printf ("Cannot open \"%s\" - %s\n", dldiFileName, strerror(errno)); 361 | return EXIT_FAILURE; 362 | } 363 | 364 | if (!(appFile = fopen (appFileName, "rb+"))) { 365 | printf ("Cannot open \"%s\" - %s\n", appFileName, strerror(errno)); 366 | return EXIT_FAILURE; 367 | } 368 | 369 | // Load the app file and the DLDI patch file 370 | fseek (appFile, 0, SEEK_END); 371 | appFileSize = ftell(appFile); 372 | appFileData = (data_t*) malloc (appFileSize); 373 | fseek (appFile, 0, SEEK_SET); 374 | 375 | fseek (dldiFile, 0, SEEK_END); 376 | dldiFileSize = ftell(dldiFile); 377 | dldiFileData = (data_t*) malloc (dldiFileSize); 378 | fseek (dldiFile, 0, SEEK_SET); 379 | 380 | if (!appFileData || !dldiFileData) { 381 | fclose (appFile); 382 | fclose (dldiFile); 383 | if (appFileData) free (appFileData); 384 | if (dldiFileData) free (dldiFileData); 385 | printf ("Out of memory\n"); 386 | return EXIT_FAILURE; 387 | } 388 | 389 | fread (appFileData, 1, appFileSize, appFile); 390 | fread (dldiFileData, 1, dldiFileSize, dldiFile); 391 | fclose (dldiFile); 392 | 393 | // Find the DSDI reserved space in the file 394 | patchOffset = quickFind (appFileData, dldiMagicString, appFileSize, sizeof(dldiMagicString)/sizeof(char)); 395 | 396 | if (patchOffset < 0) { 397 | printf ("%s does not have a DLDI section\n", appFileName); 398 | return EXIT_NO_DLDI_SECTION; 399 | } 400 | 401 | pDH = dldiFileData; 402 | pAH = &appFileData[patchOffset]; 403 | 404 | // Make sure the DLDI file is valid and usable 405 | if (strcmp ((char*)dldiMagicString, (char*)&pDH[DO_magicString]) != 0) { 406 | printf ("Invalid DLDI file\n"); 407 | return EXIT_FAILURE; 408 | } 409 | if (pDH[DO_version] != DLDI_VERSION) { 410 | printf ("Incorrect DLDI file version. Expected %d, found %d.\n", DLDI_VERSION, pDH[DO_version]); 411 | return EXIT_FAILURE; 412 | } 413 | if (pDH[DO_driverSize] > pAH[DO_allocatedSpace]) { 414 | printf ("Warning: Not enough space for patch. Available %d bytes, need %d bytes\n", ( 1 << pAH[DO_allocatedSpace]), ( 1 << pDH[DO_driverSize]) ); 415 | //return EXIT_FAILURE; 416 | } 417 | 418 | memOffset = readAddr (pAH, DO_text_start); 419 | if (memOffset == 0) { 420 | memOffset = readAddr (pAH, DO_startup) - DO_code; 421 | } 422 | ddmemOffset = readAddr (pDH, DO_text_start); 423 | relocationOffset = memOffset - ddmemOffset; 424 | 425 | printf ("Old driver: %s\n", &pAH[DO_friendlyName]); 426 | printf ("New driver: %s\n", &pDH[DO_friendlyName]); 427 | printf ("\n"); 428 | printf ("Position in file: 0x%08X\n", patchOffset); 429 | printf ("Position in memory: 0x%08X\n", memOffset); 430 | printf ("Patch base address: 0x%08X\n", ddmemOffset); 431 | printf ("Relocation offset: 0x%08X\n", relocationOffset); 432 | printf ("\n"); 433 | 434 | ddmemStart = readAddr (pDH, DO_text_start); 435 | ddmemSize = (1 << pDH[DO_driverSize]); 436 | ddmemEnd = ddmemStart + ddmemSize; 437 | 438 | // Remember how much space is actually reserved 439 | pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace]; 440 | // Copy the DLDI patch into the application 441 | memcpy (pAH, pDH, dldiFileSize); 442 | 443 | // Fix the section pointers in the header 444 | writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset); 445 | writeAddr (pAH, DO_data_end, readAddr (pAH, DO_data_end) + relocationOffset); 446 | writeAddr (pAH, DO_glue_start, readAddr (pAH, DO_glue_start) + relocationOffset); 447 | writeAddr (pAH, DO_glue_end, readAddr (pAH, DO_glue_end) + relocationOffset); 448 | writeAddr (pAH, DO_got_start, readAddr (pAH, DO_got_start) + relocationOffset); 449 | writeAddr (pAH, DO_got_end, readAddr (pAH, DO_got_end) + relocationOffset); 450 | writeAddr (pAH, DO_bss_start, readAddr (pAH, DO_bss_start) + relocationOffset); 451 | writeAddr (pAH, DO_bss_end, readAddr (pAH, DO_bss_end) + relocationOffset); 452 | // Fix the function pointers in the header 453 | writeAddr (pAH, DO_startup, readAddr (pAH, DO_startup) + relocationOffset); 454 | writeAddr (pAH, DO_isInserted, readAddr (pAH, DO_isInserted) + relocationOffset); 455 | writeAddr (pAH, DO_readSectors, readAddr (pAH, DO_readSectors) + relocationOffset); 456 | writeAddr (pAH, DO_writeSectors, readAddr (pAH, DO_writeSectors) + relocationOffset); 457 | writeAddr (pAH, DO_clearStatus, readAddr (pAH, DO_clearStatus) + relocationOffset); 458 | writeAddr (pAH, DO_shutdown, readAddr (pAH, DO_shutdown) + relocationOffset); 459 | 460 | if (pDH[DO_fixSections] & FIX_ALL) { 461 | // Search through and fix pointers within the data section of the file 462 | for (addrIter = (readAddr(pDH, DO_text_start) - ddmemStart); addrIter < (readAddr(pDH, DO_data_end) - ddmemStart); addrIter++) { 463 | if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) { 464 | writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); 465 | } 466 | } 467 | } 468 | 469 | if (pDH[DO_fixSections] & FIX_GLUE) { 470 | // Search through and fix pointers within the glue section of the file 471 | for (addrIter = (readAddr(pDH, DO_glue_start) - ddmemStart); addrIter < (readAddr(pDH, DO_glue_end) - ddmemStart); addrIter++) { 472 | if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) { 473 | writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); 474 | } 475 | } 476 | } 477 | 478 | if (pDH[DO_fixSections] & FIX_GOT) { 479 | // Search through and fix pointers within the Global Offset Table section of the file 480 | for (addrIter = (readAddr(pDH, DO_got_start) - ddmemStart); addrIter < (readAddr(pDH, DO_got_end) - ddmemStart); addrIter++) { 481 | if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) { 482 | writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); 483 | } 484 | } 485 | } 486 | 487 | if (pDH[DO_fixSections] & FIX_BSS) { 488 | // Initialise the BSS to 0 489 | memset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); 490 | } 491 | 492 | // Write the patch back to the file 493 | fseek (appFile, patchOffset, SEEK_SET); 494 | fwrite (pAH, 1, ddmemSize, appFile); 495 | fclose (appFile); 496 | 497 | free (appFileData); 498 | free (dldiFileData); 499 | 500 | printf ("Patched successfully\n"); 501 | 502 | return EXIT_SUCCESS; 503 | } 504 | 505 | -------------------------------------------------------------------------------- /src/nds_texcompress/compress_texture.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "image.h" 8 | 9 | FIBITMAP *loadImage(const char *filename) 10 | { 11 | FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(filename); 12 | FIBITMAP *temp = FreeImage_Load(fif, filename); 13 | if (temp == NULL) return (FIBITMAP*)NULL; 14 | 15 | FIBITMAP *temp2 = FreeImage_ConvertTo16Bits555(temp); // quantisize to 555 16 | FreeImage_Unload(temp); 17 | FIBITMAP *dib = FreeImage_ConvertTo24Bits(temp2); // the FI paletter-thingie likes 24 bit 18 | FreeImage_Unload(temp2); 19 | if (dib == NULL) return (FIBITMAP*)NULL; 20 | 21 | FreeImage_FlipVertical(dib); 22 | return dib; 23 | } 24 | 25 | bool saveImage(FIBITMAP * dib, const char *filename) 26 | { 27 | assert(dib != NULL); 28 | FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(filename); 29 | FreeImage_FlipVertical(dib); 30 | return (TRUE == FreeImage_Save(fif, dib, filename)); 31 | } 32 | 33 | // this routine takes advantage of that the palettizer seems to use the low color-indices only 34 | int countUniqueColors(FIBITMAP *dib) 35 | { 36 | assert(dib != NULL); 37 | assert(FIC_PALETTE == FreeImage_GetColorType(dib)); 38 | 39 | unsigned char *bits = FreeImage_GetBits(dib); 40 | int pitch = FreeImage_GetPitch(dib); 41 | int width = FreeImage_GetWidth(dib); 42 | int height = FreeImage_GetHeight(dib); 43 | 44 | int max = 0; 45 | for (int y = 0; y < height; ++y) 46 | { 47 | for (int x = 0; x < width; ++x) 48 | { 49 | if (bits[x] > max) max = bits[x]; 50 | } 51 | bits += pitch; 52 | } 53 | return max + 1; 54 | } 55 | 56 | bool colorEqual(const RGBQUAD &c1, const RGBQUAD &c2, int err) 57 | { 58 | if (abs(c1.rgbRed - c2.rgbRed ) > err) return false; 59 | if (abs(c1.rgbGreen - c2.rgbGreen) > err) return false; 60 | if (abs(c1.rgbBlue - c2.rgbBlue ) > err) return false; 61 | return true; 62 | } 63 | 64 | int colorDiff(const RGBQUAD &c1, const RGBQUAD &c2) 65 | { 66 | int maxDiff = 0; 67 | if (abs(c1.rgbRed - c2.rgbRed ) > maxDiff) maxDiff = abs(c1.rgbRed - c2.rgbRed ); 68 | if (abs(c1.rgbGreen - c2.rgbGreen) > maxDiff) maxDiff = abs(c1.rgbGreen - c2.rgbGreen ); 69 | if (abs(c1.rgbBlue - c2.rgbBlue ) > maxDiff) maxDiff = abs(c1.rgbBlue - c2.rgbBlue); 70 | return maxDiff; 71 | } 72 | 73 | RGBQUAD colorLerp(const RGBQUAD &c1, const RGBQUAD &c2, float t) 74 | { 75 | RGBQUAD result; 76 | result.rgbRed = int(c1.rgbRed * t + c2.rgbRed * (1-t)); 77 | result.rgbGreen = int(c1.rgbGreen * t + c2.rgbGreen * (1-t)); 78 | result.rgbBlue = int(c1.rgbBlue * t + c2.rgbBlue * (1-t)); 79 | return result; 80 | } 81 | 82 | bool compressTexture(const char *filename) 83 | { 84 | FIBITMAP *dib = loadImage(filename); 85 | if (NULL == dib) 86 | { 87 | fprintf(stderr, "failed to load image"); 88 | return false; 89 | } 90 | 91 | const int tileWidth = 4; 92 | const int tileHeight = 4; 93 | const int colorErr = 8; 94 | 95 | Image img(dib); 96 | if (img.getWidth() % tileWidth != 0 || img.getHeight() % tileHeight != 0 ) 97 | { 98 | fprintf(stderr, "width and height must be dividable by 4!"); 99 | return false; 100 | } 101 | 102 | Image decompResult; 103 | decompResult.create(img.getWidth(), img.getHeight(), 24); 104 | 105 | std::vector palette; 106 | std::vector blocks; 107 | std::vector headers; 108 | 109 | RGBQUAD padColor; 110 | padColor.rgbRed = 0; 111 | padColor.rgbGreen = 0; 112 | padColor.rgbBlue = 0; 113 | 114 | int lerpable = 0; 115 | int nonlerpable = 0; 116 | 117 | for (int y = 0; y < img.getHeight(); y += tileHeight) 118 | { 119 | for (int x = 0; x < img.getHeight(); x += tileWidth) 120 | { 121 | RGBQUAD lerpColors[2]; 122 | int colorCount = 4; 123 | Image tile = FreeImage_Copy(img.getFIBitmap(), x, y, x + tileWidth, y + tileHeight); 124 | Image tileQuant = FreeImage_ColorQuantizeEx(tile.getFIBitmap(), FIQ_WUQUANT, colorCount, 0, NULL); 125 | assert(NULL != tileQuant.getFIBitmap()); 126 | 127 | BITMAPINFO *info = FreeImage_GetInfo(tileQuant.getFIBitmap()); 128 | colorCount = countUniqueColors(tileQuant.getFIBitmap()); 129 | int colorPadCount = colorCount; 130 | 131 | // add palette to global palette 132 | RGBQUAD *pal = FreeImage_GetPalette(tileQuant.getFIBitmap()); 133 | 134 | int blockMode = 2; // if all else fails 135 | if (colorCount == 4) 136 | { 137 | if (colorEqual(pal[1], colorLerp(pal[0], pal[3], 0.375), 2*colorErr) && 138 | colorEqual(pal[2], colorLerp(pal[0], pal[3], 0.625), 2*colorErr)) 139 | { 140 | lerpable++; 141 | lerpColors[0] = pal[0]; 142 | lerpColors[1] = pal[3]; 143 | 144 | BYTE a = 1; 145 | BYTE b = 3; 146 | FreeImage_SwapColors(tileQuant.getFIBitmap(), &pal[a], &pal[b], true); 147 | FreeImage_SwapPaletteIndices(tileQuant.getFIBitmap(), &a, &b); 148 | 149 | pal = lerpColors; 150 | colorCount = 2; 151 | blockMode = 3; 152 | 153 | } else nonlerpable++; 154 | } 155 | else if (colorCount == 3) 156 | { 157 | if (colorEqual(pal[1], colorLerp(pal[0], pal[2], 0.5), 2*colorErr)) 158 | { 159 | lerpable++; 160 | lerpColors[0] = pal[0]; 161 | lerpColors[1] = pal[2]; 162 | 163 | BYTE a = 1; 164 | BYTE b = 2; 165 | FreeImage_SwapColors(tileQuant.getFIBitmap(), &pal[a], &pal[b], true); 166 | FreeImage_SwapPaletteIndices(tileQuant.getFIBitmap(), &a, &b); 167 | 168 | pal = lerpColors; 169 | colorCount = colorPadCount = 2; 170 | blockMode = 1; 171 | } 172 | else 173 | { 174 | colorPadCount = 4; // round up, colors are allocated two by two 175 | nonlerpable++; 176 | } 177 | } 178 | else if (colorCount == 1) 179 | { 180 | colorPadCount = 2; // round up, colors are allocated two by two 181 | } 182 | assert((colorPadCount & 1) == 0); 183 | 184 | int base; 185 | int minDiff = INT_MAX; 186 | int minDiffBase = 0; 187 | 188 | for (base = 0; base < int(palette.size()) - (colorCount - 1); base += 2) 189 | { 190 | int currMaxDiff = 0; 191 | for (int i = 0; i < colorCount; ++i) 192 | { 193 | int diff = colorDiff(palette[base + i], pal[i]); 194 | currMaxDiff = std::max(currMaxDiff, diff); 195 | } 196 | 197 | if (currMaxDiff < minDiff) 198 | { 199 | minDiff = currMaxDiff; 200 | minDiffBase = base; 201 | } 202 | } 203 | 204 | if (minDiff < colorErr) base = minDiffBase; 205 | else 206 | { 207 | base = int(palette.size()); 208 | for (int i = 0; i < colorCount; ++i) palette.push_back(pal[i]); 209 | for (int i = colorCount; i < colorPadCount; ++i) palette.push_back(padColor); 210 | } 211 | 212 | unsigned short header = 0; 213 | assert((base & 1) == 0); 214 | header |= (base >> 1) & ((1 << 14) - 1); 215 | header |= blockMode << 14; 216 | headers.push_back(header); 217 | 218 | for (int iy = tileHeight - 1; iy >= 0; --iy) 219 | { 220 | unsigned char row = 0; 221 | for (int ix = 0; ix < tileWidth; ++ix) 222 | { 223 | int val = tileQuant.getPixelIndex(ix, iy); 224 | assert((val & 3) == val); 225 | row |= val << (ix * 2); 226 | } 227 | blocks.push_back(row); 228 | } 229 | 230 | FreeImage_Paste(decompResult.getFIBitmap(), tileQuant.getFIBitmap(), x, y, 255); 231 | } 232 | } 233 | 234 | printf("lerpable pals: %d (%d non)\n", lerpable, nonlerpable); 235 | FIBITMAP *dib2 = FreeImage_ConvertTo24Bits(decompResult.getFIBitmap()); 236 | std::string resultName(filename); 237 | resultName += std::string(".result.png"); 238 | saveImage(dib2, resultName.c_str()); 239 | printf("total colors: %d\n", palette.size()); 240 | FreeImage_Unload(dib2); 241 | 242 | { 243 | std::string outName(filename); 244 | outName += std::string(".tiles.raw"); 245 | FILE *fp = fopen(outName.c_str(), "wb"); 246 | if (NULL == fp) 247 | { 248 | perror("failed to dump tiles"); 249 | return false; 250 | } 251 | 252 | fwrite(&blocks[0], sizeof(blocks[0]), blocks.size(), fp); 253 | fclose(fp); 254 | } 255 | { 256 | std::string outName(filename); 257 | outName += std::string(".headers.raw"); 258 | FILE *fp = fopen(outName.c_str(), "wb"); 259 | if (NULL == fp) 260 | { 261 | perror("failed to dump headers"); 262 | return false; 263 | } 264 | 265 | fwrite(&headers[0], sizeof(headers[0]), headers.size(), fp); 266 | fclose(fp); 267 | } 268 | { 269 | std::string outName(filename); 270 | outName += std::string(".pal"); 271 | FILE *fp = fopen(outName.c_str(), "wb"); 272 | if (NULL == fp) 273 | { 274 | perror("failed to dump headers"); 275 | return false; 276 | } 277 | for (size_t i = 0; i < palette.size(); ++i) 278 | { 279 | RGBQUAD col = palette[i]; 280 | unsigned short col555 = 281 | (col.rgbRed >> 3) | 282 | ((col.rgbGreen >> 3) << 5) | 283 | ((col.rgbBlue >> 3) << 10); 284 | fwrite(&col555, 2, 1, fp); 285 | } 286 | fclose(fp); 287 | } 288 | return true; 289 | } 290 | -------------------------------------------------------------------------------- /src/nds_texcompress/compress_texture.h: -------------------------------------------------------------------------------- 1 | #ifndef COMPRESS_TEXTURE_H 2 | #define COMPRESS_TEXTURE_H 3 | 4 | bool compressTexture(const char *filename); 5 | 6 | #endif /* COMPRESS_TEXTURE_H */ 7 | -------------------------------------------------------------------------------- /src/nds_texcompress/image.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | class Image 7 | { 8 | public: 9 | Image() : dib(NULL) 10 | { 11 | } 12 | 13 | Image(const Image &img) 14 | { 15 | dib = FreeImage_Clone(img.dib); 16 | } 17 | 18 | Image(FIBITMAP *dib) : dib(dib) 19 | { 20 | } 21 | 22 | ~Image() 23 | { 24 | if (dib != NULL) FreeImage_Unload(dib); 25 | } 26 | 27 | bool create(int w, int h, int bpp) 28 | { 29 | dib = FreeImage_Allocate(w, h, bpp); 30 | return (dib != NULL); 31 | } 32 | 33 | void *getBits() 34 | { 35 | assert(dib != NULL); 36 | return FreeImage_GetBits(dib); 37 | } 38 | 39 | void *const getBits() const 40 | { 41 | assert(dib != NULL); 42 | return FreeImage_GetBits(dib); 43 | } 44 | 45 | const int getWidth() const 46 | { 47 | assert(dib != NULL); 48 | return FreeImage_GetWidth(dib); 49 | } 50 | 51 | const int getHeight() const 52 | { 53 | assert(dib != NULL); 54 | return FreeImage_GetHeight(dib); 55 | } 56 | 57 | const int getPitch() const 58 | { 59 | assert(dib != NULL); 60 | return FreeImage_GetPitch(dib); 61 | } 62 | 63 | const int getBPP() const 64 | { 65 | assert(dib != NULL); 66 | return FreeImage_GetBPP(dib); 67 | } 68 | 69 | RGBQUAD getPixelColor(int x, int y) const 70 | { 71 | assert(dib != NULL); 72 | assert(FIC_RGB == FreeImage_GetColorType(dib)); 73 | 74 | RGBQUAD res; 75 | FreeImage_GetPixelColor(dib, x, y, &res); 76 | return res; 77 | } 78 | 79 | BYTE getPixelIndex(int x, int y) const 80 | { 81 | assert(dib != NULL); 82 | assert(FIC_PALETTE == FreeImage_GetColorType(dib)); 83 | 84 | BYTE res; 85 | FreeImage_GetPixelIndex(dib, x, y, &res); 86 | return res; 87 | } 88 | 89 | bool setPixelIndex(int x, int y, BYTE color) 90 | { 91 | assert(dib != NULL); 92 | assert(FIC_PALETTE == FreeImage_GetColorType(dib)); 93 | return FALSE == FreeImage_SetPixelIndex(dib, x, y, &color) ? false : true; 94 | } 95 | 96 | bool setPixelColor(int x, int y, RGBQUAD color) 97 | { 98 | assert(dib != NULL); 99 | assert(FIC_RGB == FreeImage_GetColorType(dib)); 100 | return FALSE == FreeImage_SetPixelColor(dib, x, y, &color) ? false : true; 101 | } 102 | 103 | const RGBQUAD *const getPalette() const 104 | { 105 | assert(dib != NULL); 106 | assert(FIC_PALETTE == FreeImage_GetColorType(dib)); 107 | 108 | return FreeImage_GetPalette(dib); 109 | } 110 | 111 | void setPalette(const RGBQUAD *const pal) 112 | { 113 | assert(dib != NULL); 114 | assert(FIC_PALETTE == FreeImage_GetColorType(dib)); 115 | RGBQUAD *dst_pal = FreeImage_GetPalette(dib); 116 | memcpy(dst_pal, pal, sizeof(RGBQUAD) * 256); 117 | } 118 | 119 | 120 | unsigned getColorsUsed() 121 | { 122 | assert(dib != NULL); 123 | assert(FIC_PALETTE == FreeImage_GetColorType(dib)); 124 | 125 | return FreeImage_GetColorsUsed(dib); 126 | } 127 | 128 | bool save(const char *filename) const 129 | { 130 | assert(dib != NULL); 131 | FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(filename); 132 | FreeImage_FlipVertical(dib); 133 | return (TRUE == FreeImage_Save(fif, dib, filename)); 134 | } 135 | 136 | bool load(const char *filename) 137 | { 138 | FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(filename); 139 | dib = FreeImage_Load(fif, filename); 140 | if (dib == NULL) return false; 141 | 142 | FreeImage_FlipVertical(dib); 143 | 144 | return true; 145 | } 146 | 147 | const FIBITMAP *getFIBitmap() const { return dib; } 148 | FIBITMAP *getFIBitmap() { return dib; } 149 | 150 | private: 151 | FIBITMAP *dib; 152 | }; 153 | -------------------------------------------------------------------------------- /src/nds_texcompress/nds_texcompress.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "compress_texture.h" 4 | 5 | int main(int argc, char* argv[]) 6 | { 7 | int exitcode = 0; 8 | 9 | FreeImage_DeInitialise(); 10 | 11 | for (int i = 1; i < argc; ++i) 12 | { 13 | printf("compressing %s...\n", argv[i]); 14 | if (!compressTexture(argv[i])) 15 | { 16 | exitcode = -1; 17 | break; 18 | } 19 | } 20 | 21 | FreeImage_DeInitialise(); 22 | 23 | return exitcode; 24 | } 25 | -------------------------------------------------------------------------------- /src/r4denc/r4denc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright(C) 2007 yasu 3 | 2009 WinterMute 4 | 5 | http://hp.vector.co.jp/authors/VA013928/ 6 | http://www.usay.jp/ 7 | http://www.yasu.nu/ 8 | http://www.devkitpro.org 9 | 10 | 2007/04/22 21:00 - First version 11 | 12 | 2009/01/08 - combined decode/encode in single app, switch on extension (.nds/.dat) 13 | 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define BIT_AT(n, i) ((n >> i) & 1) 25 | 26 | void cryptBuffer( unsigned char *buf, size_t size, int keyvalue, bool decode, int n) { 27 | unsigned short key = n ^ keyvalue; 28 | 29 | for (int i = 0; i < size; i ++) { 30 | 31 | unsigned char xorkey = 0; 32 | if (key & 0x4000) xorkey |= 0x80; 33 | if (key & 0x1000) xorkey |= 0x40; 34 | if (key & 0x0800) xorkey |= 0x20; 35 | if (key & 0x0200) xorkey |= 0x10; 36 | if (key & 0x0080) xorkey |= 0x08; 37 | if (key & 0x0040) xorkey |= 0x04; 38 | if (key & 0x0002) xorkey |= 0x02; 39 | if (key & 0x0001) xorkey |= 0x01; 40 | 41 | if (!decode) buf[i] ^= xorkey; 42 | 43 | unsigned int k = ((buf[i] << 8) ^ key) << 16; 44 | unsigned int x = k; 45 | 46 | for (int j = 1; j < 32; j ++) 47 | x ^= k >> j; 48 | 49 | key = 0x0000; 50 | 51 | if (BIT_AT(x, 23)) key |= 0x8000; 52 | if (BIT_AT(k, 22)) key |= 0x4000; 53 | if (BIT_AT(k, 21)) key |= 0x2000; 54 | if (BIT_AT(k, 20)) key |= 0x1000; 55 | if (BIT_AT(k, 19)) key |= 0x0800; 56 | if (BIT_AT(k, 18)) key |= 0x0400; 57 | if (BIT_AT(k, 17) != BIT_AT(x, 31)) key |= 0x0200; 58 | if (BIT_AT(k, 16) != BIT_AT(x, 30)) key |= 0x0100; 59 | if (BIT_AT(k, 30) != BIT_AT(k, 29)) key |= 0x0080; 60 | if (BIT_AT(k, 29) != BIT_AT(k, 28)) key |= 0x0040; 61 | if (BIT_AT(k, 28) != BIT_AT(k, 27)) key |= 0x0020; 62 | if (BIT_AT(k, 27) != BIT_AT(k, 26)) key |= 0x0010; 63 | if (BIT_AT(k, 26) != BIT_AT(k, 25)) key |= 0x0008; 64 | if (BIT_AT(k, 25) != BIT_AT(k, 24)) key |= 0x0004; 65 | if (BIT_AT(k, 25) != BIT_AT(x, 26)) key |= 0x0002; 66 | if (BIT_AT(k, 24) != BIT_AT(x, 25)) key |= 0x0001; 67 | 68 | if (decode) buf[i] ^= xorkey; 69 | } 70 | 71 | } 72 | 73 | int findkey(FILE *in) { 74 | 75 | int r; 76 | 77 | unsigned char inbuf[16]; 78 | unsigned char decodebuf[16]; 79 | const char *gamecode = "####"; 80 | 81 | r = fread(inbuf,1,16,in); 82 | fseek(in, 0, SEEK_SET); 83 | 84 | int testkey; 85 | 86 | for (testkey=0; testkey<0xffff; testkey++) { 87 | memcpy(decodebuf,inbuf,16); 88 | cryptBuffer(decodebuf, 16, testkey, true, 0); 89 | if ( memcmp(&decodebuf[12], gamecode , 4 ) == 0) break; 90 | } 91 | 92 | return testkey; 93 | } 94 | 95 | void r4denc(FILE *in, FILE *out, int keyvalue, bool decode) { 96 | 97 | int r, n = 0; 98 | 99 | unsigned char buf[512]; 100 | 101 | while ((r = fread(buf, 1, 512, in)) > 0) { 102 | cryptBuffer(buf,512,keyvalue,decode,n); 103 | fwrite(buf, 1, r, out); 104 | n++; 105 | } 106 | } 107 | 108 | void showHelp() { 109 | 110 | puts("Usage: r4denc [options] in-file [out-file]\n"); 111 | puts("--help, -h Display this information"); 112 | puts("--findkey, -f Search for decode key"); 113 | puts("--key, -k Use as encode/decode key"); 114 | puts("\n"); 115 | } 116 | 117 | int main(int argc, char *argv[]) { 118 | 119 | puts("Yasu software - r4denc"); 120 | 121 | if (argc < 2) { 122 | showHelp(); 123 | return 1; 124 | } 125 | 126 | bool decodeFlag = false; 127 | bool findKey = false; 128 | int key = 0x484A; 129 | char *optend; 130 | 131 | while(1) { 132 | static struct option long_options[] = { 133 | {"findkey", no_argument, 0, 'f'}, 134 | {"help", no_argument, 0, 'h'}, 135 | {"key", required_argument, 0, 'k'}, 136 | {0, 0, 0, 0} 137 | }; 138 | 139 | /* getopt_long stores the option index here. */ 140 | int option_index = 0, c; 141 | 142 | c = getopt_long (argc, argv, "fhk:x", long_options, &option_index); 143 | 144 | /* Detect the end of the options. */ 145 | if (c == -1) 146 | break; 147 | 148 | switch(c) { 149 | 150 | case 'f': 151 | findKey = true; 152 | break; 153 | case 'h': 154 | showHelp(); 155 | break; 156 | case 'k': 157 | key = strtol(optarg,&optend,0); 158 | if (errno) { 159 | printf("invalid key\n"); 160 | exit(1); 161 | } 162 | break; 163 | } 164 | 165 | } 166 | 167 | std::string infile, outfile, ext, outext; 168 | size_t lastdot; 169 | 170 | if (optind < argc) infile = argv[optind++]; 171 | 172 | if ( (lastdot = infile.rfind("."))!= std::string::npos ) { 173 | ext = infile.substr(lastdot); 174 | } 175 | 176 | if (optind < argc) { 177 | outfile = argv[optind++]; 178 | } else { 179 | outfile = infile.substr(0,lastdot); 180 | } 181 | 182 | if (strcasecmp(ext.c_str(),".dat")==0) { 183 | decodeFlag=true; 184 | outext = ".nds"; 185 | } else if ( strcasecmp(ext.c_str(),".nds")==0) { 186 | decodeFlag=false; 187 | outext = ".dat"; 188 | } else { 189 | printf(".nds or .dat required\n"); 190 | exit(1); 191 | } 192 | 193 | if ( (lastdot = outfile.rfind("."))!= std::string::npos ) { 194 | outfile = outfile.substr(0,lastdot); 195 | } 196 | 197 | outfile += outext; 198 | 199 | FILE *in = fopen(infile.c_str(), "rb"); 200 | 201 | if (in == NULL) { 202 | printf("Error: cannot open %s for reading\n", infile.c_str()); 203 | exit(1); 204 | } 205 | 206 | if (findKey) { 207 | if((strcasecmp(ext.c_str(),".dat")!=0)) { 208 | fclose(in); 209 | printf("Can't search for key in .nds file\n"); 210 | exit(1); 211 | } 212 | printf("finding key ...\n"); 213 | key = findkey(in); 214 | } 215 | 216 | FILE *out = fopen(outfile.c_str(), "wb"); 217 | 218 | if (out == NULL) { 219 | fclose(in); 220 | printf("Error: cannot open %s for writing\n", outfile.c_str()); 221 | exit(1); 222 | } 223 | 224 | r4denc(in, out, key, decodeFlag); 225 | 226 | printf("%scoded %s to %s using key 0x%x\n",decodeFlag?"de":"en",infile.c_str(),outfile.c_str(),key); 227 | 228 | fclose(out); 229 | fclose(in); 230 | 231 | return 0; 232 | } 233 | --------------------------------------------------------------------------------