├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── codepoints ├── mm.txt ├── oot.txt └── oot_decomp_fn.txt ├── common.sh ├── preview.gif ├── release-linux.sh ├── release-win32.sh └── src ├── gui.c ├── icon.ico ├── icon.rc ├── stb_image_write.h ├── stb_truetype.h ├── utf8.c ├── utf8.h ├── z64font.c ├── z64font.h ├── zchar.c └── zchar.h /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | release/ 3 | *.o 4 | .vscode/ 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "wowlib"] 2 | path = wowlib 3 | url = https://github.com/z64me/wowlib 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # z64font 2 | 3 | `z64font` is a font tool that rasterizes TrueType font (`.ttf`) files 4 | into a format compatible with Ocarina of Time and Majora's Mask. 5 | Whether you're looking to localize these games into new languages that 6 | rely on brand new character sets, or you're just adding a fresh coat of 7 | paint to your romhack, this program makes your job a whole lot easier. 8 | 9 | ![preview.gif](preview.gif) 10 | 11 | ## How to use 12 | 13 | `z64font` requires you to provide only two files: 14 | - A UTF8-encoded text document containing a sample string and 15 | a list of codepoints. 16 | - The TrueType font (`.ttf`) file you wish to convert. 17 | 18 | Here are the latest codepoint files (simply `Ctrl + S` in your browser): 19 | - [Ocarina of Time codepoints](https://raw.githubusercontent.com/z64me/z64font/main/codepoints/oot.txt) 20 | - [Majora's Mask codepoints](https://raw.githubusercontent.com/z64me/z64font/main/codepoints/mm.txt) 21 | 22 | You can use your scroll wheel to effortlessly tweak each control. 23 | 24 | What you do next depends on your workflow. 25 | 26 | 32 | 33 | ### Traditional hackers 34 | 35 | Once you are happy with how your font is displaying in the preview window, 36 | click the `Export Binaries` button. You will be prompted to select a 37 | location and filename for them. Let's assume you chose the name `wow`. 38 | 39 | Once you have done that, two files will be generated: `wow.font_static` 40 | and `wow.font_width`. 41 | 42 | Inject the files into your decompressed game using a hex editor. 43 | For Windows users, I recommend [HxD](https://mh-nexus.de/en/hxd/). 44 | 45 | | Game | .font_static | .font_width | 46 | | ------------- | --------------- | ----------------------------- | 47 | | OoT debug | `0x008C1000` | `0x00BCABA0` | 48 | | OoT NTSC 1.0 | `0x00928000` | `0x00B88EA0` | 49 | | MM USA | `0x00ACC000` | `0x00C669B0` and `0x00C66E50` | 50 | 51 | If you don't know how to decompress your copy of the game, look no 52 | further than [`z64decompress`](https://github.com/z64me/z64decompress). 53 | 54 | ### [OoT decomp](https://github.com/zeldaret/oot) 55 | To export for OoT decomp first make sure `decompMode` is checked. 56 | You must provide a text file with the names of the png files to export. An [`oot_decomp_fn.txt`](https://raw.githubusercontent.com/z64me/z64font/main/codepoints/oot_decomp_fn.txt) is included already. 57 | 58 | Once you are happy with how your font is displaying in the preview window, 59 | click the `Export Decomp` button. You will be prompted to select a 60 | location and filename for the export. Let's assume you chose the name `wow`. 61 | 62 | Once you have done that, a `.png` will be generated for every character, as well as a `wow.font_width.h`. 63 | 64 | To add all the textures to your decomp repository, navigate to `oot/assets/textures/nes_font_static`, and place all of the generated files in this folder, overwriting as necessary. 65 | 66 | Next, we need to update the spacing between each character. To do so, open `oot/src/code/z_message_PAL.c`, and find the [`sFontWidths`](https://github.com/zeldaret/oot/blob/master/src/code/z_message_PAL.c#L589) array. Next, replace the entire array with this: 67 | ```c 68 | f32 sFontWidths[] = { 69 | #include "textures/nes_font_static/wow.font_width.h" 70 | }; 71 | ``` 72 | 73 | Now `make clean && make` to compile the new font. 74 | 75 | ### [MM decomp](https://github.com/zeldaret/mm) users 76 | The MM decomp will be made targetable once it finalizes its font handling. 77 | -------------------------------------------------------------------------------- /codepoints/mm.txt: -------------------------------------------------------------------------------- 1 | This is sample text.\nStepping Stones in the Pond\nIf you boldly go in the direction\nyou want to jump, you will leap\nautomatically.\n¥ºªÀÁÂÄÇÈÉÊËÌÍÎÏÑÒÓÔÖÙÚÛÜβàáâäçèéêëìíîïñòóôöùúûü¡¿ 2 | 3 | ! 4 | " 5 | # 6 | $ 7 | % 8 | & 9 | ' 10 | ( 11 | ) 12 | * 13 | + 14 | , 15 | - 16 | . 17 | / 18 | 0 19 | 1 20 | 2 21 | 3 22 | 4 23 | 5 24 | 6 25 | 7 26 | 8 27 | 9 28 | : 29 | ; 30 | < 31 | = 32 | > 33 | ? 34 | @ 35 | A 36 | B 37 | C 38 | D 39 | E 40 | F 41 | G 42 | H 43 | I 44 | J 45 | K 46 | L 47 | M 48 | N 49 | O 50 | P 51 | Q 52 | R 53 | S 54 | T 55 | U 56 | V 57 | W 58 | X 59 | Y 60 | Z 61 | [ 62 | ¥ 63 | ] 64 | ^ 65 | _ 66 | ` 67 | a 68 | b 69 | c 70 | d 71 | e 72 | f 73 | g 74 | h 75 | i 76 | j 77 | k 78 | l 79 | m 80 | n 81 | o 82 | p 83 | q 84 | r 85 | s 86 | t 87 | u 88 | v 89 | w 90 | x 91 | y 92 | z 93 | { 94 | | 95 | } 96 | ~ 97 | º 98 | À 99 | Á 100 |  101 | Ä 102 | Ç 103 | È 104 | É 105 | Ê 106 | Ë 107 | Ì 108 | Í 109 | Î 110 | Ï 111 | Ñ 112 | Ò 113 | Ó 114 | Ô 115 | Ö 116 | Ù 117 | Ú 118 | Û 119 | Ü 120 | β 121 | à 122 | á 123 | â 124 | ä 125 | ç 126 | è 127 | é 128 | ê 129 | ë 130 | ì 131 | í 132 | î 133 | ï 134 | ñ 135 | ò 136 | ó 137 | ô 138 | ö 139 | ù 140 | ú 141 | û 142 | ü 143 | ¡ 144 | ¿ 145 | ª 146 | -------------------------------------------------------------------------------- /codepoints/oot.txt: -------------------------------------------------------------------------------- 1 | This is sample text.\nStepping Stones in the Pond\nIf you boldly go in the direction\nyou want to jump, you will leap\nautomatically.\n¥ÀîÂÄÇÈÉÊËÏÔÖÙÛÜβàáâäçèéêëïôöùûü 2 | 3 | ! 4 | " 5 | # 6 | $ 7 | % 8 | & 9 | ' 10 | ( 11 | ) 12 | * 13 | + 14 | , 15 | - 16 | . 17 | / 18 | 0 19 | 1 20 | 2 21 | 3 22 | 4 23 | 5 24 | 6 25 | 7 26 | 8 27 | 9 28 | : 29 | ; 30 | < 31 | = 32 | > 33 | ? 34 | @ 35 | A 36 | B 37 | C 38 | D 39 | E 40 | F 41 | G 42 | H 43 | I 44 | J 45 | K 46 | L 47 | M 48 | N 49 | O 50 | P 51 | Q 52 | R 53 | S 54 | T 55 | U 56 | V 57 | W 58 | X 59 | Y 60 | Z 61 | [ 62 | ¥ 63 | \ 64 | ^ 65 | _ 66 | ` 67 | a 68 | b 69 | c 70 | d 71 | e 72 | f 73 | g 74 | h 75 | i 76 | j 77 | k 78 | l 79 | m 80 | n 81 | o 82 | p 83 | q 84 | r 85 | s 86 | t 87 | u 88 | v 89 | w 90 | x 91 | y 92 | z 93 | { 94 | | 95 | } 96 | ~ 97 | 98 | À 99 | î 100 |  101 | Ä 102 | Ç 103 | È 104 | É 105 | Ê 106 | Ë 107 | Ï 108 | Ô 109 | Ö 110 | Ù 111 | Û 112 | Ü 113 | β 114 | à 115 | á 116 | â 117 | ä 118 | ç 119 | è 120 | é 121 | ê 122 | ë 123 | ï 124 | ô 125 | ö 126 | ù 127 | û 128 | ü 129 | -------------------------------------------------------------------------------- /codepoints/oot_decomp_fn.txt: -------------------------------------------------------------------------------- 1 | msg_char_20_space.i4.png 2 | msg_char_21_exclamation_mark.i4.png 3 | msg_char_22_quotation_mark.i4.png 4 | msg_char_23_number_sign.i4.png 5 | msg_char_24_dollar_sign.i4.png 6 | msg_char_25_percent_sign.i4.png 7 | msg_char_26_ampersand.i4.png 8 | msg_char_27_apostrophe.i4.png 9 | msg_char_28_left_parentheses.i4.png 10 | msg_char_29_right_parentheses.i4.png 11 | msg_char_2a_asterisk.i4.png 12 | msg_char_2b_plus_sign.i4.png 13 | msg_char_2c_comma.i4.png 14 | msg_char_2d_hyphen_minus.i4.png 15 | msg_char_2e_full_stop.i4.png 16 | msg_char_2f_solidus.i4.png 17 | msg_char_30_digit_0.i4.png 18 | msg_char_31_digit_1.i4.png 19 | msg_char_32_digit_2.i4.png 20 | msg_char_33_digit_3.i4.png 21 | msg_char_34_digit_4.i4.png 22 | msg_char_35_digit_5.i4.png 23 | msg_char_36_digit_6.i4.png 24 | msg_char_37_digit_7.i4.png 25 | msg_char_38_digit_8.i4.png 26 | msg_char_39_digit_9.i4.png 27 | msg_char_3a_colon.i4.png 28 | msg_char_3b_semicolon.i4.png 29 | msg_char_3c_less_than_sign.i4.png 30 | msg_char_3d_equals_sign.i4.png 31 | msg_char_3e_greater_than_sign.i4.png 32 | msg_char_3f_question_mark.i4.png 33 | msg_char_40_commercial_at.i4.png 34 | msg_char_41_latin_capital_letter_a.i4.png 35 | msg_char_42_latin_capital_letter_b.i4.png 36 | msg_char_43_latin_capital_letter_c.i4.png 37 | msg_char_44_latin_capital_letter_d.i4.png 38 | msg_char_45_latin_capital_letter_e.i4.png 39 | msg_char_46_latin_capital_letter_f.i4.png 40 | msg_char_47_latin_capital_letter_g.i4.png 41 | msg_char_48_latin_capital_letter_h.i4.png 42 | msg_char_49_latin_capital_letter_i.i4.png 43 | msg_char_4a_latin_capital_letter_j.i4.png 44 | msg_char_4b_latin_capital_letter_k.i4.png 45 | msg_char_4c_latin_capital_letter_l.i4.png 46 | msg_char_4d_latin_capital_letter_m.i4.png 47 | msg_char_4e_latin_capital_letter_n.i4.png 48 | msg_char_4f_latin_capital_letter_o.i4.png 49 | msg_char_50_latin_capital_letter_p.i4.png 50 | msg_char_51_latin_capital_letter_q.i4.png 51 | msg_char_52_latin_capital_letter_r.i4.png 52 | msg_char_53_latin_capital_letter_s.i4.png 53 | msg_char_54_latin_capital_letter_t.i4.png 54 | msg_char_55_latin_capital_letter_u.i4.png 55 | msg_char_56_latin_capital_letter_v.i4.png 56 | msg_char_57_latin_capital_letter_w.i4.png 57 | msg_char_58_latin_capital_letter_x.i4.png 58 | msg_char_59_latin_capital_letter_y.i4.png 59 | msg_char_5a_latin_capital_letter_z.i4.png 60 | msg_char_5b_left_square_bracket.i4.png 61 | msg_char_5c_yen_sign.i4.png 62 | msg_char_5d_right_square_bracket.i4.png 63 | msg_char_5e_circumflex_accent.i4.png 64 | msg_char_5f_low_line.i4.png 65 | msg_char_60_grave_accent.i4.png 66 | msg_char_61_latin_small_letter_a.i4.png 67 | msg_char_62_latin_small_letter_b.i4.png 68 | msg_char_63_latin_small_letter_c.i4.png 69 | msg_char_64_latin_small_letter_d.i4.png 70 | msg_char_65_latin_small_letter_e.i4.png 71 | msg_char_66_latin_small_letter_f.i4.png 72 | msg_char_67_latin_small_letter_g.i4.png 73 | msg_char_68_latin_small_letter_h.i4.png 74 | msg_char_69_latin_small_letter_i.i4.png 75 | msg_char_6a_latin_small_letter_j.i4.png 76 | msg_char_6b_latin_small_letter_k.i4.png 77 | msg_char_6c_latin_small_letter_l.i4.png 78 | msg_char_6d_latin_small_letter_m.i4.png 79 | msg_char_6e_latin_small_letter_n.i4.png 80 | msg_char_6f_latin_small_letter_o.i4.png 81 | msg_char_70_latin_small_letter_p.i4.png 82 | msg_char_71_latin_small_letter_q.i4.png 83 | msg_char_72_latin_small_letter_r.i4.png 84 | msg_char_73_latin_small_letter_s.i4.png 85 | msg_char_74_latin_small_letter_t.i4.png 86 | msg_char_75_latin_small_letter_u.i4.png 87 | msg_char_76_latin_small_letter_v.i4.png 88 | msg_char_77_latin_small_letter_w.i4.png 89 | msg_char_78_latin_small_letter_x.i4.png 90 | msg_char_79_latin_small_letter_y.i4.png 91 | msg_char_7a_latin_small_letter_z.i4.png 92 | msg_char_7b_left_curly_bracket.i4.png 93 | msg_char_7c_vertical_line.i4.png 94 | msg_char_7d_right_curly_bracket.i4.png 95 | msg_char_7e_tilde.i4.png 96 | msg_char_7f_blank.i4.png 97 | msg_char_80_latin_capital_letter_a_with_grave.i4.png 98 | msg_char_81_latin_capital_letter_i_with_circumflex.i4.png 99 | msg_char_82_latin_capital_letter_a_with_circumflex.i4.png 100 | msg_char_83_latin_capital_letter_a_with_diaeresis.i4.png 101 | msg_char_84_latin_capital_letter_c_with_cedilla.i4.png 102 | msg_char_85_latin_capital_letter_e_with_grave.i4.png 103 | msg_char_86_latin_capital_letter_e_with_acute.i4.png 104 | msg_char_87_latin_capital_letter_e_with_circumflex.i4.png 105 | msg_char_88_latin_capital_letter_e_with_diaeresis.i4.png 106 | msg_char_89_latin_capital_letter_i_with_diaeresis.i4.png 107 | msg_char_8a_latin_capital_letter_o_with_circumflex.i4.png 108 | msg_char_8b_latin_capital_letter_o_with_diaeresis.i4.png 109 | msg_char_8c_latin_capital_letter_u_with_grave.i4.png 110 | msg_char_8d_latin_capital_letter_u_with_circumflex.i4.png 111 | msg_char_8e_latin_capital_letter_u_with_diaeresis.i4.png 112 | msg_char_8f_latin_small_letter_sharp_s.i4.png 113 | msg_char_90_latin_small_letter_a_with_grave.i4.png 114 | msg_char_91_latin_small_letter_a_with_acute.i4.png 115 | msg_char_92_latin_small_letter_a_with_circumflex.i4.png 116 | msg_char_93_latin_small_letter_a_with_diaeresis.i4.png 117 | msg_char_94_latin_small_letter_c_with_cedilla.i4.png 118 | msg_char_95_latin_small_letter_e_with_grave.i4.png 119 | msg_char_96_latin_small_letter_e_with_acute.i4.png 120 | msg_char_97_latin_small_letter_e_with_circumflex.i4.png 121 | msg_char_98_latin_small_letter_e_with_diaeresis.i4.png 122 | msg_char_99_latin_small_letter_i_with_diaeresis.i4.png 123 | msg_char_9a_latin_small_letter_o_with_circumflex.i4.png 124 | msg_char_9b_latin_small_letter_o_with_diaeresis.i4.png 125 | msg_char_9c_latin_small_letter_u_with_grave.i4.png 126 | msg_char_9d_latin_small_letter_u_with_circumflex.i4.png 127 | msg_char_9e_latin_small_letter_u_with_diaeresis.i4.png 128 | msg_char_9f_button_a.i4.png 129 | msg_char_a0_button_b.i4.png 130 | msg_char_a1_button_c.i4.png 131 | msg_char_a2_button_l.i4.png 132 | msg_char_a3_button_r.i4.png 133 | msg_char_a4_button_z.i4.png 134 | msg_char_a5_button_c_up.i4.png 135 | msg_char_a6_button_c_down.i4.png 136 | msg_char_a7_button_c_left.i4.png 137 | msg_char_a8_button_c_right.i4.png 138 | msg_char_a9_z_target_sign.i4.png 139 | msg_char_aa_control_stick.i4.png 140 | msg_char_ab_control_pad.i4.png 141 | -------------------------------------------------------------------------------- /common.sh: -------------------------------------------------------------------------------- 1 | echo "-DNDEBUG -Wall -flto -lm -Os -s -flto -Iwowlib -DWOW_OVERLOAD_FILE src/*.c -Isrc " 2 | -------------------------------------------------------------------------------- /preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z64utils/z64font/019ee829bba46ae64dd1147b031a5a0ba111f0df/preview.gif -------------------------------------------------------------------------------- /release-linux.sh: -------------------------------------------------------------------------------- 1 | mkdir -p bin/release 2 | 3 | gcc -o bin/release/z64font-linux -DZ64FONT_GUI `./common.sh` `wowlib/deps/wow_gui_x11.sh` 4 | 5 | -------------------------------------------------------------------------------- /release-win32.sh: -------------------------------------------------------------------------------- 1 | mkdir -p bin/release 2 | mkdir -p bin/o/win32 3 | 4 | PATH=$PATH:~/c/mxe/usr/bin 5 | 6 | # icon 7 | i686-w64-mingw32.static-windres src/icon.rc -o bin/o/win32/icon.o 8 | 9 | i686-w64-mingw32.static-gcc -o bin/release/z64font.exe `./common.sh` \ 10 | -municode -DZ64FONT_GUI \ 11 | `wowlib/deps/wow_gui_win32.sh` \ 12 | bin/o/win32/icon.o 13 | 14 | -------------------------------------------------------------------------------- /src/gui.c: -------------------------------------------------------------------------------- 1 | /* z64font's gui code lives here */ 2 | 3 | #ifdef Z64FONT_GUI 4 | #include 5 | #define WOW_GUI_IMPLEMENTATION 6 | #include 7 | 8 | #include "z64font.h" 9 | 10 | #include 11 | 12 | #define WINW 440 13 | #define WINH 440 14 | #define PREVIEW_X (16) /* window coordinates at which */ 15 | #define PREVIEW_Y (128+24) /* to display text preview */ 16 | 17 | static void i8_to_rgba32( 18 | unsigned char *dst 19 | , unsigned char *src 20 | , int w 21 | , int h 22 | ) 23 | { 24 | unsigned char *dstOld = dst; 25 | dst += (w * h * 4) - 4; 26 | src += (w * h) - 1; 27 | 28 | while (dst > dstOld) 29 | { 30 | dst[0] = dst[1] = dst[2] = dst[3] = *src; 31 | src -= 1; 32 | dst -= 4; 33 | } 34 | } 35 | 36 | static void bake( 37 | struct z64font *g 38 | , unsigned char *dst 39 | , int dstW 40 | , int dstH 41 | ) 42 | { 43 | char *next; 44 | char *w; 45 | utf8_int32_t codepoint; 46 | int x = 0; 47 | int y = 0; 48 | int yadv = FONT_H; 49 | memset(dst, 0, dstW * dstH); 50 | struct zchar *zchar = g->zchar; 51 | char *str = g->chars; 52 | 53 | for (next = 0, w = str; *w; w = next) 54 | { 55 | const struct zchar *z; 56 | unsigned char *bmp; 57 | int k; 58 | int i; 59 | 60 | next = utf8codepoint(w, &codepoint); 61 | 62 | /* end of string */ 63 | if (codepoint == 0x0d || codepoint == 0x0a || !codepoint) 64 | break; 65 | 66 | /* explicit newline escape sequence */ 67 | if (codepoint == '\\' && *next == 'n') 68 | { 69 | x = 0; 70 | if (g->rightToLeft && x <= 0) 71 | x = dstW; 72 | y += yadv; 73 | ++next; 74 | continue; 75 | } 76 | 77 | /* find matching codepoint */ 78 | if (!(z = zchar_findCodepoint(zchar, codepoint))) 79 | continue; 80 | 81 | if (g->rightToLeft && x <= 0) 82 | x = dstW; 83 | 84 | bmp = z->bitmap; 85 | 86 | if (g->rightToLeft) 87 | { 88 | x -= z->width; 89 | if (x <= 0) 90 | { 91 | y += yadv; 92 | x = dstW - z->width; 93 | } 94 | } 95 | 96 | /* blend character bitmap into preview */ 97 | for (k = 0; k < FONT_H; ++k) 98 | { 99 | for (i = 0; i < FONT_W; ++i) 100 | { 101 | int dstIdx = (dstW * (y + k)) + x + i; 102 | if (dstIdx < 0 || dstIdx >= dstW * dstH) 103 | continue; 104 | dst[dstIdx] |= bmp[FONT_W * k + i]; 105 | } 106 | } 107 | 108 | if (!g->rightToLeft) 109 | { 110 | x += z->width; 111 | 112 | if (x >= dstW ) 113 | { 114 | y += yadv; 115 | x = 0; 116 | } 117 | } 118 | } 119 | 120 | i8_to_rgba32(dst, dst, dstW, dstH); 121 | } 122 | 123 | int wow_main(argc, argv) 124 | { 125 | wow_main_args(argc, argv); 126 | unsigned char *preview = 0; 127 | int previewW = WINW - (PREVIEW_X * 2); 128 | int previewH = WINH - (PREVIEW_Y + 16); 129 | struct z64font g = Z64FONT_DEFAULTS; 130 | g.info = wowGui_infof; 131 | g.error = wowGui_errorf; 132 | 133 | preview = wow_malloc_die(previewW * previewH * 4); 134 | 135 | wowGui_bind_init(PROGNAME, WINW, WINH); 136 | 137 | wow_windowicon(1); 138 | 139 | while (1) 140 | { 141 | int changed = 0; 142 | /* wowGui_frame() must be called before you do any input */ 143 | wowGui_frame(); 144 | 145 | /* events */ 146 | wowGui_bind_events(); 147 | 148 | if (!wowGui_bind_should_redraw()) 149 | goto skipRedraw; 150 | 151 | /* draw */ 152 | wowGui_viewport(0, 0, WINW, WINH); 153 | wowGui_padding(8, 8); 154 | 155 | static struct wowGui_window win = { 156 | .rect = { 157 | .x = 0 158 | , .y = 0 159 | , .w = WINW 160 | , .h = WINH 161 | } 162 | , .color = 0x301818FF 163 | , .not_scrollable = 1 164 | , .scroll_valuebox = 1 165 | }; 166 | if (wowGui_window(&win)) 167 | { 168 | wowGui_row_height(20); 169 | wowGui_columns(2); 170 | 171 | wowGui_column_width(WINW / 2); 172 | wowGui_italic(2); 173 | wowGui_label(PROG_NAME_VER_ATTRIB); 174 | wowGui_italic(0); 175 | 176 | wowGui_checkbox("decompMode", &g.isDecompMode); 177 | 178 | /* file droppers */ 179 | wowGui_columns(3); 180 | static struct wowGui_fileDropper ttfFile = { 181 | .label = "TrueType Font (.ttf)" 182 | , .labelWidth = 180 183 | , .filenameWidth = 200 184 | , .extension = "ttf" 185 | }; 186 | if (wowGui_fileDropper(&ttfFile)) 187 | { 188 | if (z64font_loadFont(&g, ttfFile.filename)) 189 | { 190 | free(ttfFile.filename); 191 | ttfFile.filename = ""; 192 | } 193 | changed = 1; 194 | } 195 | static struct wowGui_fileDropper txtFile = { 196 | .label = "Codepoint File (.txt)" 197 | , .labelWidth = 180 198 | , .filenameWidth = 200 199 | , .extension = "txt" 200 | }; 201 | if (wowGui_fileDropper(&txtFile)) 202 | { 203 | if (z64font_loadCodepoints(&g, txtFile.filename)) 204 | { 205 | free(txtFile.filename); 206 | txtFile.filename = ""; 207 | } 208 | changed = 1; 209 | } 210 | 211 | static struct wowGui_fileDropper decompFileNamesFile = { 212 | .label = "Decomp Names (.txt)" 213 | , .labelWidth = 180 214 | , .filenameWidth = 200 215 | , .extension = "txt" 216 | }; 217 | if (g.isDecompMode) 218 | { 219 | if (wowGui_fileDropper(&decompFileNamesFile)) 220 | { 221 | if (z64font_loadDecompFileNames(&g, decompFileNamesFile.filename)) 222 | { 223 | free(decompFileNamesFile.filename); 224 | decompFileNamesFile.filename = ""; 225 | } 226 | changed = 1; 227 | } 228 | } 229 | 230 | wowGui_column_width(64); 231 | wowGui_columns(6); 232 | { 233 | int ok = sizeof(g); 234 | static void *x = 0; 235 | if (!x) 236 | { 237 | x = wow_malloc_die(ok); 238 | } 239 | memcpy(x, &g, ok); 240 | wowGui_label("Y Shift"); 241 | wowGui_int_range(&g.yshift, -16, 16, 1); 242 | wowGui_label("Size"); 243 | wowGui_int_range(&g.fontSize, 1, 256, 1); 244 | wowGui_label("xPad"); 245 | wowGui_int_range(&g.xPad, -16, 16, 1); 246 | 247 | wowGui_columns(3); 248 | wowGui_column_width(128+8); 249 | wowGui_checkbox("rightToLeft", &g.rightToLeft); 250 | wowGui_checkbox("widthAdvance", &g.widthAdvance); 251 | 252 | if (memcmp(x, &g, ok)) 253 | changed = 1; 254 | } 255 | 256 | int previewOn = ( 257 | !wowGui_fileDropper_filenameIsEmpty(&ttfFile) 258 | && !wowGui_fileDropper_filenameIsEmpty(&txtFile) 259 | ); 260 | 261 | wowGui_column_width(128 + 8); 262 | 263 | if (wowGui_button(g.isDecompMode ? "Export Decomp" : "Export Binaries")) 264 | { 265 | if (previewOn) 266 | { 267 | char *ofn = 0; 268 | 269 | if (g.isDecompMode) 270 | { 271 | ofn = wowGui_askFilename("font_width.h", 0, 1); 272 | if (ofn) 273 | { 274 | z64font_exportDecomp(&g, &ofn); 275 | free(ofn); 276 | } 277 | } 278 | else 279 | { 280 | ofn = wowGui_askFilename("font_static", 0, 1); 281 | if (ofn) 282 | { 283 | z64font_exportBinaries(&g, &ofn); 284 | free(ofn); 285 | } 286 | } 287 | } 288 | } 289 | 290 | /* display preview */ 291 | if (previewOn) 292 | { 293 | /* update preview */ 294 | if (changed) 295 | { 296 | /* (re)convert font */ 297 | if (z64font_convert(&g)) 298 | wowGui_dief("something went wrong"); 299 | 300 | /* bake new preview */ 301 | bake(&g, preview, previewW, previewH); 302 | } 303 | wowGui_label("preview:"); 304 | wowGui_bind_blit_raw( 305 | preview 306 | , PREVIEW_X 307 | , PREVIEW_Y 308 | , previewW 309 | , previewH 310 | , 0 /* no blending */ 311 | ); 312 | } 313 | 314 | wowGui_column_width(100); 315 | 316 | wowGui_window_end(); 317 | } 318 | 319 | skipRedraw: 320 | 321 | wowGui_frame_end(wowGui_bind_ms()); 322 | 323 | /* display */ 324 | wowGui_bind_result(); 325 | 326 | /* loop exit condition */ 327 | if (wowGui_bind_endmainloop()) 328 | break; 329 | } 330 | 331 | free(g.zchar); 332 | 333 | wowGui_bind_quit(); 334 | 335 | return 0; 336 | (void)argv; 337 | } 338 | #endif /* Z64FONT_GUI */ 339 | 340 | -------------------------------------------------------------------------------- /src/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z64utils/z64font/019ee829bba46ae64dd1147b031a5a0ba111f0df/src/icon.ico -------------------------------------------------------------------------------- /src/icon.rc: -------------------------------------------------------------------------------- 1 | 1 ICON "icon.ico" 2 | 3 | -------------------------------------------------------------------------------- /src/stb_image_write.h: -------------------------------------------------------------------------------- 1 | /* stb_image_write - v1.16 - public domain - http://nothings.org/stb 2 | writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 3 | no warranty implied; use at your own risk 4 | 5 | Before #including, 6 | 7 | #define STB_IMAGE_WRITE_IMPLEMENTATION 8 | 9 | in the file that you want to have the implementation. 10 | 11 | Will probably not work correctly with strict-aliasing optimizations. 12 | 13 | ABOUT: 14 | 15 | This header file is a library for writing images to C stdio or a callback. 16 | 17 | The PNG output is not optimal; it is 20-50% larger than the file 18 | written by a decent optimizing implementation; though providing a custom 19 | zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. 20 | This library is designed for source code compactness and simplicity, 21 | not optimal image file size or run-time performance. 22 | 23 | BUILDING: 24 | 25 | You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. 26 | You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace 27 | malloc,realloc,free. 28 | You can #define STBIW_MEMMOVE() to replace memmove() 29 | You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function 30 | for PNG compression (instead of the builtin one), it must have the following signature: 31 | unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); 32 | The returned data will be freed with STBIW_FREE() (free() by default), 33 | so it must be heap allocated with STBIW_MALLOC() (malloc() by default), 34 | 35 | UNICODE: 36 | 37 | If compiling for Windows and you wish to use Unicode filenames, compile 38 | with 39 | #define STBIW_WINDOWS_UTF8 40 | and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert 41 | Windows wchar_t filenames to utf8. 42 | 43 | USAGE: 44 | 45 | There are five functions, one for each image file format: 46 | 47 | int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); 48 | int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); 49 | int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); 50 | int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); 51 | int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); 52 | 53 | void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically 54 | 55 | There are also five equivalent functions that use an arbitrary write function. You are 56 | expected to open/close your file-equivalent before and after calling these: 57 | 58 | int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); 59 | int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 60 | int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 61 | int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); 62 | int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); 63 | 64 | where the callback is: 65 | void stbi_write_func(void *context, void *data, int size); 66 | 67 | You can configure it with these global variables: 68 | int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE 69 | int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression 70 | int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode 71 | 72 | 73 | You can define STBI_WRITE_NO_STDIO to disable the file variant of these 74 | functions, so the library will not use stdio.h at all. However, this will 75 | also disable HDR writing, because it requires stdio for formatted output. 76 | 77 | Each function returns 0 on failure and non-0 on success. 78 | 79 | The functions create an image file defined by the parameters. The image 80 | is a rectangle of pixels stored from left-to-right, top-to-bottom. 81 | Each pixel contains 'comp' channels of data stored interleaved with 8-bits 82 | per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is 83 | monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. 84 | The *data pointer points to the first byte of the top-left-most pixel. 85 | For PNG, "stride_in_bytes" is the distance in bytes from the first byte of 86 | a row of pixels to the first byte of the next row of pixels. 87 | 88 | PNG creates output files with the same number of components as the input. 89 | The BMP format expands Y to RGB in the file format and does not 90 | output alpha. 91 | 92 | PNG supports writing rectangles of data even when the bytes storing rows of 93 | data are not consecutive in memory (e.g. sub-rectangles of a larger image), 94 | by supplying the stride between the beginning of adjacent rows. The other 95 | formats do not. (Thus you cannot write a native-format BMP through the BMP 96 | writer, both because it is in BGR order and because it may have padding 97 | at the end of the line.) 98 | 99 | PNG allows you to set the deflate compression level by setting the global 100 | variable 'stbi_write_png_compression_level' (it defaults to 8). 101 | 102 | HDR expects linear float data. Since the format is always 32-bit rgb(e) 103 | data, alpha (if provided) is discarded, and for monochrome data it is 104 | replicated across all three channels. 105 | 106 | TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed 107 | data, set the global variable 'stbi_write_tga_with_rle' to 0. 108 | 109 | JPEG does ignore alpha channels in input data; quality is between 1 and 100. 110 | Higher quality looks better but results in a bigger image. 111 | JPEG baseline (no JPEG progressive). 112 | 113 | CREDITS: 114 | 115 | 116 | Sean Barrett - PNG/BMP/TGA 117 | Baldur Karlsson - HDR 118 | Jean-Sebastien Guay - TGA monochrome 119 | Tim Kelsey - misc enhancements 120 | Alan Hickman - TGA RLE 121 | Emmanuel Julien - initial file IO callback implementation 122 | Jon Olick - original jo_jpeg.cpp code 123 | Daniel Gibson - integrate JPEG, allow external zlib 124 | Aarni Koskela - allow choosing PNG filter 125 | 126 | bugfixes: 127 | github:Chribba 128 | Guillaume Chereau 129 | github:jry2 130 | github:romigrou 131 | Sergio Gonzalez 132 | Jonas Karlsson 133 | Filip Wasil 134 | Thatcher Ulrich 135 | github:poppolopoppo 136 | Patrick Boettcher 137 | github:xeekworx 138 | Cap Petschulat 139 | Simon Rodriguez 140 | Ivan Tikhonov 141 | github:ignotion 142 | Adam Schackart 143 | Andrew Kensler 144 | 145 | LICENSE 146 | 147 | See end of file for license information. 148 | 149 | */ 150 | 151 | #ifndef INCLUDE_STB_IMAGE_WRITE_H 152 | #define INCLUDE_STB_IMAGE_WRITE_H 153 | 154 | #include 155 | 156 | // if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' 157 | #ifndef STBIWDEF 158 | #ifdef STB_IMAGE_WRITE_STATIC 159 | #define STBIWDEF static 160 | #else 161 | #ifdef __cplusplus 162 | #define STBIWDEF extern "C" 163 | #else 164 | #define STBIWDEF extern 165 | #endif 166 | #endif 167 | #endif 168 | 169 | #ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations 170 | STBIWDEF int stbi_write_tga_with_rle; 171 | STBIWDEF int stbi_write_png_compression_level; 172 | STBIWDEF int stbi_write_force_png_filter; 173 | #endif 174 | 175 | #ifndef STBI_WRITE_NO_STDIO 176 | STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); 177 | STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); 178 | STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); 179 | STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); 180 | STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); 181 | 182 | #ifdef STBIW_WINDOWS_UTF8 183 | STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); 184 | #endif 185 | #endif 186 | 187 | typedef void stbi_write_func(void *context, void *data, int size); 188 | 189 | STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); 190 | STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 191 | STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 192 | STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); 193 | STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); 194 | 195 | STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); 196 | 197 | #endif//INCLUDE_STB_IMAGE_WRITE_H 198 | 199 | #ifdef STB_IMAGE_WRITE_IMPLEMENTATION 200 | 201 | #ifdef _WIN32 202 | #ifndef _CRT_SECURE_NO_WARNINGS 203 | #define _CRT_SECURE_NO_WARNINGS 204 | #endif 205 | #ifndef _CRT_NONSTDC_NO_DEPRECATE 206 | #define _CRT_NONSTDC_NO_DEPRECATE 207 | #endif 208 | #endif 209 | 210 | #ifndef STBI_WRITE_NO_STDIO 211 | #include 212 | #endif // STBI_WRITE_NO_STDIO 213 | 214 | #include 215 | #include 216 | #include 217 | #include 218 | 219 | #if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) 220 | // ok 221 | #elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) 222 | // ok 223 | #else 224 | #error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." 225 | #endif 226 | 227 | #ifndef STBIW_MALLOC 228 | #define STBIW_MALLOC(sz) malloc(sz) 229 | #define STBIW_REALLOC(p,newsz) realloc(p,newsz) 230 | #define STBIW_FREE(p) free(p) 231 | #endif 232 | 233 | #ifndef STBIW_REALLOC_SIZED 234 | #define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) 235 | #endif 236 | 237 | 238 | #ifndef STBIW_MEMMOVE 239 | #define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) 240 | #endif 241 | 242 | 243 | #ifndef STBIW_ASSERT 244 | #include 245 | #define STBIW_ASSERT(x) assert(x) 246 | #endif 247 | 248 | #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) 249 | 250 | #ifdef STB_IMAGE_WRITE_STATIC 251 | static int stbi_write_png_compression_level = 8; 252 | static int stbi_write_tga_with_rle = 1; 253 | static int stbi_write_force_png_filter = -1; 254 | #else 255 | int stbi_write_png_compression_level = 8; 256 | int stbi_write_tga_with_rle = 1; 257 | int stbi_write_force_png_filter = -1; 258 | #endif 259 | 260 | static int stbi__flip_vertically_on_write = 0; 261 | 262 | STBIWDEF void stbi_flip_vertically_on_write(int flag) 263 | { 264 | stbi__flip_vertically_on_write = flag; 265 | } 266 | 267 | typedef struct 268 | { 269 | stbi_write_func *func; 270 | void *context; 271 | unsigned char buffer[64]; 272 | int buf_used; 273 | } stbi__write_context; 274 | 275 | // initialize a callback-based context 276 | static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) 277 | { 278 | s->func = c; 279 | s->context = context; 280 | } 281 | 282 | #ifndef STBI_WRITE_NO_STDIO 283 | 284 | static void stbi__stdio_write(void *context, void *data, int size) 285 | { 286 | fwrite(data,1,size,(FILE*) context); 287 | } 288 | 289 | #if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) 290 | #ifdef __cplusplus 291 | #define STBIW_EXTERN extern "C" 292 | #else 293 | #define STBIW_EXTERN extern 294 | #endif 295 | STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); 296 | STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); 297 | 298 | STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) 299 | { 300 | return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); 301 | } 302 | #endif 303 | 304 | static FILE *stbiw__fopen(char const *filename, char const *mode) 305 | { 306 | FILE *f; 307 | #if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) 308 | wchar_t wMode[64]; 309 | wchar_t wFilename[1024]; 310 | if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) 311 | return 0; 312 | 313 | if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) 314 | return 0; 315 | 316 | #if defined(_MSC_VER) && _MSC_VER >= 1400 317 | if (0 != _wfopen_s(&f, wFilename, wMode)) 318 | f = 0; 319 | #else 320 | f = _wfopen(wFilename, wMode); 321 | #endif 322 | 323 | #elif defined(_MSC_VER) && _MSC_VER >= 1400 324 | if (0 != fopen_s(&f, filename, mode)) 325 | f=0; 326 | #else 327 | f = fopen(filename, mode); 328 | #endif 329 | return f; 330 | } 331 | 332 | static int stbi__start_write_file(stbi__write_context *s, const char *filename) 333 | { 334 | FILE *f = stbiw__fopen(filename, "wb"); 335 | stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); 336 | return f != NULL; 337 | } 338 | 339 | static void stbi__end_write_file(stbi__write_context *s) 340 | { 341 | fclose((FILE *)s->context); 342 | } 343 | 344 | #endif // !STBI_WRITE_NO_STDIO 345 | 346 | typedef unsigned int stbiw_uint32; 347 | typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; 348 | 349 | static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) 350 | { 351 | while (*fmt) { 352 | switch (*fmt++) { 353 | case ' ': break; 354 | case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); 355 | s->func(s->context,&x,1); 356 | break; } 357 | case '2': { int x = va_arg(v,int); 358 | unsigned char b[2]; 359 | b[0] = STBIW_UCHAR(x); 360 | b[1] = STBIW_UCHAR(x>>8); 361 | s->func(s->context,b,2); 362 | break; } 363 | case '4': { stbiw_uint32 x = va_arg(v,int); 364 | unsigned char b[4]; 365 | b[0]=STBIW_UCHAR(x); 366 | b[1]=STBIW_UCHAR(x>>8); 367 | b[2]=STBIW_UCHAR(x>>16); 368 | b[3]=STBIW_UCHAR(x>>24); 369 | s->func(s->context,b,4); 370 | break; } 371 | default: 372 | STBIW_ASSERT(0); 373 | return; 374 | } 375 | } 376 | } 377 | 378 | static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) 379 | { 380 | va_list v; 381 | va_start(v, fmt); 382 | stbiw__writefv(s, fmt, v); 383 | va_end(v); 384 | } 385 | 386 | static void stbiw__write_flush(stbi__write_context *s) 387 | { 388 | if (s->buf_used) { 389 | s->func(s->context, &s->buffer, s->buf_used); 390 | s->buf_used = 0; 391 | } 392 | } 393 | 394 | static void stbiw__putc(stbi__write_context *s, unsigned char c) 395 | { 396 | s->func(s->context, &c, 1); 397 | } 398 | 399 | static void stbiw__write1(stbi__write_context *s, unsigned char a) 400 | { 401 | if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) 402 | stbiw__write_flush(s); 403 | s->buffer[s->buf_used++] = a; 404 | } 405 | 406 | static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) 407 | { 408 | int n; 409 | if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) 410 | stbiw__write_flush(s); 411 | n = s->buf_used; 412 | s->buf_used = n+3; 413 | s->buffer[n+0] = a; 414 | s->buffer[n+1] = b; 415 | s->buffer[n+2] = c; 416 | } 417 | 418 | static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) 419 | { 420 | unsigned char bg[3] = { 255, 0, 255}, px[3]; 421 | int k; 422 | 423 | if (write_alpha < 0) 424 | stbiw__write1(s, d[comp - 1]); 425 | 426 | switch (comp) { 427 | case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case 428 | case 1: 429 | if (expand_mono) 430 | stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp 431 | else 432 | stbiw__write1(s, d[0]); // monochrome TGA 433 | break; 434 | case 4: 435 | if (!write_alpha) { 436 | // composite against pink background 437 | for (k = 0; k < 3; ++k) 438 | px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; 439 | stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); 440 | break; 441 | } 442 | /* FALLTHROUGH */ 443 | case 3: 444 | stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); 445 | break; 446 | } 447 | if (write_alpha > 0) 448 | stbiw__write1(s, d[comp - 1]); 449 | } 450 | 451 | static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) 452 | { 453 | stbiw_uint32 zero = 0; 454 | int i,j, j_end; 455 | 456 | if (y <= 0) 457 | return; 458 | 459 | if (stbi__flip_vertically_on_write) 460 | vdir *= -1; 461 | 462 | if (vdir < 0) { 463 | j_end = -1; j = y-1; 464 | } else { 465 | j_end = y; j = 0; 466 | } 467 | 468 | for (; j != j_end; j += vdir) { 469 | for (i=0; i < x; ++i) { 470 | unsigned char *d = (unsigned char *) data + (j*x+i)*comp; 471 | stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); 472 | } 473 | stbiw__write_flush(s); 474 | s->func(s->context, &zero, scanline_pad); 475 | } 476 | } 477 | 478 | static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) 479 | { 480 | if (y < 0 || x < 0) { 481 | return 0; 482 | } else { 483 | va_list v; 484 | va_start(v, fmt); 485 | stbiw__writefv(s, fmt, v); 486 | va_end(v); 487 | stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); 488 | return 1; 489 | } 490 | } 491 | 492 | static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) 493 | { 494 | if (comp != 4) { 495 | // write RGB bitmap 496 | int pad = (-x*3) & 3; 497 | return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, 498 | "11 4 22 4" "4 44 22 444444", 499 | 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header 500 | 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header 501 | } else { 502 | // RGBA bitmaps need a v4 header 503 | // use BI_BITFIELDS mode with 32bpp and alpha mask 504 | // (straight BI_RGB with alpha mask doesn't work in most readers) 505 | return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0, 506 | "11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444", 507 | 'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header 508 | 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header 509 | } 510 | } 511 | 512 | STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) 513 | { 514 | stbi__write_context s = { 0 }; 515 | stbi__start_write_callbacks(&s, func, context); 516 | return stbi_write_bmp_core(&s, x, y, comp, data); 517 | } 518 | 519 | #ifndef STBI_WRITE_NO_STDIO 520 | STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) 521 | { 522 | stbi__write_context s = { 0 }; 523 | if (stbi__start_write_file(&s,filename)) { 524 | int r = stbi_write_bmp_core(&s, x, y, comp, data); 525 | stbi__end_write_file(&s); 526 | return r; 527 | } else 528 | return 0; 529 | } 530 | #endif //!STBI_WRITE_NO_STDIO 531 | 532 | static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) 533 | { 534 | int has_alpha = (comp == 2 || comp == 4); 535 | int colorbytes = has_alpha ? comp-1 : comp; 536 | int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 537 | 538 | if (y < 0 || x < 0) 539 | return 0; 540 | 541 | if (!stbi_write_tga_with_rle) { 542 | return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, 543 | "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); 544 | } else { 545 | int i,j,k; 546 | int jend, jdir; 547 | 548 | stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); 549 | 550 | if (stbi__flip_vertically_on_write) { 551 | j = 0; 552 | jend = y; 553 | jdir = 1; 554 | } else { 555 | j = y-1; 556 | jend = -1; 557 | jdir = -1; 558 | } 559 | for (; j != jend; j += jdir) { 560 | unsigned char *row = (unsigned char *) data + j * x * comp; 561 | int len; 562 | 563 | for (i = 0; i < x; i += len) { 564 | unsigned char *begin = row + i * comp; 565 | int diff = 1; 566 | len = 1; 567 | 568 | if (i < x - 1) { 569 | ++len; 570 | diff = memcmp(begin, row + (i + 1) * comp, comp); 571 | if (diff) { 572 | const unsigned char *prev = begin; 573 | for (k = i + 2; k < x && len < 128; ++k) { 574 | if (memcmp(prev, row + k * comp, comp)) { 575 | prev += comp; 576 | ++len; 577 | } else { 578 | --len; 579 | break; 580 | } 581 | } 582 | } else { 583 | for (k = i + 2; k < x && len < 128; ++k) { 584 | if (!memcmp(begin, row + k * comp, comp)) { 585 | ++len; 586 | } else { 587 | break; 588 | } 589 | } 590 | } 591 | } 592 | 593 | if (diff) { 594 | unsigned char header = STBIW_UCHAR(len - 1); 595 | stbiw__write1(s, header); 596 | for (k = 0; k < len; ++k) { 597 | stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); 598 | } 599 | } else { 600 | unsigned char header = STBIW_UCHAR(len - 129); 601 | stbiw__write1(s, header); 602 | stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); 603 | } 604 | } 605 | } 606 | stbiw__write_flush(s); 607 | } 608 | return 1; 609 | } 610 | 611 | STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) 612 | { 613 | stbi__write_context s = { 0 }; 614 | stbi__start_write_callbacks(&s, func, context); 615 | return stbi_write_tga_core(&s, x, y, comp, (void *) data); 616 | } 617 | 618 | #ifndef STBI_WRITE_NO_STDIO 619 | STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) 620 | { 621 | stbi__write_context s = { 0 }; 622 | if (stbi__start_write_file(&s,filename)) { 623 | int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); 624 | stbi__end_write_file(&s); 625 | return r; 626 | } else 627 | return 0; 628 | } 629 | #endif 630 | 631 | // ************************************************************************************************* 632 | // Radiance RGBE HDR writer 633 | // by Baldur Karlsson 634 | 635 | #define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) 636 | 637 | #ifndef STBI_WRITE_NO_STDIO 638 | 639 | static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) 640 | { 641 | int exponent; 642 | float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); 643 | 644 | if (maxcomp < 1e-32f) { 645 | rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; 646 | } else { 647 | float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; 648 | 649 | rgbe[0] = (unsigned char)(linear[0] * normalize); 650 | rgbe[1] = (unsigned char)(linear[1] * normalize); 651 | rgbe[2] = (unsigned char)(linear[2] * normalize); 652 | rgbe[3] = (unsigned char)(exponent + 128); 653 | } 654 | } 655 | 656 | static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) 657 | { 658 | unsigned char lengthbyte = STBIW_UCHAR(length+128); 659 | STBIW_ASSERT(length+128 <= 255); 660 | s->func(s->context, &lengthbyte, 1); 661 | s->func(s->context, &databyte, 1); 662 | } 663 | 664 | static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) 665 | { 666 | unsigned char lengthbyte = STBIW_UCHAR(length); 667 | STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code 668 | s->func(s->context, &lengthbyte, 1); 669 | s->func(s->context, data, length); 670 | } 671 | 672 | static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) 673 | { 674 | unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; 675 | unsigned char rgbe[4]; 676 | float linear[3]; 677 | int x; 678 | 679 | scanlineheader[2] = (width&0xff00)>>8; 680 | scanlineheader[3] = (width&0x00ff); 681 | 682 | /* skip RLE for images too small or large */ 683 | if (width < 8 || width >= 32768) { 684 | for (x=0; x < width; x++) { 685 | switch (ncomp) { 686 | case 4: /* fallthrough */ 687 | case 3: linear[2] = scanline[x*ncomp + 2]; 688 | linear[1] = scanline[x*ncomp + 1]; 689 | linear[0] = scanline[x*ncomp + 0]; 690 | break; 691 | default: 692 | linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; 693 | break; 694 | } 695 | stbiw__linear_to_rgbe(rgbe, linear); 696 | s->func(s->context, rgbe, 4); 697 | } 698 | } else { 699 | int c,r; 700 | /* encode into scratch buffer */ 701 | for (x=0; x < width; x++) { 702 | switch(ncomp) { 703 | case 4: /* fallthrough */ 704 | case 3: linear[2] = scanline[x*ncomp + 2]; 705 | linear[1] = scanline[x*ncomp + 1]; 706 | linear[0] = scanline[x*ncomp + 0]; 707 | break; 708 | default: 709 | linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; 710 | break; 711 | } 712 | stbiw__linear_to_rgbe(rgbe, linear); 713 | scratch[x + width*0] = rgbe[0]; 714 | scratch[x + width*1] = rgbe[1]; 715 | scratch[x + width*2] = rgbe[2]; 716 | scratch[x + width*3] = rgbe[3]; 717 | } 718 | 719 | s->func(s->context, scanlineheader, 4); 720 | 721 | /* RLE each component separately */ 722 | for (c=0; c < 4; c++) { 723 | unsigned char *comp = &scratch[width*c]; 724 | 725 | x = 0; 726 | while (x < width) { 727 | // find first run 728 | r = x; 729 | while (r+2 < width) { 730 | if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) 731 | break; 732 | ++r; 733 | } 734 | if (r+2 >= width) 735 | r = width; 736 | // dump up to first run 737 | while (x < r) { 738 | int len = r-x; 739 | if (len > 128) len = 128; 740 | stbiw__write_dump_data(s, len, &comp[x]); 741 | x += len; 742 | } 743 | // if there's a run, output it 744 | if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd 745 | // find next byte after run 746 | while (r < width && comp[r] == comp[x]) 747 | ++r; 748 | // output run up to r 749 | while (x < r) { 750 | int len = r-x; 751 | if (len > 127) len = 127; 752 | stbiw__write_run_data(s, len, comp[x]); 753 | x += len; 754 | } 755 | } 756 | } 757 | } 758 | } 759 | } 760 | 761 | static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) 762 | { 763 | if (y <= 0 || x <= 0 || data == NULL) 764 | return 0; 765 | else { 766 | // Each component is stored separately. Allocate scratch space for full output scanline. 767 | unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); 768 | int i, len; 769 | char buffer[128]; 770 | char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; 771 | s->func(s->context, header, sizeof(header)-1); 772 | 773 | #ifdef __STDC_LIB_EXT1__ 774 | len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); 775 | #else 776 | len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); 777 | #endif 778 | s->func(s->context, buffer, len); 779 | 780 | for(i=0; i < y; i++) 781 | stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); 782 | STBIW_FREE(scratch); 783 | return 1; 784 | } 785 | } 786 | 787 | STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) 788 | { 789 | stbi__write_context s = { 0 }; 790 | stbi__start_write_callbacks(&s, func, context); 791 | return stbi_write_hdr_core(&s, x, y, comp, (float *) data); 792 | } 793 | 794 | STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) 795 | { 796 | stbi__write_context s = { 0 }; 797 | if (stbi__start_write_file(&s,filename)) { 798 | int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); 799 | stbi__end_write_file(&s); 800 | return r; 801 | } else 802 | return 0; 803 | } 804 | #endif // STBI_WRITE_NO_STDIO 805 | 806 | 807 | ////////////////////////////////////////////////////////////////////////////// 808 | // 809 | // PNG writer 810 | // 811 | 812 | #ifndef STBIW_ZLIB_COMPRESS 813 | // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() 814 | #define stbiw__sbraw(a) ((int *) (void *) (a) - 2) 815 | #define stbiw__sbm(a) stbiw__sbraw(a)[0] 816 | #define stbiw__sbn(a) stbiw__sbraw(a)[1] 817 | 818 | #define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) 819 | #define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) 820 | #define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) 821 | 822 | #define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) 823 | #define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) 824 | #define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) 825 | 826 | static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) 827 | { 828 | int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; 829 | void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); 830 | STBIW_ASSERT(p); 831 | if (p) { 832 | if (!*arr) ((int *) p)[1] = 0; 833 | *arr = (void *) ((int *) p + 2); 834 | stbiw__sbm(*arr) = m; 835 | } 836 | return *arr; 837 | } 838 | 839 | static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) 840 | { 841 | while (*bitcount >= 8) { 842 | stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); 843 | *bitbuffer >>= 8; 844 | *bitcount -= 8; 845 | } 846 | return data; 847 | } 848 | 849 | static int stbiw__zlib_bitrev(int code, int codebits) 850 | { 851 | int res=0; 852 | while (codebits--) { 853 | res = (res << 1) | (code & 1); 854 | code >>= 1; 855 | } 856 | return res; 857 | } 858 | 859 | static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) 860 | { 861 | int i; 862 | for (i=0; i < limit && i < 258; ++i) 863 | if (a[i] != b[i]) break; 864 | return i; 865 | } 866 | 867 | static unsigned int stbiw__zhash(unsigned char *data) 868 | { 869 | stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); 870 | hash ^= hash << 3; 871 | hash += hash >> 5; 872 | hash ^= hash << 4; 873 | hash += hash >> 17; 874 | hash ^= hash << 25; 875 | hash += hash >> 6; 876 | return hash; 877 | } 878 | 879 | #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) 880 | #define stbiw__zlib_add(code,codebits) \ 881 | (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) 882 | #define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) 883 | // default huffman tables 884 | #define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) 885 | #define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) 886 | #define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) 887 | #define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) 888 | #define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) 889 | #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) 890 | 891 | #define stbiw__ZHASH 16384 892 | 893 | #endif // STBIW_ZLIB_COMPRESS 894 | 895 | STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) 896 | { 897 | #ifdef STBIW_ZLIB_COMPRESS 898 | // user provided a zlib compress implementation, use that 899 | return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); 900 | #else // use builtin 901 | static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; 902 | static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; 903 | static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; 904 | static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; 905 | unsigned int bitbuf=0; 906 | int i,j, bitcount=0; 907 | unsigned char *out = NULL; 908 | unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); 909 | if (hash_table == NULL) 910 | return NULL; 911 | if (quality < 5) quality = 5; 912 | 913 | stbiw__sbpush(out, 0x78); // DEFLATE 32K window 914 | stbiw__sbpush(out, 0x5e); // FLEVEL = 1 915 | stbiw__zlib_add(1,1); // BFINAL = 1 916 | stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman 917 | 918 | for (i=0; i < stbiw__ZHASH; ++i) 919 | hash_table[i] = NULL; 920 | 921 | i=0; 922 | while (i < data_len-3) { 923 | // hash next 3 bytes of data to be compressed 924 | int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; 925 | unsigned char *bestloc = 0; 926 | unsigned char **hlist = hash_table[h]; 927 | int n = stbiw__sbcount(hlist); 928 | for (j=0; j < n; ++j) { 929 | if (hlist[j]-data > i-32768) { // if entry lies within window 930 | int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); 931 | if (d >= best) { best=d; bestloc=hlist[j]; } 932 | } 933 | } 934 | // when hash table entry is too long, delete half the entries 935 | if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { 936 | STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); 937 | stbiw__sbn(hash_table[h]) = quality; 938 | } 939 | stbiw__sbpush(hash_table[h],data+i); 940 | 941 | if (bestloc) { 942 | // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal 943 | h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); 944 | hlist = hash_table[h]; 945 | n = stbiw__sbcount(hlist); 946 | for (j=0; j < n; ++j) { 947 | if (hlist[j]-data > i-32767) { 948 | int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); 949 | if (e > best) { // if next match is better, bail on current match 950 | bestloc = NULL; 951 | break; 952 | } 953 | } 954 | } 955 | } 956 | 957 | if (bestloc) { 958 | int d = (int) (data+i - bestloc); // distance back 959 | STBIW_ASSERT(d <= 32767 && best <= 258); 960 | for (j=0; best > lengthc[j+1]-1; ++j); 961 | stbiw__zlib_huff(j+257); 962 | if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); 963 | for (j=0; d > distc[j+1]-1; ++j); 964 | stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); 965 | if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); 966 | i += best; 967 | } else { 968 | stbiw__zlib_huffb(data[i]); 969 | ++i; 970 | } 971 | } 972 | // write out final bytes 973 | for (;i < data_len; ++i) 974 | stbiw__zlib_huffb(data[i]); 975 | stbiw__zlib_huff(256); // end of block 976 | // pad with 0 bits to byte boundary 977 | while (bitcount) 978 | stbiw__zlib_add(0,1); 979 | 980 | for (i=0; i < stbiw__ZHASH; ++i) 981 | (void) stbiw__sbfree(hash_table[i]); 982 | STBIW_FREE(hash_table); 983 | 984 | // store uncompressed instead if compression was worse 985 | if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) { 986 | stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 987 | for (j = 0; j < data_len;) { 988 | int blocklen = data_len - j; 989 | if (blocklen > 32767) blocklen = 32767; 990 | stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression 991 | stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN 992 | stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8)); 993 | stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN 994 | stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8)); 995 | memcpy(out+stbiw__sbn(out), data+j, blocklen); 996 | stbiw__sbn(out) += blocklen; 997 | j += blocklen; 998 | } 999 | } 1000 | 1001 | { 1002 | // compute adler32 on input 1003 | unsigned int s1=1, s2=0; 1004 | int blocklen = (int) (data_len % 5552); 1005 | j=0; 1006 | while (j < data_len) { 1007 | for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } 1008 | s1 %= 65521; s2 %= 65521; 1009 | j += blocklen; 1010 | blocklen = 5552; 1011 | } 1012 | stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); 1013 | stbiw__sbpush(out, STBIW_UCHAR(s2)); 1014 | stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); 1015 | stbiw__sbpush(out, STBIW_UCHAR(s1)); 1016 | } 1017 | *out_len = stbiw__sbn(out); 1018 | // make returned pointer freeable 1019 | STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); 1020 | return (unsigned char *) stbiw__sbraw(out); 1021 | #endif // STBIW_ZLIB_COMPRESS 1022 | } 1023 | 1024 | static unsigned int stbiw__crc32(unsigned char *buffer, int len) 1025 | { 1026 | #ifdef STBIW_CRC32 1027 | return STBIW_CRC32(buffer, len); 1028 | #else 1029 | static unsigned int crc_table[256] = 1030 | { 1031 | 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 1032 | 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 1033 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 1034 | 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 1035 | 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 1036 | 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 1037 | 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 1038 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 1039 | 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 1040 | 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 1041 | 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 1042 | 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 1043 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 1044 | 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 1045 | 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 1046 | 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 1047 | 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 1048 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 1049 | 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 1050 | 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 1051 | 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 1052 | 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 1053 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 1054 | 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 1055 | 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 1056 | 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 1057 | 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 1058 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 1059 | 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 1060 | 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 1061 | 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 1062 | 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D 1063 | }; 1064 | 1065 | unsigned int crc = ~0u; 1066 | int i; 1067 | for (i=0; i < len; ++i) 1068 | crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; 1069 | return ~crc; 1070 | #endif 1071 | } 1072 | 1073 | #define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) 1074 | #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); 1075 | #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) 1076 | 1077 | static void stbiw__wpcrc(unsigned char **data, int len) 1078 | { 1079 | unsigned int crc = stbiw__crc32(*data - len - 4, len+4); 1080 | stbiw__wp32(*data, crc); 1081 | } 1082 | 1083 | static unsigned char stbiw__paeth(int a, int b, int c) 1084 | { 1085 | int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); 1086 | if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); 1087 | if (pb <= pc) return STBIW_UCHAR(b); 1088 | return STBIW_UCHAR(c); 1089 | } 1090 | 1091 | // @OPTIMIZE: provide an option that always forces left-predict or paeth predict 1092 | static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) 1093 | { 1094 | static int mapping[] = { 0,1,2,3,4 }; 1095 | static int firstmap[] = { 0,1,0,5,6 }; 1096 | int *mymap = (y != 0) ? mapping : firstmap; 1097 | int i; 1098 | int type = mymap[filter_type]; 1099 | unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); 1100 | int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; 1101 | 1102 | if (type==0) { 1103 | memcpy(line_buffer, z, width*n); 1104 | return; 1105 | } 1106 | 1107 | // first loop isn't optimized since it's just one pixel 1108 | for (i = 0; i < n; ++i) { 1109 | switch (type) { 1110 | case 1: line_buffer[i] = z[i]; break; 1111 | case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; 1112 | case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; 1113 | case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; 1114 | case 5: line_buffer[i] = z[i]; break; 1115 | case 6: line_buffer[i] = z[i]; break; 1116 | } 1117 | } 1118 | switch (type) { 1119 | case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; 1120 | case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; 1121 | case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; 1122 | case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; 1123 | case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; 1124 | case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; 1125 | } 1126 | } 1127 | 1128 | STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) 1129 | { 1130 | int force_filter = stbi_write_force_png_filter; 1131 | int ctype[5] = { -1, 0, 4, 2, 6 }; 1132 | unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; 1133 | unsigned char *out,*o, *filt, *zlib; 1134 | signed char *line_buffer; 1135 | int j,zlen; 1136 | 1137 | if (stride_bytes == 0) 1138 | stride_bytes = x * n; 1139 | 1140 | if (force_filter >= 5) { 1141 | force_filter = -1; 1142 | } 1143 | 1144 | filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; 1145 | line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } 1146 | for (j=0; j < y; ++j) { 1147 | int filter_type; 1148 | if (force_filter > -1) { 1149 | filter_type = force_filter; 1150 | stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); 1151 | } else { // Estimate the best filter by running through all of them: 1152 | int best_filter = 0, best_filter_val = 0x7fffffff, est, i; 1153 | for (filter_type = 0; filter_type < 5; filter_type++) { 1154 | stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); 1155 | 1156 | // Estimate the entropy of the line using this filter; the less, the better. 1157 | est = 0; 1158 | for (i = 0; i < x*n; ++i) { 1159 | est += abs((signed char) line_buffer[i]); 1160 | } 1161 | if (est < best_filter_val) { 1162 | best_filter_val = est; 1163 | best_filter = filter_type; 1164 | } 1165 | } 1166 | if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it 1167 | stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); 1168 | filter_type = best_filter; 1169 | } 1170 | } 1171 | // when we get here, filter_type contains the filter type, and line_buffer contains the data 1172 | filt[j*(x*n+1)] = (unsigned char) filter_type; 1173 | STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); 1174 | } 1175 | STBIW_FREE(line_buffer); 1176 | zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); 1177 | STBIW_FREE(filt); 1178 | if (!zlib) return 0; 1179 | 1180 | // each tag requires 12 bytes of overhead 1181 | out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); 1182 | if (!out) return 0; 1183 | *out_len = 8 + 12+13 + 12+zlen + 12; 1184 | 1185 | o=out; 1186 | STBIW_MEMMOVE(o,sig,8); o+= 8; 1187 | stbiw__wp32(o, 13); // header length 1188 | stbiw__wptag(o, "IHDR"); 1189 | stbiw__wp32(o, x); 1190 | stbiw__wp32(o, y); 1191 | *o++ = 8; 1192 | *o++ = STBIW_UCHAR(ctype[n]); 1193 | *o++ = 0; 1194 | *o++ = 0; 1195 | *o++ = 0; 1196 | stbiw__wpcrc(&o,13); 1197 | 1198 | stbiw__wp32(o, zlen); 1199 | stbiw__wptag(o, "IDAT"); 1200 | STBIW_MEMMOVE(o, zlib, zlen); 1201 | o += zlen; 1202 | STBIW_FREE(zlib); 1203 | stbiw__wpcrc(&o, zlen); 1204 | 1205 | stbiw__wp32(o,0); 1206 | stbiw__wptag(o, "IEND"); 1207 | stbiw__wpcrc(&o,0); 1208 | 1209 | STBIW_ASSERT(o == out + *out_len); 1210 | 1211 | return out; 1212 | } 1213 | 1214 | #ifndef STBI_WRITE_NO_STDIO 1215 | STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) 1216 | { 1217 | FILE *f; 1218 | int len; 1219 | unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); 1220 | if (png == NULL) return 0; 1221 | 1222 | f = stbiw__fopen(filename, "wb"); 1223 | if (!f) { STBIW_FREE(png); return 0; } 1224 | fwrite(png, 1, len, f); 1225 | fclose(f); 1226 | STBIW_FREE(png); 1227 | return 1; 1228 | } 1229 | #endif 1230 | 1231 | STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) 1232 | { 1233 | int len; 1234 | unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); 1235 | if (png == NULL) return 0; 1236 | func(context, png, len); 1237 | STBIW_FREE(png); 1238 | return 1; 1239 | } 1240 | 1241 | 1242 | /* *************************************************************************** 1243 | * 1244 | * JPEG writer 1245 | * 1246 | * This is based on Jon Olick's jo_jpeg.cpp: 1247 | * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html 1248 | */ 1249 | 1250 | static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, 1251 | 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; 1252 | 1253 | static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { 1254 | int bitBuf = *bitBufP, bitCnt = *bitCntP; 1255 | bitCnt += bs[1]; 1256 | bitBuf |= bs[0] << (24 - bitCnt); 1257 | while(bitCnt >= 8) { 1258 | unsigned char c = (bitBuf >> 16) & 255; 1259 | stbiw__putc(s, c); 1260 | if(c == 255) { 1261 | stbiw__putc(s, 0); 1262 | } 1263 | bitBuf <<= 8; 1264 | bitCnt -= 8; 1265 | } 1266 | *bitBufP = bitBuf; 1267 | *bitCntP = bitCnt; 1268 | } 1269 | 1270 | static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { 1271 | float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; 1272 | float z1, z2, z3, z4, z5, z11, z13; 1273 | 1274 | float tmp0 = d0 + d7; 1275 | float tmp7 = d0 - d7; 1276 | float tmp1 = d1 + d6; 1277 | float tmp6 = d1 - d6; 1278 | float tmp2 = d2 + d5; 1279 | float tmp5 = d2 - d5; 1280 | float tmp3 = d3 + d4; 1281 | float tmp4 = d3 - d4; 1282 | 1283 | // Even part 1284 | float tmp10 = tmp0 + tmp3; // phase 2 1285 | float tmp13 = tmp0 - tmp3; 1286 | float tmp11 = tmp1 + tmp2; 1287 | float tmp12 = tmp1 - tmp2; 1288 | 1289 | d0 = tmp10 + tmp11; // phase 3 1290 | d4 = tmp10 - tmp11; 1291 | 1292 | z1 = (tmp12 + tmp13) * 0.707106781f; // c4 1293 | d2 = tmp13 + z1; // phase 5 1294 | d6 = tmp13 - z1; 1295 | 1296 | // Odd part 1297 | tmp10 = tmp4 + tmp5; // phase 2 1298 | tmp11 = tmp5 + tmp6; 1299 | tmp12 = tmp6 + tmp7; 1300 | 1301 | // The rotator is modified from fig 4-8 to avoid extra negations. 1302 | z5 = (tmp10 - tmp12) * 0.382683433f; // c6 1303 | z2 = tmp10 * 0.541196100f + z5; // c2-c6 1304 | z4 = tmp12 * 1.306562965f + z5; // c2+c6 1305 | z3 = tmp11 * 0.707106781f; // c4 1306 | 1307 | z11 = tmp7 + z3; // phase 5 1308 | z13 = tmp7 - z3; 1309 | 1310 | *d5p = z13 + z2; // phase 6 1311 | *d3p = z13 - z2; 1312 | *d1p = z11 + z4; 1313 | *d7p = z11 - z4; 1314 | 1315 | *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; 1316 | } 1317 | 1318 | static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { 1319 | int tmp1 = val < 0 ? -val : val; 1320 | val = val < 0 ? val-1 : val; 1321 | bits[1] = 1; 1322 | while(tmp1 >>= 1) { 1323 | ++bits[1]; 1324 | } 1325 | bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { 1368 | } 1369 | // end0pos = first element in reverse order !=0 1370 | if(end0pos == 0) { 1371 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); 1372 | return DU[0]; 1373 | } 1374 | for(i = 1; i <= end0pos; ++i) { 1375 | int startpos = i; 1376 | int nrzeroes; 1377 | unsigned short bits[2]; 1378 | for (; DU[i]==0 && i<=end0pos; ++i) { 1379 | } 1380 | nrzeroes = i-startpos; 1381 | if ( nrzeroes >= 16 ) { 1382 | int lng = nrzeroes>>4; 1383 | int nrmarker; 1384 | for (nrmarker=1; nrmarker <= lng; ++nrmarker) 1385 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); 1386 | nrzeroes &= 15; 1387 | } 1388 | stbiw__jpg_calcBits(DU[i], bits); 1389 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); 1390 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); 1391 | } 1392 | if(end0pos != 63) { 1393 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); 1394 | } 1395 | return DU[0]; 1396 | } 1397 | 1398 | static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { 1399 | // Constants that don't pollute global namespace 1400 | static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; 1401 | static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; 1402 | static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; 1403 | static const unsigned char std_ac_luminance_values[] = { 1404 | 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, 1405 | 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, 1406 | 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, 1407 | 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, 1408 | 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, 1409 | 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, 1410 | 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa 1411 | }; 1412 | static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; 1413 | static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; 1414 | static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; 1415 | static const unsigned char std_ac_chrominance_values[] = { 1416 | 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, 1417 | 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, 1418 | 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, 1419 | 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, 1420 | 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, 1421 | 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, 1422 | 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa 1423 | }; 1424 | // Huffman tables 1425 | static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; 1426 | static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; 1427 | static const unsigned short YAC_HT[256][2] = { 1428 | {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1429 | {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1430 | {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1431 | {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1432 | {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1433 | {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1434 | {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1435 | {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1436 | {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1437 | {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1438 | {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1439 | {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1440 | {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1441 | {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1442 | {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, 1443 | {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} 1444 | }; 1445 | static const unsigned short UVAC_HT[256][2] = { 1446 | {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1447 | {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1448 | {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1449 | {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1450 | {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1451 | {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1452 | {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1453 | {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1454 | {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1455 | {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1456 | {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1457 | {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1458 | {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1459 | {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, 1460 | {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, 1461 | {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} 1462 | }; 1463 | static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, 1464 | 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; 1465 | static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, 1466 | 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; 1467 | static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, 1468 | 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; 1469 | 1470 | int row, col, i, k, subsample; 1471 | float fdtbl_Y[64], fdtbl_UV[64]; 1472 | unsigned char YTable[64], UVTable[64]; 1473 | 1474 | if(!data || !width || !height || comp > 4 || comp < 1) { 1475 | return 0; 1476 | } 1477 | 1478 | quality = quality ? quality : 90; 1479 | subsample = quality <= 90 ? 1 : 0; 1480 | quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; 1481 | quality = quality < 50 ? 5000 / quality : 200 - quality * 2; 1482 | 1483 | for(i = 0; i < 64; ++i) { 1484 | int uvti, yti = (YQT[i]*quality+50)/100; 1485 | YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); 1486 | uvti = (UVQT[i]*quality+50)/100; 1487 | UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); 1488 | } 1489 | 1490 | for(row = 0, k = 0; row < 8; ++row) { 1491 | for(col = 0; col < 8; ++col, ++k) { 1492 | fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); 1493 | fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); 1494 | } 1495 | } 1496 | 1497 | // Write Headers 1498 | { 1499 | static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; 1500 | static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; 1501 | const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), 1502 | 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; 1503 | s->func(s->context, (void*)head0, sizeof(head0)); 1504 | s->func(s->context, (void*)YTable, sizeof(YTable)); 1505 | stbiw__putc(s, 1); 1506 | s->func(s->context, UVTable, sizeof(UVTable)); 1507 | s->func(s->context, (void*)head1, sizeof(head1)); 1508 | s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); 1509 | s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); 1510 | stbiw__putc(s, 0x10); // HTYACinfo 1511 | s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); 1512 | s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); 1513 | stbiw__putc(s, 1); // HTUDCinfo 1514 | s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); 1515 | s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); 1516 | stbiw__putc(s, 0x11); // HTUACinfo 1517 | s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); 1518 | s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); 1519 | s->func(s->context, (void*)head2, sizeof(head2)); 1520 | } 1521 | 1522 | // Encode 8x8 macroblocks 1523 | { 1524 | static const unsigned short fillBits[] = {0x7F, 7}; 1525 | int DCY=0, DCU=0, DCV=0; 1526 | int bitBuf=0, bitCnt=0; 1527 | // comp == 2 is grey+alpha (alpha is ignored) 1528 | int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; 1529 | const unsigned char *dataR = (const unsigned char *)data; 1530 | const unsigned char *dataG = dataR + ofsG; 1531 | const unsigned char *dataB = dataR + ofsB; 1532 | int x, y, pos; 1533 | if(subsample) { 1534 | for(y = 0; y < height; y += 16) { 1535 | for(x = 0; x < width; x += 16) { 1536 | float Y[256], U[256], V[256]; 1537 | for(row = y, pos = 0; row < y+16; ++row) { 1538 | // row >= height => use last input row 1539 | int clamped_row = (row < height) ? row : height - 1; 1540 | int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; 1541 | for(col = x; col < x+16; ++col, ++pos) { 1542 | // if col >= width => use pixel from last input column 1543 | int p = base_p + ((col < width) ? col : (width-1))*comp; 1544 | float r = dataR[p], g = dataG[p], b = dataB[p]; 1545 | Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; 1546 | U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; 1547 | V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; 1548 | } 1549 | } 1550 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); 1551 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); 1552 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); 1553 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); 1554 | 1555 | // subsample U,V 1556 | { 1557 | float subU[64], subV[64]; 1558 | int yy, xx; 1559 | for(yy = 0, pos = 0; yy < 8; ++yy) { 1560 | for(xx = 0; xx < 8; ++xx, ++pos) { 1561 | int j = yy*32+xx*2; 1562 | subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; 1563 | subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; 1564 | } 1565 | } 1566 | DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); 1567 | DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); 1568 | } 1569 | } 1570 | } 1571 | } else { 1572 | for(y = 0; y < height; y += 8) { 1573 | for(x = 0; x < width; x += 8) { 1574 | float Y[64], U[64], V[64]; 1575 | for(row = y, pos = 0; row < y+8; ++row) { 1576 | // row >= height => use last input row 1577 | int clamped_row = (row < height) ? row : height - 1; 1578 | int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; 1579 | for(col = x; col < x+8; ++col, ++pos) { 1580 | // if col >= width => use pixel from last input column 1581 | int p = base_p + ((col < width) ? col : (width-1))*comp; 1582 | float r = dataR[p], g = dataG[p], b = dataB[p]; 1583 | Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; 1584 | U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; 1585 | V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; 1586 | } 1587 | } 1588 | 1589 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); 1590 | DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); 1591 | DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); 1592 | } 1593 | } 1594 | } 1595 | 1596 | // Do the bit alignment of the EOI marker 1597 | stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); 1598 | } 1599 | 1600 | // EOI 1601 | stbiw__putc(s, 0xFF); 1602 | stbiw__putc(s, 0xD9); 1603 | 1604 | return 1; 1605 | } 1606 | 1607 | STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) 1608 | { 1609 | stbi__write_context s = { 0 }; 1610 | stbi__start_write_callbacks(&s, func, context); 1611 | return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); 1612 | } 1613 | 1614 | 1615 | #ifndef STBI_WRITE_NO_STDIO 1616 | STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) 1617 | { 1618 | stbi__write_context s = { 0 }; 1619 | if (stbi__start_write_file(&s,filename)) { 1620 | int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); 1621 | stbi__end_write_file(&s); 1622 | return r; 1623 | } else 1624 | return 0; 1625 | } 1626 | #endif 1627 | 1628 | #endif // STB_IMAGE_WRITE_IMPLEMENTATION 1629 | 1630 | /* Revision history 1631 | 1.16 (2021-07-11) 1632 | make Deflate code emit uncompressed blocks when it would otherwise expand 1633 | support writing BMPs with alpha channel 1634 | 1.15 (2020-07-13) unknown 1635 | 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels 1636 | 1.13 1637 | 1.12 1638 | 1.11 (2019-08-11) 1639 | 1640 | 1.10 (2019-02-07) 1641 | support utf8 filenames in Windows; fix warnings and platform ifdefs 1642 | 1.09 (2018-02-11) 1643 | fix typo in zlib quality API, improve STB_I_W_STATIC in C++ 1644 | 1.08 (2018-01-29) 1645 | add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter 1646 | 1.07 (2017-07-24) 1647 | doc fix 1648 | 1.06 (2017-07-23) 1649 | writing JPEG (using Jon Olick's code) 1650 | 1.05 ??? 1651 | 1.04 (2017-03-03) 1652 | monochrome BMP expansion 1653 | 1.03 ??? 1654 | 1.02 (2016-04-02) 1655 | avoid allocating large structures on the stack 1656 | 1.01 (2016-01-16) 1657 | STBIW_REALLOC_SIZED: support allocators with no realloc support 1658 | avoid race-condition in crc initialization 1659 | minor compile issues 1660 | 1.00 (2015-09-14) 1661 | installable file IO function 1662 | 0.99 (2015-09-13) 1663 | warning fixes; TGA rle support 1664 | 0.98 (2015-04-08) 1665 | added STBIW_MALLOC, STBIW_ASSERT etc 1666 | 0.97 (2015-01-18) 1667 | fixed HDR asserts, rewrote HDR rle logic 1668 | 0.96 (2015-01-17) 1669 | add HDR output 1670 | fix monochrome BMP 1671 | 0.95 (2014-08-17) 1672 | add monochrome TGA output 1673 | 0.94 (2014-05-31) 1674 | rename private functions to avoid conflicts with stb_image.h 1675 | 0.93 (2014-05-27) 1676 | warning fixes 1677 | 0.92 (2010-08-01) 1678 | casts to unsigned char to fix warnings 1679 | 0.91 (2010-07-17) 1680 | first public release 1681 | 0.90 first internal release 1682 | */ 1683 | 1684 | /* 1685 | ------------------------------------------------------------------------------ 1686 | This software is available under 2 licenses -- choose whichever you prefer. 1687 | ------------------------------------------------------------------------------ 1688 | ALTERNATIVE A - MIT License 1689 | Copyright (c) 2017 Sean Barrett 1690 | Permission is hereby granted, free of charge, to any person obtaining a copy of 1691 | this software and associated documentation files (the "Software"), to deal in 1692 | the Software without restriction, including without limitation the rights to 1693 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 1694 | of the Software, and to permit persons to whom the Software is furnished to do 1695 | so, subject to the following conditions: 1696 | The above copyright notice and this permission notice shall be included in all 1697 | copies or substantial portions of the Software. 1698 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1699 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1700 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1701 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1702 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1703 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1704 | SOFTWARE. 1705 | ------------------------------------------------------------------------------ 1706 | ALTERNATIVE B - Public Domain (www.unlicense.org) 1707 | This is free and unencumbered software released into the public domain. 1708 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 1709 | software, either in source code form or as a compiled binary, for any purpose, 1710 | commercial or non-commercial, and by any means. 1711 | In jurisdictions that recognize copyright laws, the author or authors of this 1712 | software dedicate any and all copyright interest in the software to the public 1713 | domain. We make this dedication for the benefit of the public at large and to 1714 | the detriment of our heirs and successors. We intend this dedication to be an 1715 | overt act of relinquishment in perpetuity of all present and future rights to 1716 | this software under copyright law. 1717 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1718 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1719 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1720 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 1721 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 1722 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1723 | ------------------------------------------------------------------------------ 1724 | */ -------------------------------------------------------------------------------- /src/utf8.c: -------------------------------------------------------------------------------- 1 | // The latest version of this library is available on GitHub; 2 | // https://github.com/sheredom/utf8.h 3 | 4 | // This is free and unencumbered software released into the public domain. 5 | // 6 | // Anyone is free to copy, modify, publish, use, compile, sell, or 7 | // distribute this software, either in source code form or as a compiled 8 | // binary, for any purpose, commercial or non-commercial, and by any 9 | // means. 10 | // 11 | // In jurisdictions that recognize copyright laws, the author or authors 12 | // of this software dedicate any and all copyright interest in the 13 | // software to the public domain. We make this dedication for the benefit 14 | // of the public at large and to the detriment of our heirs and 15 | // successors. We intend this dedication to be an overt act of 16 | // relinquishment in perpetuity of all present and future rights to this 17 | // software under copyright law. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | // OTHER DEALINGS IN THE SOFTWARE. 26 | // 27 | // For more information, please refer to 28 | 29 | #include "utf8.h" 30 | 31 | void *utf8valid(const void *str) { 32 | const char *s = (const char *)str; 33 | 34 | while ('\0' != *s) { 35 | if (0xf0 == (0xf8 & *s)) { 36 | // ensure each of the 3 following bytes in this 4-byte 37 | // utf8 codepoint began with 0b10xxxxxx 38 | if ((0x80 != (0xc0 & s[1])) || (0x80 != (0xc0 & s[2])) || 39 | (0x80 != (0xc0 & s[3]))) { 40 | return (void *)s; 41 | } 42 | 43 | // ensure that our utf8 codepoint ended after 4 bytes 44 | if (0x80 == (0xc0 & s[4])) { 45 | return (void *)s; 46 | } 47 | 48 | // ensure that the top 5 bits of this 4-byte utf8 49 | // codepoint were not 0, as then we could have used 50 | // one of the smaller encodings 51 | if ((0 == (0x07 & s[0])) && (0 == (0x30 & s[1]))) { 52 | return (void *)s; 53 | } 54 | 55 | // 4-byte utf8 code point (began with 0b11110xxx) 56 | s += 4; 57 | } else if (0xe0 == (0xf0 & *s)) { 58 | // ensure each of the 2 following bytes in this 3-byte 59 | // utf8 codepoint began with 0b10xxxxxx 60 | if ((0x80 != (0xc0 & s[1])) || (0x80 != (0xc0 & s[2]))) { 61 | return (void *)s; 62 | } 63 | 64 | // ensure that our utf8 codepoint ended after 3 bytes 65 | if (0x80 == (0xc0 & s[3])) { 66 | return (void *)s; 67 | } 68 | 69 | // ensure that the top 5 bits of this 3-byte utf8 70 | // codepoint were not 0, as then we could have used 71 | // one of the smaller encodings 72 | if ((0 == (0x0f & s[0])) && (0 == (0x20 & s[1]))) { 73 | return (void *)s; 74 | } 75 | 76 | // 3-byte utf8 code point (began with 0b1110xxxx) 77 | s += 3; 78 | } else if (0xc0 == (0xe0 & *s)) { 79 | // ensure the 1 following byte in this 2-byte 80 | // utf8 codepoint began with 0b10xxxxxx 81 | if (0x80 != (0xc0 & s[1])) { 82 | return (void *)s; 83 | } 84 | 85 | // ensure that our utf8 codepoint ended after 2 bytes 86 | if (0x80 == (0xc0 & s[2])) { 87 | return (void *)s; 88 | } 89 | 90 | // ensure that the top 4 bits of this 2-byte utf8 91 | // codepoint were not 0, as then we could have used 92 | // one of the smaller encodings 93 | if (0 == (0x1e & s[0])) { 94 | return (void *)s; 95 | } 96 | 97 | // 2-byte utf8 code point (began with 0b110xxxxx) 98 | s += 2; 99 | } else if (0x00 == (0x80 & *s)) { 100 | // 1-byte ascii (began with 0b0xxxxxxx) 101 | s += 1; 102 | } else { 103 | // we have an invalid 0b1xxxxxxx utf8 code point entry 104 | return (void *)s; 105 | } 106 | } 107 | 108 | return 0; 109 | } 110 | 111 | int utf8codepointcalcsize(const void *str) { 112 | const char *s = (const char *)str; 113 | 114 | if (0xf0 == (0xf8 & s[0])) { 115 | // 4 byte utf8 codepoint 116 | return 4; 117 | } else if (0xe0 == (0xf0 & s[0])) { 118 | // 3 byte utf8 codepoint 119 | return 3; 120 | } else if (0xc0 == (0xe0 & s[0])) { 121 | // 2 byte utf8 codepoint 122 | return 2; 123 | } 124 | 125 | // 1 byte utf8 codepoint otherwise 126 | return 1; 127 | } 128 | 129 | void *utf8codepoint(const void *str, 130 | utf8_int32_t *out_codepoint) { 131 | const char *s = (const char *)str; 132 | 133 | if (0xf0 == (0xf8 & s[0])) { 134 | // 4 byte utf8 codepoint 135 | *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) | 136 | ((0x3f & s[2]) << 6) | (0x3f & s[3]); 137 | s += 4; 138 | } else if (0xe0 == (0xf0 & s[0])) { 139 | // 3 byte utf8 codepoint 140 | *out_codepoint = 141 | ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]); 142 | s += 3; 143 | } else if (0xc0 == (0xe0 & s[0])) { 144 | // 2 byte utf8 codepoint 145 | *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]); 146 | s += 2; 147 | } else { 148 | // 1 byte utf8 codepoint otherwise 149 | *out_codepoint = s[0]; 150 | s += 1; 151 | } 152 | 153 | return (void *)s; 154 | } 155 | 156 | void *utf8str(const void *haystack, const void *needle) { 157 | const char *h = (const char *)haystack; 158 | utf8_int32_t throwaway_codepoint; 159 | 160 | // if needle has no utf8 codepoints before the null terminating 161 | // byte then return haystack 162 | if ('\0' == *((const char *)needle)) { 163 | return (void *)haystack; 164 | } 165 | 166 | while ('\0' != *h) { 167 | const char *maybeMatch = h; 168 | const char *n = (const char *)needle; 169 | 170 | while (*h == *n && (*h != '\0' && *n != '\0')) { 171 | n++; 172 | h++; 173 | } 174 | 175 | if ('\0' == *n) { 176 | // we found the whole utf8 string for needle in haystack at 177 | // maybeMatch, so return it 178 | return (void *)maybeMatch; 179 | } else { 180 | // h could be in the middle of an unmatching utf8 codepoint, 181 | // so we need to march it on to the next character beginning 182 | // starting from the current character 183 | h = (const char*)utf8codepoint(maybeMatch, &throwaway_codepoint); 184 | } 185 | } 186 | 187 | // no match 188 | return 0; 189 | } 190 | 191 | void *utf8chr(const void *src, utf8_int32_t chr) { 192 | char c[5] = {'\0', '\0', '\0', '\0', '\0'}; 193 | 194 | if (0 == chr) { 195 | // being asked to return position of null terminating byte, so 196 | // just run s to the end, and return! 197 | const char *s = (const char *)src; 198 | while ('\0' != *s) { 199 | s++; 200 | } 201 | return (void *)s; 202 | } else if (0 == ((utf8_int32_t)0xffffff80 & chr)) { 203 | // 1-byte/7-bit ascii 204 | // (0b0xxxxxxx) 205 | c[0] = (char)chr; 206 | } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { 207 | // 2-byte/11-bit utf8 code point 208 | // (0b110xxxxx 0b10xxxxxx) 209 | c[0] = 0xc0 | (char)(chr >> 6); 210 | c[1] = 0x80 | (char)(chr & 0x3f); 211 | } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { 212 | // 3-byte/16-bit utf8 code point 213 | // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) 214 | c[0] = 0xe0 | (char)(chr >> 12); 215 | c[1] = 0x80 | (char)((chr >> 6) & 0x3f); 216 | c[2] = 0x80 | (char)(chr & 0x3f); 217 | } else { // if (0 == ((int)0xffe00000 & chr)) { 218 | // 4-byte/21-bit utf8 code point 219 | // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) 220 | c[0] = 0xf0 | (char)(chr >> 18); 221 | c[1] = 0x80 | (char)((chr >> 12) & 0x3f); 222 | c[2] = 0x80 | (char)((chr >> 6) & 0x3f); 223 | c[3] = 0x80 | (char)(chr & 0x3f); 224 | } 225 | 226 | // we've made c into a 2 utf8 codepoint string, one for the chr we are 227 | // seeking, another for the null terminating byte. Now use utf8str to 228 | // search 229 | return utf8str(src, c); 230 | } 231 | 232 | -------------------------------------------------------------------------------- /src/utf8.h: -------------------------------------------------------------------------------- 1 | // The latest version of this library is available on GitHub; 2 | // https://github.com/sheredom/utf8.h 3 | 4 | // This is free and unencumbered software released into the public domain. 5 | // 6 | // Anyone is free to copy, modify, publish, use, compile, sell, or 7 | // distribute this software, either in source code form or as a compiled 8 | // binary, for any purpose, commercial or non-commercial, and by any 9 | // means. 10 | // 11 | // In jurisdictions that recognize copyright laws, the author or authors 12 | // of this software dedicate any and all copyright interest in the 13 | // software to the public domain. We make this dedication for the benefit 14 | // of the public at large and to the detriment of our heirs and 15 | // successors. We intend this dedication to be an overt act of 16 | // relinquishment in perpetuity of all present and future rights to this 17 | // software under copyright law. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | // OTHER DEALINGS IN THE SOFTWARE. 26 | // 27 | // For more information, please refer to 28 | 29 | #ifndef SHEREDOM_UTF8_H_INCLUDED 30 | #define SHEREDOM_UTF8_H_INCLUDED 31 | 32 | #include 33 | #define utf8_int32_t int32_t 34 | 35 | void *utf8valid(const void *str); 36 | int utf8codepointcalcsize(const void *str); 37 | void *utf8codepoint(const void *str, utf8_int32_t *out_codepoint); 38 | void *utf8str(const void *haystack, const void *needle); 39 | void *utf8chr(const void *src, utf8_int32_t chr); 40 | 41 | #endif // SHEREDOM_UTF8_H_INCLUDED 42 | 43 | -------------------------------------------------------------------------------- /src/z64font.c: -------------------------------------------------------------------------------- 1 | /* 2 | * z64font 3 | * 4 | * converts truetype font files to oot/mm format 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define WOW_IMPLEMENTATION 17 | #include 18 | 19 | #define STB_IMAGE_WRITE_IMPLEMENTATION 20 | #include "stb_image_write.h" 21 | 22 | #define STB_TRUETYPE_IMPLEMENTATION 23 | 24 | #include "z64font.h" 25 | 26 | /* 27 | * 28 | * private functions 29 | * 30 | */ 31 | 32 | /* compose codepoint in i8 color space */ 33 | static void compose( 34 | int x 35 | , int y 36 | , int w 37 | , int h 38 | , uint8_t *src 39 | , uint8_t *dst 40 | , int yshift 41 | ) 42 | { 43 | int i; 44 | int k; 45 | 46 | memset(dst, 0, FONT_W * FONT_H); 47 | 48 | for (k = 0; k < h; ++k) 49 | { 50 | for (i = 0; i < w; ++i) 51 | { 52 | int dstIdx = ((k + y) + yshift) * FONT_W + i + x; 53 | 54 | /* skip anything out of bounds */ 55 | if (i + x < 0 || dstIdx < 0 || dstIdx >= FONT_W * FONT_H) 56 | continue; 57 | dst[dstIdx] = src[k * w + i]; 58 | //fputc(" .:ioVM@"[src[k*w+i]>>5], stderr); 59 | } 60 | //fputc('\n', stderr); 61 | } 62 | } 63 | 64 | static void i8_to_i4(uint8_t *dst, uint8_t *src, int w, int h) 65 | { 66 | /* color points to last color */ 67 | int alt = 0; 68 | int i; 69 | 70 | for (i = 0; i < w * h; ++i, ++src) 71 | { 72 | uint8_t *b = dst; 73 | uint8_t c; 74 | float f; 75 | 76 | c = *b; 77 | b = &c; 78 | 79 | /* convert pixel */ 80 | f = 0.003921569f * *src; 81 | *b = roundf(f * 15); 82 | 83 | /* clear when we initially find it */ 84 | if (!(alt&1)) 85 | *dst = 0; 86 | 87 | /* how to transform result */ 88 | if (!(alt&1)) 89 | c <<= 4; 90 | else 91 | c &= 15; 92 | 93 | *dst |= c; 94 | 95 | /* pixel advancement logic */ 96 | dst += ((alt++)&1); 97 | } 98 | } 99 | 100 | static void *quickWidth(float width) 101 | { 102 | static uint8_t arr[4]; 103 | unsigned int widthU32; 104 | widthU32 = *((unsigned int*)&width); 105 | arr[0] = widthU32 >> 24; 106 | arr[1] = widthU32 >> 16; 107 | arr[2] = widthU32 >> 8; 108 | arr[3] = widthU32; 109 | return arr; 110 | } 111 | 112 | /* read file from drive; returns 0 on failure */ 113 | static void *readFile(struct z64font *g, const char *fn, unsigned *sz) 114 | { 115 | void *data; 116 | unsigned sz_; 117 | if (!sz) 118 | sz = &sz_; 119 | FILE *fp = fopen(fn, "rb"); 120 | if (!fp) 121 | { 122 | g->error("failed to open '%s' for reading", fn); 123 | return 0; 124 | } 125 | 126 | /* get file size */ 127 | fseek(fp, 0, SEEK_END); 128 | *sz = ftell(fp); 129 | fseek(fp, 0, SEEK_SET); 130 | 131 | /* allocate memory to store file */ 132 | data = malloc(*sz+1); 133 | if (!data) 134 | { 135 | fclose(fp); 136 | return 0; 137 | } 138 | ((char*)data)[*sz] = '\0'; /* in case used as string */ 139 | 140 | /* doing it in a single read failed... */ 141 | if (fread(data, 1, *sz, fp) != *sz) 142 | { 143 | fclose(fp); 144 | free(data); 145 | g->error("failed to read file '%s'", fn); 146 | return 0; 147 | } 148 | 149 | fclose(fp); 150 | return data; 151 | } 152 | 153 | /* read file from drive as string; returns 0 on failure */ 154 | static char *readFileString(struct z64font *g, const char *fn) 155 | { 156 | char *data; 157 | unsigned dataSz; 158 | data = readFile(g, fn, &dataSz); 159 | if (!data) 160 | return 0; 161 | data[dataSz] = '\0'; 162 | return data; 163 | } 164 | 165 | /* 166 | * 167 | * public api 168 | * 169 | */ 170 | 171 | 172 | void z64font_exportDecomp(struct z64font *g, char **ofn) 173 | { 174 | FILE *fp = 0; 175 | struct zchar *zchar; 176 | const char *delim = "\r\n"; 177 | char *pngFn = 0; 178 | char *decompFileNames = strdup(g->decompFileNames); 179 | unsigned char rgbaBuf[FONT_W * FONT_H][4]; 180 | const float extraWidthEntries[] = { 181 | 14.0f, // '[A]' 182 | 14.0f, // '[B]' 183 | 14.0f, // '[C]' 184 | 14.0f, // '[L]' 185 | 14.0f, // '[R]' 186 | 14.0f, // '[Z]' 187 | 14.0f, // '[C-Up]' 188 | 14.0f, // '[C-Down]' 189 | 14.0f, // '[C-Left]' 190 | 14.0f, // '[C-Right]' 191 | 14.0f, // '▼' 192 | 14.0f, // '[Control-Pad]' 193 | 14.0f, // '[D-Pad]' 194 | 14.0f, // ? 195 | 14.0f, // ? 196 | 14.0f, // ? 197 | 14.0f, // ? 198 | }; 199 | 200 | if (!ofn || !*ofn || !decompFileNames) 201 | return; 202 | 203 | pngFn = strtok(decompFileNames, delim); 204 | 205 | for (zchar = g->zchar; zchar->bitmap; ++zchar) 206 | { 207 | /* convert i8 to rgba32 */ 208 | for (int i = 0; i < FONT_W * FONT_H; ++i) 209 | { 210 | rgbaBuf[i][0] = rgbaBuf[i][1] = rgbaBuf[i][2] = ((unsigned char *)zchar->bitmap)[i]; /* rgb */ 211 | rgbaBuf[i][3] = 255; /* a */ 212 | } 213 | stbi_write_png(pngFn, FONT_W, FONT_H, 4, rgbaBuf, FONT_W * 4); 214 | pngFn = strtok(0, delim); 215 | } 216 | 217 | g->isI4 = 1; /* has converted to i4 */ 218 | 219 | /* export 'comic-sans.font_width.h' */ 220 | fp = fopen(*ofn, "w"); 221 | if (!fp) 222 | { 223 | g->error("failed to open '%s' for writing\n", *ofn); 224 | goto L_cleanup; 225 | } 226 | for (zchar = g->zchar; zchar->bitmap; ++zchar) 227 | { 228 | if (fprintf(fp, "%ff,\n", zchar->width) < 0) 229 | { 230 | g->error("failed to write '%s'\n", *ofn); 231 | goto L_cleanup; 232 | } 233 | } 234 | for (int i = 0; i < sizeof(extraWidthEntries) / sizeof(extraWidthEntries[0]); ++i) 235 | { 236 | if (fprintf(fp, "%ff,\n", extraWidthEntries[i]) < 0) 237 | { 238 | g->error("failed to write '%s'\n", *ofn); 239 | goto L_cleanup; 240 | } 241 | } 242 | fclose(fp); 243 | fp = 0; 244 | g->info("Export successful!\n"); 245 | L_cleanup: 246 | free(decompFileNames); 247 | if (fp) 248 | fclose(fp); 249 | } 250 | 251 | void z64font_exportBinaries(struct z64font *g, char **ofn) 252 | { 253 | FILE *fp = 0; 254 | struct zchar *zchar; 255 | 256 | if (!ofn || !*ofn) 257 | return; 258 | 259 | /* export 'comic-sans.font_static' */ 260 | if (wow_fnChangeExtension(ofn, "font_static")) 261 | { 262 | g->error("memory error"); 263 | goto L_cleanup; 264 | } 265 | fp = fopen(*ofn, "wb"); 266 | if (!fp) 267 | { 268 | g->error("failed to open '%s' for writing\n", *ofn); 269 | goto L_cleanup; 270 | } 271 | for (zchar = g->zchar; zchar->bitmap; ++zchar) 272 | { 273 | if (!g->isI4) 274 | i8_to_i4(zchar->bitmap, zchar->bitmap, FONT_W, FONT_H); 275 | if (fwrite(zchar->bitmap, 1, (FONT_W * FONT_H) / 2, fp) 276 | != (FONT_W * FONT_H) / 2 277 | ) 278 | { 279 | g->error("failed to write '%s'\n", *ofn); 280 | goto L_cleanup; 281 | } 282 | } 283 | fclose(fp); 284 | fp = 0; 285 | g->isI4 = 1; /* has converted to i4 */ 286 | 287 | /* export 'comic-sans.width_table' */ 288 | if (wow_fnChangeExtension(ofn, "width_table")) 289 | { 290 | g->error("memory error"); 291 | goto L_cleanup; 292 | } 293 | fp = fopen(*ofn, "wb"); 294 | if (!fp) 295 | { 296 | g->error("failed to open '%s' for writing\n", *ofn); 297 | goto L_cleanup; 298 | } 299 | for (zchar = g->zchar; zchar->bitmap; ++zchar) 300 | { 301 | if (fwrite(quickWidth(zchar->width), 1, 4, fp) != 4) 302 | { 303 | g->error("failed to write '%s'\n", *ofn); 304 | goto L_cleanup; 305 | } 306 | } 307 | fclose(fp); 308 | fp = 0; 309 | g->info("Export successful!\n"); 310 | L_cleanup: 311 | if (fp) 312 | fclose(fp); 313 | } 314 | 315 | 316 | int z64font_convert(struct z64font *g) 317 | { 318 | float scale; 319 | int ascent; 320 | int baseline; 321 | uint8_t *bitmap; 322 | struct zchar *zchar; 323 | const char *chars = g->chars; 324 | stbtt_fontinfo *font = &g->font; 325 | int yshift = g->yshift; 326 | int fontSize = g->fontSize; 327 | int xPad = g->xPad; 328 | int widthAdvance = g->widthAdvance; 329 | struct zchar *arr = g->zchar; 330 | int arrMax = ZCHAR_MAX; 331 | 332 | g->isI4 = 0; 333 | 334 | scale = stbtt_ScaleForPixelHeight(font, fontSize); 335 | stbtt_GetFontVMetrics(font, &ascent, 0, 0); 336 | baseline = scale * ascent; 337 | 338 | /* get codepoints */ 339 | if (zchar_parseCodepoints(chars, arr, arrMax, &g->zcharNum)) 340 | { 341 | g->error("too many codepoints detected"); 342 | return -1; 343 | } 344 | 345 | /* prepare each codepoint's graphic */ 346 | for (zchar = arr; zchar < arr + g->zcharNum; ++zchar) 347 | { 348 | int width; 349 | int height; 350 | int xofs; 351 | int yofs; 352 | utf8_int32_t codepoint = zchar->codepoint; 353 | uint8_t conv[FONT_W * FONT_H]; 354 | int advance; 355 | int lsb; 356 | 357 | bitmap = stbtt_GetCodepointBitmap( 358 | font 359 | , 0 360 | , scale 361 | , codepoint 362 | , &width 363 | , &height 364 | , &xofs 365 | , &yofs 366 | ); 367 | 368 | //fprintf(stderr, "xofs yofs %d %d\n", xofs, yofs); 369 | //fprintf(stderr, "ascent = %d\n", ascent); 370 | //fprintf(stderr, "baseline = %d\n", baseline); 371 | 372 | compose(xofs, baseline + yofs, width, height, bitmap, conv, yshift); 373 | stbtt_GetCodepointHMetrics(font, codepoint, &advance, &lsb); 374 | 375 | if (widthAdvance) 376 | width = advance * scale; 377 | else 378 | width = fmax(width, advance * scale); 379 | 380 | width += xPad; 381 | 382 | zchar->codepoint = codepoint; 383 | zchar->width = width; 384 | if (!zchar->bitmap) 385 | { 386 | zchar->bitmap = wow_malloc_die(sizeof(conv)); 387 | } 388 | memcpy(zchar->bitmap, conv, sizeof(conv)); 389 | 390 | free(bitmap); 391 | } 392 | 393 | return 0; 394 | } 395 | 396 | int z64font_loadFont(struct z64font *g, const char *fn) 397 | { 398 | /* ttf changed */ 399 | if (g->ttfBin) 400 | free(g->ttfBin); 401 | 402 | if (!fn || !strlen(fn)) 403 | return 1; 404 | 405 | if (!(g->ttfBin = readFile(g, fn, &g->ttfBinSz))) 406 | return 1; 407 | 408 | if (!stbtt_InitFont(&g->font, g->ttfBin, 0)) 409 | { 410 | free(g->ttfBin); 411 | g->ttfBin = 0; 412 | g->error("unsupported font file '%s'", fn); 413 | return 1; 414 | } 415 | return 0; 416 | } 417 | 418 | int z64font_loadCodepoints(struct z64font *g, const char *fn) 419 | { 420 | /* txt changed */ 421 | if (g->chars) 422 | free(g->chars); 423 | 424 | if (!fn || !strlen(fn)) 425 | return 1; 426 | 427 | /* read characters as string */ 428 | if (!(g->chars = readFileString(g, fn))) 429 | return 1; 430 | 431 | if (utf8valid(g->chars)) 432 | { 433 | g->error("'%s' contains invalid codepoint(s)", fn); 434 | return 1; 435 | } 436 | 437 | return 0; 438 | } 439 | 440 | int z64font_loadDecompFileNames(struct z64font *g, const char *fn) 441 | { 442 | /* txt changed */ 443 | if (g->decompFileNames) 444 | free(g->decompFileNames); 445 | 446 | if (!fn || !strlen(fn)) 447 | return 1; 448 | 449 | /* read characters as string */ 450 | if (!(g->decompFileNames = readFileString(g, fn))) 451 | return 1; 452 | 453 | return 0; 454 | } 455 | -------------------------------------------------------------------------------- /src/z64font.h: -------------------------------------------------------------------------------- 1 | /* z64font api */ 2 | 3 | #ifndef Z64FONT_H_INCLUDED 4 | #define Z64FONT_H_INCLUDED 5 | 6 | /* TODO make customizable so users can compile higher resolution 7 | * fonts without having to recompile the program from source 8 | */ 9 | #define FONT_W 16 10 | #define FONT_H 16 11 | 12 | #define PROGNAME "z64font" 13 | #define PROGVER "v1.1.0" 14 | #define PROGATTRIB "" 15 | #define PROG_NAME_VER_ATTRIB PROGNAME" "PROGVER" "PROGATTRIB 16 | #define ZCHAR_MAX 4096 /* 4096 character slots is plenty */ 17 | 18 | #include "zchar.h" 19 | #include "stb_truetype.h" 20 | 21 | struct z64font 22 | { 23 | void *ttfBin; 24 | unsigned ttfBinSz; 25 | char *chars; 26 | char* decompFileNames; 27 | stbtt_fontinfo font; 28 | int fontSize; 29 | int yshift; 30 | int xPad; 31 | int rightToLeft; 32 | int widthAdvance; 33 | int isDecompMode; 34 | struct zchar *zchar; 35 | unsigned zcharNum; 36 | char isI4; 37 | void (*info)(const char *fmt, ...); 38 | void (*error)(const char *fmt, ...); 39 | }; 40 | #define Z64FONT_DEFAULTS { \ 41 | .fontSize = 16 \ 42 | , .zchar = wow_calloc_die(ZCHAR_MAX, sizeof(struct zchar)) \ 43 | , .info = wow_stderr \ 44 | , .error = wow_stderr \ 45 | } 46 | 47 | int z64font_convert(struct z64font *g); 48 | void z64font_exportBinaries(struct z64font *g, char **ofn); 49 | void z64font_exportDecomp(struct z64font *g, char **ofn); 50 | int z64font_loadFont(struct z64font *g, const char *fn); 51 | int z64font_loadCodepoints(struct z64font *g, const char *fn); 52 | int z64font_loadDecompFileNames(struct z64font *g, const char *fn); 53 | 54 | #endif 55 | 56 | -------------------------------------------------------------------------------- /src/zchar.c: -------------------------------------------------------------------------------- 1 | /* zchar utf8 codepoint interpreter */ 2 | 3 | #include 4 | #include 5 | 6 | #include "zchar.h" 7 | 8 | const struct zchar *zchar_findCodepoint( 9 | const struct zchar *array 10 | , utf8_int32_t codepoint 11 | ) 12 | { 13 | const struct zchar *z = array; 14 | 15 | /* find matching codepoint */ 16 | for (z = array; z->bitmap; ++z) 17 | { 18 | if (z->codepoint == codepoint) 19 | return z; 20 | } 21 | return 0; 22 | } 23 | 24 | int zchar_parseCodepoints( 25 | const char *chars 26 | , struct zchar *arr 27 | , int arrMax 28 | , unsigned *num 29 | ) 30 | { 31 | const char *next; 32 | const char *w; 33 | struct zchar *zchar; 34 | 35 | *num = 0; 36 | 37 | /* skip first line containing sample string */ 38 | chars = utf8chr(chars, '\n') + 1; 39 | 40 | for (zchar = arr, next = 0, w = chars; *w; w = next) 41 | { 42 | utf8_int32_t codepoint; 43 | char c[16]; 44 | int sz = utf8codepointcalcsize(w); 45 | 46 | /* skip newlines */ 47 | while (*w == 0x0d || *w == 0x0a) 48 | ++w; 49 | 50 | if (!*w) 51 | break; 52 | 53 | if (zchar - arr >= arrMax) 54 | return -1; 55 | 56 | /* isolate multibyte character to its own string */ 57 | memcpy(c, w, sz); 58 | c[sz] = '\0'; 59 | fprintf(stdout, "'%s' (%d)\n", c, sz); 60 | next = utf8codepoint(w, &codepoint); 61 | 62 | zchar->codepoint = codepoint; 63 | ++zchar; 64 | ++*num; 65 | } 66 | 67 | return 0; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/zchar.h: -------------------------------------------------------------------------------- 1 | /* zchar utf8 codepoint interpreter */ 2 | 3 | #ifndef Z64_ZCHAR_H_INCLUDED 4 | 5 | #include "utf8.h" 6 | 7 | struct zchar 8 | { 9 | utf8_int32_t codepoint; 10 | void *bitmap; /* bitmap in i8 format */ 11 | float width; 12 | }; 13 | 14 | const struct zchar *zchar_findCodepoint( 15 | const struct zchar *array 16 | , utf8_int32_t codepoint 17 | ); 18 | 19 | int zchar_parseCodepoints( 20 | const char *chars 21 | , struct zchar *arr 22 | , int arrMax 23 | , unsigned *num 24 | ); 25 | 26 | #endif 27 | 28 | --------------------------------------------------------------------------------