mupen64plus-video-rice-src-2.0/INSTALL0000644000000000000000000000152012165031100015530 0ustar 00000000000000Mupen64Plus-Video-Rice INSTALL ------------------------------ This text file was written to explain the installation process of the Mupen64Plus-Video-Rice module. If this module is part of a Mupen64Plus source code bundle, the user should run the "m64p_install.sh" script in the root of the unzipped bundle to install all of the included modules in the bundle. If this module is a standalone source code release, you should build the library from source code and install it via the makefile, like this: $ cd projects/unix $ make all $ sudo make install If you want to build the Mupen64Plus-Video-Rice module for installation in a home folder for a single user, you may build it like this (replacing with your desired local installation path): $ cd projects/unix $ make all $ make install LIBDIR= SHAREDIR= mupen64plus-video-rice-src-2.0/LICENSES0000644000000000000000000004560012165031100015636 0ustar 00000000000000Mupen64Plus-video-rice LICENSE ------------------------------ Mupen64Plus-video-rice is licensed under the GNU General Public License version 2. The authors of Mupen64Plus-video-rice are: * Richard Goedeken (Richard42) * Sven Eckelmann (ecsv) * John Chadwick (NMN) * James Hood (Ebenblues) * Scott Gorman (okaygo) * Scott Knauert (Tillin9) * Jesse Dean (DarkJezter) * Louai Al-Khanji (slougi) * Bob Forder (orbitaldecay) * Jason Espinosa (hasone) * Lioncash * Littleguy77 * Metricity * HyperHacker * and others. Mupen64Plus-video-rice is based on the Rice Video plugin, which is GPL-licensed and was originally written by: * Rice1964 * Mudlord GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. mupen64plus-video-rice-src-2.0/README0000644000000000000000000000705612165031100015371 0ustar 00000000000000=============================================================================== ------------------------------------------------------------------------------- Mupen64plus-video-rice README v2.0 ------------------------------------------------------------------------------- =============================================================================== The latest version of this document can be found online at: https://code.google.com/p/mupen64plus/wiki/HighResolutionTextures ------------------------------------------------------------------------------- ABOUT ------------------------------------------------------------------------------- Mupen64Plus's Rice Video plugin supports a very nice feature which allows the user to replace all of the original textures used for 3D rendering in a game with high-resolution replacement textures drawn by graphic artists. ------------------------------------------------------------------------------- Enable Hi-Res Texture Loading in Rice Video ------------------------------------------------------------------------------- In order to begin using the hi-resolution texture feature, you must enable it by editing the Mupen64Plus config file. One option is to find the file and edit it directly with a text editor. On Linux or OSX, this is located at: "~/.config/ mupen64plus/", and on Windows it is in the "Application Data" sub-folder of your user folder. On Windows XP and prior, this is "C:\Documents and Settings\ \Application Data\Mupen64Plus\", while on Windows Vista and newer this is "C:\Users\\AppData\Mupen64Plus". You should find a section in this file labeled [Video-Rice], and within this section is a parameter called LoadHiResTextures. Set this to True to enable searching for and loading high- resolution textures. Another option to enable this feature is to use the --set option with the Mupen64Plus command-line user interface. To do this, run a game with a command similar to this: ./mupen64plus --set Video-Rice[LoadHiResTextures]=True --saveoptions m64p_test_rom.v64 ------------------------------------------------------------------------------- Installing Hi-Res Texture Files ------------------------------------------------------------------------------- To install a high-resolution texture pack for a game, all that you need to do is unzip the archive and put the extracted directory full of images into the right place. On Linux and OSX, this is usually "/home//.local/share/ mupen64plus/hires_texture". On Windows it is in the "Application Data" sub- folder of your user folder. On Windows XP and prior, this is "C:\Documents and Settings\\Application Data\Mupen64Plus\hires_texture", while on Windows Vista and newer this is "C:\Users\\AppData\Mupen64Plus\ hires_texture". If this directory doesn't exist, create it and copy the hi-res texture directory inside. The folder containing hi-res textures must be named exactly the same as the ROM's name in the header of the ROM file. Usually this name is short with all capital letters, like "MARIOKART64" or "SMASH BROTHERS". The command-line UI prints out this ROM name when running a game, right after the Goodname and before the MD5. ------------------------------------------------------------------------------- Running ------------------------------------------------------------------------------- After setup, just run the game as usual. If using the command-line UI, you should see a line printed out which says: Video: Texture loading option is enabled. Finding all hires textures mupen64plus-video-rice-src-2.0/RELEASE0000644000000000000000000001152512165031100015510 0ustar 00000000000000Mupen64Plus-Video-Rice RELEASE ------------------------------ Mupen64Plus-Video-Rice v2.0 - July 4, 2013 ------------------------------------------ - support for resizable video window - add support to build and run with OpenGL ES 2.0 - improve hi-resolution texture loading support - fix texture CRC calculation for non-x86 (or NO_ASM) platforms - support to build against SDL2 - Project files for Visual Studio 2012 - Makefile changes - add support for PowerPC and MinGW32 builds - add cross-compiling support to build Win32 executables (MXE) under Linux Mupen64Plus-Video-Rice v1.99.5 - March 10, 2012 ----------------------------------------------- - Hires texture loading: support for 8-bit PNG images - New config option for forcing vertical sync - Check OpenGL attributes after creating video window and report any that failed to set - Updated video plugin for new Mupen64plus 2.0 API versioning scheme - Update to Video API version 2.1.0. - Bugfix: hi-res textures: Scale highres textures by precalculated scaleShift exponent - Bugfix: dont call CoreVideo_Init() inside of the InitializeGFX() function. This will fix some front-end use cases - Bugfix: Fix z coordinate in 3d line rendering - Bugfix: double infinite loop in GetValidTmemInfoIndex - Bugfix: Perfect Dark randomly crashes due to divide-by-zero error - Bugfix: crash in loading Celda 2009 hi-res texture pack for Zelda Ocarina of Time - makefile fixes, improvements, and code cleanups Mupen64Plus-Video-Rice v1.99.4 - November 22, 2010 -------------------------------------------------- - new feature: anisotropic filtering - new feature: trilinear filtering - new feature: mipmaps - cleaned up FindScaleFactor function based upon r45 of the 1964 repo - bugfix: buffer overrun (and crash) when reading vendor string info on some opengl implementations - API change for reading the video buffer: new interface is more flexible and avoids some potential problems - support for anti-aliasing (GL_MULTISAMPLE) - makefile fixes, improvements, and code cleanups Mupen64Plus-Video-Rice v1.99.3 - February 13, 2010 -------------------------------------------------- - sync with core<-->plugin API change for RomOpen() - Changed default ScreenUpdateSetting to 1 for Linux, and 4 for Windows - use custom opengl extension function pointer typedefs, to avoid compilation errors with some drivers including hosed gl.h headers - merged some changes from Tillin9 commits in r1142-rice-video-gtk-refactor branch, to be more lenient in hi-res texture loading - bugfix: hi-res textures did not work in Windows - bugfix: #329: remove some deprecated types and a function call to prevent build errors with libpng 1.4 - bugfix: fixed mirroring bugs in Rice Video hi-resolution texture loading, based on Tillin9 rev 1337 in r1142-rice-video-gtk-refactor branch - bugfix: in ConvertImage.cpp none of the 4-bit conversion functions could handle 1-pixel wide textures - Makefile improvements: - added OS type GNU/kFreeBSD Mupen64Plus-Video-Rice v1.99.2 - January 6, 2010 -------------------------------------------------- - bugfix: fix fragment program combiner for Intel drivers in Win32, by ensuring that program does not allocate unused temp vars or call TEX commands for texture units that are not enabled - new feature: compile-time option for opengl debugging by calling glGetError after each opengl command (except inside of glBegin/glEnd) - portability: use ALIGN() for aligned data member declarations in header files as well as the definitions in CPP files - portability: refactor opengl code to use VidExt_GL_GetProc() for all opengl functions newer than v1.1, so that this will work in Windows - portability: Abstracted directory-handling code with new osal_files* source code - portability: replaced unix gettimeofday() function calls with SDL_GetTicks() - new feature: added MSVC8 project file, fixed minor incompatibilities with VC compiler - Makefile improvements: - throw error if OS/CPU not supported - use DESTDIR in install/uninstall paths - Allow user-specified CC/CXX/LD paths - use C++ compiler to link instead of LD, because the compiler knows where the standard C++ libs are - OSX hack for inline assembly code: mismatch between function names with-w/o preceding underscores Mupen64Plus-Video-Rice v1.99.1 - December 14, 2009 -------------------------------------------------- - Converted to new Mupen64Plus 2.0 API - Major code cleanup, removed all non-standard data types - Refactored build system to separate source and object files - added NO_ASM build option - removed some unused configuration parameters - bugfix: handle fullscreen video mode properly: start up in this mode instead of always starting in windowed and needing the core to switch to fullscreen - bugfix #209: setjmp/longjmp fixes in the BMP writer and PNG reader - bugfix: eliminated duplicate 'Found ROM ...' messages mupen64plus-video-rice-src-2.0/data/RiceVideoLinux.ini0000644000000000000000000005455412165031100021021 0ustar 00000000000000{e2f35d53f1899760-4a} Name=Wave Race 64 SE FastTextureCRC=2 FrameBufferEmulation=4 {b09d00f82318296b-4a} Name=CITY TOUR GP IncTexRectEdge {542540b304c04073-45} Name=Cruis'n USA {faf1b9fb8986f86b-45} Name=LT DUCK DODGERS {231f2836cf569700-45} Name=KEN GRIFFEY SLUGFEST {5b05a00a65df3776-50} Name=DAFFY DUCK STARRING {ec939031ef09c20f-45} Name=OFFROAD {378f8f658dd21318-44} Name=RTL WLS2000 {a2eca9b98ee4aa17-45} Name=Rush 2049 {54ddbcae4a83ff15-50} Name=Taz Express {e07359beb8edb089-45} Name=TOP GEAR RALLY 2 {aaccfabcefd814b8-45} Name=BASSMASTERS2000 {696b64f4951075c5-4a} Name=BattlePhoenix64 FastLoadTile {cec4d4558ac75377-45} Name=BATTLEZONE ForceScreenClear=2 {45f48871680a4184-4a} Name=DDR DISNEY D MUSEUM FastLoadTile {181a33df44e0d45f-45} Name=NASCAR 2000 PrimaryDepthHack {437f1c551c834991-4a} Name=TOUKON ROAD2 {4707dec0d372dfa2-4a} Name=PUZZLEBOBBLE64 {421886079fbc2ea1-45} Name=EXCITEBIKE64 FastTextureCRC=1 RenderToTexture=3 {9803f7728ba95665-45} Name=STAR WARS EP1 RACER ZHack {afe66a73c7e91741-4a} Name=MICKEY USA FastTextureCRC=1 AlternativeTxtSizeMethod=1 FrameBufferEmulation=3 RenderToTexture=3 {955f5df3693dfe8a-45} Name=CASTLEVANIA FrameBufferEmulation=1 {9aaae9c2aa705d47-45} Name=BANJO TOOIE {0693bfa4d1df0cbf-45} Name=Banjo-Kazooie FrameBufferEmulation=8 RenderToTexture=4 ScreenUpdateSetting=4 {ff2b5a632623028b-45} Name=SUPER MARIO 64 AlternativeTxtSizeMethod=1 {b655503e52da922e-45} Name=Mario Kart 64 FastTextureCRC=1 FrameBufferEmulation=3 RenderToTexture=3 {ec4ba2664fd9ad2e-45} Name=Rogue Squadron FrameBufferEmulation=2 {3863c01c26893887-45} Name=CASTLEVANIA2 {5cb6f92ad7a2e285-45} Name=MULTI RACING ForceScreenClear=2 {9c33b2d5edcabcca-50} Name=BUCK BUMBLE {9b98023de281a3d4-45} Name=Battle for Naboo {15cc9daf883d721a-45} Name=Indiana Jones {452fefaef1307ef9-45} Name=FIGHTER DESTINY2 {c33022a6884483f0-45} Name=Dual heroes USA {fc06d8d3a8a23ab4-50} Name=MTM64 {71d10ea66ed0853d-45} Name=SPIDERMAN {9deaf4dbc0823e33-45} Name=SNOWBOARD KIDS {b71170ec2bd71676-45} Name=THE LEGEND OF ZELDA FrameBufferEmulation=3 RenderToTexture=3 {b49f03462c823703-45} Name=Kirby64 {0aff1ce6710d1cce-50} Name=NEWTETRIS IncTexRectEdge {1c9651c8faaafc78-45} Name=Pilot Wings64 {3afc8a4ff22d91f7-50} Name=South Park Rally {7ebc10dd51b300f9-50} Name=V8: SECOND OFFENSE FrameBufferEmulation=3 RenderToTexture=3 {a819f4edcc0419bf-45} Name=Beetle Adventure Rac Texture1Hack {fc9ddf9889c10666-45} Name=HARVESTMOON64 {73f0868a4be545cd-45} Name=Bust A Move 2 FastLoadTile TexRectScaleHack {2ecf221e13c8aa42-45} Name=BRUNSWICKBOWLING {21cbbcfc6b3c9072-45} Name=Mystical Ninja FastLoadTile FrameBufferEmulation=1 {80205766e148e328-4a} Name=SUPERROBOTSPIRITS {4f5aa9e623ead2ba-45} Name=AIDYN_CHRONICLES {0b15d45cf1c20c47-45} Name=Extreme G 2 PrimaryDepthHack {0be1d56046eded8b-50} Name=Rayman 2 FastTextureCRC=1 {1c635453f0dea203-45} Name=ZELDA MAJORA'S MASK FrameBufferEmulation=3 RenderToTexture=3 {67cf7503aa3fa956-4a} Name=OgreBattle64 FrameBufferEmulation=3 RenderToTexture=3 {3ae5ee653c737ded-45} Name=PAPER MARIO FrameBufferEmulation=3 RenderToTexture=3 ScreenUpdateSetting=4 {7e260025cec37e2a-45} Name=RIDGE RACER 64 {4fcf0150bdb30cf3-45} Name=MarioTennis AccurateTextureMapping=1 FastTextureCRC=1 AlternativeTxtSizeMethod=1 FrameBufferEmulation=4 RenderToTexture=4 {5c52381956966e58-45} Name=MS. PAC-MAN MM {d0b4b8cd2d353288-45} Name=JET FORCE GEMINI FrameBufferEmulation=1 {db0e7e142cb1c536-4a} Name=EVANGELION AccurateTextureMapping=1 FastTextureCRC=1 {cc60f4ddc034a63c-45} Name=Perfect Dark {85e05e0c3edd67a1-45} Name=ROCKETROBOTONWHEELS FastTextureCRC=1 {8438e2bfafea48ef-45} Name=Silicon Valley AlternativeTxtSizeMethod=1 RenderToTexture=3 {0c28d5b12abca74b-4a} Name=SIM CITY 2000 {325e9b7280d928b7-45} Name=GAUNTLET LEGENDS FrameBufferEmulation=1 {0d4302e49dfcfcd2-45} Name=Diddy Kong Racing {22c04e2085d119b1-45} Name=TONY HAWK PRO SKATER {b2bb524c6b0fabce-45} Name=ARMYMENAIRCOMBAT IncTexRectEdge {b6ce09347a51c8ce-45} Name=SMASH BROTHERS {50acc7302d070477-45} Name=CONKER BFD FrameBufferEmulation=3 RenderToTexture=4 {a5b118aaeb6adb07-45} Name=Resident Evil II ForceScreenClear=1 {d150bcdca31afd09-45} Name=GOLDENEYE ZHack FrameBufferEmulation=1 ScreenUpdateSetting=4 {e8d83723ec7c8e6b-45} Name=YOSHI STORY FrameBufferEmulation=3 RenderToTexture=3 {78d90eb3f9c90330-45} Name=F-ZERO X {3603165ab0377bbc-50} Name=BOMBERMAN64E {0390a59064980831-45} Name=WRESTLEMANIA 2000 {6d208ebd1c5ec398-4a} Name=DOUBUTSUNOMORI {96fa0e65a7f9dd30-50} Name=WAVE RACE 64 VIWidth=320 VIHeight=240 {72e270fcaae7ff08-50} Name=Silicon Valley {bbe8e07eaa11e449-50} Name=Rogue Squadron {38a59bd089541a1c-50} Name=Top Gear Overdrive {f4791f15e5c8ed8e-50} Name=VIGILANTE 8 {7b5bf45be8ee6b59-50} Name=WWF: Attitude {485f9493302e0f5c-50} Name=SMASH BROTHERS {36f03ca0d2c5c1bc-50} Name=SUPER MARIO 64 FastTextureCRC=1 {8616b80c815ad85f-45} Name=Madden NFL 2000 {a475a233594450b8-50} Name=WWF War Zone RenderToTexture=3 {a526899f09b48705-50} Name=TONY HAWK SKATEBOARD {84ea4ed8b4f1b245-50} Name=SHADOWGATE64 {bfe514d6c1bc6da7-50} Name=TARZAN {4a831839290cb515-45} Name=RAZOR FREESTYLE {4d675728da3743cc-45} Name=NIGHTMARE CREATURES {9940307f7652cf52-4a} Name=LASTLEGION UX {782706acb8fcaddf-50} Name=WORLD DRIVER CHAMP FullTMEM=1 {f336411da9ee63af-45} Name=ZELDA MASTER QUEST {614b2f496a14e504-45} Name=WAVE RACE 64 {b1cc3f73f9924844-50} Name=Banjo-Kazooie {e74bc5a2b2cb1967-50} Name=CASTLEVANIA2 FastTextureCRC=1 {b609608a50e1ac94-45} Name=JET FORCE GEMINI AccurateTextureMapping=1 FastTextureCRC=1 RenderToTexture=3 {b3d9f590f0dc0e9d-45} Name=POKEMON STADIUM FrameBufferEmulation=3 RenderToTexture=3 {a059e913b0ca930e-45} Name=WORMS ARMAGEDDON {d7d81095d20d1035-45} Name=Stunt Racer 64 FullTMEM=1 {bfea58ec69717cad-45} Name=DONKEY KONG 64 EmulateClear=2 {40064b4efbbc491b-45} Name=WWF No Mercy {d68cbe33126918ec-45} Name=WCW MAYHEM {bd193e2c5eee1351-45} Name=WCWvs.NWO:World Tour FrameBufferEmulation=4 ScreenUpdateSetting=4 {b960be713cfbdb1d-45} Name=WCWvs.NWO:World Tour FrameBufferEmulation=1 ScreenUpdateSetting=4 {ab96e5dee77a3baf-45} Name=WCW / nWo REVENGE ScreenUpdateSetting=4 {253ffd588daa2ed9-50} Name=1080 SNOWBOARDING {47cfa352fc3bc14e-50} Name=NFL QBC '99 {497df9d35b132469-50} Name=YOSHI STORY FrameBufferEmulation=3 RenderToTexture=3 {af29ab1928cd1bc7-50} Name=PAPER MARIO {7d1d6172d2bd1999-58} Name=HSV ADVENTURE RACING Texture1Hack {ad84d7df036642ae-50} Name=ALL STAR TENNIS '99 {b4fb88b01d4b1e44-50} Name=BASS HUNTER 64 {d3dd3f71efa0d672-20} Name=Bike Race by NaN ForceScreenClear=2 {16d3794d331b50e8-45} Name=BEAST WARS US {d0483cfb9ff6288d-50} Name=CHARLIE BLAST'S {e89d2b491cc8ccc6-50} Name=EARTHWORM JIM 3D {3421cfdc7835d69d-50} Name=Centre Court Tennis UseCIWidthAndRatio=1 {9531740f95dba6d8-50} Name=DAIKATANA {b3c83ccca405c40e-50} Name=F1 WORLD GRAND PRIX {9d127b27ff7938dd-50} Name=Holy Magic Century {98da8b41580f8a24-50} Name=MISCHIEF MAKERS {f10bfd20871dcff5-50} Name=RAT ATTACK {7bc5212d8cc5e48f-50} Name=WORMS N64 {9bbfc5f3e2330f16-45} Name=Rayman 2 FastTextureCRC=1 {118a08497e959464-45} Name=Turok 2: Seeds of Ev AccurateTextureMapping=1 {4e2d0ff0f4aa0f34-45} Name=CARMAGEDDON64 FastTextureCRC=1 {ababd40d1ea9a2b5-45} Name=D K DISPLAY {32d9b51f1b48a93b-45} Name=Armorines Project S. {b46e28958fd56ab7-45} Name=Command&Conquer {9addd0dea72582e7-50} Name=MICKEY USA PAL {75d474fcab78029a-45} Name=PPG CHEMICAL X {b5707f1afdb9b700-45} Name=THPS3 {6a0571ea474821e4-45} Name=VIGILANTE 8 FullTMEM=2 RenderToTexture=3 {e7dda46ae7f4e2e3-45} Name=BATTLETANX {47e2a4753d960860-45} Name=BATTLETANXGA {ca243cf0cc7b23c5-45} Name=CLAYFIGHTER 63 {cbc7ef32203feac3-45} Name=Fighting Force {1a103ea89db637e9-45} Name=Doom64 {ff016e8e48f9b4cc-45} Name=Glover AccurateTextureMapping=1 {3f14532151632d99-45} Name=NEWTETRIS VIWidth=400 VIHeight=300 {a35ecf42df34139a-50} Name=STARCRAFT 64 NormalAlphaBlender=2 UseCIWidthAndRatio=1 RenderToTexture=3 {ac47477a23ecee44-44} Name=PUZZLE LEAGUE N64 VIWidth=320 VIHeight=240 FrameBufferEmulation=4 RenderToTexture=3 {fd04dc82f4822dcf-45} Name=A Bug's Life {f628fef7c3acf2c3-45} Name=WAR GODS {3f22456b565c0ef0-45} Name=W.G. 3DHOCKEY {59389d5a10e7aa97-45} Name=W.G 3D Hockey 98 {329dc9bb80aa7d11-45} Name=TWISTED EDGE {3e7450a1cd2225cf-45} Name=Toy Story 2 FrameBufferEmulation=2 {3d9b2662e8b111fe-45} Name=TOP GEAR RALLY ScreenUpdateSetting=2 {beda1f3cbae0a402-45} Name=TETRISPHERE IncTexRectEdge {5bf3e8a2d987dcc9-45} Name=SUPERMAN {c8615eab9675faa2-45} Name=PENNY RACERS {669464dcd9f02f57-4a} Name=ONEGAI MONSTER {1a5ac4d45eb225f4-45} Name=NITRO64 {eeb0255fdbc12762-45} Name=NBA LIVE 2000 {ada552424ebf6fae-45} Name=GOEMONS GREAT ADV {c59b41e6e31d0169-45} Name=OgreBattle64 {e5522da955b6261d-45} Name=FLYING DRAGON FastLoadTile {d6fd4644088278e3-45} Name=BOMBERMAN HERO {b42f2fff9a1461d1-45} Name=Cruis'n USA {5c7e4d2622468718-45} Name=Shadow of the Empire DisableObjBG=1 ScreenUpdateSetting=4 {63cff584dc7eee08-45} Name=KNIFE EDGE {9fd8224237b6e0af-45} Name=Bust A Move '99 FastLoadTile {a43c70efc99a4a4d-4a} Name=TOUKON ROAD {b3c83ccca405c40e-45} Name=F1 WORLD GRAND PRIX {8e8fc9c7de5d1442-45} Name=HOT WHEELS TURBO {36cee20de6291dd4-4a} Name=HYBRID HEAVEN JP {374cff6dfd63b7b1-4a} Name=̧н?64 {180e1599a5e66612-45} Name=THPS2 {7ff0da0488e6180d-45} Name=DUKE NUKEM ZERO HOUR {7a6882ae8d383f9a-45} Name=F1 POLE POSITION 64 {6e86c107decc7557-50} Name=F1 WORLD GRAND PRIX2 {5858a99e18b672af-45} Name=MarioParty2 {d929387cce47826e-45} Name=MarioParty3 FastTextureCRC=1 TexRectScaleHack {9207384145e067a1-45} Name=POLARISSNOCROSS TexRectScaleHack DisableAlphaBlender=1 {31e0d6ed13601368-45} Name=RUSH 2 {0d7ddff78f0152ed-00} Name=Shufflepuck 64 {ac3363d79d21b60c-4a} Name=Bass Rush {fab428e3e1284a00-50} Name=Bust A Move 3 DX {20186b2a66f4bc6a-45} Name=S.F. RUSH IncTexRectEdge {4d7a545e9507e690-45} Name=All-Star Baseball '0 {30a61376f396d63e-45} Name=FIFA 99 FastTextureCRC=1 {996e30b6b2d23eb6-4a} Name=ÄÞ×´ÓÝ2 ˶ØÉ¼ÝÃÞ {049805d8119b7392-4a} Name=ÄÞ×´ÓÝ3 ÉËÞÀÉÏÁSOS! {4cca08f927434636-45} Name=Killer Instinct Gold ForceScreenClear=1 {ac0443c321c0792d-45} Name=MK_MYTHOLOGIES {b9019507ab3202ab-4a} Name=CUSTOMROBOV2 {582ba5a441987523-45} Name=DARK RIFT EmulateClear=1 {c18944202bcf8612-45} Name=BATMAN BEYOND RETURN {b4737e23376b3bd6-45} Name=BOMBERMAN64U2 AccurateTextureMapping=1 FastTextureCRC=1 {bf2ff236f2128931-4a} Name=64ÊÅÌÀ?~ÃݼÉÔ¸¿¸~ {ec7c7fc26f80e085-50} Name=MYSTICAL NINJA2 SG {33ddbf4e849d4c66-45} Name=Tigger's Honey Hunt {dd5a6f39a7ec9366-45} Name=WCW BACKSTAGE {8c1168f44ee42ee3-4a} Name=Ultraman Battle JAPA {aff7a346d091750f-45} Name=CruisnExotica ForceScreenClear=1 FrameBufferEmulation=2 {e1a49e51e88475eb-4a} Name=KING HILL 64 {f002cc8e81de8b7f-45} Name=Top Gear Hyper Bike {54edd74d7d28f974-45} Name=Shadow of the Empire FrameBufferEmulation=3 ScreenUpdateSetting=3 {6c7450f00b827b24-45} Name=ROAD RASH 64 AccurateTextureMapping=1 {6a6d63bdba541f5d-45} Name=World Cup 98 {9516943beb5e0af9-50} Name=TWINE UseCIWidthAndRatio=1 {95351208def11005-45} Name=BIOFREAKS {abd8f7d146043b29-45} Name=Asteroids Hyper 64 {0588f752b7ca8f8b-45} Name=Fighter's Destiny {a2dc9ac4621b50f1-45} Name=GT64 IncTexRectEdge {ea406a09100abe8a-45} Name=LEGORacers FrameBufferEmulation=2 {87b4694e90e218fe-45} Name=NBA HANGTIME FastLoadTile FullTMEM=1 {47b512cae44efa71-45} Name=POKEMON SNAP FastTextureCRC=1 RenderToTexture=3 {1a1d75c2ff9bc1f8-50} Name=SNOWBOARD KIDS2 {f85c032635912b80-45} Name=Mission Impossible {f18b591b459ba2ec-45} Name=AERO FIGHTERS ASSAUL {20d568510dcd5fca-4a} Name=Banjo-Kazooie {eeea74f73eb1d8f0-4a} Name=F3 ̳ײɼÚÝ2 AccurateTextureMapping=1 FastTextureCRC=1 {6d8d76286c9779b3-45} Name=Monaco Grand Prix {821157036dd02f89-45} Name=POKEMON STADIUM 2 FrameBufferEmulation=3 {b8a5ed9403e97386-45} Name=Starshot {127edc3ec91c6ce2-45} Name=Gex 3 Deep Cover Gec {98ae2b8dbf2537d7-45} Name=NAGANO OLYMPICS {6b7e8094e462cc60-4a} Name=PUYO PUYO SUN 64 {f34791760ec13320-45} Name=SCARS VIWidth=320 VIHeight=240 FullTMEM=1 {2d16e69f37407ee9-4a} Name=TROUBLE MAKERS {8ad56680c1cadec3-45} Name=Waialae Country Club {20f9b837efb38ba5-45} Name=Twintris {9dae5305c1e0d8ea-45} Name=XENAWARRIORPRINCESS {f179a589ef977e66-45} Name=Turok 3: Shadow of O {3d8ea87371c5c53a-45} Name=RALLY CHALLENGE RenderToTexture=3 {9cf75b9fa008fed2-45} Name=Quake ForceScreenClear=1 {a7233ec41a68b140-45} Name=All Star Baseball 99 {d025c427c1992d8c-50} Name=AIR BOARDER 64 {941a95b6af49c863-4a} Name=DRACULA MOKUSHIROKU {2907d2674c7796f6-4a} Name=SMASH BROTHERS {c73b072011013b5e-45} Name=ITF 2000 {4fd5ea30f60b6231-45} Name=NFL BLITZ SPECIAL ED {80cd41d712b9a9ac-45} Name=Top Gear Overdrive {2b0996e84e4d24dc-45} Name=WHEEL OF FORTUNE {3e46beae4b4671cc-45} Name=AEROGAUGE {ec620158f18b10e3-58} Name=CARMAGEDDON64 {d245a2fd473d4aa7-45} Name=extremeg {74d7fe891be2afca-45} Name=GEX: ENTER THE GECKO {6064256986f5a3b9-45} Name=JEOPARDY! {bcb516e6888b65c9-45} Name=Iggy's Reckin' Balls {32272d1318910ec7-45} Name=Wipeout 64 {14979eef7d2c3bc0-45} Name=Tonic Trouble {163ed509b968b23a-45} Name=PIAZZA STRIKEZONE {f4d47d41e22f481b-45} Name=MORTAL KOMBAT 4 {4f47294f7a70cb30-4a} Name=KAKUTOU DENSHOU {6910969c8d48eaf5-4a} Name=64 OHZUMOU FastLoadTile {1462a21e0f9090e7-50} Name=Turok: Rage Wars {f6290781c1cf3fe0-45} Name=NBA JAM 99 {cab7f1645537a271-50} Name=CASTLEVANIA {5991f1c35abcd265-45} Name=FIFA Soccer 64 {dce23ae1e85cb64f-4a} Name=Eltail {514423656f34d3eb-4a} Name=Blastdozer {e48c53cdf9fc8a61-45} Name=Chameleon Twist2 ScreenUpdateSetting=4 {56ab73a29adb33da-45} Name=DUKE NUKEM {657e647c05d34819-45} Name=Blast Corps {e167f6a51fbd1fda-4a} Name=DERBYSTALLION 64 {92f738eb46a20e19-45} Name=Madden NFL 2001 ScreenUpdateSetting=4 {d4a34b66b7808a67-45} Name=MarioGolf64 FrameBufferEmulation=4 RenderToTexture=4 {83c871d5cf3f2d82-50} Name=BLUES BROTHERS 2000 {134d9d76fe3f23da-45} Name=DR.MARIO 64 FastTextureCRC=2 TexRectScaleHack FrameBufferEmulation=7 RenderToTexture=3 {f815d0a743aa8922-45} Name=STARFOX64 {a284e5de8711160f-45} Name=DESTRUCT DERBY {7e652928771862a0-45} Name=MarioParty FastTextureCRC=1 ScreenUpdateSetting=4 {c8fe8d30f6b52ece-45} Name=WORLD DRIVER CHAMP {d94dbbc80b435fcc-45} Name=Quest 64 {4fb5a8ce03d5217f-45} Name=Wetrix AccurateTextureMapping=1 FastTextureCRC=1 {436b4bfea7291d08-45} Name=TRIPLE PLAY 2000 {77eb3c7f0a038189-45} Name=HERCULES {b7a4ff08b653f401-45} Name=Big Mountain 2000 {d66abc75c92b5578-4a} Name=·×¯Ä¶²¹Â 64ÀÝòÀÞ {65973ce4bec1b105-4a} Name=Wonder Project J2 {78957423fd58dc80-45} Name=NASCAR 99 PrimaryDepthHack {b6730fb234fc7529-45} Name=ARMYMEN SARGE 2 {1cfb9046446dd54c-45} Name=GOLDEN NUGGET 64 {8074f13d5aed3d19-50} Name=Donald Duck Quack At FastTextureCRC=1 {cdb8580bd291b2b7-50} Name=Body Harvest ScreenUpdateSetting=2 {4dd12fd7c432ed1f-45} Name=Bottom of the 9th VIWidth=320 VIHeight=240 {c2b1f7bf8e14bfae-4a} Name=ÄÞ×´ÓÝ Ð¯Âɾ²Ú²¾· {405127a8e856b0b9-4a} Name=ÄÞ×´ÓÝ3 ÉËÞÀÉÏÁSOS! {26f7fc68bc8c6549-50} Name=G.A.S.P!!Fighters'NE {978d9fab66a7ea95-00} Name=Kings of Porn Vol 01 {4c5eb3e4c95cc41a-45} Name=MGAH VOL1 {2f96deac7ff8cbb2-50} Name=NBA PRO 98 {a55f70280e6909b5-50} Name=Monaco GP Racing 2 {420c2a397de790b7-45} Name=RAINBOW SIX {5d0ef1d379a52e05-45} Name=hey you, pikachu {d44a7da4f981fa8b-45} Name=Manic Miner 64 {231b1c14259ef43e-00} Name=(C) DATEL D&D NU10:0 {0cf10110c1d8513d-45} Name=Mia Hamm Soccer 64 {bbdd9849bcaeb7f7-45} Name=NUCLEARSTRIKE64 {25d625395ec7838c-50} Name=MADDEN NFL 99 {bf882810ca884843-45} Name=HYBRID HEAVEN USA {7a4636e49b8fde82-45} Name=INDY RACING 2000 {d04eabe3d20d0483-45} Name=NFL QBC 2000 {6960bfac62e1beea-45} Name=CHOPPER_ATTACK {707ae874d4ae9362-50} Name=ROADSTERS TROPHY {c463275fe52a4162-45} Name=I S S 64 ScreenUpdateSetting=3 {43f1a8bd622dafb1-45} Name=QUAKE II ForceScreenClear=2 {127341ec5fde31eb-4a} Name=THE MASK OF MUJURA DisableObjBG=1 {c26661e3e5a21386-58} Name=MO WORLD LEAGUE SOCC {5a211daa9abecb91-45} Name=SUPER BOWLING {e2a2bb4bb2bbf38b-00} Name=Puzzle Master 64 {9e5abd88bfdf1fe8-50} Name=NFL QBC 2000 {48a90cc04bd3608e-45} Name=South Park: Chef's L TexRectScaleHack FullTMEM=1 AlternativeTxtSizeMethod=1 {4b45d50895ccaaff-4a} Name=TETRIS64 {5a53206462800250-45} Name=Chameleon Twist {493336f51bd2f9db-45} Name=DeadlyArts {c7c4eb0c32e99c0c-4a} Name=WILD CHOPPERS {57062c866d89fd8d-45} Name=Army Men Sarge {a18efce89183739f-45} Name=CyberTiger {010c339eba14038c-45} Name=Forsaken {36fecce375bc8f39-45} Name=YOSHI STORY {1d5bce9c83e25163-00} Name= {e98889b5e84bfcb1-50} Name=Hydro Thunder {6e84e4bab0fe8ebb-45} Name=PAPERBOY {ec4716df47a9a2be-50} Name=MYSTICAL NINJA2 SG {532a11638fa89fa2-4a} Name=PERFECT STRIKER2 {2d56d52850aed5e4-4a} Name=ÃÞÝØ­³²×²×ÎÞ ScreenUpdateSetting=2 {fbabf721e8a78a6a-50} Name=Jeremy McGrath Super {0df1702fff87415c-45} Name=TUROK_DINOSAUR_HUNTE {efc64654bb478ee1-45} Name=All-Star Baseball 20 {e8603e5e95d4b54a-4a} Name=»²·®³ÊÌÞ¼®³· {cd0d702fc9c56c17-50} Name=TUROK_DINOSAUR_HUNTE {db4d6b0b82e67196-45} Name=ROADSTERS TROPHY {aea23b699f4ef1b7-45} Name=THE LEGEND OF ZELDA {3890053c8221bfc8-45} Name=V-RALLY {5b8b6b91a4850b78-45} Name=SMASH BROTHERS {89638313763c5b26-45} Name=MADDEN 64 {a93af3830dd401a9-45} Name=MortalKombatTrilogy {29b4b7ea572cc9ba-45} Name=READY 2 RUMBLE {5e6c6384fa4a9e94-4a} Name=TETRIS64 {c45db2418667721b-45} Name=Lamborghini 64 {5007706bfe21d629-45} Name=MACE {865877637b0eb85f-4a} Name=POKEMON STADIUM 2 FrameBufferEmulation=3 RenderToTexture=3 {d0f2f9989cf0d903-50} Name=Virtual Pool 64 ScreenUpdateSetting=3 {f311e83524277999-4a} Name=½½?À²¾ÝÊß½ÞÙÀÞÏ TexRectScaleHack {2dac77289a13dcc3-44} Name=Racing Simulation 2 FastLoadTile {d8526891efeadb73-45} Name=NBA Courtside 2 {3754838eb44857cd-45} Name=I.S.S.2000 {f336411da9ee63af-50} Name=THE LEGEND OF ZELDA FrameBufferEmulation=7 {0000000000000000-00} Name= {decd1acbf21d29cf-45} Name=FIFA: RTWC 98 ScreenUpdateSetting=2 {6930669c804af280-50} Name=MarioParty {79c712671d78723b-50} Name=IT&F SUMMERGAMES {f49e624b9b1db299-50} Name=quarterback_club_98 {8725c27e23e31aef-45} Name=OLYMPIC HOCKEY {f0ed310ed54972c3-50} Name=FIFA: RTWC 98 {51a69801849d21fc-50} Name=FIFA 99 {dbe5388cd7277cb3-50} Name=ECW Hardcore Revolut {2ce9cbf412ed92b3-50} Name=STARFOX64 {796690e4053f249f-50} Name=MAGICAL TETRIS {7e9598edacdc4282-45} Name=WIN BACK {ba8bb7de9dbdf652-45} Name=MADDEN NFL 99 {604167c53c455f0f-50} Name=MarioParty3 TexRectScaleHack {d057e9625d5ac17f-50} Name=MarioGolf64 FrameBufferEmulation=3 RenderToTexture=3 {396d17c9d17947ea-50} Name=BANJO TOOIE {185bf98d7b49daec-45} Name=NBA IN THE ZONE 2000 {9c9094082dd8d4da-45} Name=Knockout Kings 2000 UseCIWidthAndRatio=1 RenderToTexture=3 {fb4e4f2bfe11c543-50} Name=TOM AND JERRY {dadf3a4daefc9875-50} Name=RUGRATSTREASUREHUNT {02c608eea6d5c26b-50} Name=PGA European Tour Go {94ad4c21243b1abe-45} Name=CHOPPER_ATTACK {4716b67578bfda7a-45} Name=MAGICAL TETRIS {350c85f11279e0ac-45} Name=MICROMACHINES64TURBO {e183c35a87e312d7-45} Name=monopoly {168bc185af2296df-4a} Name=64 µµ½ÞÓ³ 2 {fbb1ab739360ca9c-45} Name=PENNY RACERS {e4f99fc27dfe4b26-45} Name=RAMPAGE {99d7e0fc546c3165-45} Name=KNIFE EDGE {0ca3d88317c15285-00} Name=YOSHI BOOT EMU {8d3bda777c0d2b16-4a} Name=²ÃÞÖ³½¹Éϰ¼Þ¬Ý¼Þ­¸ {986c006081a30526-4a} Name=VIOLENCEKILLER {cd0c011cfab7d322-4a} Name=½Þ°Ù ϼޭ³Â¶²ÃÞݾ {222ee09cb0f16e20-4a} Name=SUPER SPEED RACE 64 {dccda73ba0524e46-4a} Name=MARIO STORY {1e82cccc838ae896-4a} Name=ϰ¼Þ¬Ýγ۳·CLASSIC {20b93bd8166440cc-4a} Name=ǼÂÞØ64 {3b4b5574b5bcaef4-4a} Name=PACHINKO365NICHI {ad5b4934269d2e50-4a} Name=PAWAFURU PUROYAKYU4 {da4329d2c0772bac-4a} Name=PAWAFURU PUROYAKYU5 {b7205eb7fdfdfeb3-4a} Name=PAWAFURU PUROYAKYU6 {547fd2f3f9ac11c1-50} Name=Premier Manager 64 {3b5966d6075ca2d7-4a} Name=RockMan Dash {ff04fc84e93c25b1-4a} Name=½ÉÎÞ·¯½Þ ScreenUpdateSetting=4 {c1a7caff37858568-4a} Name=STARFOX64 {87a91f0fa6afc1bf-45} Name=Re-Volt {5db998df78098458-4a} Name=BANGAIOH IncTexRectEdge {8824ae7e5aa3409d-4a} Name=BioHazard II {c4085c048b79fd4a-4a} Name=ÊÞ°Á¬Ù ÌßÛÚ½ØÝ¸Þ 64 FrameBufferEmulation=2 ScreenUpdateSetting=3 {9c167989a0f689f1-4a} Name=DEZAEMON3D {819b9b3911ad33d5-4a} Name=´¸½ÄذÑG2 PrimaryDepthHack {66e8703ee8ba3844-4a} Name=HEIWA ÊßÁݺ ܰÙÄÞ64 RenderToTexture=3 {f5d919afcc2302b7-4a} Name=G1STABLE {ac90989adf13c3f0-4a} Name=ÏØµÉÌ«ÄËß° {0f692b27777a0aad-4a} Name=Robopon64 FrameBufferEmulation=3 RenderToTexture=3 {339521e9bdaffb13-45} Name=Ready to Rumble {f480fe3f7e5fc1a7-45} Name=NBA SHOWTIME {56a48bb9af762b5b-4a} Name=ÐÝÅÃÞÀϺޯÁܰÙÄÞ FastLoadTile FullTMEM=1 {69025b840295de57-4a} Name=Top Gear Hyper Bike {e6849c48f9496e4c-4a} Name=Getter Love!! {b157ae0937562a18-4a} Name=MASTERS'98 {f127177deb836b6c-00} Name=Test Program {93b8a075b521a34c-00} Name= {321536813f64eb2a-00} Name= {e04dda1e8d69bf22-00} Name=Test Program {0ab5b39a056166bc-44} Name=HEXEN {6805ed0d5e510215-4a} Name=´²º³É¾ÝıÝÄÞØ­°½ {c851318f45f53a4f-44} Name=WWF: Attitude {8ef08d6dcfc308d0-50} Name=WWF No Mercy {dbe6647cdb24b955-50} Name=Blast Corps {ce97680354fad4e0-45} Name=SHADOWGATE64 {324b8eac2673b4e7-45} Name=ROBOTRON-64 {424a5554fb5f98e4-4a} Name=J LEAGUE LIVE 64 {d218739cc10dae24-4a} Name=BEETLE ADVENTURE JP Texture1Hack {614ab6a10b9414d0-50} Name=Beetle Adventure Rac Texture1Hack {5cc0c180f45e06ea-45} Name=MLB FEATURING K G JR FastLoadTile {be98b9cdc8a52410-50} Name=MLB FEATURING K G JR FastLoadTile AlternativeTxtSizeMethod=1 {1e93f3833d2272cb-50} Name=CRUIS'N WORLD UseCIWidthAndRatio=2 {80064660720e5f30-50} Name=Lode Runner 3D ScreenUpdateSetting=1 {140efa7505d1b3c9-44} Name=Holy Magic Century {3e269b97040047f8-50} Name=Killer Instinct Gold {2bc6673d5031d031-4a} Name=LET'S SMASH {87a9c3c94c341058-4a} Name=MARIOKART64 {b8a588e6183f4bb1-50} Name=TWISTED EDGE {30dcef8261246a80-45} Name=BLADES OF STEEL '99 {b01a15d04ba15cfe-45} Name=DAIKATANA {bae28f9e7007278b-45} Name=KILLER INSTINCT GOLD ForceScreenClear=1 {61f1ba1ff1541c2c-41} Name=1080 SNOWBOARDING FastTextureCRC=2 ScreenUpdateSetting=2 {e08b138c460e7095-45} Name=BASS HUNTER 64 {8b24b3824d243ee7-45} Name=VIRTUALCHESS {9369a7da7cf7acd8-00} Name= {4986248e52de1c2e-00} Name= {74ab4cb4299a0207-50} Name=SUPERMAN {1ed568f51eba497e-45} Name=BOMBERMAN64U {f558c10e96683efb-45} Name=Mega Man 64 {dab629518c3cef9d-45} Name=NAMCOMUSEUM64 {60a73e50960e30e1-50} Name=Cruis'n USA {9723feeb34da74ff-45} Name=SPACE INVADERS {0e4016ac1a075dcf-45} Name=CAL SPEED {e8960e1e6b82284e-45} Name=CHARLIE BLAST'S {a00b78ba34db210f-45} Name=STARFOX64 {e740d45311b01975-45} Name=Diddy Kong Racing {134c3f03a7e79e31-45} Name=TWINE {ccffc42d215affc8-50} Name=AIDYN_CHRONICLES {91e285e16d76504e-45} Name=ALL STAR TENNIS '99 {df1850253aaed657-45} Name=Lode Runner 3D {71458cfac0f9e7bb-45} Name=MICKEY USA mupen64plus-video-rice-src-2.0/projects/msvc11/mupen64plus-video-rice.vcxproj0000644000000000000000000003075212165031100025316 0ustar 00000000000000 Debug Win32 Release Win32 {7D4AFF6A-B7D9-4C25-975A-038B8079098E} mupen64plusvideorice Win32Proj DynamicLibrary MultiByte true v110 DynamicLibrary MultiByte v110 <_ProjectFileVersion>10.0.40219.1 $(SolutionDir)$(Configuration)\ $(Configuration)\ true $(SolutionDir)$(Configuration)\ $(Configuration)\ false AllRules.ruleset AllRules.ruleset Disabled ..\..\..\mupen64plus-core\src\api;..\..\..\mupen64plus-win32-deps\SDL-1.2.14\include;..\..\..\mupen64plus-win32-deps\libpng-1.2.37\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.3\include;%(AdditionalIncludeDirectories) WIN32;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue user32.lib;gdi32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL-1.2.14\lib\SDL.lib;..\..\..\mupen64plus-win32-deps\libpng-1.2.37\lib\libpng.lib;%(AdditionalDependencies) true Windows MachineX86 ..\..\..\mupen64plus-core\src\api;..\..\..\mupen64plus-win32-deps\SDL-1.2.14\include;..\..\..\mupen64plus-win32-deps\libpng-1.2.37\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.3\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) MultiThreadedDLL Level3 ProgramDatabase Default user32.lib;gdi32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL-1.2.14\lib\SDL.lib;..\..\..\mupen64plus-win32-deps\libpng-1.2.37\lib\libpng.lib;%(AdditionalDependencies) true Windows true true MachineX86 mupen64plus-video-rice-src-2.0/projects/msvc8/mupen64plus-video-rice.vcproj0000644000000000000000000003175012165031100025053 0ustar 00000000000000 mupen64plus-video-rice-src-2.0/projects/unix/Makefile0000644000000000000000000003227712165031100020770 0ustar 00000000000000#/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # * Mupen64plus-video-rice - Makefile * # * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * # * Copyright (C) 2007-2009 Richard Goedeken * # * Copyright (C) 2007-2008 DarkJeztr Tillin9 * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU General Public License as published by * # * the Free Software Foundation; either version 2 of the License, or * # * (at your option) any later version. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU General Public License for more details. * # * * # * You should have received a copy of the GNU General Public License * # * along with this program; if not, write to the * # * Free Software Foundation, Inc., * # * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ # Makefile for RiceVideo plugin in Mupen64Plus # detect operating system UNAME ?= $(shell uname -s) OS := NONE ifeq ("$(UNAME)","Linux") OS = LINUX SO_EXTENSION = so SHARED = -shared endif ifeq ("$(UNAME)","linux") OS = LINUX SO_EXTENSION = so SHARED = -shared endif ifneq ("$(filter GNU hurd,$(UNAME))","") OS = LINUX SO_EXTENSION = so SHARED = -shared endif ifeq ("$(UNAME)","Darwin") OS = OSX SO_EXTENSION = dylib SHARED = -bundle PIC = 1 # force PIC under OSX endif ifeq ("$(UNAME)","FreeBSD") OS = FREEBSD SO_EXTENSION = so SHARED = -shared endif ifeq ("$(UNAME)","OpenBSD") OS = FREEBSD SO_EXTENSION = so SHARED = -shared $(warning OS type "$(UNAME)" not officially supported.') endif ifneq ("$(filter GNU/kFreeBSD kfreebsd,$(UNAME))","") OS = LINUX SO_EXTENSION = so SHARED = -shared endif ifeq ("$(patsubst MINGW%,MINGW,$(UNAME))","MINGW") OS = MINGW SO_EXTENSION = dll SHARED = -shared PIC = 0 endif ifeq ("$(OS)","NONE") $(error OS type "$(UNAME)" not supported. Please file bug report at 'http://code.google.com/p/mupen64plus/issues') endif # detect system architecture HOST_CPU ?= $(shell uname -m) CPU := NONE ifneq ("$(filter x86_64 amd64,$(HOST_CPU))","") CPU := X86 ifeq ("$(BITS)", "32") ARCH_DETECTED := 64BITS_32 PIC ?= 0 else ARCH_DETECTED := 64BITS PIC ?= 1 endif endif ifneq ("$(filter pentium i%86,$(HOST_CPU))","") CPU := X86 ARCH_DETECTED := 32BITS PIC ?= 0 endif ifneq ("$(filter ppc macppc socppc powerpc,$(HOST_CPU))","") CPU := PPC ARCH_DETECTED := 32BITS BIG_ENDIAN := 1 PIC ?= 1 NO_ASM := 1 $(warning Architecture "$(HOST_CPU)" not officially supported.') endif ifneq ("$(filter ppc64 powerpc64,$(HOST_CPU))","") CPU := PPC ARCH_DETECTED := 64BITS BIG_ENDIAN := 1 PIC ?= 1 NO_ASM := 1 $(warning Architecture "$(HOST_CPU)" not officially supported.') endif ifneq ("$(filter arm%,$(HOST_CPU))","") ifeq ("$(filter arm%b,$(HOST_CPU))","") CPU := ARM ARCH_DETECTED := 32BITS PIC ?= 1 NO_ASM := 1 $(warning Architecture "$(HOST_CPU)" not officially supported.') endif endif ifeq ("$(CPU)","NONE") $(error CPU type "$(HOST_CPU)" not supported. Please file bug report at 'http://code.google.com/p/mupen64plus/issues') endif # base CFLAGS, LDLIBS, and LDFLAGS OPTFLAGS ?= -O3 -flto WARNFLAGS ?= -Wall CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -ffast-math -fno-strict-aliasing -fvisibility=hidden -I../../src CXXFLAGS += -fvisibility-inlines-hidden LDFLAGS += $(SHARED) ifeq ($(CPU), X86) CFLAGS += -msse endif # Since we are building a shared library, we must compile with -fPIC on some architectures # On 32-bit x86 systems we do not want to use -fPIC because we don't have to and it has a big performance penalty on this arch ifeq ($(PIC), 1) CFLAGS += -fPIC else CFLAGS += -fno-PIC endif ifeq ($(BIG_ENDIAN), 1) CFLAGS += -DM64P_BIG_ENDIAN endif # tweak flags for 32-bit build on 64-bit system ifeq ($(ARCH_DETECTED), 64BITS_32) ifeq ($(OS), FREEBSD) $(error Do not use the BITS=32 option with FreeBSD, use -m32 and -m elf_i386) endif CFLAGS += -m32 LDFLAGS += -Wl,-m,elf_i386 endif # set special flags per-system ifeq ($(OS), LINUX) LDLIBS += -ldl # only export api symbols LDFLAGS += -Wl,-version-script,$(SRCDIR)/video_api_export.ver endif ifeq ($(OS), OSX) # Select the proper SDK # Also, SDKs are stored in a different location since XCode 4.3 OSX_SDK ?= $(shell sw_vers -productVersion | cut -f1 -f2 -d .) OSX_XCODEMAJ = $(shell xcodebuild -version | grep '[0-9]*\.[0-9]*' | cut -f2 -d ' ' | cut -f1 -d .) OSX_XCODEMIN = $(shell xcodebuild -version | grep '[0-9]*\.[0-9]*' | cut -f2 -d ' ' | cut -f2 -d .) OSX_XCODEGE43 = $(shell echo "`expr $(OSX_XCODEMAJ) \>= 4``expr $(OSX_XCODEMIN) \>= 3`") ifeq ($(OSX_XCODEGE43), 11) OSX_SYSROOT := /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs else OSX_SYSROOT := /Developer/SDKs endif ifeq ($(CPU), X86) ifeq ($(ARCH_DETECTED), 64BITS) CFLAGS += -pipe -arch x86_64 -mmacosx-version-min=$(OSX_SDK) -isysroot $(OSX_SYSROOT)/MacOSX$(OSX_SDK).sdk LDFLAGS += -bundle LDLIBS += -ldl else CFLAGS += -pipe -mmmx -msse -fomit-frame-pointer -arch i686 -mmacosx-version-min=$(OSX_SDK) -isysroot $(OSX_SYSROOT)/MacOSX$(OSX_SDK).sdk LDFLAGS += -bundle LDLIBS += -ldl endif endif endif # test for essential build dependencies ifeq ($(origin PKG_CONFIG), undefined) PKG_CONFIG = $(CROSS_COMPILE)pkg-config ifeq ($(shell which $(PKG_CONFIG) 2>/dev/null),) $(error $(PKG_CONFIG) not found) endif endif ifeq ($(origin LIBPNG_CFLAGS) $(origin LIBPNG_LDLIBS), undefined undefined) ifeq ($(shell $(PKG_CONFIG) --modversion libpng 2>/dev/null),) $(error No libpng development libraries found!) endif LIBPNG_CFLAGS += $(shell $(PKG_CONFIG) --cflags libpng) LIBPNG_LDLIBS += $(shell $(PKG_CONFIG) --libs libpng) endif CFLAGS += $(LIBPNG_CFLAGS) LDLIBS += $(LIBPNG_LDLIBS) # search for OpenGL libraries ifeq ($(OS), OSX) GL_LDLIBS = -framework OpenGL endif ifeq ($(OS), MINGW) GL_LDLIBS = -lopengl32 endif ifeq ($(origin GL_CFLAGS) $(origin GL_LDLIBS), undefined undefined) ifeq ($(shell $(PKG_CONFIG) --modversion gl 2>/dev/null),) $(error No OpenGL development libraries found!) endif GL_CFLAGS += $(shell $(PKG_CONFIG) --cflags gl) GL_LDLIBS += $(shell $(PKG_CONFIG) --libs gl) endif CFLAGS += $(GL_CFLAGS) LDLIBS += $(GL_LDLIBS) # test for presence of SDL ifeq ($(origin SDL_CFLAGS) $(origin SDL_LDLIBS), undefined undefined) SDL_CONFIG = $(CROSS_COMPILE)sdl-config ifeq ($(shell which $(SDL_CONFIG) 2>/dev/null),) $(error No SDL development libraries found!) endif SDL_CFLAGS += $(shell $(SDL_CONFIG) --cflags) SDL_LDLIBS += $(shell $(SDL_CONFIG) --libs) endif CFLAGS += $(SDL_CFLAGS) LDLIBS += $(SDL_LDLIBS) # set mupen64plus core API header path ifneq ("$(APIDIR)","") CFLAGS += "-I$(APIDIR)" else TRYDIR = ../../../mupen64plus-core/src/api ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","") CFLAGS += -I$(TRYDIR) else TRYDIR = /usr/local/include/mupen64plus ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","") CFLAGS += -I$(TRYDIR) else TRYDIR = /usr/include/mupen64plus ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","") CFLAGS += -I$(TRYDIR) else $(error Mupen64Plus API header files not found! Use makefile parameter APIDIR to force a location.) endif endif endif endif # reduced compile output when running make without V=1 ifneq ($(findstring $(MAKEFLAGS),s),s) ifndef V Q_CC = @echo ' CC '$@; Q_CXX = @echo ' CXX '$@; Q_LD = @echo ' LD '$@; endif endif # set base program pointers and flags CC = $(CROSS_COMPILE)gcc CXX = $(CROSS_COMPILE)g++ RM ?= rm -f INSTALL ?= install MKDIR ?= mkdir -p COMPILE.c = $(Q_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c COMPILE.cc = $(Q_CXX)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c LINK.o = $(Q_LD)$(CXX) $(CXXFLAGS) $(LDFLAGS) $(TARGET_ARCH) # set special flags for given Makefile parameters ifeq ($(DEBUG),1) CFLAGS += -g INSTALL_STRIP_FLAG ?= else ifneq ($(OS),OSX) INSTALL_STRIP_FLAG ?= -s endif endif ifeq ($(NO_ASM), 1) CFLAGS += -DNO_ASM endif # set installation options ifeq ($(PREFIX),) PREFIX := /usr/local endif ifeq ($(SHAREDIR),) SHAREDIR := $(PREFIX)/share/mupen64plus endif ifeq ($(LIBDIR),) LIBDIR := $(PREFIX)/lib endif ifeq ($(PLUGINDIR),) PLUGINDIR := $(LIBDIR)/mupen64plus endif SRCDIR = ../../src OBJDIR = _obj$(POSTFIX) # list of source files to compile SOURCE = \ $(SRCDIR)/liblinux/BMGImage.c \ $(SRCDIR)/liblinux/BMGUtils.cpp \ $(SRCDIR)/liblinux/bmp.c \ $(SRCDIR)/liblinux/pngrw.c \ $(SRCDIR)/Blender.cpp \ $(SRCDIR)/Combiner.cpp \ $(SRCDIR)/CombinerTable.cpp \ $(SRCDIR)/Config.cpp \ $(SRCDIR)/ConvertImage.cpp \ $(SRCDIR)/ConvertImage16.cpp \ $(SRCDIR)/CNvTNTCombiner.cpp \ $(SRCDIR)/Debugger.cpp \ $(SRCDIR)/DecodedMux.cpp \ $(SRCDIR)/DirectXDecodedMux.cpp \ $(SRCDIR)/DeviceBuilder.cpp \ $(SRCDIR)/FrameBuffer.cpp \ $(SRCDIR)/GeneralCombiner.cpp \ $(SRCDIR)/GraphicsContext.cpp \ $(SRCDIR)/OGLCombiner.cpp \ $(SRCDIR)/OGLCombinerNV.cpp \ $(SRCDIR)/OGLCombinerTNT2.cpp \ $(SRCDIR)/OGLDecodedMux.cpp \ $(SRCDIR)/OGLExtCombiner.cpp \ $(SRCDIR)/OGLExtensions.cpp \ $(SRCDIR)/OGLExtRender.cpp \ $(SRCDIR)/OGLFragmentShaders.cpp \ $(SRCDIR)/OGLGraphicsContext.cpp \ $(SRCDIR)/OGLRender.cpp \ $(SRCDIR)/OGLRenderExt.cpp \ $(SRCDIR)/OGLTexture.cpp \ $(SRCDIR)/Render.cpp \ $(SRCDIR)/RenderBase.cpp \ $(SRCDIR)/RenderExt.cpp \ $(SRCDIR)/RenderTexture.cpp \ $(SRCDIR)/RSP_Parser.cpp \ $(SRCDIR)/RSP_S2DEX.cpp \ $(SRCDIR)/Texture.cpp \ $(SRCDIR)/TextureFilters.cpp \ $(SRCDIR)/TextureFilters_2xsai.cpp \ $(SRCDIR)/TextureFilters_hq2x.cpp \ $(SRCDIR)/TextureFilters_hq4x.cpp \ $(SRCDIR)/TextureManager.cpp \ $(SRCDIR)/VectorMath.cpp \ $(SRCDIR)/Video.cpp ifeq ($(OS),MINGW) SOURCE += \ $(SRCDIR)/osal_dynamiclib_win32.c \ $(SRCDIR)/osal_files_win32.c else SOURCE += \ $(SRCDIR)/osal_dynamiclib_unix.c \ $(SRCDIR)/osal_files_unix.c endif # generate a list of object files build, make a temporary directory for them OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(filter %.c, $(SOURCE))) OBJECTS += $(patsubst $(SRCDIR)/%.cpp, $(OBJDIR)/%.o, $(filter %.cpp, $(SOURCE))) OBJDIRS = $(dir $(OBJECTS)) $(shell $(MKDIR) $(OBJDIRS)) # build targets TARGET = mupen64plus-video-rice$(POSTFIX).$(SO_EXTENSION) targets: @echo "Mupen64plus-video-rice N64 Graphics plugin makefile. " @echo " Targets:" @echo " all == Build Mupen64plus-video-rice plugin" @echo " clean == remove object files" @echo " rebuild == clean and re-build all" @echo " install == Install Mupen64Plus-video-rice plugin" @echo " uninstall == Uninstall Mupen64Plus-video-rice plugin" @echo " Options:" @echo " BITS=32 == build 32-bit binaries on 64-bit machine" @echo " NO_ASM=1 == build without inline assembly code (x86 MMX/SSE)" @echo " APIDIR=path == path to find Mupen64Plus Core headers" @echo " OPTFLAGS=flag == compiler optimization (default: -O3 -flto)" @echo " WARNFLAGS=flag == compiler warning levels (default: -Wall)" @echo " PIC=(1|0) == Force enable/disable of position independent code" @echo " POSTFIX=name == String added to the name of the the build (default: '')" @echo " Install Options:" @echo " PREFIX=path == install/uninstall prefix (default: /usr/local)" @echo " SHAREDIR=path == path to install shared data files (default: PREFIX/share/mupen64plus)" @echo " LIBDIR=path == library prefix (default: PREFIX/lib)" @echo " PLUGINDIR=path == path to install plugin libraries (default: LIBDIR/mupen64plus)" @echo " DESTDIR=path == path to prepend to all installation paths (only for packagers)" @echo " Debugging Options:" @echo " DEBUG=1 == add debugging symbols" @echo " V=1 == show verbose compiler output" all: $(TARGET) install: $(TARGET) $(INSTALL) -d "$(DESTDIR)$(PLUGINDIR)" $(INSTALL) -m 0644 $(INSTALL_STRIP_FLAG) $(TARGET) "$(DESTDIR)$(PLUGINDIR)" $(INSTALL) -d "$(DESTDIR)$(SHAREDIR)" $(INSTALL) -m 0644 "../../data/RiceVideoLinux.ini" "$(DESTDIR)$(SHAREDIR)" uninstall: $(RM) "$(DESTDIR)$(PLUGINDIR)/$(TARGET)" $(RM) "$(DESTDIR)$(SHAREDIR)/RiceVideoLinux.ini" clean: $(RM) -r $(OBJDIR) $(TARGET) rebuild: clean all # build dependency files CFLAGS += -MD -include $(OBJECTS:.o=.d) CXXFLAGS += $(CFLAGS) # standard build rules $(OBJDIR)/%.o: $(SRCDIR)/%.c $(COMPILE.c) -o $@ $< $(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(COMPILE.cc) -o $@ $< $(TARGET): $(OBJECTS) $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ .PHONY: all clean install uninstall targets mupen64plus-video-rice-src-2.0/src/Blender.cpp0000644000000000000000000003633012165031100017354 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Render.h" const char * sc_szBlClr[4] = { "In", "Mem", "Bl", "Fog" }; const char * sc_szBlA1[4] = { "AIn", "AFog", "AShade", "0" }; const char * sc_szBlA2[4] = { "1-A", "AMem", "1", "0" }; //======================================================================== void CBlender::InitBlenderMode(void) // Set Alpha Blender mode { //1. Z_COMPARE -- Enable / Disable Zbuffer compare // 1 - Enable ZBuffer // 0 - Disable ZBuffer //2. Z_UPDATE -- Enable / Disable Zbuffer update // 1 - Enable ZBuffer writeable // 0 - Zbuffer not writeable //3. AA_EN and IM_RD -- Anti-Alias // AA_EN - Enable anti-aliase // AA_EN | IM_RD - Reduced anti-aliase // IM_RD - ?? // - - Disable anti-aliase //4. ZMode // #define ZMODE_OPA 0 -- Usually used with Z_COMPARE and Z_UPDATE // or used without neither Z_COMPARE or Z_UPDATE // if used with Z_COMPARE and Z_UPDATE, then this is // the regular ZBuffer mode, with compare and update // #define ZMODE_INTER 0x400 // #define ZMODE_XLU 0x800 -- Usually used with Z_COMPARE, but not with Z_UPDATE // Do only compare, no zbuffer update. // Not output if the z value is the same // #define ZMODE_DEC 0xc00 -- Usually used with Z_COMPARE, but not with Z_UPDATE // Do only compare, no update, but because this is // decal mode, so image should be updated even // the z value is the same as compared. CRender *render = CRender::g_pRender; // Alpha Blender Modes /* 6. FORCE_BL - Alpha blending at blender stage 1 - Enable alpha blending at blender 0 - Disable alpha blending at blender Alpha blending at blender is usually used to render XLU surface if enabled, then use the blending setting of C1 and C2 7. ALPHA_CVG_SEL - Output full alpha from the color combiner, usually not used together with FORCE_BL. If it is used together with FORCE_BL, then ignore this 8. CVG_X_ALPHA - Before output the color from color combiner, mod it with alpha 9. TEX_EDGE - Ignore this 10.CLR_ON_CVG - Used with XLU surfaces, ignore it 11.CVG_DST #define CVG_DST_CLAMP 0 - Usually used with OPA surface #define CVG_DST_WRAP 0x100 - Usually used with XLU surface or OPA line #define CVG_DST_FULL 0x200 - ? #define CVG_DST_SAVE 0x300 - ? Possible Blending Inputs: In - Input from color combiner Mem - Input from current frame buffer Fog - Fog generator BL - Blender Possible Blending Factors: A-IN - Alpha from color combiner A-MEM - Alpha from current frame buffer (1-A) - A-FOG - Alpha of fog color A-SHADE - Alpha of shade 1 - 1 0 - 0 */ #define BLEND_NOOP 0x0000 #define BLEND_NOOP5 0xcc48 // Fog * 0 + Mem * 1 #define BLEND_NOOP4 0xcc08 // Fog * 0 + In * 1 #define BLEND_FOG_ASHADE 0xc800 #define BLEND_FOG_3 0xc000 // Fog * AIn + In * 1-A #define BLEND_FOG_MEM 0xc440 // Fog * AFog + Mem * 1-A #define BLEND_FOG_APRIM 0xc400 // Fog * AFog + In * 1-A #define BLEND_BLENDCOLOR 0x8c88 #define BLEND_BI_AFOG 0x8400 // Bl * AFog + In * 1-A #define BLEND_BI_AIN 0x8040 // Bl * AIn + Mem * 1-A #define BLEND_MEM 0x4c40 // Mem*0 + Mem*(1-0)?! #define BLEND_FOG_MEM_3 0x44c0 // Mem * AFog + Fog * 1-A #define BLEND_NOOP3 0x0c48 // In * 0 + Mem * 1 #define BLEND_PASS 0x0c08 // In * 0 + In * 1 #define BLEND_FOG_MEM_IN_MEM 0x0440 // In * AFog + Mem * 1-A #define BLEND_FOG_MEM_FOG_MEM 0x04c0 // In * AFog + Fog * 1-A #define BLEND_OPA 0x0044 // In * AIn + Mem * AMem #define BLEND_XLU 0x0040 #define BLEND_MEM_ALPHA_IN 0x4044 // Mem * AIn + Mem * AMem uint32 blendmode_1 = (uint32)( gRDP.otherMode.blender & 0xcccc ); uint32 blendmode_2 = (uint32)( gRDP.otherMode.blender & 0x3333 ); uint32 cycletype = gRDP.otherMode.cycle_type; switch( cycletype ) { case CYCLE_TYPE_FILL: //BlendFunc(BLEND_ONE, BLEND_ZERO); //Enable(); Disable(); break; case CYCLE_TYPE_COPY: //Disable(); BlendFunc(BLEND_ONE, BLEND_ZERO); Enable(); break; case CYCLE_TYPE_2: if( gRDP.otherMode.force_bl && gRDP.otherMode.z_cmp ) { BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); Enable(); break; } /* if( gRDP.otherMode.alpha_cvg_sel && gRDP.otherMode.cvg_x_alpha==0 ) { BlendFunc(BLEND_ONE, BLEND_ZERO); Enable(); break; } */ switch( blendmode_1+blendmode_2 ) { case BLEND_PASS+(BLEND_PASS>>2): // In * 0 + In * 1 case BLEND_FOG_APRIM+(BLEND_PASS>>2): BlendFunc(BLEND_ONE, BLEND_ZERO); if( gRDP.otherMode.alpha_cvg_sel ) { Enable(); } else { Disable(); } render->SetAlphaTestEnable( ((gRDP.otherModeL >> RSP_SETOTHERMODE_SHIFT_ALPHACOMPARE) & 0x3)==1 ? TRUE : FALSE); break; case BLEND_PASS+(BLEND_OPA>>2): // 0x0c19 // Cycle1: In * 0 + In * 1 // Cycle2: In * AIn + Mem * AMem if( gRDP.otherMode.cvg_x_alpha && gRDP.otherMode.alpha_cvg_sel ) { BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); Enable(); } else { BlendFunc(BLEND_ONE, BLEND_ZERO); Enable(); } break; case BLEND_PASS + (BLEND_XLU>>2): // 0x0c18 // Cycle1: In * 0 + In * 1 // Cycle2: In * AIn + Mem * 1-A case BLEND_FOG_ASHADE + (BLEND_XLU>>2): //Cycle1: Fog * AShade + In * 1-A //Cycle2: In * AIn + Mem * 1-A case BLEND_FOG_APRIM + (BLEND_XLU>>2): //Cycle1: Fog * AFog + In * 1-A //Cycle2: In * AIn + Mem * 1-A //case BLEND_FOG_MEM_FOG_MEM + (BLEND_OPA>>2): //Cycle1: In * AFog + Fog * 1-A //Cycle2: In * AIn + Mem * AMem case BLEND_FOG_MEM_FOG_MEM + (BLEND_PASS>>2): //Cycle1: In * AFog + Fog * 1-A //Cycle2: In * 0 + In * 1 case BLEND_XLU + (BLEND_XLU>>2): //Cycle1: Fog * AFog + In * 1-A //Cycle2: In * AIn + Mem * 1-A case BLEND_BI_AFOG + (BLEND_XLU>>2): //Cycle1: Bl * AFog + In * 1-A //Cycle2: In * AIn + Mem * 1-A case BLEND_XLU + (BLEND_FOG_MEM_IN_MEM>>2): //Cycle1: In * AIn + Mem * 1-A //Cycle2: In * AFog + Mem * 1-A case BLEND_PASS + (BLEND_FOG_MEM_IN_MEM>>2): //Cycle1: In * 0 + In * 1 //Cycle2: In * AFog + Mem * 1-A BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); Enable(); break; case BLEND_FOG_MEM_FOG_MEM + (BLEND_OPA>>2): //Cycle1: In * AFog + Fog * 1-A //Cycle2: In * AIn + Mem * AMem BlendFunc(BLEND_ONE, BLEND_ZERO); Enable(); break; case BLEND_FOG_APRIM + (BLEND_OPA>>2): // For Golden Eye //Cycle1: Fog * AFog + In * 1-A //Cycle2: In * AIn + Mem * AMem case BLEND_FOG_ASHADE + (BLEND_OPA>>2): //Cycle1: Fog * AShade + In * 1-A //Cycle2: In * AIn + Mem * AMem case BLEND_BI_AFOG + (BLEND_OPA>>2): //Cycle1: Bl * AFog + In * 1-A //Cycle2: In * AIn + Mem * 1-AMem case BLEND_FOG_ASHADE + (BLEND_NOOP>>2): //Cycle1: Fog * AShade + In * 1-A //Cycle2: In * AIn + In * 1-A case BLEND_NOOP + (BLEND_OPA>>2): //Cycle1: In * AIn + In * 1-A //Cycle2: In * AIn + Mem * AMem case BLEND_NOOP4 + (BLEND_NOOP>>2): //Cycle1: Fog * AIn + In * 1-A //Cycle2: In * 0 + In * 1 case BLEND_FOG_ASHADE+(BLEND_PASS>>2): //Cycle1: Fog * AShade + In * 1-A //Cycle2: In * 0 + In * 1 case BLEND_FOG_3+(BLEND_PASS>>2): BlendFunc(BLEND_ONE, BLEND_ZERO); Enable(); break; case BLEND_FOG_ASHADE+0x0301: // c800 - Cycle1: Fog * AShade + In * 1-A // 0301 - Cycle2: In * 0 + In * AMem BlendFunc(BLEND_SRCALPHA, BLEND_ZERO); Enable(); break; case 0x0c08+0x1111: // 0c08 - Cycle1: In * 0 + In * 1 // 1111 - Cycle2: Mem * AFog + Mem * AMem BlendFunc(BLEND_ZERO, BLEND_DESTALPHA); Enable(); break; default: #ifdef DEBUGGER if( pauseAtNext ) { uint32 dwM1A_1 = (gRDP.otherMode.blender>>14) & 0x3; uint32 dwM1B_1 = (gRDP.otherMode.blender>>10) & 0x3; uint32 dwM2A_1 = (gRDP.otherMode.blender>>6) & 0x3; uint32 dwM2B_1 = (gRDP.otherMode.blender>>2) & 0x3; uint32 dwM1A_2 = (gRDP.otherMode.blender>>12) & 0x3; uint32 dwM1B_2 = (gRDP.otherMode.blender>>8) & 0x3; uint32 dwM2A_2 = (gRDP.otherMode.blender>>4) & 0x3; uint32 dwM2B_2 = (gRDP.otherMode.blender ) & 0x3; TRACE0("Unknown Blender Mode: 2 cycle"); DebuggerAppendMsg( "\tblender:\t\t%04x - Cycle1:\t%s * %s + %s * %s\n\t\t%04x - Cycle2:\t%s * %s + %s * %s", blendmode_1, sc_szBlClr[dwM1A_1], sc_szBlA1[dwM1B_1], sc_szBlClr[dwM2A_1], sc_szBlA2[dwM2B_1], blendmode_2, sc_szBlClr[dwM1A_2], sc_szBlA1[dwM1B_2], sc_szBlClr[dwM2A_2], sc_szBlA2[dwM2B_2]); } #endif if( blendmode_2 == (BLEND_PASS>>2) ) { BlendFunc(BLEND_ONE, BLEND_ZERO); } else { BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); } Enable(); break; } break; default: // 1/2 Cycle or Copy if( gRDP.otherMode.force_bl && gRDP.otherMode.z_cmp && blendmode_1 != BLEND_FOG_ASHADE ) { BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); Enable(); break; } if( gRDP.otherMode.force_bl && options.enableHackForGames == HACK_FOR_COMMANDCONQUER ) { BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); Enable(); break; } #ifdef DEBUGGER //if( (blendmode_1>>2) != blendmode_2 ) //{ // DebuggerAppendMsg("Warning: in 1 cycle mode, blend1!=blend2"); //} #endif switch ( blendmode_1 ) //switch ( blendmode_2<<2 ) { case BLEND_XLU: // IN * A_IN + MEM * (1-A_IN) case BLEND_BI_AIN: // Bl * AIn + Mem * 1-A case BLEND_FOG_MEM: // c440 - Cycle1: Fog * AFog + Mem * 1-A case BLEND_FOG_MEM_IN_MEM: // c440 - Cycle1: In * AFog + Mem * 1-A case BLEND_BLENDCOLOR: //Bl * 0 + Bl * 1 case 0x00c0: //In * AIn + Fog * 1-A BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); Enable(); break; case BLEND_MEM_ALPHA_IN: // Mem * AIn + Mem * AMem BlendFunc(BLEND_ZERO, BLEND_DESTALPHA); Enable(); break; case BLEND_PASS: // IN * 0 + IN * 1 BlendFunc(BLEND_ONE, BLEND_ZERO); if( gRDP.otherMode.alpha_cvg_sel ) { Enable(); } else { Disable(); } break; case BLEND_OPA: // IN * A_IN + MEM * A_MEM if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS ) { BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); } else { BlendFunc(BLEND_ONE, BLEND_ZERO); } Enable(); break; case BLEND_NOOP: // IN * A_IN + IN * (1 - A_IN) case BLEND_FOG_ASHADE: // Fog * AShade + In * 1-A case BLEND_FOG_MEM_3: // Mem * AFog + Fog * 1-A case BLEND_BI_AFOG: // Bl * AFog + In * 1-A BlendFunc(BLEND_ONE, BLEND_ZERO); Enable(); break; case BLEND_FOG_APRIM: // Fog * AFog + In * 1-A BlendFunc(BLEND_INVSRCALPHA, BLEND_ZERO); Enable(); break; case BLEND_NOOP3: // In * 0 + Mem * 1 case BLEND_NOOP5: // Fog * 0 + Mem * 1 BlendFunc(BLEND_ZERO, BLEND_ONE); Enable(); break; case BLEND_MEM: // Mem * 0 + Mem * 1-A // WaveRace BlendFunc(BLEND_ZERO, BLEND_ONE); Enable(); break; default: #ifdef DEBUGGER if( pauseAtNext ) { uint32 dwM1A_1 = (gRDP.otherMode.blender>>14) & 0x3; uint32 dwM1B_1 = (gRDP.otherMode.blender>>10) & 0x3; uint32 dwM2A_1 = (gRDP.otherMode.blender>>6) & 0x3; uint32 dwM2B_1 = (gRDP.otherMode.blender>>2) & 0x3; uint32 dwM1A_2 = (gRDP.otherMode.blender>>12) & 0x3; uint32 dwM1B_2 = (gRDP.otherMode.blender>>8) & 0x3; uint32 dwM2A_2 = (gRDP.otherMode.blender>>4) & 0x3; uint32 dwM2B_2 = (gRDP.otherMode.blender ) & 0x3; TRACE0("Unknown Blender Mode: 1 cycle"); DebuggerAppendMsg( "\tblender:\t\t%04x - Cycle1:\t%s * %s + %s * %s\n\t\t\tCycle2:\t%s * %s + %s * %s", blendmode_1, sc_szBlClr[dwM1A_1], sc_szBlA1[dwM1B_1], sc_szBlClr[dwM2A_1], sc_szBlA2[dwM2B_1], sc_szBlClr[dwM1A_2], sc_szBlA1[dwM1B_2], sc_szBlClr[dwM2A_2], sc_szBlA2[dwM2B_2]); } #endif BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); Enable(); render->SetAlphaTestEnable(TRUE); break; } } } mupen64plus-video-rice-src-2.0/src/Blender.h0000644000000000000000000000323312165031100017015 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _BLENDER_H_ #define _BLENDER_H_ #include "typedefs.h" class CRender; class CBlender { public: virtual ~CBlender() {} virtual void InitBlenderMode(void); virtual void NormalAlphaBlender(void)=0; virtual void DisableAlphaBlender(void)=0; virtual void BlendFunc(uint32 srcFunc, uint32 desFunc)=0; virtual void Enable()=0; virtual void Disable()=0; protected: CBlender(CRender *pRender) : m_pRender(pRender) {} CRender *m_pRender; }; typedef enum _BLEND { BLEND_ZERO = 1, BLEND_ONE = 2, BLEND_SRCCOLOR = 3, BLEND_INVSRCCOLOR = 4, BLEND_SRCALPHA = 5, BLEND_INVSRCALPHA = 6, BLEND_DESTALPHA = 7, BLEND_INVDESTALPHA = 8, BLEND_DESTCOLOR = 9, BLEND_INVDESTCOLOR = 10, BLEND_SRCALPHASAT = 11, BLEND_BOTHSRCALPHA = 12, BLEND_BOTHINVSRCALPHA = 13, BLEND_BLENDFACTOR = 14, BLEND_INVBLENDFACTOR = 15, BLEND_FORCE_DWORD = 0x7fffffff } BLEND; #endif mupen64plus-video-rice-src-2.0/src/CNvTNTCombiner.cpp0000644000000000000000000002550512165031100020536 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "CNvTNTCombiner.h" CNvTNTCombiner::CNvTNTCombiner() { m_lastIndexTNT = 0; } CNvTNTCombiner::~CNvTNTCombiner() { } int CNvTNTCombiner::FindCompiledMux( ) { for( uint32 i=0; im_dwMux0 && m_vCompiledTNTSettings[i].dwMux1 == (*m_ppDecodedMux)->m_dwMux1 ) { m_lastIndexTNT = i; return i; } } return -1; } bool isTex(uint32 val); bool isComb(uint32 val); int CNvTNTCombiner::ParseDecodedMux() { TNT2CombinerSaveType res; res.numOfUnits = 2; (*m_ppDecodedMux)->To_AB_Add_CD_Format(); for( int i=0; isplitType[i]; N64CombinerType &m = (*m_ppDecodedMux)->m_n64Combiners[i]; comb.arg0 = comb.arg1 = comb.arg2 = comb.arg3 = MUX_0; unit.ops[i%2] = 0x0104; //Add; //Subtract switch( type ) { case CM_FMT_TYPE_NOT_USED: comb.arg0 = MUX_COMBINED; comb.arg1 = MUX_1; comb.arg2 = MUX_0; comb.arg3 = MUX_1; case CM_FMT_TYPE_D: // = A comb.arg0 = m.d; comb.arg1 = MUX_1; comb.arg2 = MUX_0; comb.arg3 = MUX_0; break; case CM_FMT_TYPE_A_ADD_D: // = A+D comb.arg0 = m.a; comb.arg1 = MUX_1; comb.arg2 = m.d; comb.arg3 = MUX_1; if( isComb(m.d) ) { swap(comb.arg0, comb.arg2); swap(comb.arg1, comb.arg3); } break; case CM_FMT_TYPE_A_SUB_B: // = A-B comb.arg0 = m.a^MUX_COMPLEMENT; comb.arg1 = MUX_1; unit.ops[i%2] = GL_SUBTRACT_ARB; comb.arg2 = m.b; comb.arg3 = MUX_1; break; case CM_FMT_TYPE_A_MOD_C: // = A*C comb.arg0 = m.a; comb.arg1 = m.c; comb.arg2 = MUX_0; comb.arg3 = MUX_0; break; case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D comb.arg0 = m.a; comb.arg1 = m.c; comb.arg2 = m.d; comb.arg3 = MUX_1; if( isComb(m.d) ) { swap(comb.arg0, comb.arg2); swap(comb.arg1, comb.arg3); } break; case CM_FMT_TYPE_A_LERP_B_C: // = (A-B)*C+B comb.arg0 = m.a; comb.arg1 = m.c; comb.arg2 = m.c^MUX_COMPLEMENT; comb.arg3 = m.b; if( isComb(m.b) ) { swap(comb.arg0, comb.arg2); swap(comb.arg1, comb.arg3); } break; case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D // fix me, to use 2 texture units if( isTex(m.b) && isTex(m.d) ) { comb.arg0 = m.a; comb.arg1 = m.b; comb.arg2 = m.d; comb.arg3 = MUX_1; if( isComb(m.d) ) { swap(comb.arg0, comb.arg2); swap(comb.arg1, comb.arg3); } } else if( isTex(m.b) && !isComb(m.d) ) { comb.arg0 = m.a^MUX_COMPLEMENT; comb.arg1 = MUX_1; comb.arg2 = m.b; comb.arg3 = MUX_1; unit.ops[i%2] = GL_SUBTRACT_ARB; } else if( !isTex(m.b) && isTex(m.d) ) { comb.arg0 = m.a; comb.arg1 = MUX_1; comb.arg2 = m.d; comb.arg3 = MUX_1; if( isComb(m.d) ) { swap(comb.arg0, comb.arg2); swap(comb.arg1, comb.arg3); } } else { comb.arg0 = m.a; comb.arg1 = m.b; comb.arg2 = m.d; comb.arg3 = MUX_1; if( isComb(m.d) ) { swap(comb.arg0, comb.arg2); swap(comb.arg1, comb.arg3); } } break; case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C comb.arg0 = m.a^MUX_COMPLEMENT; comb.arg1 = m.c; comb.arg2 = m.c; comb.arg3 = m.b; unit.ops[i%2] = GL_SUBTRACT_ARB; break; case CM_FMT_TYPE_AB_ADD_CD: // = AB+CD comb.arg0 = m.a; comb.arg1 = m.b; comb.arg2 = m.c; comb.arg3 = m.d; if( isComb(m.d) || isComb(m.c) ) { swap(comb.arg0, comb.arg2); swap(comb.arg1, comb.arg3); } break; case CM_FMT_TYPE_AB_SUB_CD: // = AB-CD comb.arg0 = m.a^MUX_COMPLEMENT; comb.arg1 = m.b; unit.ops[i%2] = GL_SUBTRACT_ARB; comb.arg2 = m.c; comb.arg3 = m.d; break; case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D default: if( !isComb(m.d) && !isTex(m.d) ) { comb.arg0 = m.a^MUX_COMPLEMENT; comb.arg1 = m.c; unit.ops[i%2] = GL_SUBTRACT_ARB; comb.arg2 = m.c; comb.arg3 = m.b; } else if( !isComb(m.b) && !isTex(m.b) ) { comb.arg0 = m.a; comb.arg1 = m.c; comb.arg2 = m.d; comb.arg3 = MUX_1; if( isComb(m.d) ) { swap(comb.arg0, comb.arg2); swap(comb.arg1, comb.arg3); } } else if( !isComb(m.c) && !isTex(m.c) ) { comb.arg0 = m.a; comb.arg1 = m.b; comb.arg2 = m.d; comb.arg3 = MUX_1; if( isComb(m.d) ) { swap(comb.arg0, comb.arg2); swap(comb.arg1, comb.arg3); } } else { comb.arg0 = m.a; comb.arg1 = m.c; comb.arg2 = m.d; comb.arg3 = MUX_1; if( isComb(m.d) ) { swap(comb.arg0, comb.arg2); swap(comb.arg1, comb.arg3); } } break; } } ParseDecodedMuxForConstants(res); return SaveParserResult(res); } int CNvTNTCombiner::SaveParserResult(TNT2CombinerSaveType &result) { result.dwMux0 = (*m_ppDecodedMux)->m_dwMux0; result.dwMux1 = (*m_ppDecodedMux)->m_dwMux1; m_vCompiledTNTSettings.push_back(result); m_lastIndexTNT = m_vCompiledTNTSettings.size()-1; #ifdef DEBUGGER if( logCombiners ) { DisplaySimpleMuxString(); } #endif return m_lastIndexTNT; } void CNvTNTCombiner::ParseDecodedMuxForConstants(TNT2CombinerSaveType &res) { res.unit1.constant = MUX_0; res.unit2.constant = MUX_0; for( int i=0; i<2; i++ ) { if( (*m_ppDecodedMux)->isUsedInCycle(MUX_PRIM, i,COLOR_CHANNEL) || (*m_ppDecodedMux)->isUsedInCycle(MUX_PRIM, i,ALPHA_CHANNEL) ) { res.units[i].constant = MUX_PRIM; } else if( (*m_ppDecodedMux)->isUsedInCycle(MUX_ENV, i,COLOR_CHANNEL) || (*m_ppDecodedMux)->isUsedInCycle(MUX_ENV, i,ALPHA_CHANNEL) ) { res.units[i].constant = MUX_ENV; } else if( (*m_ppDecodedMux)->isUsedInCycle(MUX_LODFRAC, i,COLOR_CHANNEL) || (*m_ppDecodedMux)->isUsedInCycle(MUX_LODFRAC, i,ALPHA_CHANNEL) ) { res.units[i].constant = MUX_LODFRAC; } else if( (*m_ppDecodedMux)->isUsedInCycle(MUX_PRIMLODFRAC, i,COLOR_CHANNEL) || (*m_ppDecodedMux)->isUsedInCycle(MUX_PRIMLODFRAC, i,ALPHA_CHANNEL) ) { res.units[i].constant = MUX_PRIMLODFRAC; } } } #ifdef DEBUGGER extern const char *translatedCombTypes[]; void CNvTNTCombiner::DisplaySimpleMuxString() { char buf0[30]; char buf1[30]; char buf2[30]; char buf3[30]; TNT2CombinerSaveType &result = m_vCompiledTNTSettings[m_lastIndexTNT]; TRACE0("\nNVidia TNT2+ Combiner\n"); DebuggerAppendMsg("//aRGB0:\t(%s * %s) %s (%s * %s)\n", DecodedMux::FormatStr(result.unit1.rgbArg0,buf0), DecodedMux::FormatStr(result.unit1.rgbArg1,buf1), result.unit1.rgbOp==0x0104?"+":"-", DecodedMux::FormatStr(result.unit1.rgbArg2,buf2), DecodedMux::FormatStr(result.unit1.rgbArg3,buf3)); DebuggerAppendMsg("//aRGB1:\t(%s * %s) %s (%s * %s)\n", DecodedMux::FormatStr(result.unit2.rgbArg0,buf0), DecodedMux::FormatStr(result.unit2.rgbArg1,buf1), result.unit2.rgbOp==0x0104?"+":"-", DecodedMux::FormatStr(result.unit2.rgbArg2,buf2), DecodedMux::FormatStr(result.unit2.rgbArg3,buf3)); DebuggerAppendMsg("//aAlpha0:\t(%s * %s) %s (%s * %s)\n", DecodedMux::FormatStr(result.unit1.alphaArg0,buf0), DecodedMux::FormatStr(result.unit1.alphaArg1,buf1), result.unit1.alphaOp==0x0104?"+":"-", DecodedMux::FormatStr(result.unit1.alphaArg2,buf2), DecodedMux::FormatStr(result.unit1.alphaArg3,buf3)); DebuggerAppendMsg("//aAlpha1:\t(%s * %s) %s (%s * %s)\n", DecodedMux::FormatStr(result.unit2.alphaArg0,buf0), DecodedMux::FormatStr(result.unit2.alphaArg1,buf1), result.unit2.alphaOp==0x0104?"+":"-", DecodedMux::FormatStr(result.unit2.alphaArg2,buf2), DecodedMux::FormatStr(result.unit2.alphaArg3,buf3)); if( result.unit1.constant != MUX_0 ) DebuggerAppendMsg("//Constant for unit 1:\t%s\n", DecodedMux::FormatStr(result.unit1.constant,buf0)); if( result.unit2.constant != MUX_0 ) DebuggerAppendMsg("//Constant for unit 2:\t%s\n", DecodedMux::FormatStr(result.unit2.constant,buf0)); TRACE0("\n\n"); } #endif mupen64plus-video-rice-src-2.0/src/CNvTNTCombiner.h0000644000000000000000000000435712165031100020205 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _NVIDIA_TNT_COMBINER_H_ #define _NVIDIA_TNT_COMBINER_H_ #include #include "Combiner.h" typedef struct { uint8 arg0; uint8 arg1; uint8 arg2; uint8 arg3; } TNT2CombType; typedef struct { union { struct { unsigned int rgbOp; unsigned int alphaOp; }; unsigned int ops[2]; }; union { struct { uint8 rgbArg0; uint8 rgbArg1; uint8 rgbArg2; uint8 rgbArg3; uint8 alphaArg0; uint8 alphaArg1; uint8 alphaArg2; uint8 alphaArg3; }; TNT2CombType Combs[2]; uint8 args[2][4]; }; int constant; } TNT2CombinerType; typedef struct { uint32 dwMux0; uint32 dwMux1; union { struct { TNT2CombinerType unit1; TNT2CombinerType unit2; }; TNT2CombinerType units[2]; }; int numOfUnits; } TNT2CombinerSaveType; class CNvTNTCombiner { protected: CNvTNTCombiner(); virtual ~CNvTNTCombiner(); int FindCompiledMux(); int ParseDecodedMux(); // Compile the decodedMux into NV register combiner setting virtual void ParseDecodedMuxForConstants(TNT2CombinerSaveType &res); int SaveParserResult(TNT2CombinerSaveType &result); #ifdef DEBUGGER void DisplaySimpleMuxString(); #endif std::vector m_vCompiledTNTSettings; int m_lastIndexTNT; DecodedMux **m_ppDecodedMux; }; #endif mupen64plus-video-rice-src-2.0/src/COLOR.h0000644000000000000000000000542212165031100016322 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - COLOR.h * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2002 Rice1964 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef XCOLOR_H #define XCOLOR_H typedef struct _COLORVALUE { float r; float g; float b; float a; } COLORVALUE; typedef struct XCOLOR { float r, g, b, a; #ifdef __cplusplus public: XCOLOR() { } XCOLOR( unsigned int argb ); XCOLOR( const float * ); XCOLOR( const COLORVALUE& ); XCOLOR( float r, float g, float b, float a ); // casting operator unsigned int () const; operator float* (); operator const float* () const; operator COLORVALUE* (); operator const COLORVALUE* () const; operator COLORVALUE& (); operator const COLORVALUE& () const; // assignment operators XCOLOR& operator += ( const XCOLOR& ); XCOLOR& operator -= ( const XCOLOR& ); XCOLOR& operator *= ( float ); XCOLOR& operator /= ( float ); // unary operators XCOLOR operator + () const; XCOLOR operator - () const; // binary operators XCOLOR operator + ( const XCOLOR& ) const; XCOLOR operator - ( const XCOLOR& ) const; XCOLOR operator * ( float ) const; XCOLOR operator / ( float ) const; friend XCOLOR operator * (float, const XCOLOR& ); bool operator == ( const XCOLOR& ) const; bool operator != ( const XCOLOR& ) const; #endif //__cplusplus } XCOLOR; #endif mupen64plus-video-rice-src-2.0/src/CSortedList.h0000644000000000000000000000674112165031100017650 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _SORTED_LIST_H_ #define _SORTED_LIST_H_ #include template class CSortedList { private: Key *keys; Element *elements; int curSize; int maxSize; public: CSortedList(int size=1000) { maxSize = size; curSize = 0; keys = new Key[size]; elements = new Element[size]; } ~CSortedList() { delete [] keys; delete [] elements; } int size() { return curSize; } void clear() { curSize = 0; } void add(Key key, Element ele) { int i = find(key); if( i >= 0 ) { elements[i] = ele; return; } if( curSize == maxSize ) { // Need to increase maxSize Key *oldkeys = keys; Element *oldelements = elements; int oldmaxsize = maxSize; maxSize *= 2; keys = new Key[maxSize]; elements = new Element[maxSize]; std::memcpy(keys,oldkeys,oldmaxsize*sizeof(Key)); std::memcpy(elements,oldelements,oldmaxsize*sizeof(Element)); } for( i=0; i key ) { // Found the spot break; } } for( int j=curSize; j>i; j-- ) { keys[j] = keys[j-1]; elements[j] = elements[j-1]; } keys[i] = key; elements[i] = ele; curSize++; } Element operator[](int index) { if( index >= curSize ) index = curSize-1; else if( index < 0 ) index = 0; return elements[index]; } Element get(Key key) { int index = Find(key); return this->operator[](index); } // Binary search int find(Key key) { if( curSize <= 0 ) return -1; int dwMin = 0; int dwMax = curSize - 1; int index = -1; int dwRange; int dwIndex; while (true) { dwRange = dwMax - dwMin; dwIndex = dwMin + (dwRange/2); if( keys[dwIndex] == key ) { index = dwIndex; break; } // If the range is 0, and we didn't match above, then it must be unmatched if (dwRange == 0) break; // If lower, check from min..index // If higher, check from index..max if (key < keys[dwIndex]) { // Lower dwMax = dwIndex; } else { // Higher dwMin = dwIndex + 1; } } return index; } }; #endif mupen64plus-video-rice-src-2.0/src/Combiner.cpp0000644000000000000000000002721612165031100017542 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Combiner.h" #include "Config.h" #include "RenderBase.h" //static BOOL g_bHiliteRGBAHack = FALSE; #ifdef DEBUGGER const char *constStrs[] = { "MUX_0", "MUX_1", "MUX_COMBINED", "MUX_TEXEL0", "MUX_TEXEL1", "MUX_PRIM", "MUX_SHADE", "MUX_ENV", "MUX_COMBALPHA", "MUX_T0_ALPHA", "MUX_T1_ALPHA", "MUX_PRIM_ALPHA", "MUX_SHADE_ALPHA", "MUX_ENV_ALPHA", "MUX_LODFRAC", "MUX_PRIMLODFRAC", "MUX_K5", "MUX_UNK", }; const char *cycleTypeStrs[] = { "1 Cycle", "2 Cycle", "Copy Mode", "Fill Mode" }; const char* constStr(uint32 op) { if(op<=MUX_UNK) return constStrs[op]; else return "Invalid-Const"; } #endif void swap(uint8 &a, uint8 &b) { uint8 c=a; a=b; b=c; } //======================================================================== //======================================================================== inline IColor GetIColor(uint8 flag, uint32 curCol) { IColor newc; switch(flag&MUX_MASK) { case MUX_0: newc = 0; break; case MUX_1: newc = 0xFFFFFFFF; break; case MUX_PRIM: newc = gRDP.primitiveColor; break; case MUX_ENV: newc = gRDP.envColor; break; case MUX_COMBINED: case MUX_SHADE: newc = curCol; break; case MUX_K5: newc = 0xFFFFFFFF; break; case MUX_UNK: newc = curCol; if( options.enableHackForGames == HACK_FOR_CONKER ) newc = 0xFFFFFFFF; break; default: newc = curCol; break; } if( flag&MUX_COMPLEMENT ) { newc.Complement(); } if( flag&MUX_ALPHAREPLICATE ) { newc.AlphaReplicate(); } return newc; } COLOR CalculateConstFactor(uint32 colorOp, uint32 alphaOp, uint32 curCol) { N64CombinerType m; IColor color(curCol); IColor alpha(curCol); // For color channel *(uint32*)&m = colorOp; if( m.c != MUX_0 && m.a!=m.b) { if( m.a != MUX_0 ) color = GetIColor(m.a, curCol); if( m.b != MUX_0 ) color -= GetIColor(m.b, curCol); if( m.c != MUX_1 ) color *= GetIColor(m.c, curCol); } if( m.d != MUX_0 ) color += GetIColor(m.d, curCol); // For alpha channel *(uint32*)&m = alphaOp; if( m.c != MUX_0 && m.a!=m.b) { if( m.a != MUX_0 ) alpha = GetIColor(m.a, curCol); if( m.b != MUX_0 ) alpha -= GetIColor(m.b, curCol); if( m.c != MUX_1 ) alpha *= GetIColor(m.c, curCol); } if( m.d != MUX_0 ) alpha += GetIColor(m.d, curCol); return (COLOR)(((uint32)color&0x00FFFFFF)|((uint32)alpha&0xFF000000)); } COLOR CColorCombiner::GetConstFactor(uint32 colorFlag, uint32 alphaFlag, uint32 defaultColor) { // Allows a combine mode to select what TFACTOR should be uint32 color = defaultColor; uint32 alpha = defaultColor; switch (colorFlag&MUX_MASK) { case MUX_0: break; case MUX_FORCE_0: color = 0; break; case MUX_1: color = 0xFFFFFFFF; break; case MUX_PRIM: color = gRDP.primitiveColor; break; case MUX_ENV: color = gRDP.envColor; break; case MUX_LODFRAC: color = COLOR_RGBA(gRDP.LODFrac, gRDP.LODFrac, gRDP.LODFrac, gRDP.LODFrac); break; case MUX_PRIMLODFRAC: color = COLOR_RGBA(gRDP.primLODFrac, gRDP.primLODFrac, gRDP.primLODFrac, gRDP.primLODFrac); break; case MUX_PRIM_ALPHA: { IColor col(gRDP.primitiveColor); col.AlphaReplicate(); color = (COLOR)col; } break; case MUX_ENV_ALPHA: { IColor col(gRDP.envColor); col.AlphaReplicate(); color = (COLOR)col; } break; case MUX_K5: color = 0xFFFFFFFF; break; case MUX_UNK: color = defaultColor; if( options.enableHackForGames == HACK_FOR_CONKER ) color = 0xFFFFFFFF; break; default: color = defaultColor; break; } if( colorFlag & MUX_COMPLEMENT ) { color = 0xFFFFFFFF - color; } if( colorFlag & MUX_ALPHAREPLICATE ) { color = color>>24; color = color | (color<<8) | (color <<16) | (color<<24); } color &= 0x00FFFFFF; // For color channel only, not the alpha channel switch (alphaFlag&MUX_MASK) { case MUX_0: break; case MUX_FORCE_0: alpha = 0; break; case MUX_1: alpha = 0xFFFFFFFF; break; case MUX_PRIM: alpha = gRDP.primitiveColor; break; case MUX_ENV: alpha = gRDP.envColor; break; case MUX_LODFRAC: alpha = COLOR_RGBA(gRDP.LODFrac, gRDP.LODFrac, gRDP.LODFrac, gRDP.LODFrac); break; case MUX_PRIMLODFRAC: alpha = COLOR_RGBA(gRDP.primLODFrac, gRDP.primLODFrac, gRDP.primLODFrac, gRDP.primLODFrac); break; case MUX_PRIM_ALPHA: { IColor col(gRDP.primitiveColor); col.AlphaReplicate(); alpha = (COLOR)col; } break; case MUX_ENV_ALPHA: { IColor col(gRDP.envColor); col.AlphaReplicate(); alpha = (COLOR)col; } break; default: alpha = defaultColor; break; } if( alphaFlag & MUX_COMPLEMENT ) { alpha = 0xFFFFFFFF - alpha; } alpha &= 0xFF000000; return (color|alpha); } //***************************************************************************** // //***************************************************************************** bool gUsingPrimColour = false; bool gUsingEnvColour = false; int CountTexel1Cycle(N64CombinerType &m) { int hasTexel[2]; uint8 *p = (uint8*)&m; for( int i=0; i<2; i++) { hasTexel[i]=0; for( int j=0; j<4; j++) { if( (p[j]&MUX_MASK) == MUX_TEXEL0+i ) { hasTexel[i]=1; break; } } } return hasTexel[0]+hasTexel[1]; } uint32 GetTexelNumber(N64CombinerType &m) { if( (m.a&MUX_MASK) == MUX_TEXEL1 || (m.b&MUX_MASK) == MUX_TEXEL1 || (m.c&MUX_MASK) == MUX_TEXEL1 || (m.d&MUX_MASK) == MUX_TEXEL1 ) return TEX_1; else return TEX_0; } bool IsTxtrUsed(N64CombinerType &m) { if( (m.a&MUX_MASK) == MUX_TEXEL1 || (m.b&MUX_MASK) == MUX_TEXEL1 || (m.c&MUX_MASK) == MUX_TEXEL1 || (m.d&MUX_MASK) == MUX_TEXEL1 ) return true; if( (m.a&MUX_MASK) == MUX_TEXEL0 || (m.b&MUX_MASK) == MUX_TEXEL0 || (m.c&MUX_MASK) == MUX_TEXEL0 || (m.d&MUX_MASK) == MUX_TEXEL0 ) return true; else return false; } //======================================================================== void CColorCombiner::InitCombinerMode(void) { #ifdef DEBUGGER LOG_UCODE(cycleTypeStrs[gRDP.otherMode.cycle_type]); if( debuggerDropDecodedMux ) { UpdateCombiner(m_pDecodedMux->m_dwMux0, m_pDecodedMux->m_dwMux1); } #endif if( currentRomOptions.bNormalCombiner ) { DisableCombiner(); } else if( gRDP.otherMode.cycle_type == CYCLE_TYPE_COPY ) { InitCombinerCycleCopy(); m_bCycleChanged = true; } else if ( gRDP.otherMode.cycle_type == CYCLE_TYPE_FILL ) //else if ( gRDP.otherMode.cycle_type == CYCLE_TYPE_FILL && gRSP.ucode != 5 ) //hack { InitCombinerCycleFill(); m_bCycleChanged = true; } else { InitCombinerCycle12(); m_bCycleChanged = false; } } bool bConkerHideShadow=false; void CColorCombiner::UpdateCombiner(uint32 dwMux0, uint32 dwMux1) { #ifdef DEBUGGER if( debuggerDropDecodedMux ) { debuggerDropDecodedMux = false; m_pDecodedMux->m_dwMux0 = m_pDecodedMux->m_dwMux1 = 0; m_DecodedMuxList.clear(); } #endif DecodedMux &m_decodedMux = *m_pDecodedMux; if( m_decodedMux.m_dwMux0 != dwMux0 || m_decodedMux.m_dwMux1 != dwMux1 ) { if( options.enableHackForGames == HACK_FOR_DR_MARIO ) { // Hack for Dr. Mario if( dwMux1 == 0xfffcf239 && ((m_decodedMux.m_dwMux0 == dwMux0 && dwMux0 == 0x00ffffff && m_decodedMux.m_dwMux1 != dwMux1 && m_decodedMux.m_dwMux1 == 0xfffcf279 ) || (m_decodedMux.m_dwMux0 == 0x00ffb3ff && m_decodedMux.m_dwMux1 == 0xff64fe7f && dwMux0 == 0x00ffffff ) )) { //dwMux1 = 0xffcf23A; dwMux1 = 0xfffcf438; } } uint64 mux64 = (((uint64)dwMux1)<<32)+dwMux0; int index=m_DecodedMuxList.find(mux64); if( options.enableHackForGames == HACK_FOR_CONKER ) { // Conker's shadow, to disable the shadow //Mux=0x00ffe9ff Used in CONKER BFD //Color0: (0 - 0) * 0 + SHADE //Color1: (0 - 0) * 0 + SHADE //Alpha0: (1 - TEXEL0) * SHADE + 0 //Alpha1: (1 - TEXEL0) * SHADE + 0 if( dwMux1 == 0xffd21f0f && dwMux0 == 0x00ffe9ff ) { bConkerHideShadow = true; } else { bConkerHideShadow = false; } } if( index >= 0 ) { m_decodedMux = m_DecodedMuxList[index]; } else { m_decodedMux.Decode(dwMux0, dwMux1); m_decodedMux.splitType[0] = CM_FMT_TYPE_NOT_CHECKED; m_decodedMux.splitType[1] = CM_FMT_TYPE_NOT_CHECKED; m_decodedMux.splitType[2] = CM_FMT_TYPE_NOT_CHECKED; m_decodedMux.splitType[3] = CM_FMT_TYPE_NOT_CHECKED; m_decodedMux.Hack(); if( !m_bSupportMultiTexture ) { m_decodedMux.ReplaceVal(MUX_TEXEL1, MUX_TEXEL0); m_decodedMux.ReplaceVal(MUX_LODFRAC,1); m_decodedMux.ReplaceVal(MUX_PRIMLODFRAC,1); } m_decodedMux.Simplify(); if( m_supportedStages>1) m_decodedMux.SplitComplexStages(); m_DecodedMuxList.add(m_decodedMux.m_u64Mux, *m_pDecodedMux); #ifdef DEBUGGER if( logCombiners ) { TRACE0("Add a new mux"); DisplayMuxString(); } #endif } m_bTex0Enabled = m_decodedMux.m_bTexel0IsUsed; m_bTex1Enabled = m_decodedMux.m_bTexel1IsUsed; m_bTexelsEnable = m_bTex0Enabled||m_bTex1Enabled; gRSP.bProcessDiffuseColor = (m_decodedMux.m_dwShadeColorChannelFlag != MUX_0 || m_decodedMux.m_dwShadeAlphaChannelFlag != MUX_0); gRSP.bProcessSpecularColor = false; } } #ifdef DEBUGGER void CColorCombiner::DisplayMuxString(void) { if( gRDP.otherMode.cycle_type == CYCLE_TYPE_COPY) { TRACE0("COPY Mode\n"); } else if( gRDP.otherMode.cycle_type == CYCLE_TYPE_FILL) { TRACE0("FILL Mode\n"); } m_pDecodedMux->DisplayMuxString("Used"); } void CColorCombiner::DisplaySimpleMuxString(void) { m_pDecodedMux->DisplaySimpliedMuxString("Used"); } #endif mupen64plus-video-rice-src-2.0/src/Combiner.h0000644000000000000000000000536512165031100017210 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _COMBINER_H_ #define _COMBINER_H_ #include "typedefs.h" #include "CombinerDefs.h" #include "CSortedList.h" #include "DecodedMux.h" class CRender; extern const char* cycleTypeStrs[]; class CColorCombiner { friend class CRender; public: virtual ~CColorCombiner() {}; COLOR GetConstFactor(uint32 colorFlag, uint32 alphaFlag, uint32 defaultColor = 0); virtual void InitCombinerMode(void); virtual bool Initialize(void)=0; virtual void CleanUp(void) {}; virtual void UpdateCombiner(uint32 dwMux0, uint32 dwMux1); virtual void InitCombinerBlenderForSimpleTextureDraw(uint32 tile=0)=0; virtual void DisableCombiner(void)=0; #ifdef DEBUGGER virtual void DisplaySimpleMuxString(void); virtual void DisplayMuxString(void); #endif DecodedMux *m_pDecodedMux; protected: CColorCombiner(CRender *pRender) : m_pDecodedMux(NULL), m_bTex0Enabled(false),m_bTex1Enabled(false),m_bTexelsEnable(false), m_bCycleChanged(false), m_supportedStages(1),m_bSupportMultiTexture(true),m_pRender(pRender) { } virtual void InitCombinerCycleCopy(void)=0; virtual void InitCombinerCycleFill(void)=0; virtual void InitCombinerCycle12(void)=0; bool m_bTex0Enabled; bool m_bTex1Enabled; bool m_bTexelsEnable; bool m_bCycleChanged; // A flag will be set if cycle is changed to FILL or COPY int m_supportedStages; bool m_bSupportMultiTexture; CRender *m_pRender; CSortedList m_DecodedMuxList; }; uint32 GetTexelNumber(N64CombinerType &m); int CountTexel1Cycle(N64CombinerType &m); bool IsTxtrUsed(N64CombinerType &m); void swap(uint8 &a, uint8 &b); inline bool isEqual(uint8 val1, uint8 val2) { if( (val1&MUX_MASK) == (val2&MUX_MASK) ) return true; else return false; } inline bool isTexel(uint8 val) { if( (val&MUX_MASK) == MUX_TEXEL0 || (val&MUX_MASK) == MUX_TEXEL1 ) return true; else return false; } COLOR CalculateConstFactor(uint32 colorOp, uint32 alphaOp, uint32 curCol=0); #endif mupen64plus-video-rice-src-2.0/src/CombinerDefs.h0000644000000000000000000000766112165031100020013 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _COMBINER_DEFS_H_ #define _COMBINER_DEFS_H_ #include "typedefs.h" #define MUX_MASK 0x1F #define MUX_MASK_WITH_ALPHA 0x5F #define MUX_MASK_WITH_NEG 0x3F #define MUX_MASK_WITH_COMP 0x9F enum { MUX_0 = 0, MUX_1, MUX_COMBINED, MUX_TEXEL0, MUX_TEXEL1, MUX_PRIM, MUX_SHADE, MUX_ENV, MUX_COMBALPHA, MUX_T0_ALPHA, MUX_T1_ALPHA, MUX_PRIM_ALPHA, MUX_SHADE_ALPHA, MUX_ENV_ALPHA, MUX_LODFRAC, MUX_PRIMLODFRAC, MUX_K5, MUX_UNK, //Use this if you want to factor to be set to 0 // Don't change value of these three flags, then need to be within 1 uint8 MUX_NEG = 0x20, //Support by NVidia register combiner MUX_ALPHAREPLICATE = 0x40, MUX_COMPLEMENT = 0x80, MUX_FORCE_0 = 0xFE, MUX_ERR = 0xFF, }; enum CombinerFormatType { CM_FMT_TYPE_NOT_USED, CM_FMT_TYPE_D, // = A can mapped to SEL(arg1) CM_FMT_TYPE_A_MOD_C, // = A*C can mapped to MOD(arg1,arg2) CM_FMT_TYPE_A_ADD_D, // = A+D can mapped to ADD(arg1,arg2) CM_FMT_TYPE_A_SUB_B, // = A-B can mapped to SUB(arg1,arg2) CM_FMT_TYPE_A_MOD_C_ADD_D, // = A*C+D can mapped to MULTIPLYADD(arg1,arg2,arg0) CM_FMT_TYPE_A_LERP_B_C, // = (A-B)*C+B can mapped to LERP(arg1,arg2,arg0) // or mapped to BLENDALPHA(arg1,arg2) if C is // alpha channel or DIF, TEX, FAC, CUR CM_FMT_TYPE_A_SUB_B_ADD_D, // = A-B+C can not map very well in 1 stage CM_FMT_TYPE_A_SUB_B_MOD_C, // = (A-B)*C can not map very well in 1 stage CM_FMT_TYPE_A_ADD_B_MOD_C, // = (A+B)*C can not map very well in 1 stage CM_FMT_TYPE_A_B_C_D, // = (A-B)*C+D can not map very well in 1 stage CM_FMT_TYPE_A_B_C_A, // = (A-B)*C+D can not map very well in 1 stage // Don't use these two types in default functions CM_FMT_TYPE_AB_ADD_CD, // = A*B+C*D Use by nvidia video cards CM_FMT_TYPE_AB_SUB_CD, // = A*B-C*D Use by nvidia video cards CM_FMT_TYPE_AB_ADD_C, // = A*B+C Use by ATI video cards CM_FMT_TYPE_AB_SUB_C, // = A*B-C Use by ATI video cards CM_FMT_TYPE_NOT_CHECKED = 0xFF, }; typedef enum { ENABLE_BOTH, DISABLE_ALPHA, DISABLE_COLOR, DISABLE_BOTH, COLOR_ONE, ALPHA_ONE, } BlendingFunc; typedef enum { COLOR_CHANNEL, ALPHA_CHANNEL, } CombineChannel; typedef struct { uint8 a; uint8 b; uint8 c; uint8 d; } N64CombinerType; #define CONST_FLAG4(a,b,c,d) (a|(b<<8)|(c<<16)|(d<<24)) //(A-B)*C+D #define CONST_MOD(a,b) (a|(b<<16)) //A*B #define CONST_SEL(a) (a<<24) //=D #define CONST_ADD(a,b) (a|b<<24) //A+D #define CONST_SUB(a,b) (a|b<<8) //A-B #define CONST_MULADD(a,b,c) (a|b<<16|c<<24) //A*C+D #define G_CCMUX_TEXEL1 2 #define G_ACMUX_TEXEL1 2 #define NOTUSED MUX_0 enum { TEX_0=0, TEX_1=1}; typedef struct { uint32 op; uint32 Arg1; uint32 Arg2; uint32 Arg0; } StageOperate; #endif mupen64plus-video-rice-src-2.0/src/CombinerTable.cpp0000644000000000000000000055463012165031100020517 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "GeneralCombiner.h" //Attention // If using CUR as an argument, use it as Arg2, not Arg1. I don't know why, // Geforce2 seems to be picky about this // LERP and MULTIPLYADD are actually implemented in 2 stages in video chip // they can only be used with SEL() before it, or use 1 stage only // SEL(SPE) only is not good for alpha channel // In fact, Specular color does not have alpha channel // ADDSMOOTH does not work // When using MOD with TEX and other, TEX must be the first argument, Arg1 // When MOD the DIF and FAC, using MOD(FAC,DIF) instead of MOD(DIF,FAC) // Don't MOD(TEX,DIF) at Alpha channel, I don't know why this does not work // probably there is not alpha blending for DIFFUSE at alpha channel // Modifier COMPLEMENT and ALPHAREPLICATE only works as the first argument of the MOD operate // Modifier ALPHAREPLICATE works // Combined modifier of COMPLEMENT and ALPHAREPLICATE also works #define MUX_T0 MUX_TEXEL0 #define MUX_T1 MUX_TEXEL1 #define MUX_DIF MUX_SHADE #define MUX_COM MUX_COMBINED #define MUX_CUR MUX_COMBINED #define MUX_PRI MUX_PRIM #define MUX_T0A (MUX_TEXEL0|MUX_ALPHAREPLICATE) #define MUX_T1A (MUX_TEXEL1|MUX_ALPHAREPLICATE) #define MUX_DIFA (MUX_SHADE|MUX_ALPHAREPLICATE) #define MUX_COMA (MUX_COMBINED|MUX_ALPHAREPLICATE) #define MUX_CURA (MUX_COMBINED|MUX_ALPHAREPLICATE) #define MUX_PRIA (MUX_PRIM|MUX_ALPHAREPLICATE) #define MUX_ENVA (MUX_ENV|MUX_ALPHAREPLICATE) #define MUX_T0C (MUX_TEXEL0|MUX_COMPLEMENT) #define MUX_T1C (MUX_TEXEL1|MUX_COMPLEMENT) #define MUX_DIFC (MUX_SHADE|MUX_COMPLEMENT) #define MUX_COMC (MUX_COMBINED|MUX_COMPLEMENT) #define MUX_CURC (MUX_COMBINED|MUX_COMPLEMENT) #define MUX_PRIC (MUX_PRIM|MUX_COMPLEMENT) #define MUX_ENVC (MUX_ENV|MUX_COMPLEMENT) #define MUX_T0AC (MUX_TEXEL0|MUX_COMPLEMENT|MUX_ALPHAREPLICATE) #define MUX_T1AC (MUX_TEXEL1|MUX_COMPLEMENT|MUX_ALPHAREPLICATE) #define MUX_DIFAC (MUX_SHADE|MUX_COMPLEMENT|MUX_ALPHAREPLICATE) #define MUX_COMAC (MUX_COMBINED|MUX_COMPLEMENT|MUX_ALPHAREPLICATE) #define MUX_CURAC (MUX_COMBINED|MUX_COMPLEMENT|MUX_ALPHAREPLICATE) #define MUX_PRIAC (MUX_PRIM|MUX_COMPLEMENT|MUX_ALPHAREPLICATE) #define MUX_ENVAC (MUX_ENV|MUX_COMPLEMENT|MUX_ALPHAREPLICATE) #define ONEARGS(op, arg1) {CM_##op, MUX_##arg1} #define TWOARGS(op, arg1,arg2) {CM_##op, MUX_##arg1, MUX_##arg2} #define TRIARGS(op, arg1,arg2,arg3) {CM_##op, MUX_##arg1, MUX_##arg2, MUX_##arg3} #define SEL(arg1) ONEARGS(REPLACE,arg1) #define MOD(arg1,arg2) TWOARGS(MODULATE,arg1,arg2) #define ADD(arg1,arg2) TWOARGS(ADD,arg1,arg2) #define SUB(arg1,arg2) TWOARGS(SUBTRACT,arg1,arg2) #define ADDSMOOTH(arg1,arg2) TWOARGS(ADDSMOOTH,arg1,arg2) #define LERP(arg1,arg2,arg3) TRIARGS(INTERPOLATE,arg1,arg2,arg3) #define MULADD(arg1,arg2,arg3) TRIARGS(MULTIPLYADD,arg1,arg2,arg3) #define SKIP SEL(CUR) GeneralCombinerInfo twostages[]= { /* Stage overflow //Mux=0x00267e60350cf37f Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL1 - PRIM) * ENV|A + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00267e60350cf37f Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=03470604, 00060003, 07020706, 02000000 Color0: (TEXEL1 - SHADE) * ENV|A + TEXEL0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKED Shade = PRIM in color channel Shade = PRIM in alpha channel */ { {0x03470604, 0x00060003, 0x07020706, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000005, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {SUB(T1,DIF), SKIP, 1, true}, // Stage 0 {MULADD(CUR,ENVA,T0), MOD(T0,DIF), 0, true}, // Stage 1 } }, /* //Mux=0x002527ff1ffc9238 Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL1 - TEXEL0) * PRIM|A + TEXEL0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - TEXEL0) * PRIM + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x002527ff1ffc9238 Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=03460304, 03060304, 02000000, 02000000 Color0: (TEXEL1 - TEXEL0) * SHADE|A + TEXEL0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = PRIM in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlDifA - TEXEL1, COMBINED, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x03460304, 0x03060304, 0x02000000, 0x02000000}, // Simplified mux 0x002527FF, 0x1FFC9238, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T1,PRIA), MOD(T1,PRI), 1, true}, // Stage 0 {ADD(T0,CUR), ADD(T0,CUR), 0, true}, // Stage 1 } }, { {0x03460304, 0x03060304, 0x02000000, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, 0, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T1,DIFA), MOD(T1,DIF), 1, true}, // Stage 0 {ADD(T0,CUR), ADD(T0,CUR), 0, true}, // Stage 1 } }, /* //Mux=0x00262a60150c937f Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL1 - TEXEL0) * ENV|A + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - TEXEL0) * ENV + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00262a60150c937f Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=03460304, 03060304, 06020605, 00020005 Color0: (TEXEL1 - TEXEL0) * SHADE|A + TEXEL0 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (PRIM - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = ENV in color channel Shade = ENV in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlDifA - TEXEL1, COMBINED, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x03460304, 0x03060304, 0x06020605, 0x00020005}, // Simplified mux 0x00262A60, 0x150C937F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0, 0, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T1,ENVA), MOD(T1,ENV), 1, true}, // Stage 0 {ADD(T0,CUR), ADD(T0,CUR), 0, true}, // Stage 1 } }, { {0x03460304, 0x03060304, 0x06020605, 0x00020005}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, 0, // Constant color 0x00000007, 0x00000007, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T1,DIFA), MOD(T1,DIF), 1, true}, // Stage 0 {ADD(T0,CUR), ADD(T0,CUR), 0, true}, // Stage 1 } }, /* //Mux=0x00267e041ffcfdf8 Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL1 - TEXEL0) * ENV|A + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00267e041ffcfdf8 Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=03460304, 01000000, 00020006, 02000000 Color0: (TEXEL1 - TEXEL0) * SHADE|A + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = ENV in alpha channel Generated combiners: Stages:2, Alpha:DISABLE_ALPHA, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlDifA - TEXEL1, COMBINED, -Tex1 0:Alpha: Sel - COMBINED, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x03460304, 0x01000000, 0x00020006, 0x02000000}, // Simplified mux 0x00267e04, 0x1ffcfdf8, // 64bit Mux 2, // number of stages DISABLE_ALPHA, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { //{MOD(T1,DIFA), SKIP, 1, true}, // Stage 0 {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 //{MULADD(T0,CUR,DIF), SKIP, 0, true}, // Stage 1 {LERP(T1,CUR,ENVA), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00267e041f0cfdff Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL1 - TEXEL0) * ENV|A + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + 1 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00267e041f0cfdff Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=03470304, 06000000, 00020006, 02000000 Color0: (TEXEL1 - TEXEL0) * ENV|A + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = PRIM in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlFacA - TEXEL1, COMBINED, -Tex1 0:Alpha: Sel - SHADE, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x03470304, 0x06000000, 0x00020006, 0x02000000}, // Simplified mux 0x00267E04, 0x1F0CFDFF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T1,ENVA), SEL(DIFA), 1, true}, // Stage 0 {MULADD(T0,DIF,CUR), SKIP, 0, true}, // Stage 1 } }, /* //Mux=0x00117ffffffdfc38 Overflowed in MarioTennis Color0: (TEXEL0 - 0) * TEXEL1 + PRIM Color1: (0 - 0) * 0 + COMBINED Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00117ffffffdfc38 Overflowed in MarioTennis Simplied DWORDs=00030004, 01000000, 02010006, 02000000 Color0: (TEXEL1 - 0) * TEXEL0 + 0 Color1: (SHADE - 0) * 1 + COMBINED Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE5_A_MOD_C_ADD_D Shade = PRIM in color channel Generated combiners: Stages:2, Alpha:DISABLE_ALPHA, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL1, , 1:Color: Mod - TEXEL0, COMBINED, 0:Alpha: Sel - COMBINED, , 1:Alpha: Sel - COMBINED, , */ { {0x00030004, 0x01000000, 0x02010006, 0x02000000}, // Simplified mux 0x00117FFF, 0xFFFDFC38, // 64bit Mux 2, // number of stages DISABLE_ALPHA, 0, // Constant color 0x00000005, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {SEL(T0), SKIP, 0, true}, // Stage 0 {MULADD(T1,CUR,DIF), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00ffa1ffff0d923f Overflowed in MarioTennis Color0: (0 - 0) * 0 + PRIM Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00ffa1ffff0d923f Overflowed in MarioTennis Simplied DWORDs=05000000, 03060304, 02000000, 00020005 Color0: (0 - 0) * 0 + PRIM Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (PRIM - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - PRIM, , 1:Color: Sel - COMBINED, , -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x05000000, 0x03060304, 0x02000000, 0x00020005}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, 0, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {SEL(PRI), MOD(T0,PRIM), 0, true}, // Stage 0 {SKIP, TRIARGS(BLENDDIFFUSEALPHA,T1,CUR,DIFA), 1, true}, // Stage 1 } }, /* //Mux=0x00ffb9ffffebdbc0 Used in MarioTennis Color0: (0 - 0) * 0 + 0 Color1: (0 - 0) * 0 + 0 Alpha0: (PRIM - ENV) * SHADE + ENV Alpha1: (0 - COMBINED) * TEXEL1 + COMBINED //Simplied Mux=0x00ffb9ffffebdbc0 Used in MarioTennis Simplied DWORDs=00000000, 00060083, 02000000, 02000000 Color0: (0 - 0) * 0 + 0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL0|C - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE2_A_ADD_D Shade = 07060705 in alpha channel Generated combiners: */ { {0x00000000, 0x00060083, 0x02000000, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages DISABLE_COLOR, 0, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {SKIP, MOD(T0,PRIM), 0, true}, // Stage 0 {SKIP, TRIARGS(BLENDDIFFUSEALPHA,T0,CUR,DIFA), 0, true}, // Stage 1 } }, /* //Mux=0x0030b2045ffefff8 Used in THE LEGEND OF ZELDA Color0: (PRIM - ENV) * TEXEL0 + ENV Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (PRIM - 0) * TEXEL0 + 0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0030b2045ffefff8 Used in THE LEGEND OF ZELDA Simplied DWORDs=07030704, 04000000, 00020006, 00020003 Color0: (TEXEL1 - ENV) * TEXEL0 + ENV Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + TEXEL1 Alpha1: (TEXEL0 - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Tex 1 = PRIM Stages:2, Alpha:ENABLE_BOTH, Factor:MUX_ENV, Specular:MUX_0 Dif Color:0x0 Dif Alpha:0x0 0:Color: SELECTARG1 - TEXTURE, _, _ 1:Color: LERP - TEXTURE, TFACTOR, CURRENT -Tex1 0:Alpha: SELECTARG1 - CURRENT, _, _ 1:Alpha: SELECTARG1 - TEXTURE, _, _ -Tex1 */ { {0x07030704, 0x04000000, 0x00020006, 0x00020003}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages DISABLE_COLOR, 0, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {MOD(T0,DIF), SEL(T0), 0, true}, // Stage 0 {LERP(T1,ENV,CUR), MOD(T1,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x0026a0041f1093ff Overflowed in Perfect Dark Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x0026a0041f1093ff Overflowed in Perfect Dark Simplied DWORDs=030E0304, 03060304, 00020006, 00020006 Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, COMBINED, LODFRAC -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x030E0304, 0x03060304, 0x00020006, 0x00020006}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, 0, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 //{LERP(T1,CUR,LODFRAC), LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 {SKIP, SKIP, 0, false}, // Stage 1 } }, /* //Mux=0x0026a0041ffc93fc Overflowed in Perfect Dark Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (0 - 0) * 0 + SHADE //Simplied Mux=0x0026a0041ffc93fc Overflowed in Perfect Dark Simplied DWORDs=030E0304, 06000000, 00020006, 02000000 Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, COMBINED, LODFRAC -Tex1 0:Alpha: Sel - SHADE, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x030E0304, 0x06000000, 0x00020006, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, 0, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(DIF), 0, true}, // Stage 0 //{LERP(T1,CUR,LODFRAC), SKIP, 1, true}, // Stage 1 {SKIP, SKIP, 0, false}, // Stage 1 } }, /* //Mux=0x002526041f1093ff Overflowed in Perfect Dark Color0: (TEXEL1 - TEXEL0) * PRIM|A + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * PRIM + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x002526041f1093ff Overflowed in Perfect Dark Simplied DWORDs=03450304, 03050304, 00020006, 00020006 Color0: (TEXEL1 - TEXEL0) * PRIM|A + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * PRIM + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlFacA - TEXEL1, COMBINED, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlFacA - TEXEL1, COMBINED, -Tex1 */ { {0x03450304, 0x03050304, 0x00020006, 0x00020006}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(DIF), 0, true}, // Stage 0 {TRIARGS(BLENDDIFFUSEALPHA,T1,CUR,DIFA), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x0026a0041f1093fb Overflowed in Perfect Dark Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + PRIM //Simplied Mux=0x0026a0041f1093fb Overflowed in Perfect Dark Simplied DWORDs=030E0304, 03060304, 00020006, 05020006 Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + PRIM Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, COMBINED, LODFRAC -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x030E0304, 0x03060304, 0x00020006, 0x05020006}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {SKIP, ADD(CUR,PRI), 0, false}, // Stage 1 } }, /* //Mux=0x00272c041f1093ff Overflowed in GOLDENEYE Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x00272c041f1093ff Overflowed in GOLDENEYE Simplied DWORDs=030F0304, 00060004, 00020006, 02000000 Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, COMBINED, PRIMLODFRAC -Tex1 0:Alpha: Sel - COMBINED, , 1:Alpha: Mod - TEXEL1, SHADE, -Tex1 */ { {0x030F0304, 0x00060004, 0x00020006, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 {SKIP, MOD(T1,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x0026a0041f1493ff Overflowed in GOLDENEYE Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x0026a0041f1493ff Overflowed in GOLDENEYE Simplied DWORDs=00060003, 03060304, 02000000, 00020007 Color0: (TEXEL0 - 0) * SHADE + 0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (ENV - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Mod - TEXEL0, SHADE, 1:Color: Sel - COMBINED, , -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x00060003, 0x03060304, 0x02000000, 0x00020007}, // Simplified mux 0x0026A004, 0x1F1493FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000007, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {SKIP, SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x0030fe045ffefdf8 Overflowed in Kirby64 Color0: (PRIM - ENV) * TEXEL0 + ENV Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0030fe045ffefdf8 Overflowed in Kirby64 Simplied DWORDs=07030704, 01000000, 00020006, 02000000 Color0: (TEXEL1 - ENV) * TEXEL0 + ENV Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Tex 1 = PRIM Generated combiners: Stages:2, Alpha:DISABLE_ALPHA, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, ENV, COMBINED -Tex1 0:Alpha: Sel - COMBINED, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x07030704, 0x01000000, 0x00020006, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages DISABLE_ALPHA, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 {LERP(T1,ENV,CUR), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00309e045ffefdf8 Overflowed in Kirby64 Color0: (PRIM - ENV) * TEXEL0 + ENV Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00309e045ffefdf8 Overflowed in Kirby64 Simplied DWORDs=07030704, 01000000, 00020006, 02000000 Color0: (TEXEL1 - ENV) * TEXEL0 + ENV Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Tex 1 = PRIM Generated combiners: Stages:2, Alpha:DISABLE_ALPHA, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, ENV, COMBINED -Tex1 0:Alpha: Sel - COMBINED, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x07030704, 0x01000000, 0x00020006, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {MOD(T0,DIF), SEL(T0), 0, true}, // Stage 0 {LERP(T1,ENV,CUR), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x0026a0041ffc93f8 Overflowed in ZELDA MAJORA'S MASK Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0026a0041ffc93f8 Overflowed in ZELDA MAJORA'S MASK Simplied DWORDs=030E0304, 03060304, 00020006, 02000000 Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, COMBINED, LODFRAC -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x030E0304, 0x03060304, 0x00020006, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_LODFRAC, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(T0), 0, true}, // Stage 0 {SKIP, LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 } }, /* //Mux=0x00209c03ff0f93ff Overflowed in ZELDA MAJORA'S MASK Color0: (TEXEL1 - 0) * TEXEL0 + 0 Color1: (COMBINED - 0) * PRIM + 0 Alpha0: (TEXEL0 - TEXEL0) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00209c03ff0f93ff Overflowed in ZELDA MAJORA'S MASK Simplied DWORDs=00050004, 00050003, 00020003, 02000000 Color0: (TEXEL1 - 0) * PRIM + 0 Color1: (TEXEL0 - 0) * COMBINED + 0 Alpha0: (TEXEL0 - 0) * PRIM + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE2_A_ADD_D Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Mod - TEXEL1, PRIM, -Tex1 1:Color: Mod - TEXEL0, COMBINED, 0:Alpha: Sel - COMBINED, , -Tex1 1:Alpha: Mod - TEXEL0, PRIM, */ { {0x00050004, 0x00050003, 0x00020003, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,PRI), MOD(T0,PRI), 0, true}, // Stage 0 {MOD(T1,CUR), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x001229ffff17fe3f Overflowed in Rayman 2 Color0: (TEXEL0 - 0) * SHADE + 0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x001229ffff17fe3f Overflowed in Rayman 2 Simplied DWORDs=00060003, 00060004, 02000000, 00020007 Color0: (TEXEL0 - 0) * SHADE + 0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (ENV - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE2_A_ADD_D Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Mod - TEXEL0, SHADE, 1:Color: Sel - COMBINED, , -Tex1 0:Alpha: Sel - COMBINED, , 1:Alpha: Mod - TEXEL1, SHADE, -Tex1 */ { {0x00060003, 0x00060004, 0x02000000, 0x00020007}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(DIF,ENV), 0, true}, // Stage 0 {SKIP, MOD(T1,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x0030fe0254feff3e Overflowed in Beetle Adventure Rac Color0: (PRIM - ENV) * TEXEL0 + ENV Color1: (COMBINED - SHADE) * TEXEL1 + SHADE Alpha0: (0 - 0) * 0 + 0 Alpha1: (0 - 0) * 0 + 1 //Simplied Mux=0x0030fe0254feff3e Overflowed in Beetle Adventure Rac Simplied DWORDs=07030704, 01000000, 06030602, 02000000 Color0: (TEXEL1 - ENV) * TEXEL0 + ENV Color1: (COMBINED - SHADE) * TEXEL0 + SHADE Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Tex 1 = PRIM Generated combiners: Stages:2, Alpha:DISABLE_ALPHA, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, ENV, COMBINED -Tex1 0:Alpha: Sel - COMBINED, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x07030704, 0x01000000, 0x06030602, 0x02000000}, // Simplified mux 0x0030FE02, 0x54FEFF3E, // 64bit Mux 2, // number of stages DISABLE_ALPHA, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(DIFA,ENV,T0), SKIP, 0, true}, // Stage 0 {LERP(CUR,DIF,T1), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x0015fe042ffd79fc Overflowed in Beetle Adventure Rac Color0: (TEXEL0 - TEXEL1) * SHADE|A + TEXEL1 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + SHADE //Simplied Mux=0x0015fe042ffd79fc Overflowed in Beetle Adventure Rac Simplied DWORDs=04460403, 06000000, 00020006, 02000000 Color0: (TEXEL0 - TEXEL1) * SHADE|A + TEXEL1 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlDifA - COMBINED, TEXEL1, -Tex1 0:Alpha: Sel - SHADE, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x04460403, 0x06000000, 0x00020006, 0x02000000}, // Simplified mux 0x0015FE04, 0x2FFD79FC, // 64bit Mux 2, // number of stages ENABLE_BOTH, 0, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIFA), SEL(DIF), 0, true}, // Stage 0 {LERP(CUR,T1,DIF), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x0020fe0a14fcf938 Overflowed in Beetle Adventure Rac Color0: (TEXEL1 - TEXEL0) * TEXEL0 + TEXEL0 Color1: (COMBINED - SHADE) * PRIM|A + SHADE Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0020fe0a14fcf938 Overflowed in Beetle Adventure Rac Simplied DWORDs=03030304, 06000000, 06450602, 02000000 Color0: (TEXEL1 - TEXEL0) * TEXEL0 + TEXEL0 Color1: (COMBINED - SHADE) * PRIM|A + SHADE Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, COMBINED, COMBINED -Tex1 0:Alpha: Sel - SHADE, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x03030304, 0x06000000, 0x06450602, 0x02000000}, // Simplified mux 0x0020FE0A, 0x14FCF938, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {SEL(T0), SEL(DIF), 0, true}, // Stage 0 {LERP(CUR,DIF,PRIA), SKIP, 0, true}, // Stage 1 } }, /* //Mux=0x0017fe042ffd73f8 Overflowed in Beetle Adventure Rac Color0: (TEXEL0 - TEXEL1) * UNK + TEXEL1 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0017fe042ffd73f8 Overflowed in Beetle Adventure Rac Simplied DWORDs=04100403, 03000000, 00020006, 02000000 Color0: (TEXEL0 - TEXEL1) * UNK + TEXEL1 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - COMBINED, TEXEL1, UNK -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x04100403, 0x03000000, 0x00020006, 0x02000000}, // Simplified mux 0x0017FE04, 0x2FFD73F8, // 64bit Mux 2, // number of stages ENABLE_BOTH, 0, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {SEL(T0), SEL(T0), 0, true}, // Stage 0 {LERP(CUR,T1,DIF), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x001218245531feff Overflowed in CONKER BFD Color0: (TEXEL0 - ENV) * SHADE + PRIM Color1: (TEXEL0 - ENV) * SHADE + PRIM Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (TEXEL0 - 0) * SHADE + 0 //Simplied Mux=0x001218245531feff Overflowed in CONKER BFD Simplied DWORDs=00060703, 00060003, 02010004, 02000000 Color0: (TEXEL0 - ENV) * SHADE + 0 Color1: (TEXEL1 - 0) * 1 + COMBINED Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKED Tex 1 = PRIM Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sub - TEXEL0, ENV, 1:Color: Mod - COMBINED, SHADE, 0:Alpha: Mod - TEXEL0, SHADE, 1:Alpha: Sel - COMBINED, , */ { {0x00060703, 0x00060003, 0x02010004, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {SUB(T0,ENV), MOD(T0,DIF), 0, true}, // Stage 0 {MULADD(CUR,DIF,T1), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00127e2455fdf2f9 Overflowed in CONKER BFD Color0: (TEXEL0 - ENV) * SHADE + PRIM Color1: (TEXEL0 - ENV) * SHADE + PRIM Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + TEXEL0 //Simplied Mux=0x00127e2455fdf2f9 Overflowed in CONKER BFD Simplied DWORDs=00060703, 03000000, 02010004, 02000000 Color0: (TEXEL0 - ENV) * SHADE + 0 Color1: (TEXEL1 - 0) * 1 + COMBINED Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKED Tex 1 = PRIM Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sub - TEXEL0, ENV, 1:Color: Mod - COMBINED, SHADE, 0:Alpha: Sel - TEXEL0, , 1:Alpha: Sel - COMBINED, , */ { {0x00060703, 0x03000000, 0x02010004, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {SUB(T0,ENV), SEL(T0), 0, true}, // Stage 0 {MULADD(CUR,DIF,T1), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x0026a004151092ff Overflowed in CONKER BFD Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (COMBINED - ENV) * SHADE + PRIM Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x0026a004151092ff Overflowed in CONKER BFD Simplied DWORDs=00060703, 03060304, 02010005, 00020006 Color0: (TEXEL0 - ENV) * SHADE + 0 Color1: (PRIM - 0) * 1 + COMBINED Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE_NOT_CHECKED Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sub - TEXEL0, ENV, 1:Color: Mod - COMBINED, SHADE, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x00060703, 0x03060304, 0x02010005, 0x00020006}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 //{LERP(T1,CUR,LODFRAC), LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 {ADD(CUR,PRI), SKIP, 0, false}, // Stage 1 } }, /* //Mux=0x0026a00415fc92f8 Overflowed in CONKER BFD Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (COMBINED - ENV) * SHADE + PRIM Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0026a00415fc92f8 Overflowed in CONKER BFD Simplied DWORDs=00060703, 03060304, 02010005, 02000000 Color0: (TEXEL0 - ENV) * SHADE + 0 Color1: (PRIM - 0) * 1 + COMBINED Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKED Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sub - TEXEL0, ENV, 1:Color: Mod - COMBINED, SHADE, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x00060703, 0x03060304, 0x02010005, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_LODFRAC, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(T0), 0, true}, // Stage 0 {SKIP, LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 } }, /* //Mux=0x001219ff5f15fe3f Overflowed in CONKER BFD Color0: (TEXEL0 - ENV) * SHADE + PRIM Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x001219ff5f15fe3f Overflowed in CONKER BFD Simplied DWORDs=00060703, 00060003, 02010004, 00020007 Color0: (TEXEL0 - ENV) * SHADE + 0 Color1: (TEXEL1 - 0) * 1 + COMBINED Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (ENV - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE_NOT_CHECKED Tex 1 = PRIM Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sub - TEXEL0, ENV, 1:Color: Mod - COMBINED, SHADE, 0:Alpha: Mod - TEXEL0, SHADE, 1:Alpha: Mod - ENV, COMBINED, */ { {0x00060703, 0x00060003, 0x02010004, 0x00020007}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {SUB(T0,ENV), MOD(T0,DIF), 0, true}, // Stage 0 {MULADD(CUR,DIF,T1), MOD(CUR,ENV), 1, true}, // Stage 1 } }, /* //Mux=0x00ff9880f514feff Overflowed in CONKER BFD Color0: (0 - 0) * 0 + TEXEL0 Color1: (SHADE - ENV) * COMBINED + PRIM Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x00ff9880f514feff Overflowed in CONKER BFD Simplied DWORDs=00030706, 00060003, 02010004, 00020007 Color0: (SHADE - ENV) * TEXEL0 + 0 Color1: (TEXEL1 - 0) * 1 + COMBINED Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (ENV - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE_NOT_CHECKED Shade = 00000706 in color channel Tex 1 = PRIM Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sub - SHADE, ENV, 1:Color: Mod - COMBINED, TEXEL0, 0:Alpha: Mod - TEXEL0, SHADE, 1:Alpha: Mod - ENV, COMBINED, */ { {0x00030706, 0x00060003, 0x02010004, 0x00020007}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {SUB(T0,ENV), MOD(T0,DIF), 0, true}, // Stage 0 {MULADD(CUR,DIF,T1), MOD(CUR,ENV), 1, true}, // Stage 1 } }, /* //Mux=0x0026a080151492ff Overflowed in CONKER BFD Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + PRIM Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x0026a080151492ff Overflowed in CONKER BFD Simplied DWORDs=030E0304, 03060304, 05020706, 00020007 Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + PRIM Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (ENV - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE_NOT_CHECKED Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, COMBINED, LODFRAC -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x030E0304, 0x03060304, 0x05020706, 0x00020007}, // Simplified mux 0x0026A080, 0x151492FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000706, 0x00000007, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 //{LERP(T1,CUR,LODFRAC), LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 {ADD(CUR,PRI), SKIP, 0, false}, // Stage 1 } }, /* //Mux=0x0026a004151092ff Overflowed in CONKER BFD Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (COMBINED - ENV) * SHADE + PRIM Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x0026a004151092ff Overflowed in CONKER BFD Simplied DWORDs=030E0304, 03060304, 05060702, 00020006 Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (COMBINED - ENV) * SHADE + PRIM Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x030E0304, 0x03060304, 0x05060702, 0x00020006}, // Simplified mux 0x0026A004, 0x151092FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_LODFRAC, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(T0), 0, true}, // Stage 0 //{LERP(T1,CUR,LODFRAC), LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 {SKIP, LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 } }, /* //Mux=0x00ff9880f514feff Overflowed in CONKER BFD Color0: (0 - 0) * 0 + TEXEL0 Color1: (SHADE - ENV) * COMBINED + PRIM Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x00ff9880f514feff Overflowed in CONKER BFD Simplied DWORDs=00030706, 00060003, 02010004, 00020007 Color0: (SHADE - ENV) * TEXEL0 + 0 Color1: (TEXEL1 - 0) * 1 + COMBINED Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (ENV - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE_NOT_CHECKED Shade = 00000706 in color channel Tex 1 = PRIM Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sub - SHADE, ENV, 1:Color: Mod - COMBINED, TEXEL0, 0:Alpha: Mod - TEXEL0, SHADE, 1:Alpha: Mod - ENV, COMBINED, */ { {0x00030706, 0x00060003, 0x02010004, 0x00020007}, // Simplified mux 0x00FF9880, 0xF514FEFF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000706, 0x00070006, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {ADD(CUR,PRI), SKIP, 0, false}, // Stage 1 } }, /* //Mux=0x00262a041f0c93ff Overflowed in JET FORCE GEMINI Color0: (TEXEL1 - TEXEL0) * ENV|A + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * ENV + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00262a041f0c93ff Overflowed in JET FORCE GEMINI Simplied DWORDs=03460304, 03060304, 00020006, 00020005 Color0: (TEXEL1 - TEXEL0) * SHADE|A + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (PRIM - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = ENV in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlDifA - TEXEL1, COMBINED, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x03460304, 0x03060304, 0x00020006, 0x00020005}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000007, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,CUR,ENVA), LERP(T1,CUR,ENV), 1, true}, // Stage 1 } }, /* //Mux=0x00262a6014fc9338 Overflowed in JET FORCE GEMINI Color0: (TEXEL1 - TEXEL0) * ENV|A + TEXEL0 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (TEXEL1 - TEXEL0) * ENV + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00262a6014fc9338 Overflowed in JET FORCE GEMINI Simplied DWORDs=03460304, 03060304, 06020605, 02000000 Color0: (TEXEL1 - TEXEL0) * SHADE|A + TEXEL0 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = ENV in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlDifA - TEXEL1, COMBINED, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x03460304, 0x03060304, 0x06020605, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000007, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(T0), 0, true}, // Stage 0 {LERP(T1,CUR,ENVA), LERP(T1,CUR,ENV), 1, true}, // Stage 1 } }, /* //Mux=0x00127e2455fdf8fc Overflowed in KILLER INSTINCT GOLD Color0: (TEXEL0 - ENV) * SHADE + PRIM Color1: (TEXEL0 - ENV) * SHADE + PRIM Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + SHADE //Simplied Mux=0x00127e2455fdf8fc Overflowed in KILLER INSTINCT GOLD Simplied DWORDs=00060703, 06000000, 02010004, 02000000 Color0: (TEXEL0 - ENV) * SHADE + 0 Color1: (TEXEL1 - 0) * 1 + COMBINED Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKED Tex 1 = PRIM Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sub - TEXEL0, ENV, 1:Color: Mod - COMBINED, SHADE, 0:Alpha: Sel - SHADE, , 1:Alpha: Sel - COMBINED, , */ { {0x00060703, 0x06000000, 0x02010004, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {SUB(T0,ENV), SEL(DIF), 0, true}, // Stage 0 {MULADD(CUR,DIF,T1), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00fffe6af5fcf438 Overflowed in KILLER INSTINCT GOLD Color0: (0 - 0) * 0 + TEXEL0 Color1: (PRIM - ENV) * PRIM|A + COMBINED Alpha0: (0 - 0) * 0 + TEXEL1 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00fffe6af5fcf438 Overflowed in KILLER INSTINCT GOLD Simplied DWORDs=00460706, 04000000, 02010003, 02000000 Color0: (SHADE - ENV) * SHADE|A + 0 Color1: (TEXEL0 - 0) * 1 + COMBINED Alpha0: (0 - 0) * 0 + TEXEL1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKED Shade = PRIM in color channel Shade = PRIM in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sub - SHADE, ENV, -Tex1 1:Color: Mod - COMBINED, SHADE|A, 0:Alpha: Sel - TEXEL1, , -Tex1 1:Alpha: Sel - COMBINED, , */ { {0x00460706, 0x04000000, 0x02010003, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000005, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {SUB(DIF,ENV), SEL(T1), 1, true}, // Stage 0 {MULADD(CUR,DIFA,T0), SKIP, 0, true}, // Stage 1 } }, /* //Mux=0x00262a041f5893f8 Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL1 - TEXEL0) * ENV|A + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * ENV + TEXEL0 Alpha1: (TEXEL1 - 0) * 1 + COMBINED //Simplied Mux=0x00262a041f5893f8 Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=03460304, 03060304, 00020006, 02010004 Color0: (TEXEL1 - TEXEL0) * SHADE|A + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (TEXEL1 - 0) * 1 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = ENV in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlDifA - TEXEL1, COMBINED, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x03460304, 0x03060304, 0x00020006, 0x02010004}, // Simplified mux 0x00262A04, 0x1F5893F8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(T0), 0, true}, // Stage 0 {LERP(T1,CUR,ENVA), LERP(T1,CUR,ENV), 1, true}, // Stage 1 } }, /* //Mux=0x00272c60350ce37f Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL1 - PRIM) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - 1) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00272c60350ce37f Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=030F0604, 00060003, 07020706, 02000000 Color0: (TEXEL1 - SHADE) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKED Shade = PRIM in color channel Shade = PRIM in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Mod - TEXEL1, PRIMLODFRAC, -Tex1 1:Color: Add - COMBINED, TEXEL0, 0:Alpha: Sel - COMBINED, , -Tex1 1:Alpha: Mod - TEXEL0, SHADE, */ { {0x030F0604, 0x00060003, 0x07020706, 0x02000000}, // Simplified mux 0x00272C60, 0x350CE37F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000005, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T1,DIF), MOD(T1,DIF), 1, true}, // Stage 0 {MULADD(DIF,T0,CUR), MOD(T0,CUR), 0, true}, // Stage 1 } }, /* //Mux=0x0026a0041f1093ff Overflowed in Perfect Dark Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x0026a0041f1093ff Overflowed in Perfect Dark Simplied DWORDs=00060003, 03060304, 02000000, 00020006 Color0: (TEXEL0 - 0) * SHADE + 0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Mod - TEXEL0, SHADE, 1:Color: Sel - COMBINED, , -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x00060003, 0x03060304, 0x02000000, 0x00020006}, // Simplified mux 0x0026A004, 0x1F1093FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_LODFRAC, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {SKIP, SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x0026a08015fc937b Overflowed in ROCKETROBOTONWHEELS Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (0 - 0) * 0 + PRIM //Simplied Mux=0x0026a08015fc937b Overflowed in ROCKETROBOTONWHEELS Simplied DWORDs=030E0304, 06000000, 07020706, 02000000 Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = PRIM in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, COMBINED, LODFRAC -Tex1 0:Alpha: Sel - SHADE, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x030E0304, 0x06000000, 0x07020706, 0x02000000}, // Simplified mux 0x0026A080, 0x15FC937B, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_LODFRAC, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,CUR,LODFRAC), LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 } }, /* //Mux=0x0026a0801ffc93fb Overflowed in ROCKETROBOTONWHEELS Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (0 - 0) * 0 + PRIM //Simplied Mux=0x0026a0801ffc93fb Overflowed in ROCKETROBOTONWHEELS Simplied DWORDs=030E0304, 06000000, 00020006, 02000000 Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = PRIM in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, COMBINED, LODFRAC -Tex1 0:Alpha: Sel - SHADE, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x030E0304, 0x06000000, 0x00020006, 0x02000000}, // Simplified mux 0x0026A080, 0x1FFC93FB, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_LODFRAC, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,CUR,LODFRAC), LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 } }, /* //Mux=0x0025a8801f1493ff Overflowed in ROCKETROBOTONWHEELS Color0: (TEXEL1 - TEXEL0) * SHADE|A + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x0025a8801f1493ff Overflowed in ROCKETROBOTONWHEELS Simplied DWORDs=03460304, 03060304, 00020006, 00020007 Color0: (TEXEL1 - TEXEL0) * SHADE|A + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (ENV - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlDifA - TEXEL1, COMBINED, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x03460304, 0x03060304, 0x00020006, 0x00020007}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,ENV), 0, true}, // Stage 0 {LERP(T1,CUR,DIFA), LERP(T1,CUR,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x0026a0801510937f Overflowed in ROCKETROBOTONWHEELS Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x0026a0801510937f Overflowed in ROCKETROBOTONWHEELS Simplied DWORDs=030E0304, 03060304, 07020706, 00020006 Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, COMBINED, LODFRAC -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x030E0304, 0x03060304, 0x07020706, 0x00020006}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_LODFRAC, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,CUR,LODFRAC), LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 } }, /* //Mux=0x004099ff5f0efe3f Overflowed in ROCKETROBOTONWHEELS Color0: (SHADE - ENV) * TEXEL0 + ENV Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x004099ff5f0efe3f Overflowed in ROCKETROBOTONWHEELS Simplied DWORDs=07030706, 00060003, 02000000, 00020004 Color0: (SHADE - ENV) * TEXEL0 + ENV Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (TEXEL1 - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = 00000706 in color channel Tex 1 = PRIM Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Lerp - SHADE, ENV, TEXEL0 1:Color: Sel - COMBINED, , -Tex1 0:Alpha: Mod - TEXEL0, SHADE, 1:Alpha: Mod - TEXEL1, COMBINED, -Tex1 */ { {0x07030706, 0x00060003, 0x02000000, 0x00020004}, // Simplified mux 0x004099FF, 0x5F0EFE3F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {LERP(DIF,ENV,T0), MOD(T0,DIF), 0, true}, // Stage 0 {SKIP, MOD(T1,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x0025a8a01414933f Overflowed in ROCKETROBOTONWHEELS Color0: (TEXEL1 - TEXEL0) * SHADE|A + TEXEL0 Color1: (ENV - SHADE) * COMBINED + SHADE Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x0025a8a01414933f Overflowed in ROCKETROBOTONWHEELS Simplied DWORDs=03460304, 03060304, 06020607, 00020007 Color0: (TEXEL1 - TEXEL0) * SHADE|A + TEXEL0 Color1: (ENV - SHADE) * COMBINED + SHADE Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (ENV - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlDifA - TEXEL1, COMBINED, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x03460304, 0x03060304, 0x06020607, 0x00020007}, // Simplified mux 0x0025A8A0, 0x1414933F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {LERP(ENV,DIF,T0), MOD(T0,ENV), 0, true}, // Stage 0 {LERP(T1,CUR,DIFA), LERP(T1,CUR,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x001298043f15ffff Overflowed in BANJO TOOIE Color0: (TEXEL0 - PRIM) * ENV + PRIM Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x001298043f15ffff Overflowed in BANJO TOOIE Simplied DWORDs=04070403, 00060003, 00020006, 00020007 Color0: (TEXEL0 - TEXEL1) * ENV + TEXEL1 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (ENV - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Tex 1 = PRIM Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - COMBINED, TEXEL1, ENV 0:Alpha: Mod - TEXEL0, SHADE, 1:Alpha: Mod - ENV, COMBINED, */ { {0x04070403, 0x00060003, 0x00020006, 0x00020007}, // Simplified mux 0x00129804, 0x3F15FFFF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(CUR,T1,ENV), MOD(CUR,ENV), 1, true}, // Stage 1 } }, /* //Mux=0x0062fe043f15f9ff Overflowed in BANJO TOOIE Color0: (1 - PRIM) * ENV + PRIM Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + SHADE Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x0062fe043f15f9ff Overflowed in BANJO TOOIE Simplied DWORDs=03070301, 06000000, 00020006, 02000000 Color0: (1 - TEXEL0) * ENV + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = 00070006 in alpha channel Tex 0 = PRIM Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: AddSmooth - TEXEL0, ENV, 1:Color: Mod - SHADE, COMBINED, 0:Alpha: Sel - SHADE, , 1:Alpha: Sel - COMBINED, , */ { {0x03070301, 0x06000000, 0x00020006, 0x02000000}, // Simplified mux 0x0062FE04, 0x3F15F9FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000005, 0x00000000}, // constant color texture flags { {MULADD(T0C,ENV,T0), SEL(DIF), 0, true}, // Stage 0 {MOD(CUR,DIF), SKIP, 0, true}, // Stage 1 } }, /* //Mux=0x0025266015fc9378 Overflowed in ZELDA MAJORA'S MASK Color0: (TEXEL1 - TEXEL0) * PRIM|A + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - TEXEL0) * PRIM + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0025266015fc9378 Overflowed in ZELDA MAJORA'S MASK Simplied DWORDs=03460304, 03060304, 06020605, 02000000 Color0: (TEXEL1 - TEXEL0) * SHADE|A + TEXEL0 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = ENV in color channel Shade = PRIM in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlDifA - TEXEL1, COMBINED, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x03460304, 0x03060304, 0x06020605, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000007, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(PRI,DIF,T0), SEL(T0), 0, true}, // Stage 0 {LERP(T1,CUR,DIFA), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x0061a5ff1f10d23f Overflowed in PAPER MARIO Color0: (1 - TEXEL0) * PRIM + TEXEL0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - ENV) * TEXEL1 + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x0061a5ff1f10d23f Overflowed in PAPER MARIO Simplied DWORDs=03060301, 03040704, 02000000, 00020006 Color0: (1 - TEXEL0) * SHADE + TEXEL0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - ENV) * TEXEL1 + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE_NOT_CHECKED Shade = PRIM in color channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: AddSmooth - TEXEL0, SHADE, 1:Color: Sel - COMBINED, , -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: Mod - COMBINED, TEXEL1, -Tex1 */ { {0x03060301, 0x03040704, 0x02000000, 0x00020006}, // Simplified mux 0x0061A5FF, 0x1F10D23F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000005, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MULADD(T0C,DIF,T0), MOD(T0,DIF), 0, true}, // Stage 0 {SKIP, LERP(T1,ENV,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x00322bff5f0e923f Overflowed in PAPER MARIO Color0: (PRIM - ENV) * SHADE + ENV Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - TEXEL0) * ENV + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00322bff5f0e923f Overflowed in PAPER MARIO Simplied DWORDs=06000000, 03070304, 02000000, 00020006 Color0: (0 - 0) * 0 + SHADE Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - TEXEL0) * ENV + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = 07060705 in color channel Shade = PRIM in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - SHADE, , 1:Color: Sel - COMBINED, , -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlFacA - TEXEL1, COMBINED, -Tex1 */ { {0x06000000, 0x03070304, 0x02000000, 0x00020006}, // Simplified mux 0x00322BFF, 0x5F0E923F, // 64bit Mux 23, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x07060705, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {SEL(DIF), MOD(T0,DIF), 0, true}, // Stage 0 {SKIP, LERP(T1,CUR,ENV), 1, true}, // Stage 1 } }, /* //Mux=0x0010e5e0230b157f Overflowed in PAPER MARIO Color0: (TEXEL0 - TEXEL1) * TEXEL0 + 1 Color1: (0 - PRIM) * COMBINED + ENV Alpha0: (1 - TEXEL0) * TEXEL1 + TEXEL1 Alpha1: (COMBINED - 0) * TEXEL1 + 0 //Simplied Mux=0x0010e5e0230b157f Overflowed in PAPER MARIO Simplied DWORDs=00010600, 04830004, 02010007, 00020004 Color0: (0 - SHADE) * 1 + 0 Color1: (ENV - 0) * 1 + COMBINED Alpha0: (TEXEL1 - 0) * TEXEL0|C + TEXEL1 Alpha1: (TEXEL1 - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE7_A_SUB_B_ADD_D Shade = PRIM in color channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sub - 0, SHADE, 1:Color: Add - ENV, COMBINED, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: MulAdd - TEXEL1, COMBINED|C, TEXEL1 -Tex1 */ { {0x00010600, 0x04830004, 0x02010007, 0x00020004}, // Simplified mux 0x0010E5E0, 0x230B157F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000005, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MULADD(T0,DIF,ENV), SEL(T0), 0, true}, // Stage 0 {SKIP, MULADD(CURC,T1,T1), 1, true}, // Stage 1 } }, /* //Mux=0x00117e045ffef3f8 Overflowed in RIDGE RACER 64 Color0: (TEXEL0 - ENV) * TEXEL1 + ENV Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00117e045ffef3f8 Overflowed in RIDGE RACER 64 Simplied DWORDs=07040703, 03000000, 00020006, 02000000 Color0: (TEXEL0 - ENV) * TEXEL1 + ENV Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - COMBINED, ENV, TEXEL1 -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x07040703, 0x03000000, 0x00020006, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T1,DIF), SKIP, 1, true}, // Stage 0 {LERP(T0,ENV,CUR), SEL(T0), 0, true}, // Stage 1 } }, /* //Mux=0x0040b467f0fffe3e Overflowed in RIDGE RACER 64 Color0: (SHADE - 0) * TEXEL0 + 0 Color1: (PRIM - COMBINED) * COMBINED|A + COMBINED Alpha0: (PRIM - 0) * TEXEL1 + 0 Alpha1: (0 - 0) * 0 + 1 //Simplied Mux=0x0040b467f0fffe3e Overflowed in RIDGE RACER 64 Simplied DWORDs=00060003, 00050004, 02420205, 01000000 Color0: (TEXEL0 - 0) * SHADE + 0 Color1: (PRIM - COMBINED) * COMBINED|A + COMBINED Alpha0: (TEXEL1 - 0) * PRIM + 0 Alpha1: (0 - 0) * 0 + 1 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:DISABLE_ALPHA, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Mod - TEXEL0, SHADE, 1:Color: BlCurA - PRIM, COMBINED, -Tex1 0:Alpha: Sel - COMBINED, , 1:Alpha: Mod - TEXEL1, PRIM, -Tex1 */ { {0x00060003, 0x00050004, 0x02420205, 0x01000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 //{LERP(PRI,CUR,CURA), MOD(T1,PRI), 1, true}, // Stage 1 {SKIP, MOD(T1,PRI), 1, true}, // Stage 1 } }, /* //Mux=0x0022aa041f0c93ff Overflowed in RIDGE RACER 64 Color0: (TEXEL1 - TEXEL0) * ENV + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * ENV + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x0022aa041f0c93ff Overflowed in RIDGE RACER 64 Simplied DWORDs=03070304, 03070304, 00020006, 00020006 Color0: (TEXEL1 - TEXEL0) * ENV + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * ENV + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = PRIM in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, COMBINED, ENV -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlFacA - TEXEL1, COMBINED, -Tex1 */ { {0x03070304, 0x03070304, 0x00020006, 0x00020006}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,CUR,ENV), LERP(T1,CUR,ENV), 1, true}, // Stage 1 } }, /* //Mux=0x0030fe045ffef3f8 Overflowed in RIDGE RACER 64 Color0: (PRIM - ENV) * TEXEL0 + ENV Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0030fe045ffef3f8 Overflowed in RIDGE RACER 64 Simplied DWORDs=07030704, 03000000, 00020006, 02000000 Color0: (TEXEL1 - ENV) * TEXEL0 + ENV Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Tex 1 = PRIM Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, ENV, COMBINED -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x07030704, 0x03000000, 0x00020006, 0x02000000}, // Simplified mux 0x0030FE04, 0x5FFEF3F8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {MOD(T0,DIF), SEL(T0), 0, true}, // Stage 0 {LERP(T1,ENV,CUR), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00272c041ffc93f8 Overflowed in RIDGE RACER 64 Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * 1 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00272c041ffc93f8 Overflowed in RIDGE RACER 64 Simplied DWORDs=030F0304, 04000000, 00020006, 02000000 Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + TEXEL1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, COMBINED, PRIMLODFRAC -Tex1 0:Alpha: Sel - COMBINED, , 1:Alpha: Sel - TEXEL1, , -Tex1 */ { {0x030F0304, 0x04000000, 0x00020006, 0x02000000}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 {LERP(T1,CUR,PRIMLODFRAC), SEL(T1), 1, true}, // Stage 1 } }, /* //Mux=0x00272c6015fc9378 Overflowed in RIDGE RACER 64 Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - TEXEL0) * 1 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00272c6015fc9378 Overflowed in RIDGE RACER 64 Simplied DWORDs=030F0304, 04000000, 06020605, 02000000 Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (0 - 0) * 0 + TEXEL1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = ENV in color channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, COMBINED, PRIMLODFRAC -Tex1 0:Alpha: Sel - COMBINED, , 1:Alpha: Sel - TEXEL1, , -Tex1 */ { {0x030F0304, 0x04000000, 0x06020605, 0x02000000}, // Simplified mux 0x00272C60, 0x15FC9378, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000705, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(DIF,T0), SKIP, 0, true}, // Stage 0 {LERP(T1,CUR,PRIMLODFRAC), SEL(T1), 1, true}, // Stage 1 } }, /* //Mux=0x001516032f1125ff Overflowed in CASTLEVANIA2 Color0: (TEXEL0 - TEXEL1) * PRIM|A + TEXEL1 Color1: (COMBINED - 0) * PRIM + 0 Alpha0: (TEXEL0 - TEXEL1) * PRIM + TEXEL1 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x001516032f1125ff Overflowed in CASTLEVANIA2 Simplied DWORDs=04460403, 04060403, 00020006, 00020006 Color0: (TEXEL0 - TEXEL1) * SHADE|A + TEXEL1 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL0 - TEXEL1) * SHADE + TEXEL1 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = PRIM in color channel Shade = PRIM in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlDifA - COMBINED, TEXEL1, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - COMBINED, TEXEL1, -Tex1 */ { {0x04460403, 0x04060403, 0x00020006, 0x00020006}, // Simplified mux 0x00151603, 0x2F1125FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,PRI), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T0,T1,PRIA), LERP(T0,T1,PRI), 1, true}, // Stage 1 } }, /* //Mux=0x001516602515257f Overflowed in CASTLEVANIA2 Color0: (TEXEL0 - TEXEL1) * PRIM|A + TEXEL1 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL0 - TEXEL1) * PRIM + TEXEL1 Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x001516602515257f Overflowed in CASTLEVANIA2 Simplied DWORDs=04450403, 04050403, 06020605, 00020006 Color0: (TEXEL0 - TEXEL1) * PRIM|A + TEXEL1 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (TEXEL0 - TEXEL1) * PRIM + TEXEL1 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = ENV in color channel Shade = ENV in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlFacA - COMBINED, TEXEL1, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlFacA - COMBINED, TEXEL1, -Tex1 */ { {0x04450403, 0x04050403, 0x06020605, 0x00020006}, // Simplified mux 0x00151660, 0x2515257F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000007, 0x00000007, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(PRI,DIF,T0), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T0,T1,PRIA), LERP(T0,T1,PRI), 1, true}, // Stage 1 } }, /* //Mux=0x001516032f1525ff Overflowed in CASTLEVANIA2 Color0: (TEXEL0 - TEXEL1) * PRIM|A + TEXEL1 Color1: (COMBINED - 0) * PRIM + 0 Alpha0: (TEXEL0 - TEXEL1) * PRIM + TEXEL1 Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x001516032f1525ff Overflowed in CASTLEVANIA2 Simplied DWORDs=04460403, 04060403, 00020006, 00020007 Color0: (TEXEL0 - TEXEL1) * SHADE|A + TEXEL1 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL0 - TEXEL1) * SHADE + TEXEL1 Alpha1: (ENV - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = PRIM in color channel Shade = PRIM in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: BlDifA - COMBINED, TEXEL1, -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - COMBINED, TEXEL1, -Tex1 */ { {0x04460403, 0x04060403, 0x00020006, 0x00020007}, // Simplified mux 0x00151603, 0x2F1525FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000005, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,ENV), 0, true}, // Stage 0 {LERP(T0,T1,DIFA), LERP(T0,T1,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x00ffd5fffffcf238 Overflowed in CASTLEVANIA Color0: (0 - 0) * 0 + TEXEL0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (ENV - 0) * TEXEL1 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00ffd5fffffcf238 Overflowed in CASTLEVANIA Simplied DWORDs=03000000, 00060004, 02000000, 02010003 Color0: (0 - 0) * 0 + TEXEL0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (TEXEL0 - 0) * 1 + COMBINED Simplfied type: CM_FMT_TYPE5_A_MOD_C_ADD_D Shade = ENV in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Sel - COMBINED, , -Tex1 0:Alpha: Sel - COMBINED, , 1:Alpha: Mod - TEXEL1, SHADE, -Tex1 */ { {0x03000000, 0x00060004, 0x02000000, 0x02010003}, // Simplified mux 0x00FFD5FF, 0xFFFCF238, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {SKIP, MOD(T0,DIF), 1, true}, // Stage 0 {SEL(T0), ADD(T0,CUR), 0, true}, // Stage 1 } }, /* //Mux=0x0026a0041f0c93ff Overflowed in NEWTETRIS Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x0026a0041f0c93ff Overflowed in NEWTETRIS Simplied DWORDs=00060003, 03060304, 02000000, 00020005 Color0: (TEXEL0 - 0) * SHADE + 0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (PRIM - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Mod - TEXEL0, SHADE, 1:Color: Sel - COMBINED, , -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x00060003, 0x03060304, 0x02000000, 0x00020005}, // Simplified mux 0x0026A004, 0x1F0C93FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_LODFRAC, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,CUR,LODFRAC), LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 } }, /* //Mux=0x0017166045fe7f78 Overflowed in DOUBUTSUNOMORI Color0: (TEXEL0 - SHADE) * PRIMLODFRAC + SHADE Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL0 - 0) * PRIM + 0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0017166045fe7f78 Overflowed in DOUBUTSUNOMORI Simplied DWORDs=060F0603, 04000000, 07020704, 00020003 Color0: (TEXEL0 - SHADE) * PRIMLODFRAC + SHADE Color1: (TEXEL1 - ENV) * COMBINED + ENV Alpha0: (0 - 0) * 0 + TEXEL1 Alpha1: (TEXEL0 - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Tex 1 = PRIM Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Lerp - TEXEL0, SHADE, PRIMLODFRAC 1:Color: Lerp - TEXEL1, ENV, COMBINED -Tex1 0:Alpha: Sel - COMBINED, , 1:Alpha: Sel - TEXEL1, , -Tex1 */ { {0x060F0603, 0x04000000, 0x07020704, 0x00020003}, // Simplified mux 0x00171660, 0x45FE7F78, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {MOD(T1,DIF), SEL(T1), 1, true}, // Stage 0 {LERP(T0,CUR,PRIMLODFRAC), MOD(T0,CUR), 0, true}, // Stage 1 } }, /* //Mux=0x003095ff5f1af43f Overflowed in DOUBUTSUNOMORI Color0: (PRIM - ENV) * TEXEL0 + ENV Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL0 - 0) * TEXEL1 + TEXEL1 Alpha1: (COMBINED - 0) * 1 + 0 //Simplied Mux=0x003095ff5f1af43f Overflowed in DOUBUTSUNOMORI Simplied DWORDs=06030605, 00030004, 02000000, 02010004 Color0: (PRIM - SHADE) * TEXEL0 + SHADE Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - 0) * TEXEL0 + 0 Alpha1: (TEXEL1 - 0) * 1 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = ENV in color channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Lerp - PRIM, SHADE, TEXEL0 -Tex1 1:Color: Sel - COMBINED, , 0:Alpha: Sel - TEXEL1, , -Tex1 1:Alpha: Mod - TEXEL0, COMBINED, */ { {0x06030605, 0x00030004, 0x02000000, 0x02010004}, // Simplified mux 0x003095FF, 0x5F1AF43F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000007, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(PRI,DIF,T0), SEL(T0), 0, true}, // Stage 0 {SKIP, MULADD(CUR,T1,T1), 1, true}, // Stage 1 } }, /* //Mux=0x003717fffffefe38 Overflowed in DOUBUTSUNOMORI Color0: (PRIM - 0) * PRIMLODFRAC + ENV Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL0 - 0) * PRIM + 0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x003717fffffefe38 Overflowed in DOUBUTSUNOMORI Simplied DWORDs=000F0006, 00060003, 02010004, 02000000 Color0: (SHADE - 0) * PRIMLODFRAC + 0 Color1: (TEXEL1 - 0) * 1 + COMBINED Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE5_A_MOD_C_ADD_D Shade = PRIM in color channel Shade = PRIM in alpha channel Tex 1 = ENV Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Mod - SHADE, PRIMLODFRAC, 1:Color: Add - TEXEL1, COMBINED, -Tex1 0:Alpha: Mod - TEXEL0, SHADE, 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x000F0006, 0x00060003, 0x02010004, 0x02000000}, // Simplified mux 0x003717FF, 0xFFFEFE38, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000005, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000007}, // constant color texture flags { {MOD(DIF,PRIMLODFRAC), MOD(T0,DIF), 0, true}, // Stage 0 {ADD(T1,CUR), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00272a8013fc92f8 Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - PRIM) * COMBINED + PRIM Alpha0: (TEXEL1 - TEXEL0) * ENV + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00272a8013fc92f8 Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=030F0304, 03060304, 05020506, 02000000 Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - PRIM) * COMBINED + PRIM Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Shade = ENV in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sel - TEXEL0, , 1:Color: Lerp - TEXEL1, COMBINED, PRIMLODFRAC -Tex1 0:Alpha: Sel - TEXEL0, , 1:Alpha: BlDifA - TEXEL1, COMBINED, -Tex1 */ { {0x030F0304, 0x03060304, 0x05020506, 0x02000000}, // Simplified mux 0x00272A80, 0x13FC92F8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000007, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(DIF,PRI,T0), SEL(T0), 0, true}, // Stage 0 {SKIP, LERP(T1,CUR,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x00127e60f5fffd78 Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL0 - 0) * SHADE + 0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00127e60f5fffd78 Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=00060003, 01000000, 07020704, 02000000 Color0: (TEXEL0 - 0) * SHADE + 0 Color1: (TEXEL1 - ENV) * COMBINED + ENV Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_C Tex 1 = PRIM Generated combiners: Stages:2, Alpha:DISABLE_ALPHA, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Mod - TEXEL0, SHADE, 1:Color: Lerp - TEXEL1, ENV, COMBINED -Tex1 0:Alpha: Sel - COMBINED, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x00060003, 0x01000000, 0x07020704, 0x02000000}, // Simplified mux 0x00127E60, 0xF5FFFD78, // 64bit Mux 2, // number of stages DISABLE_ALPHA, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 {LERP(T1,ENV,CUR), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x0020ac60350c937f Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL1 - PRIM) * TEXEL0 + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - TEXEL0) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x0020ac60350c937f Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=00038604, 00060004, 07020706, 02000000 Color0: (TEXEL1 - SHADE|C) * TEXEL0 + 0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE8_A_SUB_B_MOD_C Shade = PRIM in color channel Shade = PRIM in alpha channel Generated combiners: Stages:2, Alpha:ENABLE_BOTH, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Sub - TEXEL1, SHADE|C, -Tex1 1:Color: Mod - COMBINED, TEXEL0, 0:Alpha: Mod - TEXEL1, SHADE, -Tex1 1:Alpha: Sel - COMBINED, , */ { {0x00038604, 0x00060004, 0x07020706, 0x02000000}, // Simplified mux 0x0020AC60, 0x350C937F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000005, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(DIF,ENV,T0), MOD(T0,DIF), 0, true}, // Stage 0 {MOD(T1,CUR), MOD(T1,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x00177e6035fcfd7e Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL0 - PRIM) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + 1 //Simplied Mux=0x00177e6035fcfd7e Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=030F0603, 01000000, 04020406, 02000000 Color0: (TEXEL0 - SHADE) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - TEXEL1) * COMBINED + TEXEL1 Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: Color0 Shade = PRIM in color channel Tex 1 = ENV Generated combiners: Stages:2, Alpha:DISABLE_ALPHA, Factor:0, Specular:0 Dif Color:0xCCCCCCCC Dif Alpha:0xCCCCCCCC 0:Color: Lerp - TEXEL0, SHADE, PRIMLODFRAC 1:Color: Lerp - SHADE, TEXEL1, COMBINED -Tex1 0:Alpha: Sel - COMBINED, , 1:Alpha: Sel - COMBINED, , -Tex1 */ { {0x030F0603, 0x01000000, 0x04020406, 0x02000000}, // Simplified mux 0x00177E60, 0x35FCFD7E, // 64bit Mux 2, // number of stages DISABLE_ALPHA, MUX_PRIMLODFRAC, // Constant color 0x00000005, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000007}, // constant color texture flags { {LERP(T0,DIF,PRIMLODFRAC), SKIP, 0, true}, // Stage 0 {LERP(DIF,T1,CUR), SKIP, 0, true}, // Stage 1 } }, /* //Mux=0x00276c6035d8ed76 Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL1 - PRIM) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (1 - 1) * 1 + 1 Alpha1: (1 - 1) * 1 + 1 //Simplied Mux=0x00276c6035d8ed76 Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=030F0604, 01000000, 07020706, 02000000Color0: (TEXEL1 - SHADE) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x030F0604, 0x01000000, 0x07020706, 0x02000000}, // Simplified mux 0x00276C60, 0x35D8ED76, // 64bit Mux 2, // number of stages DISABLE_ALPHA, MUX_PRIMLODFRAC, // Constant color 0x00000005, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 {LERP(T1,CUR,PRIMLODFRAC), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00277e60150cf37f Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00277e60150cf37f Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=030F0304, 00060003, 06020605, 02000000Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x030F0304, 0x00060003, 0x06020605, 0x02000000}, // Simplified mux 0x00277E60, 0x150CF37F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000007, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,CUR,PRIMLODFRAC), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x001596a430fdfe38 Overflowed in Diddy Kong Racing Color0: (TEXEL0 - PRIM) * SHADE|A + PRIM Color1: (ENV - COMBINED) * SHADE + COMBINED Alpha0: (TEXEL0 - 0) * PRIM + 0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x001596a430fdfe38 Overflowed in Diddy Kong Racing Simplied DWORDs=04460403, 04000000, 02060207, 00020003Color0: (TEXEL0 - TEXEL1) * SHADE|A + TEXEL1 Color1: (ENV - COMBINED) * SHADE + COMBINED Alpha0: (0 - 0) * 0 + TEXEL1 Alpha1: (TEXEL0 - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x04460403, 0x04000000, 0x02060207, 0x00020003}, // Simplified mux 0x001596A4, 0x30FDFE38, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000007}, // constant color texture flags { {LERP(T0,PRI,DIFA), MOD(T0,PRI), 0, true}, // Stage 0 {LERP(T1,CUR,DIF), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x001218acf00ffe3f Overflowed in Diddy Kong Racing Color0: (TEXEL0 - 0) * SHADE + 0 Color1: (ENV - COMBINED) * ENV|A + COMBINED Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x001218acf00ffe3f Overflowed in Diddy Kong Racing Simplied DWORDs=00060003, 00060003, 02470207, 00020004Color0: (TEXEL0 - 0) * SHADE + 0 Color1: (ENV - COMBINED) * ENV|A + COMBINED Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (TEXEL1 - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x00060003, 0x00060003, 0x02470207, 0x00020004}, // Simplified mux 0x001218AC, 0xF00FFE3F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(ENV,CUR,ENVA), MOD(T1,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x002266ac1010923f Overflowed in Diddy Kong Racing Color0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Color1: (ENV - COMBINED) * ENV|A + COMBINED Alpha0: (1 - TEXEL0) * PRIM + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x002266ac1010923f Overflowed in Diddy Kong Racing Simplied DWORDs=03060304, 03050301, 02470207, 00020006Color0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Color1: (ENV - COMBINED) * ENV|A + COMBINED Alpha0: (1 - TEXEL0) * PRIM + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x03060304, 0x03050301, 0x02470207, 0x00020006}, // Simplified mux 0x002266AC, 0x1010923F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(ENV,T0,ENVA), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,CUR,DIF), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x0030fe045ffefbf8 Overflowed in F-ZERO X Color0: (PRIM - ENV) * TEXEL0 + ENV Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + ENV Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0030fe045ffefbf8 Overflowed in F-ZERO X Simplied DWORDs=07030704, 06000000, 00020006, 02000000Color0: (TEXEL1 - ENV) * TEXEL0 + ENV Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x07030704, 0x06000000, 0x00020006, 0x02000000}, // Simplified mux 0x0030FE04, 0x5FFEFBF8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {MOD(T0,DIF), SEL(ENV), 0, true}, // Stage 0 {LERP(T1,ENV,CUR), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x0026a0801f0c93ff Overflowed in ROCKETROBOTONWHEELS Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x0026a0801f0c93ff Overflowed in ROCKETROBOTONWHEELS Simplied DWORDs=030E0304, 03060304, 00020006, 00020005Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (PRIM - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x030E0304, 0x03060304, 0x00020006, 0x00020005}, // Simplified mux 0x0026A080, 0x1F0C93FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_LODFRAC, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,CUR,LODFRAC), LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 } }, /* //Mux=0x00272c60150c937f Overflowed in POKEMON STADIUM Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - TEXEL0) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00272c60150c937f Overflowed in POKEMON STADIUM Simplied DWORDs=030F0304, 00060004, 06020605, 02000000Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x030F0304, 0x00060004, 0x06020605, 0x02000000}, // Simplified mux 0x00272C60, 0x150C937F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000007, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 {LERP(T1,CUR,PRIMLODFRAC), MOD(T1,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x00162a0325fe13f8 Overflowed in POKEMON STADIUM Color0: (TEXEL0 - TEXEL1) * ENV|A + SHADE Color1: (COMBINED - ENV) * PRIM + 0 Alpha0: (TEXEL1 - TEXEL0) * ENV + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00162a0325fe13f8 Overflowed in POKEMON STADIUM Simplied DWORDs=06460403, 03060304, 00050702, 02000000Color0: (TEXEL0 - TEXEL1) * SHADE|A + SHADE Color1: (COMBINED - ENV) * PRIM + 0 Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x06460403, 0x03060304, 0x00050702, 0x02000000}, // Simplified mux 0x00162A03, 0x25FE13F8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(T0), 0, true}, // Stage 0 {LERP(CUR,T1,ENVA), LERP(T1,CUR,ENV), 1, true}, // Stage 1 } }, /* //Mux=0x00167e03f5fe77f8 Overflowed in POKEMON STADIUM Color0: (TEXEL0 - 0) * ENV|A + SHADE Color1: (COMBINED - ENV) * PRIM + 0 Alpha0: (0 - 0) * 0 + PRIM Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00167e03f5fe77f8 Overflowed in POKEMON STADIUM Simplied DWORDs=06470003, 04000000, 00040702, 02000000Color0: (TEXEL0 - 0) * ENV|A + SHADE Color1: (COMBINED - ENV) * TEXEL1 + 0 Alpha0: (0 - 0) * 0 + TEXEL1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE8_A_SUB_B_MOD_CGenerated combiners: */ { {0x06470003, 0x04000000, 0x00040702, 0x02000000}, // Simplified mux 0x00167E03, 0xF5FE77F8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {MULADD(T0,ENVA,DIF), SKIP, 0, true}, // Stage 0 {MOD(CUR,T1), SEL(T1), 1, true}, // Stage 1 } }, /* //Mux=0x002698801514feff Overflowed in CONKER BFD Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + PRIM Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x002698801514feff Overflowed in CONKER BFD Simplied DWORDs=00030706, 00060003, 02010004, 00020007Color0: (SHADE - ENV) * TEXEL0 + 0 Color1: (TEXEL1 - 0) * 1 + COMBINED Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (ENV - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE_NOT_CHECKEDShade = 00000706 in color channelGenerated combiners: */ { {0x00030706, 0x00060003, 0x02010004, 0x00020007}, // Simplified mux 0x00269880, 0x1514FEFF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_LODFRAC, // Constant color 0x00000706, 0x00070006, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,CUR,LODFRAC), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00127e04f513f4ff Overflowed in CONKER BFD Color0: (TEXEL0 - 0) * SHADE + 0 Color1: (COMBINED - ENV) * SHADE + PRIM Alpha0: (0 - 0) * 0 + TEXEL1 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x00127e04f513f4ff Overflowed in CONKER BFD Simplied DWORDs=00060003, 00060004, 05060702, 02000000Color0: (TEXEL0 - 0) * SHADE + 0 Color1: (COMBINED - ENV) * SHADE + PRIM Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x00060003, 0x00060004, 0x05060702, 0x02000000}, // Simplified mux 0x00127E04, 0xF513F4FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 {MULADD(CUR,DIF,PRI), MOD(T1,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x00277e60350cf37f Overflowed in THE MASK OF MUJURA Color0: (TEXEL1 - PRIM) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00277e60350cf37f Overflowed in THE MASK OF MUJURA Simplied DWORDs=030F0604, 00060003, 07020706, 02000000Color0: (TEXEL1 - SHADE) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x030F0604, 0x00060003, 0x07020706, 0x02000000}, // Simplified mux 0x00277E60, 0x350CF37F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000005, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {MULADD(T1,PRIMLODFRAC,CUR), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00272c041f0c93ff Overflowed in THE MASK OF MUJURA Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00272c041f0c93ff Overflowed in THE MASK OF MUJURA Simplied DWORDs=030F0304, 00060004, 00020006, 02000000Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x030F0304, 0x00060004, 0x00020006, 0x02000000}, // Simplified mux 0x00272C04, 0x1F0C93FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 {LERP(T1,CUR,PRIMLODFRAC), MOD(T1,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x002714041f0cffff Overflowed in THE MASK OF MUJURA Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL0 - 0) * TEXEL1 + 0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x002714041f0cffff Overflowed in THE MASK OF MUJURA Simplied DWORDs=030F0304, 00060003, 00020006, 00020004Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (TEXEL1 - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x030F0304, 0x00060003, 0x00020006, 0x00020004}, // Simplified mux 0x00271404, 0x1F0CFFFF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,CUR,PRIMLODFRAC), MOD(T1,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x002722041f0cffff Overflowed in THE MASK OF MUJURA Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - 0) * TEXEL0 + 0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x002722041f0cffff Overflowed in THE MASK OF MUJURA Simplied DWORDs=030F0304, 00060004, 00020006, 00020003Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (TEXEL0 - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x030F0304, 0x00060004, 0x00020006, 0x00020003}, // Simplified mux 0x00272204, 0x1F0CFFFF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,CUR,PRIMLODFRAC), MOD(T1,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x00272c603510f37f Overflowed in THE MASK OF MUJURA Color0: (TEXEL1 - PRIM) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - 0) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x00272c603510f37f Overflowed in THE MASK OF MUJURA Simplied DWORDs=030F0604, 04010003, 07020706, 00020006Color0: (TEXEL1 - SHADE) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (TEXEL0 - 0) * 1 + TEXEL1 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x030F0604, 0x04010003, 0x07020706, 0x00020006}, // Simplified mux 0x00272C60, 0x3510F37F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000005, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {MULADD(T1,PRIMLODFRAC,CUR), MOD(T1,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x00209204ff0fffff Overflowed in THE MASK OF MUJURA Color0: (TEXEL1 - 0) * TEXEL0 + 0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL0 - 0) * TEXEL0 + 0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00209204ff0fffff Overflowed in THE MASK OF MUJURA Simplied DWORDs=00060004, 00030003, 00020003, 00020005Color0: (TEXEL1 - 0) * SHADE + 0 Color1: (TEXEL0 - 0) * COMBINED + 0 Alpha0: (TEXEL0 - 0) * TEXEL0 + 0 Alpha1: (PRIM - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE2_A_ADD_DGenerated combiners: */ { {0x00060004, 0x00030003, 0x00020003, 0x00020005}, // Simplified mux 0x00209204, 0xFF0FFFFF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,T0), 0, true}, // Stage 0 {MOD(T1,CUR), MOD(PRI,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x002714031f0cffff Overflowed in THE MASK OF MUJURA Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (COMBINED - 0) * PRIM + 0 Alpha0: (TEXEL0 - 0) * TEXEL1 + 0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x002714031f0cffff Overflowed in THE MASK OF MUJURA Simplied DWORDs=030F0304, 00060003, 00020006, 00020004Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (TEXEL1 - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x030F0304, 0x00060003, 0x00020006, 0x00020004}, // Simplified mux 0x00271403, 0x1F0CFFFF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000005, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,T0,PRIMLODFRAC), MOD(T1,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x00272c031f1093ff Overflowed in THE MASK OF MUJURA Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (COMBINED - 0) * PRIM + 0 Alpha0: (TEXEL1 - TEXEL0) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x00272c031f1093ff Overflowed in THE MASK OF MUJURA Simplied DWORDs=030F0304, 00060004, 00020006, 02000000Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x030F0304, 0x00060004, 0x00020006, 0x02000000}, // Simplified mux 0x00272C03, 0x1F1093FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000005, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 {LERP(T1,CUR,PRIMLODFRAC), MOD(T1,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x0012fe043ffe77f8 Overflowed in THE MASK OF MUJURA Color0: (TEXEL0 - PRIM) * ENV + SHADE Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + PRIM Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0012fe043ffe77f8 Overflowed in THE MASK OF MUJURA Simplied DWORDs=06070403, 04000000, 00020006, 02000000Color0: (TEXEL0 - TEXEL1) * ENV + SHADE Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + TEXEL1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x06070403, 0x04000000, 0x00020006, 0x02000000}, // Simplified mux 0x0012FE04, 0x3FFE77F8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MULADD(T0,ENV,DIF), SEL(DIF), 0, true}, // Stage 0 {MOD(CUR,DIF), SKIP, 0, false}, // Stage 1 } }, /* //Mux=0x0020fe05f3fff738 Overflowed in THE MASK OF MUJURA Color0: (TEXEL1 - 0) * TEXEL0 + 0 Color1: (COMBINED - PRIM) * ENV + SHADE Alpha0: (0 - 0) * 0 + PRIM Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0020fe05f3fff738 Overflowed in THE MASK OF MUJURA Simplied DWORDs=00030004, 06000000, 06070502, 02000000Color0: (TEXEL1 - 0) * TEXEL0 + 0 Color1: (COMBINED - PRIM) * ENV + SHADE Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x00030004, 0x06000000, 0x06070502, 0x02000000}, // Simplified mux 0x0020FE05, 0xF3FFF738, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,ENV), SEL(DIF), 0, true}, // Stage 0 {MULADD(T1,CUR,DIF), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x0012fe043f1677ff Overflowed in THE MASK OF MUJURA Color0: (TEXEL0 - PRIM) * ENV + SHADE Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + PRIM Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x0012fe043f1677ff Overflowed in THE MASK OF MUJURA Simplied DWORDs=06070403, 00070004, 00020006, 02000000Color0: (TEXEL0 - TEXEL1) * ENV + SHADE Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - 0) * ENV + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x06070403, 0x00070004, 0x00020006, 0x02000000}, // Simplified mux 0x0012FE04, 0x3F1677FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MULADD(T0,ENV,DIF), MOD(DIF,ENV), 0, true}, // Stage 0 {MOD(CUR,DIF), SKIP, 0, false}, // Stage 1 } }, /* //Mux=0x0011fe04ff17f7ff Overflowed in THE MASK OF MUJURA Color0: (TEXEL0 - 0) * PRIM + 0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + PRIM Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x0011fe04ff17f7ff Overflowed in THE MASK OF MUJURA Simplied DWORDs=00030006, 00070004, 00020004, 02000000Color0: (SHADE - 0) * TEXEL0 + 0 Color1: (TEXEL1 - 0) * COMBINED + 0 Alpha0: (TEXEL1 - 0) * ENV + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE2_A_ADD_DGenerated combiners: */ { {0x00030006, 0x00070004, 0x00020004, 0x02000000}, // Simplified mux 0x0011FE04, 0xFF17F7FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 {MOD(T1,CUR), MOD(T1,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x00272c031f0c93ff Overflowed in MULTI RACING Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (COMBINED - 0) * PRIM + 0 Alpha0: (TEXEL1 - TEXEL0) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00272c031f0c93ff Overflowed in MULTI RACING Simplied DWORDs=030F0304, 00060004, 00020006, 02000000Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x030F0304, 0x00060004, 0x00020006, 0x02000000}, // Simplified mux 0x00272C03, 0x1F0C93FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000005, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 {LERP(T1,CUR,PRIMLODFRAC), MOD(T1,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x00272c041f0c93ff Overflowed in MULTI RACING Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00272c041f0c93ff Overflowed in MULTI RACING Simplied DWORDs=030F0304, 00060004, 00020006, 02000000Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x030F0304, 0x00060004, 0x00020006, 0x02000000}, // Simplified mux 0x00272C04, 0x1F0C93FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 {LERP(T1,CUR,PRIMLODFRAC), MOD(T1,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x0030fe045ffef7f8 Overflowed in MULTI RACING Color0: (PRIM - ENV) * TEXEL0 + ENV Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + PRIM Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0030fe045ffef7f8 Overflowed in MULTI RACING Simplied DWORDs=07030704, 04000000, 00020006, 02000000Color0: (TEXEL1 - ENV) * TEXEL0 + ENV Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + TEXEL1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x07030704, 0x04000000, 0x00020006, 0x02000000}, // Simplified mux 0x0030FE04, 0x5FFEF7F8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 {LERP(T1,ENV,CUR), SEL(T1), 1, true}, // Stage 1 } }, /* //Mux=0x0026a08015fc93f8 Overflowed in Monaco Grand Prix Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0026a08015fc93f8 Overflowed in Monaco Grand Prix Simplied DWORDs=030E0304, 03060304, 00020706, 02000000Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE8_A_SUB_B_MOD_CGenerated combiners: */ { {0x030E0304, 0x03060304, 0x00020706, 0x02000000}, // Simplified mux 0x0026A080, 0x15FC93F8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_LODFRAC, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(T0), 0, true}, // Stage 0 {LERP(T1,CUR,LODFRAC), LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 } }, /* //Mux=0x0050fe043ffdf3f8 Overflowed in KING HILL 64 Color0: (ENV - PRIM) * TEXEL0 + PRIM Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0050fe043ffdf3f8 Overflowed in KING HILL 64 Simplied DWORDs=04030407, 03000000, 00020006, 02000000Color0: (ENV - TEXEL1) * TEXEL0 + TEXEL1 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x04030407, 0x03000000, 0x00020006, 0x02000000}, // Simplified mux 0x0050FE04, 0x3FFDF3F8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000007}, // constant color texture flags { {MOD(T0,DIF), SEL(T0), 0, true}, // Stage 0 {LERP(T1,PRI,CUR), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00209a04ffcfffc8 Overflowed in HSV ADVENTURE RACING Color0: (TEXEL1 - 0) * TEXEL0 + 0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL0 - 0) * ENV + 0 Alpha1: (1 - TEXEL0) * PRIM + COMBINED //Simplied Mux=0x00209a04ffcfffc8 Overflowed in HSV ADVENTURE RACING Simplied DWORDs=00060004, 00070003, 00020003, 02060083Color0: (TEXEL1 - 0) * SHADE + 0 Color1: (TEXEL0 - 0) * COMBINED + 0 Alpha0: (TEXEL0 - 0) * ENV + 0 Alpha1: (TEXEL0|C - 0) * SHADE + COMBINED Simplfied type: CM_FMT_TYPE5_A_MOD_C_ADD_DGenerated combiners: */ { {0x00060004, 0x00070003, 0x00020003, 0x02060083}, // Simplified mux 0x00209A04, 0xFFCFFFC8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,ENV), 0, true}, // Stage 0 {MOD(T1,CUR), MULADD(T0C,DIF,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x00ffa1ffff12123f Overflowed in HSV ADVENTURE RACING Color0: (0 - 0) * 0 + SHADE Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x00ffa1ffff12123f Overflowed in HSV ADVENTURE RACING Simplied DWORDs=06000000, 03060304, 02000000, 00020006Color0: (0 - 0) * 0 + SHADE Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x06000000, 0x03060304, 0x02000000, 0x00020006}, // Simplified mux 0x00FFA1FF, 0xFF12123F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {SEL(DIF), SEL(T0), 0, true}, // Stage 0 {SKIP, LERP(T1,T0,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x0020980a14fcff38 Overflowed in HSV ADVENTURE RACING Color0: (TEXEL1 - TEXEL0) * TEXEL0 + TEXEL0 Color1: (COMBINED - SHADE) * PRIM|A + SHADE Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0020980a14fcff38 Overflowed in HSV ADVENTURE RACING Simplied DWORDs=03030304, 00060003, 06450602, 02000000Color0: (TEXEL1 - TEXEL0) * TEXEL0 + TEXEL0 Color1: (COMBINED - SHADE) * PRIM|A + SHADE Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x03030304, 0x00060003, 0x06450602, 0x02000000}, // Simplified mux 0x0020980A, 0x14FCFF38, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MULADD(T0,PRIA,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,T0,CUR), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00247ec0f2fffebe Overflowed in HSV ADVENTURE RACING Color0: (TEXEL1 - 0) * TEXEL0|A + 0 Color1: (1 - TEXEL1) * COMBINED + TEXEL1 Alpha0: (0 - 0) * 0 + 0 Alpha1: (0 - 0) * 0 + 1 //Simplied Mux=0x00247ec0f2fffebe Overflowed in HSV ADVENTURE RACING Simplied DWORDs=00430004, 01000000, 03020301, 02000000Color0: (TEXEL1 - 0) * TEXEL0|A + 0 Color1: (1 - TEXEL0) * COMBINED + TEXEL0 Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x00430004, 0x01000000, 0x03020301, 0x02000000}, // Simplified mux 0x00247EC0, 0xF2FFFEBE, // 64bit Mux 2, // number of stages DISABLE_ALPHA, 0, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {SEL(T0), SKIP, 0, true}, // Stage 0 {MULADD(T1C,CUR,T1), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x0020fe0411fd7ebe Overflowed in HSV ADVENTURE RACING Color0: (TEXEL1 - TEXEL0) * TEXEL0 + TEXEL1 Color1: (COMBINED - TEXEL0) * SHADE + TEXEL1 Alpha0: (0 - 0) * 0 + 0 Alpha1: (0 - 0) * 0 + 1 //Simplied Mux=0x0020fe0411fd7ebe Overflowed in HSV ADVENTURE RACING Simplied DWORDs=04030304, 01000000, 03060302, 02000000Color0: (TEXEL1 - TEXEL0) * TEXEL0 + TEXEL1 Color1: (COMBINED - TEXEL0) * SHADE + TEXEL0 Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: Color0Generated combiners: */ { {0x04030304, 0x01000000, 0x03060302, 0x02000000}, // Simplified mux 0x0020FE04, 0x11FD7EBE, // 64bit Mux 2, // number of stages DISABLE_ALPHA, 0, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SKIP, 0, true}, // Stage 0 {MOD(T1,CUR), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00111480f513ff7f Overflowed in HSV ADVENTURE RACING Color0: (TEXEL0 - 0) * TEXEL1 + 0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (TEXEL0 - 0) * TEXEL1 + 0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x00111480f513ff7f Overflowed in HSV ADVENTURE RACING Simplied DWORDs=00040003, 00060003, 07020706, 00020004Color0: (TEXEL0 - 0) * TEXEL1 + 0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (TEXEL1 - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x00040003, 0x00060003, 0x07020706, 0x00020004}, // Simplified mux 0x00111480, 0xF513FF7F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(DIF,ENV,T0), MOD(T0,DIF), 0, true}, // Stage 0 {MOD(T1,CUR), MOD(T1,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x00117e042ffd79f8 Overflowed in HSV ADVENTURE RACING Color0: (TEXEL0 - TEXEL1) * TEXEL1 + TEXEL1 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00117e042ffd79f8 Overflowed in HSV ADVENTURE RACING Simplied DWORDs=04040403, 06000000, 00020006, 02000000Color0: (TEXEL0 - TEXEL1) * TEXEL1 + TEXEL1 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x04040403, 0x06000000, 0x00020006, 0x02000000}, // Simplified mux 0x00117E04, 0x2FFD79F8, // 64bit Mux 2, // number of stages ENABLE_BOTH, 0, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(DIF), 0, true}, // Stage 0 {MOD(T1,CUR), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00257e041ffcf3f8 Overflowed in G.A.S.P!!Fighters'NE Color0: (TEXEL1 - TEXEL0) * PRIM|A + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00257e041ffcf3f8 Overflowed in G.A.S.P!!Fighters'NE Simplied DWORDs=03460304, 03000000, 00020006, 02000000 Color0: (TEXEL1 - TEXEL0) * SHADE|A + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x03460304, 0x03000000, 0x00020006, 0x02000000}, // Simplified mux 0x00257E04, 0x1FFCF3F8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(T0), 0, true}, // Stage 0 {LERP(T1,CUR,PRI), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00ff9480fffcfff8 Overflowed in G.A.S.P!!Fighters'NE Color0: (0 - 0) * 0 + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL0 - 0) * TEXEL1 + 0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00ff9480fffcfff8 Overflowed in G.A.S.P!!Fighters'NE Simplied DWORDs=00060003, 04000000, 02000000, 00020003 Color0: (TEXEL0 - 0) * SHADE + 0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (0 - 0) * 0 + TEXEL1 Alpha1: (TEXEL0 - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE2_A_ADD_DGenerated combiners: */ { {0x00060003, 0x04000000, 0x02000000, 0x00020003}, // Simplified mux 0, 0, // 64bit Mux 2, // number of stages ENABLE_BOTH, 0, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(T0), 0, true}, // Stage 0 {SKIP, MOD(T1,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x00612680fffcf3f8 Overflowed in G.A.S.P!!Fighters'NE Color0: (1 - 0) * TEXEL1 + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - 0) * PRIM + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00612680fffcf3f8 Overflowed in G.A.S.P!!Fighters'NE Simplied DWORDs=03010004, 00060004, 00020006, 02010003Color0: (TEXEL1 - 0) * 1 + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (TEXEL0 - 0) * 1 + COMBINED Simplfied type: CM_FMT_TYPE5_A_MOD_C_ADD_DGenerated combiners: */ { {0x03010004, 0x00060004, 0x00020006, 0x02010003}, // Simplified mux 0x00612680, 0xFFFCF3F8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T1,DIF), MOD(T1,PRI), 1, true}, // Stage 0 {MOD(T0,CUR), ADD(T0,CUR), 0, true}, // Stage 1 } }, /* //Mux=0x0026a06015fc9378 Overflowed in FIFA Soccer 64 Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0026a06015fc9378 Overflowed in FIFA Soccer 64 Simplied DWORDs=030E0304, 03060304, 06020605, 02000000Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x030E0304, 0x03060304, 0x06020605, 0x02000000}, // Simplified mux 0x0026A060, 0x15FC9378, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_LODFRAC, // Constant color 0x00000005, 0x00000007, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(DIF,DIFA,T0), SEL(T0), 0, true}, // Stage 0 {LERP(T1,CUR,LODFRAC), LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 } }, /* //Mux=0x0026a0041ffc93fe Overflowed in Taz Express Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (0 - 0) * 0 + 1 //Simplied Mux=0x0026a0041ffc93fe Overflowed in Taz Express Simplied DWORDs=030E0304, 01000000, 00020006, 02000000 Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x030E0304, 0x01000000, 0x00020006, 0x02000000}, // Simplified mux 0x0026A004, 0x1FFC93FE, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_LODFRAC, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(T0), 0, true}, // Stage 0 {LERP(T1,CUR,LODFRAC), LERP(T1,CUR,LODFRAC), 1, true}, // Stage 1 } }, /* //Mux=0x003716041ffcfff8 Overflowed in GAUNTLET LEGENDS Color0: (PRIM - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL0 - 0) * PRIM + 0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x003716041ffcfff8 Overflowed in GAUNTLET LEGENDS Simplied DWORDs=030F0304, 04000000, 00020006, 00020003 Color0: (TEXEL1 - TEXEL0) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + TEXEL1 Alpha1: (TEXEL0 - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x030F0304, 0x04000000, 0x00020006, 0x00020003}, // Simplified mux 0x00371604, 0x1FFCFFF8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,CUR,PRIMLODFRAC), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00157e602ffd77f8 Overflowed in MarioTennis Color0: (TEXEL0 - TEXEL1) * PRIM|A + TEXEL1 Color1: (PRIM - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + PRIM Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00157e602ffd77f8 Overflowed in MarioTennis Simplied DWORDs=04460403, 06000000, 00020006, 02000000 Color0: (TEXEL0 - TEXEL1) * SHADE|A + TEXEL1 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x04460403, 0x06000000, 0x00020006, 0x02000000}, // Simplified mux 0x00157E60, 0x2FFD77F8, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000005, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(DIF), 0, true}, // Stage 0 {LERP(T1,CUR,DIFA), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00157e6025fd7778 Overflowed in MarioTennis Color0: (TEXEL0 - TEXEL1) * PRIM|A + TEXEL1 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (0 - 0) * 0 + PRIM Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00157e6025fd7778 Overflowed in MarioTennis Simplied DWORDs=04460403, 06000000, 06020605, 02000000 Color0: (TEXEL0 - TEXEL1) * SHADE|A + TEXEL1 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x04460403, 0x06000000, 0x06020605, 0x02000000}, // Simplified mux 0x00157E60, 0x25FD7778, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x000000007, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(PRI,DIF,T0), SEL(DIF), 0, true}, // Stage 0 {LERP(CUR,T1,DIFA), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00fffe80f514f8ff Overflowed in CONKER BFD Color0: (0 - 0) * 0 + TEXEL0 Color1: (SHADE - ENV) * COMBINED + PRIM Alpha0: (0 - 0) * 0 + SHADE Alpha1: (COMBINED - 0) * ENV + 0 */ { {0x00030706, 0x06000000, 0x02010004, 0x02000000}, // Simplified mux 0x00FFFE80, 0xF514F8FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000706, 0x00070006, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), SEL(DIF), 0, true}, // Stage 0 {ADD(PRI,CUR), SKIP, 0, false}, // Stage 1 } }, /* //Mux=0x0017166035fcff78 Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL0 - PRIM) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL0 - 0) * PRIM + 0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0017166035fcff78 Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=030F0603, 00060003, 04020406, 02000000 Color0: (TEXEL0 - SHADE) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - TEXEL1) * COMBINED + TEXEL1 Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: Color0Generated combiners: */ { {0x030F0603, 0x00060003, 0x04020406, 0x02000000}, // Simplified mux 0x00171660, 0x35FCFF78, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIMLODFRAC, // Constant color 0x00000005, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000007}, // constant color texture flags { {LERP(T0,DIF,PRIMLODFRAC), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(DIF,T1,CUR), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x00262a041f1093ff Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL1 - TEXEL0) * ENV|A + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * ENV + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x00262a041f1093ff Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=03470304, 03070304, 00020006, 00020006 Color0: (TEXEL1 - TEXEL0) * ENV|A + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (TEXEL1 - TEXEL0) * ENV + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x03470304, 0x03070304, 0x00020006, 0x00020006}, // Simplified mux 0x00262A04, 0x1F1093FF, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(T1,CUR,ENVA), LERP(T1,CUR,ENV), 1, true}, // Stage 1 } }, /* //Mux=0x00267e051ffcfdf8 Overflowed in THE LEGEND OF ZELDA Color0: (TEXEL1 - TEXEL0) * ENV|A + TEXEL0 Color1: (COMBINED - 0) * ENV + 0 Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00267e051ffcfdf8 Overflowed in THE LEGEND OF ZELDA Simplied DWORDs=03460304, 01000000, 00020006, 02000000 Color0: (TEXEL1 - TEXEL0) * SHADE|A + TEXEL0 Color1: (SHADE - 0) * COMBINED + 0 Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x03460304, 0x01000000, 0x00020006, 0x02000000}, // Simplified mux 0x00267E05, 0x1FFCFDF8, // 64bit Mux 2, // number of stages DISABLE_ALPHA, MUX_ENV, // Constant color 0x00000007, 0x00000007, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,ENV), SKIP, 0, true}, // Stage 0 {LERP(T1,CUR,ENVA), SKIP, 1, true}, // Stage 1 } }, /* //Mux=0x0026a0041f1093fb Overflowed in GOLDENEYE Color0: (TEXEL1 - TEXEL0) * LODFRAC + TEXEL0 Color1: (COMBINED - 0) * SHADE + 0 Alpha0: (TEXEL1 - TEXEL0) * COMBINED + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + PRIM //Simplied Mux=0x0026a0041f1093fb Overflowed in GOLDENEYE Simplied DWORDs=00060003, 03060304, 02000000, 05020006 Color0: (TEXEL0 - 0) * SHADE + 0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - TEXEL0) * SHADE + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + PRIM Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x00060003, 0x03060304, 0x02000000, 0x05020006}, // Simplified mux 0x0026A004, 0x1F1093FB, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {SKIP, ADD(CUR,PRI), 0, false}, // Stage 1 } }, /* //Mux=0x0017666025fd7f78 Overflowed in POKEMON STADIUM 2 Color0: (TEXEL0 - TEXEL1) * PRIMLODFRAC + TEXEL1 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (1 - 0) * PRIM + 0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0017666025fd7f78 Overflowed in POKEMON STADIUM 2 Simplied DWORDs=040F0403, 06000000, 06020605, 02000000 Color0: (TEXEL0 - TEXEL1) * PRIMLODFRAC + TEXEL1 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x040F0403, 0x06000000, 0x06020605, 0x02000000}, // Simplified mux 0x00176660, 0x25FD7F78, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(DIF,ENV,T0), SEL(DIF), 0, true}, // Stage 0 {SKIP, SKIP, 0, false}, // Stage 1 } }, /* //Mux=0x0077666045fd7f78 Overflowed in POKEMON STADIUM 2 Color0: (COMBALPHA - SHADE) * PRIMLODFRAC + TEXEL1 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (1 - 0) * PRIM + 0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0077666045fd7f78 Overflowed in POKEMON STADIUM 2 Simplied DWORDs=040F0608, 03000000, 07020703, 02000000 Color0: (COMBALPHA - SHADE) * PRIMLODFRAC + TEXEL1 Color1: (TEXEL0 - ENV) * COMBINED + ENV Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDShade = 000F0608 in color channelGenerated combiners: */ { {0x040F0608, 0x03000000, 0x07020703, 0x02000000}, // Simplified mux 0x00776660, 0x45FD7F78, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000005, 0x00000000}, // constant color texture flags { {MOD(T1,DIF), SKIP, 1, true}, // Stage 0 {LERP(T1,ENV,CUR), SEL(T0), 0, true}, // Stage 1 } }, /* //Mux=0x00457fff3ffcfe3f Overflowed in POKEMON STADIUM 2 Color0: (SHADE - PRIM) * PRIM|A + TEXEL0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (0 - 0) * 0 + 0 Alpha1: (0 - 0) * 0 + 0 //Simplied Mux=0x00457fff3ffcfe3f Overflowed in POKEMON STADIUM 2 Simplied DWORDs=00460506, 00000000, 02010003, 02000000 Color0: (SHADE - PRIM) * SHADE|A + 0 Color1: (TEXEL0 - 0) * 1 + COMBINED Alpha0: (0 - 0) * 0 + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDShade = 00460506 in color channelGenerated combiners: */ { {0x00460506, 0x00000000, 0x02010003, 0x02000000}, // Simplified mux 0x00457FFF, 0x3FFCFE3F, // 64bit Mux 2, // number of stages DISABLE_ALPHA, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {SUB(DIF,PRI), SKIP, 0, false}, // Stage 0 {MULADD(CUR,PRIA,T0), SKIP, 0, true}, // Stage 1 } }, /* //Mux=0x00272c603510e37f Overflowed in POKEMON STADIUM 2 Color0: (TEXEL1 - PRIM) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - 1) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x00272c603510e37f Overflowed in POKEMON STADIUM 2 Simplied DWORDs=030F0604, 00060003, 07020706, 02000000 Color0: (TEXEL1 - SHADE) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x030F0604, 0x00060003, 0x07020706, 0x02000000}, // Simplified mux 0x00272C60, 0x3510E37F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000005, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(DIF,ENV,T0), MOD(T0,DIF), 0, true}, // Stage 0 {SKIP, MULADD(T1,DIF,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x0025a660f510f37f Overflowed in POKEMON STADIUM 2 Color0: (TEXEL1 - 0) * SHADE|A + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - 0) * PRIM + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x0025a660f510f37f Overflowed in POKEMON STADIUM 2 Simplied DWORDs=03460004, 03050004, 07020705, 00020006 Color0: (TEXEL1 - 0) * SHADE|A + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - 0) * PRIM + TEXEL0 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x03460004, 0x03050004, 0x07020705, 0x00020006}, // Simplified mux 0x0025A660, 0xF510F37F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000005, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(DIF,ENV,T0), MOD(T0,DIF), 0, true}, // Stage 0 {MULADD(T1,DIFA,CUR), MULADD(T1,DIF,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x00171607f511a97f Overflowed in POKEMON STADIUM 2 Color0: (TEXEL0 - 0) * PRIMLODFRAC + PRIM Color1: (COMBINED - ENV) * COMBINED|A + ENV Alpha0: (TEXEL0 - TEXEL1) * PRIM + SHADE Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x00171607f511a97f Overflowed in POKEMON STADIUM 2 Simplied DWORDs=050F0003, 06050403, 06420602, 00020006 Color0: (TEXEL0 - 0) * PRIMLODFRAC + PRIM Color1: (COMBINED - SHADE) * COMBINED|A + SHADE Alpha0: (TEXEL0 - TEXEL1) * PRIM + SHADE Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x050F0003, 0x06050403, 0x06420602, 0x00020006}, // Simplified mux 0x00171607, 0xF511A97F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000005, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {ADD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0 {LERP(CUR,ENV,CURA), SUB(CUR,T1), 1, true}, // Stage 1 } }, /* //Mux=0x00177e6025fd7378 Overflowed in POKEMON STADIUM 2 Color0: (TEXEL0 - TEXEL1) * PRIMLODFRAC + TEXEL1 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00177e6025fd7378 Overflowed in POKEMON STADIUM 2 Simplied DWORDs=040F0403, 03000000, 06020605, 02000000 Color0: (TEXEL0 - TEXEL1) * PRIMLODFRAC + TEXEL1 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x040F0403, 0x03000000, 0x06020605, 0x02000000}, // Simplified mux 0x00177E60, 0x25FD7378, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000005, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(DIF,ENV,T0), SEL(T0), 0, true}, // Stage 0 {SKIP, SKIP, 0, true}, // Stage 1 } }, /* //Mux=0x0017666025fd7f78 Overflowed in POKEMON STADIUM 2 Color0: (TEXEL0 - TEXEL1) * PRIMLODFRAC + TEXEL1 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (1 - 0) * PRIM + 0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x0017666025fd7f78 Overflowed in POKEMON STADIUM 2 Simplied DWORDs=040F0403, 06000000, 06020605, 02000000 Color0: (TEXEL0 - TEXEL1) * PRIMLODFRAC + TEXEL1 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (0 - 0) * 0 + SHADE Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x040F0403, 0x06000000, 0x06020605, 0x02000000}, // Simplified mux 0x00176660, 0x25FD7F78, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000007, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(PRI,DIF,T0), SEL(PRI), 0, true}, // Stage 0 {SKIP, SKIP, 0, false}, // Stage 1 } }, /* //Mux=0x00177e6025fd7378 Overflowed in POKEMON STADIUM 2 Color0: (TEXEL0 - TEXEL1) * PRIMLODFRAC + TEXEL1 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00177e6025fd7378 Overflowed in POKEMON STADIUM 2 Simplied DWORDs=040F0403, 03000000, 06020605, 02000000 Color0: (TEXEL0 - TEXEL1) * PRIMLODFRAC + TEXEL1 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (0 - 0) * 0 + TEXEL0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x040F0403, 0x03000000, 0x06020605, 0x02000000}, // Simplified mux 0x00177E60, 0x25FD7378, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000007, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(PRI,DIF,T0), SEL(T0), 0, true}, // Stage 0 {SKIP, SKIP, 0, false}, // Stage 1 } }, /* //Mux=0x00457fff3ffcfe3f Overflowed in POKEMON STADIUM 2 Color0: (SHADE - PRIM) * PRIM|A + TEXEL0 Color1: (0 - 0) * 0 + COMBINED Alpha0: (0 - 0) * 0 + 0 Alpha1: (0 - 0) * 0 + 0 //Simplied Mux=0x00457fff3ffcfe3f Overflowed in POKEMON STADIUM 2 Simplied DWORDs=00460506, 00000000, 02010003, 02000000 Color0: (SHADE - PRIM) * SHADE|A + 0 Color1: (TEXEL0 - 0) * 1 + COMBINED Alpha0: (0 - 0) * 0 + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDShade = 00460506 in color channelGenerated combiners: */ { {0x00460506, 0x00000000, 0x02010003, 0x02000000}, // Simplified mux 0x00457FFF, 0x3FFCFE3F, // 64bit Mux 2, // number of stages DISABLE_ALPHA, MUX_ENV, // Constant color 0x00460506, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {ADD(T0,DIF), SKIP, 0, true}, // Stage 0 {SKIP, SKIP, 0, false}, // Stage 1 } }, /* //Mux=0x00272c60350c937f Overflowed in POKEMON STADIUM 2 Color0: (TEXEL1 - PRIM) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - TEXEL0) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * PRIM + 0 //Simplied Mux=0x00272c60350c937f Overflowed in POKEMON STADIUM 2 Simplied DWORDs=030F0604, 00060004, 07020706, 02000000 Color0: (TEXEL1 - SHADE) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x030F0604, 0x00060004, 0x07020706, 0x02000000}, // Simplified mux 0x00272C60, 0x350C937F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000007, 0x00000005, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(PRI,DIF,T0),SKIP, 0, true}, // Stage 0 {SKIP, MOD(T1,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x00272c603510e37f Overflowed in POKEMON STADIUM 2 Color0: (TEXEL1 - PRIM) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - 1) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x00272c603510e37f Overflowed in POKEMON STADIUM 2 Simplied DWORDs=030F0604, 00060003, 07020706, 02000000 Color0: (TEXEL1 - SHADE) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (TEXEL0 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x030F0604, 0x00060003, 0x07020706, 0x02000000}, // Simplified mux 0x00272C60, 0x3510E37F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000005, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {SKIP,MOD(T1,DIF), 1, true}, // Stage 0 {LERP(DIF,ENV,T0), MULADD(T0,DIF,CUR), 0, true}, // Stage 1 } }, /* //Mux=0x0030e5ff5f16f63f Overflowed in POKEMON STADIUM 2 Color0: (PRIM - ENV) * TEXEL0 + ENV Color1: (0 - 0) * 0 + COMBINED Alpha0: (1 - 0) * TEXEL1 + PRIM Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x0030e5ff5f16f63f Overflowed in POKEMON STADIUM 2 Simplied DWORDs=06030605, 05010004, 02000000, 00020006 Color0: (PRIM - SHADE) * TEXEL0 + SHADE Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL1 - 0) * 1 + PRIM Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x06030605, 0x05010004, 0x02000000, 0x00020006}, // Simplified mux 0x0030E5FF, 0x5F16F63F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000007, 0x00000007, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(PRI,DIF,T0), MOD(PRI,DIF), 0, true}, // Stage 0 {SKIP, MULADD(T1,DIF,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x003117ff5f16fe3f Overflowed in POKEMON STADIUM 2 Color0: (PRIM - ENV) * TEXEL1 + ENV Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL0 - 0) * PRIM + 0 Alpha1: (COMBINED - 0) * ENV + 0 //Simplied Mux=0x003117ff5f16fe3f Overflowed in POKEMON STADIUM 2 Simplied DWORDs=06040605, 00050003, 02000000, 00020006 Color0: (PRIM - SHADE) * TEXEL1 + SHADE Color1: (0 - 0) * 0 + COMBINED Alpha0: (TEXEL0 - 0) * PRIM + 0 Alpha1: (SHADE - 0) * COMBINED + 0 Simplfied type: CM_FMT_TYPE6_A_LERP_B_CGenerated combiners: */ { {0x06040605, 0x00050003, 0x02000000, 0x00020006}, // Simplified mux 0x003117FF, 0x5F16FE3F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000007, 0x00000007, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {SKIP, MOD(T0,PRI), 0, true}, // Stage 0 {LERP(PRI,DIF,T1), MOD(DIF,CUR), 1, true}, // Stage 1 } }, /* //Mux=0x00272c603410933f Overflowed in POKEMON STADIUM 2 Color0: (TEXEL1 - PRIM) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (TEXEL1 - TEXEL0) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x00272c603410933f Overflowed in POKEMON STADIUM 2 Simplied DWORDs=030F0504, 00060004, 06020605, 02000000 Color0: (TEXEL1 - PRIM) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - SHADE) * COMBINED + SHADE Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x030F0504, 0x00060004, 0x06020605, 0x02000000}, // Simplified mux 0x00272C60, 0x3410933F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_PRIM, // Constant color 0x00000000, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(PRI,DIF,T0), SKIP, 0, true}, // Stage 0 {SKIP, MOD(T1,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x00272c603510937f Overflowed in POKEMON STADIUM 2 Color0: (TEXEL1 - PRIM) * PRIMLODFRAC + TEXEL0 Color1: (PRIM - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - TEXEL0) * 1 + TEXEL0 Alpha1: (COMBINED - 0) * SHADE + 0 //Simplied Mux=0x00272c603510937f Overflowed in POKEMON STADIUM 2 Simplied DWORDs=030F0604, 00060004, 07020706, 02000000 Color0: (TEXEL1 - SHADE) * PRIMLODFRAC + TEXEL0 Color1: (SHADE - ENV) * COMBINED + ENV Alpha0: (TEXEL1 - 0) * SHADE + 0 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE_NOT_CHECKEDGenerated combiners: */ { {0x030F0604, 0x00060004, 0x07020706, 0x02000000}, // Simplified mux 0x00272C60, 0x3510937F, // 64bit Mux 2, // number of stages ENABLE_BOTH, MUX_ENV, // Constant color 0x00000005, 0x00000000, 0, // Shade and specular color flags {0x00000000, 0x00000000}, // constant color texture flags { {LERP(DIF,ENV,T0), SKIP, 0, true}, // Stage 0 {SKIP, MOD(T1,DIF), 1, true}, // Stage 1 } }, /* //Mux=0x00167e835ffffc38 Overflowed in POKEMON STADIUM 2 Color0: (TEXEL0 - ENV) * ENV|A + 0 Color1: (SHADE - 0) * PRIM + COMBINED Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED //Simplied Mux=0x00167e835ffffc38 Overflowed in POKEMON STADIUM 2 Simplied DWORDs=00460703, 01000000, 02060004, 02000000 Color0: (TEXEL0 - ENV) * SHADE|A + 0 Color1: (TEXEL1 - 0) * SHADE + COMBINED Alpha0: (0 - 0) * 0 + 1 Alpha1: (0 - 0) * 0 + COMBINED Simplfied type: CM_FMT_TYPE8_A_SUB_B_MOD_CGenerated combiners: */ { {0x00460703, 0x01000000, 0x02060004, 0x02000000}, // Simplified mux 0x00167E83, 0x5FFFFC38, // 64bit Mux 2, // number of stages DISABLE_ALPHA, MUX_ENV, // Constant color 0x00050006, 0x00000007, 0, // Shade and specular color flags {0x00000000, 0x00000005}, // constant color texture flags { {SUB(T0,ENV), SKIP, 0, true}, // Stage 0 {MULADD(CUR,ENVA,DIF), SKIP, 1, true}, // Stage 1 } }, }; int noOfTwoStages = sizeof(twostages)/sizeof(GeneralCombinerInfo); mupen64plus-video-rice-src-2.0/src/Config.cpp0000644000000000000000000015630312165031100017211 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #define M64P_PLUGIN_PROTOTYPES 1 #include "osal_preproc.h" #include "m64p_types.h" #include "m64p_plugin.h" #include "m64p_config.h" #include "Config.h" #include "Debugger.h" #include "DeviceBuilder.h" #include "RenderBase.h" #include "TextureManager.h" #include "Video.h" #define INI_FILE "RiceVideoLinux.ini" static m64p_handle l_ConfigVideoRice = NULL; static m64p_handle l_ConfigVideoGeneral = NULL; static int FindIniEntry(uint32 dwCRC1, uint32 dwCRC2, uint8 nCountryID, char* szName, int PrintInfo); const char *frameBufferSettings[] = { "None (default)", "Hide Framebuffer Effects", "Basic Framebuffer", "Basic & Write Back", "Write Back & Reload", "Write Back Every Frame", "With Emulator", "Basic Framebuffer & With Emulator", "With Emulator Read Only", "With Emulator Write Only", }; const int resolutions[][2] = { {320, 240}, {400, 300}, {480, 360}, {512, 384}, {640, 480}, {800, 600}, {1024, 768}, {1152, 864}, {1280, 960}, {1400, 1050}, {1600, 1200}, {1920, 1440}, {2048, 1536}, }; const int numberOfResolutions = sizeof(resolutions)/sizeof(int)/2; const char* resolutionsS[] = { "320 x 240", "400 x 300", "480 x 360", "512 x 384", "640 x 480", "800 x 600", "1024 x 768", "1152 x 864", "1280 x 960", "1400 x 1050", "1600 x 1200", "1920 x 1440", "2048 x 1536" }; const char *frameBufferWriteBackControlSettings[] = { "Every Frame (default)", "Every 2 Frames", "Every 3 Frames", "Every 4 Frames", "Every 5 Frames", "Every 6 Frames", "Every 7 Frames", "Every 8 Frames", }; const char *renderToTextureSettings[] = { "None (default)", "Hide Render-to-texture Effects", "Basic Render-to-texture", "Basic & Write Back", "Write Back & Reload", }; const char *screenUpdateSettings[] = { "At VI origin update", "At VI origin change", "At CI change", "At the 1st CI change", "At the 1st drawing", "Before clear the screen", "At VI origin update after screen is drawn (default)", }; WindowSettingStruct windowSetting; GlobalOptions options; RomOptions defaultRomOptions; RomOptions currentRomOptions; FrameBufferOptions frameBufferOptions; std::vector IniSections; bool bIniIsChanged = false; char szIniFileName[300]; SettingInfo TextureQualitySettings[] = { {"Default", FORCE_DEFAULT_FILTER}, {"32-bit Texture", FORCE_POINT_FILTER}, {"16-bit Texture", FORCE_LINEAR_FILTER}, }; SettingInfo ForceTextureFilterSettings[] = { {"N64 Default Texture Filter", FORCE_DEFAULT_FILTER}, {"Force Nearest Filter (faster, low quality)", FORCE_POINT_FILTER}, {"Force Linear Filter (slower, better quality)", FORCE_LINEAR_FILTER}, }; SettingInfo TextureEnhancementSettings[] = { {"N64 original texture (No enhancement)", TEXTURE_NO_ENHANCEMENT}, {"2x (Double the texture size)", TEXTURE_2X_ENHANCEMENT}, {"2xSaI", TEXTURE_2XSAI_ENHANCEMENT}, {"hq2x", TEXTURE_HQ2X_ENHANCEMENT}, {"lq2x", TEXTURE_LQ2X_ENHANCEMENT}, {"hq4x", TEXTURE_HQ4X_ENHANCEMENT}, {"Sharpen", TEXTURE_SHARPEN_ENHANCEMENT}, {"Sharpen More", TEXTURE_SHARPEN_MORE_ENHANCEMENT}, }; SettingInfo TextureEnhancementControlSettings[] = { {"Normal", TEXTURE_ENHANCEMENT_NORMAL}, {"Smooth", TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1}, {"Less smooth", TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2}, {"2xSaI smooth", TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3}, {"Less 2xSaI smooth", TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4}, }; SettingInfo colorQualitySettings[] = { {"16-bit", TEXTURE_FMT_A4R4G4B4}, {"32-bit (def)", TEXTURE_FMT_A8R8G8B8}, }; const char* strDXDeviceDescs[] = { "HAL", "REF" }; SettingInfo openGLDepthBufferSettings[] = { {"16-bit (def)", 16}, {"32-bit", 32}, }; RenderEngineSetting OpenGLRenderSettings[] = { {"To Fit Your Video Card", OGL_DEVICE}, {"OpenGL 1.1 (Lowest)", OGL_1_1_DEVICE}, {"OpenGL 1.2/1.3", OGL_1_2_DEVICE}, {"OpenGL 1.4", OGL_1_4_DEVICE}, //{"OpenGL 1.4, the 2nd combiner", OGL_1_4_V2_DEVICE}, {"OpenGL for Nvidia TNT or better", OGL_TNT2_DEVICE}, {"OpenGL for Nvidia GeForce or better ", NVIDIA_OGL_DEVICE}, {"OpenGL Fragment Program Extension", OGL_FRAGMENT_PROGRAM}, }; SettingInfo OnScreenDisplaySettings[] = { {"Display Nothing", ONSCREEN_DISPLAY_NOTHING}, {"Display DList Per Second", ONSCREEN_DISPLAY_DLIST_PER_SECOND}, {"Display Frame Per Second", ONSCREEN_DISPLAY_FRAME_PER_SECOND}, {"Display Debug Information Only", ONSCREEN_DISPLAY_DEBUG_INFORMATION_ONLY}, {"Display Messages From CPU Core Only", ONSCREEN_DISPLAY_TEXT_FROM_CORE_ONLY}, {"Display DList Per Second With Core Msgs", ONSCREEN_DISPLAY_DLIST_PER_SECOND_WITH_CORE_MSG}, {"Display Frame Per Second With Core Msgs", ONSCREEN_DISPLAY_FRAME_PER_SECOND_WITH_CORE_MSG}, {"Display Debug Information With Core Msgs", ONSCREEN_DISPLAY_DEBUG_INFORMATION_WITH_CORE_MSG}, }; const int numberOfOpenGLRenderEngineSettings = sizeof(OpenGLRenderSettings)/sizeof(RenderEngineSetting); void GenerateFrameBufferOptions(void) { if( CDeviceBuilder::GetGeneralDeviceType() == OGL_DEVICE ) { // OpenGL does not support much yet if( currentRomOptions.N64FrameBufferEmuType != FRM_BUF_NONE ) currentRomOptions.N64FrameBufferEmuType = FRM_BUF_IGNORE; if( currentRomOptions.N64RenderToTextureEmuType != TXT_BUF_NONE ) currentRomOptions.N64RenderToTextureEmuType = TXT_BUF_IGNORE; } frameBufferOptions.bUpdateCIInfo = false; frameBufferOptions.bCheckBackBufs = false; frameBufferOptions.bWriteBackBufToRDRAM = false; frameBufferOptions.bLoadBackBufFromRDRAM = false; frameBufferOptions.bIgnore = true; frameBufferOptions.bSupportRenderTextures = false; frameBufferOptions.bCheckRenderTextures = false; frameBufferOptions.bRenderTextureWriteBack = false; frameBufferOptions.bLoadRDRAMIntoRenderTexture = false; frameBufferOptions.bProcessCPUWrite = false; frameBufferOptions.bProcessCPURead = false; frameBufferOptions.bAtEachFrameUpdate = false; frameBufferOptions.bIgnoreRenderTextureIfHeightUnknown = false; switch( currentRomOptions.N64FrameBufferEmuType ) { case FRM_BUF_NONE: break; case FRM_BUF_COMPLETE: frameBufferOptions.bAtEachFrameUpdate = true; frameBufferOptions.bProcessCPUWrite = true; frameBufferOptions.bProcessCPURead = true; frameBufferOptions.bUpdateCIInfo = true; break; case FRM_BUF_WRITEBACK_AND_RELOAD: frameBufferOptions.bLoadBackBufFromRDRAM = true; case FRM_BUF_BASIC_AND_WRITEBACK: frameBufferOptions.bWriteBackBufToRDRAM = true; case FRM_BUF_BASIC: frameBufferOptions.bCheckBackBufs = true; case FRM_BUF_IGNORE: frameBufferOptions.bUpdateCIInfo = true; break; case FRM_BUF_BASIC_AND_WITH_EMULATOR: // Banjo Kazooie frameBufferOptions.bCheckBackBufs = true; case FRM_BUF_WITH_EMULATOR: frameBufferOptions.bUpdateCIInfo = true; frameBufferOptions.bProcessCPUWrite = true; frameBufferOptions.bProcessCPURead = true; break; case FRM_BUF_WITH_EMULATOR_READ_ONLY: frameBufferOptions.bUpdateCIInfo = true; frameBufferOptions.bProcessCPURead = true; break; case FRM_BUF_WITH_EMULATOR_WRITE_ONLY: frameBufferOptions.bUpdateCIInfo = true; frameBufferOptions.bProcessCPUWrite = true; break; } switch( currentRomOptions.N64RenderToTextureEmuType ) { case TXT_BUF_NONE: frameBufferOptions.bSupportRenderTextures = false; break; case TXT_BUF_WRITE_BACK_AND_RELOAD: frameBufferOptions.bLoadRDRAMIntoRenderTexture = true; case TXT_BUF_WRITE_BACK: frameBufferOptions.bRenderTextureWriteBack = true; case TXT_BUF_NORMAL: frameBufferOptions.bCheckRenderTextures = true; frameBufferOptions.bIgnore = false; case TXT_BUF_IGNORE: frameBufferOptions.bUpdateCIInfo = true; frameBufferOptions.bSupportRenderTextures = true; break; } if( currentRomOptions.screenUpdateSetting >= SCREEN_UPDATE_AT_CI_CHANGE ) { frameBufferOptions.bUpdateCIInfo = true; } } BOOL InitConfiguration(void) { if (ConfigOpenSection("Video-General", &l_ConfigVideoGeneral) != M64ERR_SUCCESS) { DebugMessage(M64MSG_ERROR, "Unable to open Video-General configuration section"); return FALSE; } if (ConfigOpenSection("Video-Rice", &l_ConfigVideoRice) != M64ERR_SUCCESS) { DebugMessage(M64MSG_ERROR, "Unable to open Video-Rice configuration section"); return FALSE; } ConfigSetDefaultBool(l_ConfigVideoGeneral, "Fullscreen", 0, "Use fullscreen mode if True, or windowed mode if False "); ConfigSetDefaultInt(l_ConfigVideoGeneral, "ScreenWidth", 640, "Width of output window or fullscreen width"); ConfigSetDefaultInt(l_ConfigVideoGeneral, "ScreenHeight", 480, "Height of output window or fullscreen height"); ConfigSetDefaultBool(l_ConfigVideoGeneral, "VerticalSync", 0, "If true, activate the SDL_GL_SWAP_CONTROL attribute"); ConfigSetDefaultInt(l_ConfigVideoRice, "FrameBufferSetting", FRM_BUF_NONE, "Frame Buffer Emulation (0=ROM default, 1=disable)"); ConfigSetDefaultInt(l_ConfigVideoRice, "FrameBufferWriteBackControl", FRM_BUF_WRITEBACK_NORMAL, "Frequency to write back the frame buffer (0=every frame, 1=every other frame, etc)"); ConfigSetDefaultInt(l_ConfigVideoRice, "RenderToTexture", TXT_BUF_NONE, "Render-to-texture emulation (0=none, 1=ignore, 2=normal, 3=write back, 4=write back and reload)"); #if defined(WIN32) ConfigSetDefaultInt(l_ConfigVideoRice, "ScreenUpdateSetting", SCREEN_UPDATE_AT_1ST_CI_CHANGE, "Control when the screen will be updated (0=ROM default, 1=VI origin update, 2=VI origin change, 3=CI change, 4=first CI change, 5=first primitive draw, 6=before screen clear, 7=after screen drawn)"); // SCREEN_UPDATE_AT_VI_UPDATE_AND_DRAWN #else ConfigSetDefaultInt(l_ConfigVideoRice, "ScreenUpdateSetting", SCREEN_UPDATE_AT_VI_UPDATE, "Control when the screen will be updated (0=ROM default, 1=VI origin update, 2=VI origin change, 3=CI change, 4=first CI change, 5=first primitive draw, 6=before screen clear, 7=after screen drawn)"); // SCREEN_UPDATE_AT_VI_UPDATE_AND_DRAWN #endif ConfigSetDefaultBool(l_ConfigVideoRice, "NormalAlphaBlender", FALSE, "Force to use normal alpha blender"); ConfigSetDefaultBool(l_ConfigVideoRice, "FastTextureLoading", FALSE, "Use a faster algorithm to speed up texture loading and CRC computation"); ConfigSetDefaultBool(l_ConfigVideoRice, "AccurateTextureMapping", TRUE, "Use different texture coordinate clamping code"); ConfigSetDefaultBool(l_ConfigVideoRice, "InN64Resolution", FALSE, "Force emulated frame buffers to be in N64 native resolution"); ConfigSetDefaultBool(l_ConfigVideoRice, "SaveVRAM", FALSE, "Try to reduce Video RAM usage (should never be used)"); ConfigSetDefaultBool(l_ConfigVideoRice, "DoubleSizeForSmallTxtrBuf", FALSE, "Enable this option to have better render-to-texture quality"); ConfigSetDefaultBool(l_ConfigVideoRice, "DefaultCombinerDisable", FALSE, "Force to use normal color combiner"); ConfigSetDefaultBool(l_ConfigVideoRice, "EnableHacks", TRUE, "Enable game-specific settings from INI file"); ConfigSetDefaultBool(l_ConfigVideoRice, "WinFrameMode", FALSE, "If enabled, graphics will be drawn in WinFrame mode instead of solid and texture mode"); ConfigSetDefaultBool(l_ConfigVideoRice, "FullTMEMEmulation", FALSE, "N64 Texture Memory Full Emulation (may fix some games, may break others)"); ConfigSetDefaultBool(l_ConfigVideoRice, "OpenGLVertexClipper", FALSE, "Enable vertex clipper for fog operations"); ConfigSetDefaultBool(l_ConfigVideoRice, "EnableSSE", TRUE, "Enable/Disable SSE optimizations for capable CPUs"); ConfigSetDefaultBool(l_ConfigVideoRice, "EnableVertexShader", FALSE, "Use GPU vertex shader"); ConfigSetDefaultBool(l_ConfigVideoRice, "SkipFrame", FALSE, "If this option is enabled, the plugin will skip every other frame"); ConfigSetDefaultBool(l_ConfigVideoRice, "TexRectOnly", FALSE, "If enabled, texture enhancement will be done only for TxtRect ucode"); ConfigSetDefaultBool(l_ConfigVideoRice, "SmallTextureOnly", FALSE, "If enabled, texture enhancement will be done only for textures width+height<=128"); ConfigSetDefaultBool(l_ConfigVideoRice, "LoadHiResCRCOnly", TRUE, "Select hi-resolution textures based only on the CRC and ignore format+size information (Glide64 compatibility)"); ConfigSetDefaultBool(l_ConfigVideoRice, "LoadHiResTextures", FALSE, "Enable hi-resolution texture file loading"); ConfigSetDefaultBool(l_ConfigVideoRice, "DumpTexturesToFiles", FALSE, "Enable texture dumping"); ConfigSetDefaultBool(l_ConfigVideoRice, "ShowFPS", FALSE, "Display On-screen FPS"); ConfigSetDefaultInt(l_ConfigVideoRice, "Mipmapping", 2, "Use Mipmapping? 0=no, 1=nearest, 2=bilinear, 3=trilinear"); ConfigSetDefaultInt(l_ConfigVideoRice, "FogMethod", 0, "Enable, Disable or Force fog generation (0=Disable, 1=Enable n64 choose, 2=Force Fog)"); ConfigSetDefaultInt(l_ConfigVideoRice, "ForceTextureFilter", 0, "Force to use texture filtering or not (0=auto: n64 choose, 1=force no filtering, 2=force filtering)"); ConfigSetDefaultInt(l_ConfigVideoRice, "TextureEnhancement", 0, "Primary texture enhancement filter (0=None, 1=2X, 2=2XSAI, 3=HQ2X, 4=LQ2X, 5=HQ4X, 6=Sharpen, 7=Sharpen More, 8=External, 9=Mirrored)"); ConfigSetDefaultInt(l_ConfigVideoRice, "TextureEnhancementControl", 0, "Secondary texture enhancement filter (0 = none, 1-4 = filtered)"); ConfigSetDefaultInt(l_ConfigVideoRice, "TextureQuality", TXT_QUALITY_DEFAULT, "Color bit depth to use for textures (0=default, 1=32 bits, 2=16 bits)"); ConfigSetDefaultInt(l_ConfigVideoRice, "OpenGLDepthBufferSetting", 16, "Z-buffer depth (only 16 or 32)"); ConfigSetDefaultInt(l_ConfigVideoRice, "MultiSampling", 0, "Enable/Disable MultiSampling (0=off, 2,4,8,16=quality)"); ConfigSetDefaultInt(l_ConfigVideoRice, "ColorQuality", TEXTURE_FMT_A8R8G8B8, "Color bit depth for rendering window (0=32 bits, 1=16 bits)"); ConfigSetDefaultInt(l_ConfigVideoRice, "OpenGLRenderSetting", OGL_DEVICE, "OpenGL level to support (0=auto, 1=OGL_1.1, 2=OGL_1.2, 3=OGL_1.3, 4=OGL_1.4, 5=OGL_1.4_V2, 6=OGL_TNT2, 7=NVIDIA_OGL, 8=OGL_FRAGMENT_PROGRAM)"); ConfigSetDefaultInt(l_ConfigVideoRice, "AnisotropicFiltering", 0, "Enable/Disable Anisotropic Filtering for Mipmapping (0=no filtering, 2-16=quality). This is uneffective if Mipmapping is 0. If the given value is to high to be supported by your graphic card, the value will be the highest value your graphic card can support. Better result with Trilinear filtering"); return TRUE; } bool isMMXSupported() { int IsMMXSupported = 0; #if !defined(__GNUC__) && !defined(NO_ASM) __asm { mov eax,1 // CPUID level 1 cpuid // EDX = feature flag and edx,0x800000 // test bit 23 of feature flag mov IsMMXSupported,edx // != 0 if MMX is supported } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) return true; #elif !defined(NO_ASM) // GCC assumed asm volatile ( "push %%ebx \n" "mov $1, %%eax \n" // CPUID level 1 "cpuid \n" // EDX = feature flag "and $0x800000, %%edx \n" // test bit 23 of feature flag "pop %%ebx \n" : "=d"(IsMMXSupported) : : "memory", "cc", "eax", "ecx" ); #endif if (IsMMXSupported != 0) return true; else return false; } bool isSSESupported() { int SSESupport = 0; // And finally, check the CPUID for Streaming SIMD Extensions support. #if !defined(__GNUC__) && !defined(NO_ASM) _asm { mov eax, 1 // Put a "1" in eax to tell CPUID to get the feature bits cpuid // Perform CPUID (puts processor feature info into EDX) and edx, 02000000h // Test bit 25, for Streaming SIMD Extensions existence. mov SSESupport, edx // SIMD Extensions). Set return value to 1 to indicate, } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) return true; #elif !defined(NO_ASM) // GCC assumed asm volatile ( "push %%ebx \n" "mov $1, %%eax \n" // Put a "1" in eax to tell CPUID to get the feature bits "cpuid \n" // Perform CPUID (puts processor feature info into EDX) "and $0x02000000, %%edx \n" // Test bit 25, for Streaming SIMD Extensions existence. "pop %%ebx \n" : "=d"(SSESupport) : : "memory", "cc", "eax", "ecx" ); # endif if (SSESupport != 0) return true; else return false; } static void ReadConfiguration(void) { windowSetting.bDisplayFullscreen = ConfigGetParamBool(l_ConfigVideoGeneral, "Fullscreen"); windowSetting.uDisplayWidth = ConfigGetParamInt(l_ConfigVideoGeneral, "ScreenWidth"); windowSetting.uDisplayHeight = ConfigGetParamInt(l_ConfigVideoGeneral, "ScreenHeight"); windowSetting.bVerticalSync = ConfigGetParamBool(l_ConfigVideoGeneral, "VerticalSync"); defaultRomOptions.N64FrameBufferEmuType = ConfigGetParamInt(l_ConfigVideoRice, "FrameBufferSetting"); defaultRomOptions.N64FrameBufferWriteBackControl = ConfigGetParamInt(l_ConfigVideoRice, "FrameBufferWriteBackControl"); defaultRomOptions.N64RenderToTextureEmuType = ConfigGetParamInt(l_ConfigVideoRice, "RenderToTexture"); defaultRomOptions.screenUpdateSetting = ConfigGetParamInt(l_ConfigVideoRice, "screenUpdateSetting"); defaultRomOptions.bNormalBlender = ConfigGetParamBool(l_ConfigVideoRice, "NormalAlphaBlender"); defaultRomOptions.bFastTexCRC = ConfigGetParamBool(l_ConfigVideoRice, "FastTextureLoading"); defaultRomOptions.bAccurateTextureMapping = ConfigGetParamBool(l_ConfigVideoRice, "AccurateTextureMapping"); defaultRomOptions.bInN64Resolution = ConfigGetParamBool(l_ConfigVideoRice, "InN64Resolution"); defaultRomOptions.bSaveVRAM = ConfigGetParamBool(l_ConfigVideoRice, "SaveVRAM"); defaultRomOptions.bDoubleSizeForSmallTxtrBuf = ConfigGetParamBool(l_ConfigVideoRice, "DoubleSizeForSmallTxtrBuf"); defaultRomOptions.bNormalCombiner = ConfigGetParamBool(l_ConfigVideoRice, "DefaultCombinerDisable"); options.bEnableHacks = ConfigGetParamBool(l_ConfigVideoRice, "EnableHacks"); options.bWinFrameMode = ConfigGetParamBool(l_ConfigVideoRice, "WinFrameMode"); options.bFullTMEM = ConfigGetParamBool(l_ConfigVideoRice, "FullTMEMEmulation"); options.bOGLVertexClipper = ConfigGetParamBool(l_ConfigVideoRice, "OpenGLVertexClipper"); options.bEnableSSE = ConfigGetParamBool(l_ConfigVideoRice, "EnableSSE"); options.bEnableVertexShader = ConfigGetParamBool(l_ConfigVideoRice, "EnableVertexShader"); options.bSkipFrame = ConfigGetParamBool(l_ConfigVideoRice, "SkipFrame"); options.bTexRectOnly = ConfigGetParamBool(l_ConfigVideoRice, "TexRectOnly"); options.bSmallTextureOnly = ConfigGetParamBool(l_ConfigVideoRice, "SmallTextureOnly"); options.bLoadHiResTextures = ConfigGetParamBool(l_ConfigVideoRice, "LoadHiResTextures"); options.bLoadHiResCRCOnly = ConfigGetParamBool(l_ConfigVideoRice, "LoadHiResCRCOnly"); options.bDumpTexturesToFiles = ConfigGetParamBool(l_ConfigVideoRice, "DumpTexturesToFiles"); options.bShowFPS = ConfigGetParamBool(l_ConfigVideoRice, "ShowFPS"); options.mipmapping = ConfigGetParamInt(l_ConfigVideoRice, "Mipmapping"); options.fogMethod = ConfigGetParamInt(l_ConfigVideoRice, "FogMethod"); options.forceTextureFilter = ConfigGetParamInt(l_ConfigVideoRice, "ForceTextureFilter"); options.textureEnhancement = ConfigGetParamInt(l_ConfigVideoRice, "TextureEnhancement"); options.textureEnhancementControl = ConfigGetParamInt(l_ConfigVideoRice, "TextureEnhancementControl"); options.textureQuality = ConfigGetParamInt(l_ConfigVideoRice, "TextureQuality"); options.OpenglDepthBufferSetting = ConfigGetParamInt(l_ConfigVideoRice, "OpenGLDepthBufferSetting"); options.multiSampling = ConfigGetParamInt(l_ConfigVideoRice, "MultiSampling"); options.colorQuality = ConfigGetParamInt(l_ConfigVideoRice, "ColorQuality"); options.OpenglRenderSetting = ConfigGetParamInt(l_ConfigVideoRice, "OpenGLRenderSetting"); options.anisotropicFiltering = ConfigGetParamInt(l_ConfigVideoRice, "AnisotropicFiltering"); CDeviceBuilder::SelectDeviceType((SupportedDeviceType)options.OpenglRenderSetting); status.isMMXSupported = isMMXSupported(); status.isSSESupported = isSSESupported(); status.isVertexShaderSupported = false; status.isSSEEnabled = status.isSSESupported && options.bEnableSSE; #if !defined(NO_ASM) if( status.isSSEEnabled ) { ProcessVertexData = ProcessVertexDataSSE; DebugMessage(M64MSG_INFO, "SSE processing enabled."); } else #endif { ProcessVertexData = ProcessVertexDataNoSSE; DebugMessage(M64MSG_INFO, "Disabled SSE processing."); } status.isVertexShaderEnabled = status.isVertexShaderSupported && options.bEnableVertexShader; status.bUseHW_T_L = false; } BOOL LoadConfiguration(void) { IniSections.clear(); bIniIsChanged = false; strcpy(szIniFileName, INI_FILE); if (!ReadIniFile()) { DebugMessage(M64MSG_ERROR, "Unable to read ini file from disk"); return FALSE; } if (l_ConfigVideoGeneral == NULL || l_ConfigVideoRice == NULL) { DebugMessage(M64MSG_ERROR, "Rice Video configuration sections are not open!"); return FALSE; } // Read config parameters from core config API and set up internal variables ReadConfiguration(); return TRUE; } void GenerateCurrentRomOptions() { currentRomOptions.N64FrameBufferEmuType =g_curRomInfo.dwFrameBufferOption; currentRomOptions.N64FrameBufferWriteBackControl =defaultRomOptions.N64FrameBufferWriteBackControl; currentRomOptions.N64RenderToTextureEmuType =g_curRomInfo.dwRenderToTextureOption; currentRomOptions.screenUpdateSetting =g_curRomInfo.dwScreenUpdateSetting; currentRomOptions.bNormalCombiner =g_curRomInfo.dwNormalCombiner; currentRomOptions.bNormalBlender =g_curRomInfo.dwNormalBlender; currentRomOptions.bFastTexCRC =g_curRomInfo.dwFastTextureCRC; currentRomOptions.bAccurateTextureMapping =g_curRomInfo.dwAccurateTextureMapping; options.enableHackForGames = NO_HACK_FOR_GAME; if ((strncmp((char*)g_curRomInfo.szGameName, "BANJO TOOIE", 11) == 0)) { options.enableHackForGames = HACK_FOR_BANJO_TOOIE; } else if ((strncmp((char*)g_curRomInfo.szGameName, "DR.MARIO", 8) == 0)) { options.enableHackForGames = HACK_FOR_DR_MARIO; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "Pilot", 5) == 0)) { options.enableHackForGames = HACK_FOR_PILOT_WINGS; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "YOSHI", 5) == 0)) { options.enableHackForGames = HACK_FOR_YOSHI; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "NITRO", 5) == 0)) { options.enableHackForGames = HACK_FOR_NITRO; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "TONY HAWK", 9) == 0)) { options.enableHackForGames = HACK_FOR_TONYHAWK; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "THPS", 4) == 0)) { options.enableHackForGames = HACK_FOR_TONYHAWK; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "SPIDERMAN", 9) == 0)) { options.enableHackForGames = HACK_FOR_TONYHAWK; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "NASCAR", 6) == 0)) { options.enableHackForGames = HACK_FOR_NASCAR; } else if ((strstr((char*)g_curRomInfo.szGameName, "ZELDA") != 0) && (strstr((char*)g_curRomInfo.szGameName, "MASK") != 0)) { options.enableHackForGames = HACK_FOR_ZELDA_MM; } else if ((strstr((char*)g_curRomInfo.szGameName, "ZELDA") != 0)) { options.enableHackForGames = HACK_FOR_ZELDA; } else if ((strstr((char*)g_curRomInfo.szGameName, "Ogre") != 0)) { options.enableHackForGames = HACK_FOR_OGRE_BATTLE; } else if ((strstr((char*)g_curRomInfo.szGameName, "TWINE") != 0)) { options.enableHackForGames = HACK_FOR_TWINE; } else if ((strstr((char*)g_curRomInfo.szGameName, "Squadron") != 0)) { options.enableHackForGames = HACK_FOR_ROGUE_SQUADRON; } else if ((strstr((char*)g_curRomInfo.szGameName, "Baseball") != 0) && (strstr((char*)g_curRomInfo.szGameName, "Star") != 0)) { options.enableHackForGames = HACK_FOR_ALL_STAR_BASEBALL; } else if ((strstr((char*)g_curRomInfo.szGameName, "Tigger") != 0) && (strstr((char*)g_curRomInfo.szGameName, "Honey") != 0)) { options.enableHackForGames = HACK_FOR_TIGER_HONEY_HUNT; } else if ((strstr((char*)g_curRomInfo.szGameName, "Bust") != 0) && (strstr((char*)g_curRomInfo.szGameName, "Move") != 0)) { options.enableHackForGames = HACK_FOR_BUST_A_MOVE; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MarioTennis",11) == 0)) { options.enableHackForGames = HACK_FOR_MARIO_TENNIS; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "SUPER BOWLING",13) == 0)) { options.enableHackForGames = HACK_FOR_SUPER_BOWLING; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "CONKER",6) == 0)) { options.enableHackForGames = HACK_FOR_CONKER; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MK_MYTHOLOGIES",14) == 0)) { options.enableHackForGames = HACK_REVERSE_Y_COOR; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "Fighting Force",14) == 0)) { options.enableHackForGames = HACK_REVERSE_XY_COOR; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "GOLDENEYE",9) == 0)) { options.enableHackForGames = HACK_FOR_GOLDEN_EYE; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "F-ZERO",6) == 0)) { options.enableHackForGames = HACK_FOR_FZERO; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "Command&Conquer",15) == 0)) { options.enableHackForGames = HACK_FOR_COMMANDCONQUER; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "READY 2 RUMBLE",14) == 0)) { options.enableHackForGames = HACK_FOR_RUMBLE; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "READY to RUMBLE",15) == 0)) { options.enableHackForGames = HACK_FOR_RUMBLE; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "South Park Rally",16) == 0)) { options.enableHackForGames = HACK_FOR_SOUTH_PARK_RALLY; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "Extreme G 2",11) == 0)) { options.enableHackForGames = HACK_FOR_EXTREME_G2; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MarioGolf64",11) == 0)) { options.enableHackForGames = HACK_FOR_MARIO_GOLF; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MLB FEATURING",13) == 0)) { options.enableHackForGames = HACK_FOR_MLB; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "POLARISSNOCROSS",15) == 0)) { options.enableHackForGames = HACK_FOR_POLARISSNOCROSS; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "TOP GEAR RALLY",14) == 0)) { options.enableHackForGames = HACK_FOR_TOPGEARRALLY; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "DUKE NUKEM",10) == 0)) { options.enableHackForGames = HACK_FOR_DUKE_NUKEM; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MARIOKART64",11) == 0)) { options.enableHackForGames = HACK_FOR_MARIO_KART; } if (options.enableHackForGames != NO_HACK_FOR_GAME) DebugMessage(M64MSG_INFO, "Enabled hacks for game: '%s'", g_curRomInfo.szGameName); if( currentRomOptions.N64FrameBufferEmuType == 0 ) currentRomOptions.N64FrameBufferEmuType = defaultRomOptions.N64FrameBufferEmuType; else currentRomOptions.N64FrameBufferEmuType--; if( currentRomOptions.N64RenderToTextureEmuType == 0 ) currentRomOptions.N64RenderToTextureEmuType = defaultRomOptions.N64RenderToTextureEmuType; else currentRomOptions.N64RenderToTextureEmuType--; if( currentRomOptions.screenUpdateSetting == 0 ) currentRomOptions.screenUpdateSetting = defaultRomOptions.screenUpdateSetting; if( currentRomOptions.bNormalCombiner == 0 ) currentRomOptions.bNormalCombiner = defaultRomOptions.bNormalCombiner; else currentRomOptions.bNormalCombiner--; if( currentRomOptions.bNormalBlender == 0 ) currentRomOptions.bNormalBlender = defaultRomOptions.bNormalBlender; else currentRomOptions.bNormalBlender--; if( currentRomOptions.bFastTexCRC == 0 ) currentRomOptions.bFastTexCRC = defaultRomOptions.bFastTexCRC; else currentRomOptions.bFastTexCRC--; if( currentRomOptions.bAccurateTextureMapping == 0 ) currentRomOptions.bAccurateTextureMapping = defaultRomOptions.bAccurateTextureMapping; else currentRomOptions.bAccurateTextureMapping--; options.bUseFullTMEM = ((options.bFullTMEM && (g_curRomInfo.dwFullTMEM == 0)) || g_curRomInfo.dwFullTMEM == 2); GenerateFrameBufferOptions(); if( options.enableHackForGames == HACK_FOR_MARIO_GOLF || options.enableHackForGames == HACK_FOR_MARIO_TENNIS ) { frameBufferOptions.bIgnoreRenderTextureIfHeightUnknown = true; } } void Ini_GetRomOptions(LPGAMESETTING pGameSetting) { int i; i = FindIniEntry(pGameSetting->romheader.dwCRC1, pGameSetting->romheader.dwCRC2, pGameSetting->romheader.nCountryID, (char*)pGameSetting->szGameName, 1); pGameSetting->bDisableTextureCRC = IniSections[i].bDisableTextureCRC; pGameSetting->bDisableCulling = IniSections[i].bDisableCulling; pGameSetting->bIncTexRectEdge = IniSections[i].bIncTexRectEdge; pGameSetting->bZHack = IniSections[i].bZHack; pGameSetting->bTextureScaleHack = IniSections[i].bTextureScaleHack; pGameSetting->bPrimaryDepthHack = IniSections[i].bPrimaryDepthHack; pGameSetting->bTexture1Hack = IniSections[i].bTexture1Hack; pGameSetting->bFastLoadTile = IniSections[i].bFastLoadTile; pGameSetting->bUseSmallerTexture = IniSections[i].bUseSmallerTexture; pGameSetting->VIWidth = IniSections[i].VIWidth; pGameSetting->VIHeight = IniSections[i].VIHeight; pGameSetting->UseCIWidthAndRatio = IniSections[i].UseCIWidthAndRatio; pGameSetting->dwFullTMEM = IniSections[i].dwFullTMEM; pGameSetting->bTxtSizeMethod2 = IniSections[i].bTxtSizeMethod2; pGameSetting->bEnableTxtLOD = IniSections[i].bEnableTxtLOD; pGameSetting->dwFastTextureCRC = IniSections[i].dwFastTextureCRC; pGameSetting->bEmulateClear = IniSections[i].bEmulateClear; pGameSetting->bForceScreenClear = IniSections[i].bForceScreenClear; pGameSetting->dwAccurateTextureMapping = IniSections[i].dwAccurateTextureMapping; pGameSetting->dwNormalBlender = IniSections[i].dwNormalBlender; pGameSetting->bDisableBlender = IniSections[i].bDisableBlender; pGameSetting->dwNormalCombiner = IniSections[i].dwNormalCombiner; pGameSetting->bForceDepthBuffer = IniSections[i].bForceDepthBuffer; pGameSetting->bDisableObjBG = IniSections[i].bDisableObjBG; pGameSetting->dwFrameBufferOption = IniSections[i].dwFrameBufferOption; pGameSetting->dwRenderToTextureOption = IniSections[i].dwRenderToTextureOption; pGameSetting->dwScreenUpdateSetting = IniSections[i].dwScreenUpdateSetting; } void Ini_StoreRomOptions(LPGAMESETTING pGameSetting) { int i; i = FindIniEntry(pGameSetting->romheader.dwCRC1, pGameSetting->romheader.dwCRC2, pGameSetting->romheader.nCountryID, (char*)pGameSetting->szGameName, 0); if( IniSections[i].bDisableTextureCRC !=pGameSetting->bDisableTextureCRC ) { IniSections[i].bDisableTextureCRC =pGameSetting->bDisableTextureCRC ; bIniIsChanged=true; } if( IniSections[i].bDisableCulling !=pGameSetting->bDisableCulling ) { IniSections[i].bDisableCulling =pGameSetting->bDisableCulling ; bIniIsChanged=true; } if( IniSections[i].dwFastTextureCRC !=pGameSetting->dwFastTextureCRC ) { IniSections[i].dwFastTextureCRC =pGameSetting->dwFastTextureCRC ; bIniIsChanged=true; } if( IniSections[i].bEmulateClear !=pGameSetting->bEmulateClear ) { IniSections[i].bEmulateClear =pGameSetting->bEmulateClear ; bIniIsChanged=true; } if( IniSections[i].dwNormalBlender !=pGameSetting->dwNormalBlender ) { IniSections[i].dwNormalBlender =pGameSetting->dwNormalBlender ; bIniIsChanged=true; } if( IniSections[i].bDisableBlender !=pGameSetting->bDisableBlender ) { IniSections[i].bDisableBlender =pGameSetting->bDisableBlender ; bIniIsChanged=true; } if( IniSections[i].bForceScreenClear !=pGameSetting->bForceScreenClear ) { IniSections[i].bForceScreenClear =pGameSetting->bForceScreenClear ; bIniIsChanged=true; } if( IniSections[i].dwAccurateTextureMapping !=pGameSetting->dwAccurateTextureMapping ) { IniSections[i].dwAccurateTextureMapping =pGameSetting->dwAccurateTextureMapping ; bIniIsChanged=true; } if( IniSections[i].dwNormalCombiner !=pGameSetting->dwNormalCombiner ) { IniSections[i].dwNormalCombiner =pGameSetting->dwNormalCombiner ; bIniIsChanged=true; } if( IniSections[i].bForceDepthBuffer !=pGameSetting->bForceDepthBuffer ) { IniSections[i].bForceDepthBuffer =pGameSetting->bForceDepthBuffer ; bIniIsChanged=true; } if( IniSections[i].bDisableObjBG !=pGameSetting->bDisableObjBG ) { IniSections[i].bDisableObjBG =pGameSetting->bDisableObjBG ; bIniIsChanged=true; } if( IniSections[i].dwFrameBufferOption !=pGameSetting->dwFrameBufferOption ) { IniSections[i].dwFrameBufferOption =pGameSetting->dwFrameBufferOption ; bIniIsChanged=true; } if( IniSections[i].dwRenderToTextureOption !=pGameSetting->dwRenderToTextureOption ) { IniSections[i].dwRenderToTextureOption =pGameSetting->dwRenderToTextureOption ; bIniIsChanged=true; } if( IniSections[i].dwScreenUpdateSetting !=pGameSetting->dwScreenUpdateSetting ) { IniSections[i].dwScreenUpdateSetting =pGameSetting->dwScreenUpdateSetting ; bIniIsChanged=true; } if( IniSections[i].bIncTexRectEdge != pGameSetting->bIncTexRectEdge ) { IniSections[i].bIncTexRectEdge =pGameSetting->bIncTexRectEdge; bIniIsChanged=true; } if( IniSections[i].bZHack != pGameSetting->bZHack ) { IniSections[i].bZHack =pGameSetting->bZHack; bIniIsChanged=true; } if( IniSections[i].bTextureScaleHack != pGameSetting->bTextureScaleHack ) { IniSections[i].bTextureScaleHack =pGameSetting->bTextureScaleHack; bIniIsChanged=true; } if( IniSections[i].bPrimaryDepthHack != pGameSetting->bPrimaryDepthHack ) { IniSections[i].bPrimaryDepthHack =pGameSetting->bPrimaryDepthHack; bIniIsChanged=true; } if( IniSections[i].bTexture1Hack != pGameSetting->bTexture1Hack ) { IniSections[i].bTexture1Hack =pGameSetting->bTexture1Hack; bIniIsChanged=true; } if( IniSections[i].bFastLoadTile != pGameSetting->bFastLoadTile ) { IniSections[i].bFastLoadTile =pGameSetting->bFastLoadTile; bIniIsChanged=true; } if( IniSections[i].bUseSmallerTexture != pGameSetting->bUseSmallerTexture ) { IniSections[i].bUseSmallerTexture =pGameSetting->bUseSmallerTexture; bIniIsChanged=true; } if( IniSections[i].VIWidth != pGameSetting->VIWidth ) { IniSections[i].VIWidth =pGameSetting->VIWidth; bIniIsChanged=true; } if( IniSections[i].VIHeight != pGameSetting->VIHeight ) { IniSections[i].VIHeight =pGameSetting->VIHeight; bIniIsChanged=true; } if( IniSections[i].UseCIWidthAndRatio != pGameSetting->UseCIWidthAndRatio ) { IniSections[i].UseCIWidthAndRatio =pGameSetting->UseCIWidthAndRatio; bIniIsChanged=true; } if( IniSections[i].dwFullTMEM != pGameSetting->dwFullTMEM ) { IniSections[i].dwFullTMEM =pGameSetting->dwFullTMEM; bIniIsChanged=true; } if( IniSections[i].bTxtSizeMethod2 != pGameSetting->bTxtSizeMethod2 ) { IniSections[i].bTxtSizeMethod2 =pGameSetting->bTxtSizeMethod2; bIniIsChanged=true; } if( IniSections[i].bEnableTxtLOD != pGameSetting->bEnableTxtLOD ) { IniSections[i].bEnableTxtLOD =pGameSetting->bEnableTxtLOD; bIniIsChanged=true; } if( bIniIsChanged ) { WriteIniFile(); TRACE0("Rom option is changed and saved"); } } std::ifstream& getline( std::ifstream &is, char *str ); char * left(const char * src, int nchars) { static char dst[300]; strncpy(dst,src,nchars); dst[nchars]=0; return dst; } char * right(const char *src, int nchars) { static char dst[300]; int srclen = strlen(src); if (nchars >= srclen) { strcpy(dst, src); } else { strncpy(dst, src + srclen - nchars, nchars); dst[nchars]=0; } return dst; } char * tidy(char * s) { char * p = s + strlen(s); p--; while (p >= s && (*p == ' ' || *p == 0xa || *p == '\n') ) { *p = 0; p--; } return s; } BOOL ReadIniFile() { std::ifstream inifile; char readinfo[100]; const char *ini_filepath = ConfigGetSharedDataFilepath(szIniFileName); DebugMessage(M64MSG_VERBOSE, "Reading .ini file: %s", ini_filepath); inifile.open(ini_filepath); if (inifile.fail()) { return FALSE; } while (getline(inifile,readinfo)/*&§ionno<999*/) { tidy(readinfo); if (readinfo[0] == '/') continue; if (!strcasecmp(readinfo,"")==0) { if (readinfo[0] == '{') //if a section heading { section newsection; readinfo[strlen(readinfo)-1]='\0'; strcpy(newsection.crccheck, readinfo+1); newsection.bDisableTextureCRC = FALSE; newsection.bDisableCulling = FALSE; newsection.bIncTexRectEdge = FALSE; newsection.bZHack = FALSE; newsection.bTextureScaleHack = FALSE; newsection.bFastLoadTile = FALSE; newsection.bUseSmallerTexture = FALSE; newsection.bPrimaryDepthHack = FALSE; newsection.bTexture1Hack = FALSE; newsection.bDisableObjBG = FALSE; newsection.VIWidth = -1; newsection.VIHeight = -1; newsection.UseCIWidthAndRatio = NOT_USE_CI_WIDTH_AND_RATIO; newsection.dwFullTMEM = 0; newsection.bTxtSizeMethod2 = FALSE; newsection.bEnableTxtLOD = FALSE; newsection.bEmulateClear = FALSE; newsection.bForceScreenClear = FALSE; newsection.bDisableBlender = FALSE; newsection.bForceDepthBuffer = FALSE; newsection.dwFastTextureCRC = 0; newsection.dwAccurateTextureMapping = 0; newsection.dwNormalBlender = 0; newsection.dwNormalCombiner = 0; newsection.dwFrameBufferOption = 0; newsection.dwRenderToTextureOption = 0; newsection.dwScreenUpdateSetting = 0; IniSections.push_back(newsection); } else { int sectionno = IniSections.size() - 1; if (strcasecmp(left(readinfo,4), "Name")==0) strcpy(IniSections[sectionno].name,right(readinfo,strlen(readinfo)-5)); if (strcasecmp(left(readinfo,17), "DisableTextureCRC")==0) IniSections[sectionno].bDisableTextureCRC=true; if (strcasecmp(left(readinfo,14), "DisableCulling")==0) IniSections[sectionno].bDisableCulling=true; if (strcasecmp(left(readinfo,16), "PrimaryDepthHack")==0) IniSections[sectionno].bPrimaryDepthHack=true; if (strcasecmp(left(readinfo,12), "Texture1Hack")==0) IniSections[sectionno].bTexture1Hack=true; if (strcasecmp(left(readinfo,12), "FastLoadTile")==0) IniSections[sectionno].bFastLoadTile=true; if (strcasecmp(left(readinfo,17), "UseSmallerTexture")==0) IniSections[sectionno].bUseSmallerTexture=true; if (strcasecmp(left(readinfo,14), "IncTexRectEdge")==0) IniSections[sectionno].bIncTexRectEdge=true; if (strcasecmp(left(readinfo,5), "ZHack")==0) IniSections[sectionno].bZHack=true; if (strcasecmp(left(readinfo,16), "TexRectScaleHack")==0) IniSections[sectionno].bTextureScaleHack=true; if (strcasecmp(left(readinfo,7), "VIWidth")==0) IniSections[sectionno].VIWidth = strtol(right(readinfo,3),NULL,10); if (strcasecmp(left(readinfo,8), "VIHeight")==0) IniSections[sectionno].VIHeight = strtol(right(readinfo,3),NULL,10); if (strcasecmp(left(readinfo,18), "UseCIWidthAndRatio")==0) IniSections[sectionno].UseCIWidthAndRatio = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,8), "FullTMEM")==0) IniSections[sectionno].dwFullTMEM = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,24), "AlternativeTxtSizeMethod")==0) IniSections[sectionno].bTxtSizeMethod2 = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,12), "EnableTxtLOD")==0) IniSections[sectionno].bEnableTxtLOD = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,12), "DisableObjBG")==0) IniSections[sectionno].bDisableObjBG = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,16), "ForceScreenClear")==0) IniSections[sectionno].bForceScreenClear = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,22), "AccurateTextureMapping")==0) IniSections[sectionno].dwAccurateTextureMapping = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,14), "FastTextureCRC")==0) IniSections[sectionno].dwFastTextureCRC = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,12), "EmulateClear")==0) IniSections[sectionno].bEmulateClear = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,18), "NormalAlphaBlender")==0) IniSections[sectionno].dwNormalBlender = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,19), "DisableAlphaBlender")==0) IniSections[sectionno].bDisableBlender = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,19), "NormalColorCombiner")==0) IniSections[sectionno].dwNormalCombiner = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,16), "ForceDepthBuffer")==0) IniSections[sectionno].bForceDepthBuffer = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,20), "FrameBufferEmulation")==0) IniSections[sectionno].dwFrameBufferOption = strtol(readinfo+21,NULL,10); if (strcasecmp(left(readinfo,15), "RenderToTexture")==0) IniSections[sectionno].dwRenderToTextureOption = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,19), "ScreenUpdateSetting")==0) IniSections[sectionno].dwScreenUpdateSetting = strtol(right(readinfo,1),NULL,10); } } } inifile.close(); return TRUE; } //read a line from the ini file std::ifstream & getline(std::ifstream & is, char *str) { char buf[100]; is.getline(buf,100); strcpy( str,buf); return is; } void WriteIniFile() { uint32 i; FILE * fhIn; FILE * fhOut; /* get path to game-hack INI file and read it */ const char *ini_filepath = ConfigGetSharedDataFilepath(szIniFileName); if (ini_filepath == NULL) return; fhIn = fopen(ini_filepath, "r"); if (fhIn == NULL) return; fseek(fhIn, 0L, SEEK_END); long filelen = ftell(fhIn); fseek(fhIn, 0L, SEEK_SET); char *chIniData = (char *) malloc(filelen + 1); if (chIniData == NULL) { fclose(fhIn); return; } long bytesread = fread(chIniData, 1, filelen, fhIn); fclose(fhIn); if (bytesread != filelen) { free(chIniData); return; } chIniData[filelen] = 0; /* now try to open the file for writing */ fhOut = fopen(ini_filepath, "w"); if (fhOut == NULL) { free(chIniData); return; } // Mark all sections and needing to be written for (i = 0; i < IniSections.size(); i++) { IniSections[i].bOutput = false; } char *thisline = chIniData; while ((thisline - chIniData) < filelen) { char *nextline = strchr(thisline, '\n'); if (nextline == NULL) nextline = thisline + strlen(thisline) + 1; else nextline++; if (thisline[0] == '{') { BOOL bFound = FALSE; // Start of section tidy((char*) thisline); thisline[strlen(thisline) - 1] = '\0'; for (i = 0; i < IniSections.size(); i++) { if (IniSections[i].bOutput) continue; if (strcasecmp((char*) thisline + 1, IniSections[i].crccheck) == 0) { // Output this CRC OutputSectionDetails(i, fhOut); IniSections[i].bOutput = true; bFound = TRUE; break; } } if (!bFound) { // Do what? This should never happen, unless the user // replaces the inifile while game is running! } } else if (thisline[0] == '/') { // Comment fputs((char*) thisline, fhOut); } thisline = nextline; } // Input buffer done- process any new entries! for (i = 0; i < IniSections.size(); i++) { // Skip any that have not been done. if (IniSections[i].bOutput) continue; // Output this CRC OutputSectionDetails(i, fhOut); IniSections[i].bOutput = true; } fclose(fhOut); free(chIniData); bIniIsChanged = false; } void OutputSectionDetails(uint32 i, FILE * fh) { fprintf(fh, "{%s}\n", IniSections[i].crccheck); fprintf(fh, "Name=%s\n", IniSections[i].name); //fprintf(fh, "UCode=%d\n", IniSections[i].ucode); // Tri-state variables if (IniSections[i].dwAccurateTextureMapping != 0) fprintf(fh, "AccurateTextureMapping=%d\n", IniSections[i].dwAccurateTextureMapping); if (IniSections[i].dwFastTextureCRC != 0) fprintf(fh, "FastTextureCRC=%d\n", IniSections[i].dwFastTextureCRC); if (IniSections[i].dwNormalBlender != 0) fprintf(fh, "NormalAlphaBlender=%d\n", IniSections[i].dwNormalBlender); if (IniSections[i].dwNormalCombiner != 0) fprintf(fh, "NormalColorCombiner=%d\n", IniSections[i].dwNormalCombiner); // Normal bi-state variables if (IniSections[i].bDisableTextureCRC) fprintf(fh, "DisableTextureCRC\n"); if (IniSections[i].bDisableCulling) fprintf(fh, "DisableCulling\n"); if (IniSections[i].bPrimaryDepthHack) fprintf(fh, "PrimaryDepthHack\n"); if (IniSections[i].bTexture1Hack) fprintf(fh, "Texture1Hack\n"); if (IniSections[i].bFastLoadTile) fprintf(fh, "FastLoadTile\n"); if (IniSections[i].bUseSmallerTexture) fprintf(fh, "UseSmallerTexture\n"); if (IniSections[i].bIncTexRectEdge) fprintf(fh, "IncTexRectEdge\n"); if (IniSections[i].bZHack) fprintf(fh, "ZHack\n"); if (IniSections[i].bTextureScaleHack) fprintf(fh, "TexRectScaleHack\n"); if (IniSections[i].VIWidth > 0) fprintf(fh, "VIWidth=%d\n", IniSections[i].VIWidth); if (IniSections[i].VIHeight > 0) fprintf(fh, "VIHeight=%d\n", IniSections[i].VIHeight); if (IniSections[i].UseCIWidthAndRatio > 0) fprintf(fh, "UseCIWidthAndRatio=%d\n", IniSections[i].UseCIWidthAndRatio); if (IniSections[i].dwFullTMEM > 0) fprintf(fh, "FullTMEM=%d\n", IniSections[i].dwFullTMEM); if (IniSections[i].bTxtSizeMethod2 != FALSE ) fprintf(fh, "AlternativeTxtSizeMethod=%d\n", IniSections[i].bTxtSizeMethod2); if (IniSections[i].bEnableTxtLOD != FALSE ) fprintf(fh, "EnableTxtLOD=%d\n", IniSections[i].bEnableTxtLOD); if (IniSections[i].bDisableObjBG != 0 ) fprintf(fh, "DisableObjBG=%d\n", IniSections[i].bDisableObjBG); if (IniSections[i].bForceScreenClear != 0) fprintf(fh, "ForceScreenClear=%d\n", IniSections[i].bForceScreenClear); if (IniSections[i].bEmulateClear != 0) fprintf(fh, "EmulateClear=%d\n", IniSections[i].bEmulateClear); if (IniSections[i].bDisableBlender != 0) fprintf(fh, "DisableAlphaBlender=%d\n", IniSections[i].bDisableBlender); if (IniSections[i].bForceDepthBuffer != 0) fprintf(fh, "ForceDepthBuffer=%d\n", IniSections[i].bForceDepthBuffer); if (IniSections[i].dwFrameBufferOption != 0) fprintf(fh, "FrameBufferEmulation=%d\n", IniSections[i].dwFrameBufferOption); if (IniSections[i].dwRenderToTextureOption != 0) fprintf(fh, "RenderToTexture=%d\n", IniSections[i].dwRenderToTextureOption); if (IniSections[i].dwScreenUpdateSetting != 0) fprintf(fh, "ScreenUpdateSetting=%d\n", IniSections[i].dwScreenUpdateSetting); fprintf(fh, "\n"); // Spacer } // Find the entry corresponding to the specified rom. // If the rom is not found, a new entry is created // The resulting value is returned void __cdecl DebuggerAppendMsg (const char * Message, ...); static int FindIniEntry(uint32 dwCRC1, uint32 dwCRC2, uint8 nCountryID, char* szName, int PrintInfo) { uint32 i; unsigned char szCRC[50+1]; // Generate the CRC-ID for this rom: sprintf((char*)szCRC, "%08x%08x-%02x", (unsigned int)dwCRC1, (unsigned int)dwCRC2, nCountryID); for (i = 0; i < IniSections.size(); i++) { if (strcasecmp((char*)szCRC, IniSections[i].crccheck) == 0) { if (PrintInfo) DebugMessage(M64MSG_INFO, "Found ROM '%s', CRC %s", IniSections[i].name, szCRC); return i; } } // Add new entry!!! section newsection; if (PrintInfo) DebugMessage(M64MSG_INFO, "ROM (CRC %s) not found in INI file", szCRC); strcpy(newsection.crccheck, (char*)szCRC); strncpy(newsection.name, szName, 50); newsection.bDisableTextureCRC = FALSE; newsection.bDisableCulling = FALSE; newsection.bIncTexRectEdge = FALSE; newsection.bZHack = FALSE; newsection.bTextureScaleHack = FALSE; newsection.bFastLoadTile = FALSE; newsection.bUseSmallerTexture = FALSE; newsection.bPrimaryDepthHack = FALSE; newsection.bTexture1Hack = FALSE; newsection.bDisableObjBG = FALSE; newsection.VIWidth = -1; newsection.VIHeight = -1; newsection.UseCIWidthAndRatio = NOT_USE_CI_WIDTH_AND_RATIO; newsection.dwFullTMEM = 0; newsection.bTxtSizeMethod2 = FALSE; newsection.bEnableTxtLOD = FALSE; newsection.bEmulateClear = FALSE; newsection.bForceScreenClear = FALSE; newsection.bDisableBlender = FALSE; newsection.bForceDepthBuffer = FALSE; newsection.dwFastTextureCRC = 0; newsection.dwAccurateTextureMapping = 0; newsection.dwNormalBlender = 0; newsection.dwNormalCombiner = 0; newsection.dwFrameBufferOption = 0; newsection.dwRenderToTextureOption = 0; newsection.dwScreenUpdateSetting = 0; IniSections.push_back(newsection); bIniIsChanged = true; // Flag to indicate we should be updated return IniSections.size()-1; // -1 takes into account increment } GameSetting g_curRomInfo; void ROM_GetRomNameFromHeader(unsigned char * szName, ROMHeader * pHdr) { unsigned char * p; memcpy(szName, pHdr->szName, 20); szName[20] = '\0'; p = szName + (strlen((char*)szName) -1); // -1 to skip null while (p >= szName && *p == ' ') { *p = 0; p--; } } uint32 CountryCodeToTVSystem(uint32 countryCode) { uint32 system; switch(countryCode) { /* Demo */ case 0: system = TV_SYSTEM_NTSC; break; case '7': system = TV_SYSTEM_NTSC; break; case 0x41: system = TV_SYSTEM_NTSC; break; /* Germany */ case 0x44: system = TV_SYSTEM_PAL; break; /* USA */ case 0x45: system = TV_SYSTEM_NTSC; break; /* France */ case 0x46: system = TV_SYSTEM_PAL; break; /* Italy */ case 'I': system = TV_SYSTEM_PAL; break; /* Japan */ case 0x4A: system = TV_SYSTEM_NTSC; break; /* Europe - PAL */ case 0x50: system = TV_SYSTEM_PAL; break; case 'S': /* Spain */ system = TV_SYSTEM_PAL; break; /* Australia */ case 0x55: system = TV_SYSTEM_PAL; break; case 0x58: system = TV_SYSTEM_PAL; break; /* Australia */ case 0x59: system = TV_SYSTEM_PAL; break; case 0x20: case 0x21: case 0x38: case 0x70: system = TV_SYSTEM_PAL; break; /* ??? */ default: system = TV_SYSTEM_PAL; break; } return system; } mupen64plus-video-rice-src-2.0/src/Config.h0000644000000000000000000002424612165031100016656 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _RICE_CONFIG_H_ #define _RICE_CONFIG_H_ #include #include "typedefs.h" typedef enum { OGL_DEVICE, OGL_1_1_DEVICE, OGL_1_2_DEVICE, OGL_1_3_DEVICE, OGL_1_4_DEVICE, OGL_1_4_V2_DEVICE, OGL_TNT2_DEVICE, NVIDIA_OGL_DEVICE, OGL_FRAGMENT_PROGRAM, DIRECTX_DEVICE, } SupportedDeviceType; enum DirectXCombinerType { DX_DISABLE_COMBINER, DX_BEST_FIT, DX_LOW_END, DX_HIGH_END, DX_NVIDIA_TNT, DX_2_STAGES, DX_3_STAGES, DX_4_STAGES, DX_PIXEL_SHADER, DX_SEMI_PIXEL_SHADER, }; typedef struct { const char* name; SupportedDeviceType type; } RenderEngineSetting; enum { FRM_BUF_NONE, FRM_BUF_IGNORE, FRM_BUF_BASIC, FRM_BUF_BASIC_AND_WRITEBACK, FRM_BUF_WRITEBACK_AND_RELOAD, FRM_BUF_COMPLETE, FRM_BUF_WITH_EMULATOR, FRM_BUF_BASIC_AND_WITH_EMULATOR, FRM_BUF_WITH_EMULATOR_READ_ONLY, FRM_BUF_WITH_EMULATOR_WRITE_ONLY, }; enum { FRM_BUF_WRITEBACK_NORMAL, FRM_BUF_WRITEBACK_1_2, FRM_BUF_WRITEBACK_1_3, FRM_BUF_WRITEBACK_1_4, FRM_BUF_WRITEBACK_1_5, FRM_BUF_WRITEBACK_1_6, FRM_BUF_WRITEBACK_1_7, FRM_BUF_WRITEBACK_1_8, }; enum { TXT_BUF_NONE, TXT_BUF_IGNORE, TXT_BUF_NORMAL, TXT_BUF_WRITE_BACK, TXT_BUF_WRITE_BACK_AND_RELOAD, }; enum { TXT_QUALITY_DEFAULT, TXT_QUALITY_32BIT, TXT_QUALITY_16BIT, }; enum { FORCE_DEFAULT_FILTER, FORCE_POINT_FILTER, FORCE_LINEAR_FILTER, }; enum { TEXTURE_NO_MIPMAP = 0, TEXTURE_NO_FILTER, TEXTURE_BILINEAR_FILTER, TEXTURE_TRILINEAR_FILTER, }; enum { TEXTURE_NO_ENHANCEMENT, TEXTURE_2X_ENHANCEMENT, TEXTURE_2XSAI_ENHANCEMENT, TEXTURE_HQ2X_ENHANCEMENT, TEXTURE_LQ2X_ENHANCEMENT, TEXTURE_HQ4X_ENHANCEMENT, TEXTURE_SHARPEN_ENHANCEMENT, TEXTURE_SHARPEN_MORE_ENHANCEMENT, TEXTURE_EXTERNAL, TEXTURE_MIRRORED, }; enum { TEXTURE_ENHANCEMENT_NORMAL, TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1, TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2, TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3, TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4, }; enum { SCREEN_UPDATE_DEFAULT = 0, SCREEN_UPDATE_AT_VI_UPDATE = 1, SCREEN_UPDATE_AT_VI_CHANGE = 2, SCREEN_UPDATE_AT_CI_CHANGE = 3, SCREEN_UPDATE_AT_1ST_CI_CHANGE = 4, SCREEN_UPDATE_AT_1ST_PRIMITIVE = 5, SCREEN_UPDATE_BEFORE_SCREEN_CLEAR = 6, SCREEN_UPDATE_AT_VI_UPDATE_AND_DRAWN = 7, // Update screen at VI origin is updated and the screen has been drawn }; enum { ONSCREEN_DISPLAY_NOTHING = 0, ONSCREEN_DISPLAY_DLIST_PER_SECOND, ONSCREEN_DISPLAY_FRAME_PER_SECOND, ONSCREEN_DISPLAY_DEBUG_INFORMATION_ONLY, ONSCREEN_DISPLAY_TEXT_FROM_CORE_ONLY, ONSCREEN_DISPLAY_DLIST_PER_SECOND_WITH_CORE_MSG, ONSCREEN_DISPLAY_FRAME_PER_SECOND_WITH_CORE_MSG, ONSCREEN_DISPLAY_DEBUG_INFORMATION_WITH_CORE_MSG, }; enum HACK_FOR_GAMES { NO_HACK_FOR_GAME, HACK_FOR_BANJO_TOOIE, HACK_FOR_DR_MARIO, HACK_FOR_ZELDA, HACK_FOR_MARIO_TENNIS, HACK_FOR_BANJO, HACK_FOR_PD, HACK_FOR_GE, HACK_FOR_PILOT_WINGS, HACK_FOR_YOSHI, HACK_FOR_NITRO, HACK_FOR_TONYHAWK, HACK_FOR_NASCAR, HACK_FOR_SUPER_BOWLING, HACK_FOR_CONKER, HACK_FOR_ALL_STAR_BASEBALL, HACK_FOR_TIGER_HONEY_HUNT, HACK_REVERSE_XY_COOR, HACK_REVERSE_Y_COOR, HACK_FOR_GOLDEN_EYE, HACK_FOR_FZERO, HACK_FOR_COMMANDCONQUER, HACK_FOR_RUMBLE, HACK_FOR_SOUTH_PARK_RALLY, HACK_FOR_BUST_A_MOVE, HACK_FOR_OGRE_BATTLE, HACK_FOR_TWINE, HACK_FOR_EXTREME_G2, HACK_FOR_ROGUE_SQUADRON, HACK_FOR_MARIO_GOLF, HACK_FOR_MLB, HACK_FOR_POLARISSNOCROSS, HACK_FOR_TOPGEARRALLY, HACK_FOR_DUKE_NUKEM, HACK_FOR_ZELDA_MM, HACK_FOR_MARIO_KART, }; enum { NOT_USE_CI_WIDTH_AND_RATIO, USE_CI_WIDTH_AND_RATIO_FOR_NTSC, USE_CI_WIDTH_AND_RATIO_FOR_PAL, }; typedef struct { BOOL bEnableHacks; BOOL bWinFrameMode; BOOL bOGLVertexClipper; BOOL bEnableSSE; BOOL bEnableVertexShader; BOOL bSkipFrame; BOOL bFullTMEM; BOOL bUseFullTMEM; BOOL bShowFPS; uint32 mipmapping; uint32 fogMethod; uint32 forceTextureFilter; uint32 textureEnhancement; uint32 textureEnhancementControl; uint32 textureQuality; uint32 anisotropicFiltering; uint32 multiSampling; BOOL bTexRectOnly; BOOL bSmallTextureOnly; BOOL bDumpTexturesToFiles; BOOL bLoadHiResTextures; BOOL bLoadHiResCRCOnly; int OpenglDepthBufferSetting; int OpenglRenderSetting; uint32 colorQuality; HACK_FOR_GAMES enableHackForGames; } GlobalOptions; typedef struct { bool bUpdateCIInfo; bool bCheckBackBufs; // Check texture again against the recent backbuffer addresses bool bWriteBackBufToRDRAM; // If a recent backbuffer is used, write its content back to RDRAM bool bLoadBackBufFromRDRAM; // Load content from RDRAM and draw into backbuffer bool bIgnore; // Ignore all rendering into texture buffers bool bSupportRenderTextures; // Support render-to-texture bool bCheckRenderTextures; // Check texture again against the the last render_texture addresses bool bRenderTextureWriteBack; // Write back render_texture into RDRAM bool bLoadRDRAMIntoRenderTexture; // Load RDRAM content and render into render_texture bool bAtEachFrameUpdate; // Reload and write back at each frame buffer and CI update bool bProcessCPUWrite; bool bProcessCPURead; bool bFillRectNextTextureBuffer; bool bIgnoreRenderTextureIfHeightUnknown; //bool bFillColor; } FrameBufferOptions; typedef struct { uint32 N64FrameBufferEmuType; uint32 N64FrameBufferWriteBackControl; uint32 N64RenderToTextureEmuType; uint32 screenUpdateSetting; BOOL bNormalCombiner; BOOL bNormalBlender; BOOL bFastTexCRC; BOOL bAccurateTextureMapping; BOOL bInN64Resolution; BOOL bDoubleSizeForSmallTxtrBuf; BOOL bSaveVRAM; } RomOptions; typedef struct IniSection { bool bOutput; char crccheck[50]; char name[50]; // Options with changeable default values uint32 dwNormalCombiner; uint32 dwNormalBlender; uint32 dwFastTextureCRC; uint32 dwAccurateTextureMapping; uint32 dwFrameBufferOption; uint32 dwRenderToTextureOption; uint32 dwScreenUpdateSetting; // Options with FALSE as default values BOOL bDisableBlender; BOOL bForceScreenClear; BOOL bEmulateClear; BOOL bForceDepthBuffer; // Less useful options BOOL bDisableObjBG; BOOL bDisableTextureCRC; BOOL bIncTexRectEdge; BOOL bZHack; BOOL bTextureScaleHack; BOOL bFastLoadTile; BOOL bUseSmallerTexture; BOOL bPrimaryDepthHack; BOOL bTexture1Hack; BOOL bDisableCulling; int VIWidth; int VIHeight; uint32 UseCIWidthAndRatio; uint32 dwFullTMEM; BOOL bTxtSizeMethod2; BOOL bEnableTxtLOD; } section; struct ROMHeader { uint8 x1, x2, x3, x4; uint32 dwClockRate; uint32 dwBootAddressOffset; uint32 dwRelease; uint32 dwCRC1; uint32 dwCRC2; uint64 qwUnknown1; char szName[20]; uint32 dwUnknown2; uint16 wUnknown3; uint8 nUnknown4; uint8 nManufacturer; uint16 wCartID; s8 nCountryID; uint8 nUnknown5; }; typedef struct { // Other info from the rom. This is for convenience unsigned char szGameName[50+1]; s8 nCountryID; // Copy of the ROM header ROMHeader romheader; // With changeable default values uint32 dwNormalCombiner; uint32 dwNormalBlender; uint32 dwAccurateTextureMapping; uint32 dwFastTextureCRC; uint32 dwFrameBufferOption; uint32 dwRenderToTextureOption; uint32 dwScreenUpdateSetting; // With FALSE as its default values BOOL bForceScreenClear; BOOL bEmulateClear; BOOL bForceDepthBuffer; BOOL bDisableBlender; // Less useful options BOOL bDisableObjBG; BOOL bDisableTextureCRC; BOOL bIncTexRectEdge; BOOL bZHack; BOOL bTextureScaleHack; BOOL bFastLoadTile; BOOL bUseSmallerTexture; BOOL bPrimaryDepthHack; BOOL bTexture1Hack; BOOL bDisableCulling; int VIWidth; int VIHeight; uint32 UseCIWidthAndRatio; uint32 dwFullTMEM; BOOL bTxtSizeMethod2; BOOL bEnableTxtLOD; } GameSetting, *LPGAMESETTING; typedef struct { s8 nCountryID; char* szName; uint32 nTvType; } CountryIDInfo; #define TV_SYSTEM_NTSC 1 #define TV_SYSTEM_PAL 0 extern GlobalOptions options; extern FrameBufferOptions frameBufferOptions; extern RomOptions defaultRomOptions; extern RomOptions currentRomOptions; extern const CountryIDInfo g_CountryCodeInfo[]; extern GameSetting g_curRomInfo; extern bool bIniIsChanged; extern char szIniFileName[300]; extern BOOL InitConfiguration(void); extern BOOL LoadConfiguration(void); extern void WriteIniFile(); extern BOOL ReadIniFile(); extern void OutputSectionDetails(uint32 i, FILE * fh); extern void GenerateCurrentRomOptions(); extern void Ini_GetRomOptions(LPGAMESETTING pGameSetting); extern void Ini_StoreRomOptions(LPGAMESETTING pGameSetting); extern uint32 CountryCodeToTVSystem(uint32 countryCode); extern void ROM_GetRomNameFromHeader(unsigned char * szName, ROMHeader * pHdr); #endif mupen64plus-video-rice-src-2.0/src/ConvertImage.cpp0000644000000000000000000013335712165031100020373 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Config.h" #include "ConvertImage.h" #include "RenderBase.h" ConvertFunction gConvertFunctions_FullTMEM[ 8 ][ 4 ] = { // 4bpp 8bpp 16bpp 32bpp { Convert4b, Convert8b, Convert16b, ConvertRGBA32 }, // RGBA { NULL, NULL, ConvertYUV, NULL }, // YUV { Convert4b, Convert8b, NULL, NULL }, // CI { Convert4b, Convert8b, Convert16b, NULL }, // IA { Convert4b, Convert8b, Convert16b, NULL }, // I { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL } // ? }; ConvertFunction gConvertFunctions[ 8 ][ 4 ] = { // 4bpp 8bpp 16bpp 32bpp { ConvertCI4, ConvertCI8, ConvertRGBA16, ConvertRGBA32 }, // RGBA { NULL, NULL, ConvertYUV, NULL }, // YUV { ConvertCI4, ConvertCI8, NULL, NULL }, // CI { ConvertIA4, ConvertIA8, ConvertIA16, NULL }, // IA { ConvertI4, ConvertI8, ConvertIA16, NULL }, // I { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL } // ? }; ConvertFunction gConvertTlutFunctions[ 8 ][ 4 ] = { // 4bpp 8bpp 16bpp 32bpp { ConvertCI4, ConvertCI8, ConvertRGBA16, ConvertRGBA32 }, // RGBA { NULL, NULL, ConvertYUV, NULL }, // YUV { ConvertCI4, ConvertCI8, NULL, NULL }, // CI { ConvertCI4, ConvertCI8, ConvertIA16, NULL }, // IA { ConvertCI4, ConvertCI8, ConvertIA16, NULL }, // I { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL } // ? }; extern bool conkerSwapHack; void ConvertRGBA16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; // Copy of the base pointer uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; if (!pTexture->StartUpdate(&dInfo)) return; uint32 nFiddle; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y&1) == 0) nFiddle = 0x2; else nFiddle = 0x2 | 0x4; // dwDst points to start of destination row uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); // DWordOffset points to the current dword we're looking at // (process 2 pixels at a time). May be a problem if we don't start on even pixel uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint16 w = *(uint16 *)&pByteSrc[dwWordOffset ^ nFiddle]; dwDst[x] = Convert555ToRGBA(w); // Increment word offset to point to the next two pixels dwWordOffset += 2; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { // dwDst points to start of destination row uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); // DWordOffset points to the current dword we're looking at // (process 2 pixels at a time). May be a problem if we don't start on even pixel uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint16 w = *(uint16 *)&pByteSrc[dwWordOffset ^ 0x2]; dwDst[x] = Convert555ToRGBA(w); // Increment word offset to point to the next two pixels dwWordOffset += 2; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } void ConvertRGBA32(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; uint32 * pSrc = (uint32*)(tinfo.pPhysicalAddress); if( options.bUseFullTMEM ) { Tile &tile = gRDP.tiles[tinfo.tileNo]; uint32 *pWordSrc; if( tinfo.tileNo >= 0 ) { pWordSrc = (uint32*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); uint32 nFiddle = ( y&1 )? 0x2 : 0; int idx = tile.dwLine*4*y; for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) { uint32 w = pWordSrc[idx^nFiddle]; uint8* psw = (uint8*)&w; uint8* pdw = (uint8*)&dwDst[x]; pdw[0] = psw[2]; // Blue pdw[1] = psw[1]; // Green pdw[2] = psw[0]; // Red pdw[3] = psw[3]; // Alpha } } } } else { if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; uint8 *pS = (uint8 *)pSrc + (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { pDst[0] = pS[1]; // Blue pDst[1] = pS[2]; // Green pDst[2] = pS[3]; // Red pDst[3] = pS[0]; // Alpha pS+=4; pDst+=4; } } else { uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint8 *pS = (uint8 *)pSrc; int n; n = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { *pDst++ = COLOR_RGBA(pS[(n+3)^0x8], pS[(n+2)^0x8], pS[(n+1)^0x8], pS[(n+0)^0x8]); n += 4; } } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; uint8 *pS = (uint8 *)pSrc + (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { pDst[0] = pS[1]; // Blue pDst[1] = pS[2]; // Green pDst[2] = pS[3]; // Red pDst[3] = pS[0]; // Alpha pS+=4; pDst+=4; } } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // E.g. Dear Mario text // Copy, Score etc void ConvertIA4(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); #ifdef DEBUGGER if (((long long)pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); #endif if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; // For odd lines, swap words too if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; // This may not work if X is not even? uint32 dwByteOffset = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad/2); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ nFiddle]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = OneToEight[(b & 0x10) >> 4]; } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // Do two pixels at a time uint8 b = pSrc[dwByteOffset ^ nFiddle]; // Even *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = OneToEight[(b & 0x10) >> 4]; // Odd *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; *pDst++ = OneToEight[(b & 0x01) ]; dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + (y * dInfo.lPitch); // This may not work if X is not even? uint32 dwByteOffset = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad/2); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ 0x3]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = OneToEight[(b & 0x10) >> 4]; } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // Do two pixels at a time uint8 b = pSrc[dwByteOffset ^ 0x3]; // Even *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = OneToEight[(b & 0x10) >> 4]; // Odd *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; *pDst++ = OneToEight[(b & 0x01) ]; dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // E.g Mario's head textures void ConvertIA8(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); #ifdef DEBUGGER if (((long long)pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); #endif if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { // For odd lines, swap words too if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; // Points to current byte uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; uint8 I = FourToEight[(b & 0xf0)>>4]; *pDst++ = I; *pDst++ = I; *pDst++ = I; *pDst++ = FourToEight[(b & 0x0f) ]; dwByteOffset++; } } } else { register const uint8* FourToEightArray = &FourToEight[0]; for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; // Points to current byte uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { register uint8 b = pSrc[(dwByteOffset++) ^ 0x3]; uint8 I = *(FourToEightArray+(b>>4)); *pDst++ = I; *pDst++ = I; *pDst++ = I; *pDst++ = *(FourToEightArray+(b&0xF)); } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // E.g. camera's clouds, shadows void ConvertIA16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; if ((y%2) == 0) nFiddle = 0x2; else nFiddle = 0x4 | 0x2; // Points to current word uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint16 w = *(uint16 *)&pByteSrc[dwWordOffset^nFiddle]; *pDst++ = (uint8)(w >> 8); *pDst++ = (uint8)(w >> 8); *pDst++ = (uint8)(w >> 8); *pDst++ = (uint8)(w & 0xFF); dwWordOffset += 2; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; // Points to current word uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint16 w = *(uint16 *)&pByteSrc[dwWordOffset^0x2]; *pDst++ = (uint8)(w >> 8); *pDst++ = (uint8)(w >> 8); *pDst++ = (uint8)(w >> 8); *pDst++ = (uint8)(w & 0xFF); dwWordOffset += 2; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // Used by MarioKart void ConvertI4(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); #ifdef DEBUGGER if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); #endif if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; // Might not work with non-even starting X uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); // For odd lines, swap words too if( !conkerSwapHack || (y&4) == 0 ) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; } else { if ((y%2) == 1) nFiddle = 0x3; else nFiddle = 0x7; } if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ nFiddle]; *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // two pixels at a time uint8 b = pSrc[dwByteOffset ^ nFiddle]; // Even *pDst++ = FourToEight[(b & 0xF0)>>4]; // Other implementations seem to or in (b&0xF0)>>4 *pDst++ = FourToEight[(b & 0xF0)>>4]; // why? *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; // Odd *pDst++ = FourToEight[(b & 0x0F)]; *pDst++ = FourToEight[(b & 0x0F)]; *pDst++ = FourToEight[(b & 0x0F)]; *pDst++ = FourToEight[(b & 0x0F)]; dwByteOffset++; } } conkerSwapHack = false; } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; // Might not work with non-even starting X uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ 0x3]; *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // two pixels at a time uint8 b = pSrc[dwByteOffset ^ 0x3]; // Even *pDst++ = FourToEight[(b & 0xF0)>>4]; // Other implementations seem to or in (b&0xF0)>>4 *pDst++ = FourToEight[(b & 0xF0)>>4]; // why? *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; // Odd *pDst++ = FourToEight[(b & 0x0F)]; *pDst++ = FourToEight[(b & 0x0F)]; *pDst++ = FourToEight[(b & 0x0F)]; *pDst++ = FourToEight[(b & 0x0F)]; dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // Used by MarioKart void ConvertI8(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; long long pSrc = (long long) tinfo.pPhysicalAddress; if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = *(uint8*)((pSrc+dwByteOffset)^nFiddle); *pDst++ = b; *pDst++ = b; *pDst++ = b; *pDst++ = b; // Alpha not 255? dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = *(uint8*)((pSrc+dwByteOffset)^0x3); *pDst++ = b; *pDst++ = b; *pDst++ = b; *pDst++ = b; // Alpha not 255? dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } //***************************************************************************** // Convert CI4 images. We need to switch on the palette type //***************************************************************************** void ConvertCI4( CTexture * p_texture, const TxtrInfo & tinfo ) { if ( tinfo.TLutFmt == TLUT_FMT_RGBA16 ) { ConvertCI4_RGBA16( p_texture, tinfo ); } else if ( tinfo.TLutFmt == TLUT_FMT_IA16 ) { ConvertCI4_IA16( p_texture, tinfo ); } } //***************************************************************************** // Convert CI8 images. We need to switch on the palette type //***************************************************************************** void ConvertCI8( CTexture * p_texture, const TxtrInfo & tinfo ) { if ( tinfo.TLutFmt == TLUT_FMT_RGBA16 ) { ConvertCI8_RGBA16( p_texture, tinfo ); } else if ( tinfo.TLutFmt == TLUT_FMT_IA16 ) { ConvertCI8_IA16( p_texture, tinfo ); } } // Used by Starfox intro void ConvertCI4_RGBA16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ nFiddle]; uint8 bhi = (b&0xf0)>>4; *pDst = Convert555ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { *pDst |= 0xFF000000; } } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // two at a time uint8 b = pSrc[dwByteOffset ^ nFiddle]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = Convert555ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = Convert555ToRGBA(pPal[blo^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { pDst[0] |= 0xFF000000; pDst[1] |= 0xFF000000; } pDst+=2; dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ 0x3]; uint8 bhi = (b&0xf0)>>4; *pDst = Convert555ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { *pDst |= 0xFF000000; } } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // two at a time uint8 b = pSrc[dwByteOffset ^ 0x3]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = Convert555ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = Convert555ToRGBA(pPal[blo^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { pDst[0] |= 0xFF000000; pDst[1] |= 0xFF000000; } pDst+=2; dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // Used by Starfox intro void ConvertCI4_IA16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); #ifdef DEBUGGER if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); #endif uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ nFiddle]; uint8 bhi = (b&0xf0)>>4; *pDst = ConvertIA16ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) *pDst |= 0xFF000000; } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // two at a time uint8 b = pSrc[dwByteOffset ^ nFiddle]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = ConvertIA16ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = ConvertIA16ToRGBA(pPal[blo^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { pDst[0] |= 0xFF000000; pDst[1] |= 0xFF000000; } pDst+=2; dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ 0x3]; uint8 bhi = (b&0xf0)>>4; *pDst = ConvertIA16ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) *pDst |= 0xFF000000; } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // two pixels at a time uint8 b = pSrc[dwByteOffset ^ 0x3]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = ConvertIA16ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = ConvertIA16ToRGBA(pPal[blo^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { pDst[0] |= 0xFF000000; pDst[1] |= 0xFF000000; } pDst+=2; dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // Used by MarioKart for Cars etc void ConvertCI8_RGBA16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); #ifdef DEBUGGER if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); #endif uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; *pDst++ = Convert555ToRGBA(pPal[b^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { *(pDst-1) |= 0xFF000000; } dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); int dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ 0x3]; *pDst++ = Convert555ToRGBA(pPal[b^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { *(pDst-1) |= 0xFF000000; } dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // Used by MarioKart for Cars etc void ConvertCI8_IA16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); #ifdef DEBUGGER if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); #endif uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; *pDst++ = ConvertIA16ToRGBA(pPal[b^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { *(pDst-1) |= 0xFF000000; } dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ 0x3]; *pDst++ = ConvertIA16ToRGBA(pPal[b^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { *(pDst-1) |= 0xFF000000; } dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } void ConvertYUV(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; uint32 x, y; uint32 nFiddle; if( options.bUseFullTMEM ) { Tile &tile = gRDP.tiles[tinfo.tileNo]; uint16 * pSrc; if( tinfo.tileNo >= 0 ) pSrc = (uint16*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; else pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; for (y = 0; y < tinfo.HeightToLoad; y++) { nFiddle = ( y&1 )? 0x4 : 0; int dwWordOffset = tinfo.tileNo>=0? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); for (x = 0; x < tinfo.WidthToLoad/2; x++) { int y0 = *(uint8*)&pByteSrc[(dwWordOffset+1)^nFiddle]; int y1 = *(uint8*)&pByteSrc[(dwWordOffset+3)^nFiddle]; int u0 = *(uint8*)&pByteSrc[(dwWordOffset )^nFiddle]; int v0 = *(uint8*)&pByteSrc[(dwWordOffset+2)^nFiddle]; dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0); dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0); dwWordOffset += 4; } } } else { uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; if (tinfo.bSwapped) { for (y = 0; y < tinfo.HeightToLoad; y++) { if ((y&1) == 0) nFiddle = 0x3; else nFiddle = 0x7; // dwDst points to start of destination row uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); // DWordOffset points to the current dword we're looking at // (process 2 pixels at a time). May be a problem if we don't start on even pixel uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (x = 0; x < tinfo.WidthToLoad/2; x++) { int y0 = *(uint8*)&pByteSrc[(dwWordOffset+2)^nFiddle]; int v0 = *(uint8*)&pByteSrc[(dwWordOffset+1)^nFiddle]; int y1 = *(uint8*)&pByteSrc[(dwWordOffset )^nFiddle]; int u0 = *(uint8*)&pByteSrc[(dwWordOffset+3)^nFiddle]; dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0); dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0); dwWordOffset += 4; } } } else { for (y = 0; y < tinfo.HeightToLoad; y++) { // dwDst points to start of destination row uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); uint32 dwByteOffset = y * 32; for (x = 0; x < tinfo.WidthToLoad/2; x++) { int y0 = *(uint8*)&pByteSrc[(dwByteOffset+2)]; int v0 = *(uint8*)&pByteSrc[(dwByteOffset+1)]; int y1 = *(uint8*)&pByteSrc[(dwByteOffset )]; int u0 = *(uint8*)&pByteSrc[(dwByteOffset+3)]; dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0); dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0); // Increment word offset to point to the next two pixels dwByteOffset += 4; } } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } uint32 ConvertYUV16ToR8G8B8(int Y, int U, int V) { /* int R = int(g_convc0 *(Y-16) + g_convc1 * V); int G = int(g_convc0 *(Y-16) + g_convc2 * U - g_convc3 * V); int B = int(g_convc0 *(Y-16) + g_convc4 * U); */ Y += 80; int R = int(Y + (1.370705f * (V-128))); int G = int(Y - (0.698001f * (V-128)) - (0.337633f * (U-128))); int B = int(Y + (1.732446f * (U-128))); R = R < 0 ? 0 : (R>255 ? 255 : R); G = G < 0 ? 0 : (G>255 ? 255 : G); B = B < 0 ? 0 : (B>255 ? 255 : B); return COLOR_RGBA(R, G, B, 0xFF); } // Used by Starfox intro void Convert4b(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); if( tinfo.Format <= TXT_FMT_CI ) bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); Tile &tile = gRDP.tiles[tinfo.tileNo]; uint8 *pByteSrc = tinfo.tileNo >= 0 ? (uint8*)&g_Tmem.g_Tmem64bit[tile.dwTMem] : (uint8*)(tinfo.pPhysicalAddress); for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 nFiddle; if( tinfo.tileNo < 0 ) { if (tinfo.bSwapped) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; } else { nFiddle = 3; } } else { nFiddle = ( y&1 )? 0x4 : 0; } uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); int idx = tinfo.tileNo>=0 ? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pByteSrc[idx^nFiddle]; uint8 bhi = (b&0xf0)>>4; if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) ) { if( tinfo.TLutFmt == TLUT_FMT_IA16 ) { if( tinfo.tileNo>=0 ) *pDst = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); else *pDst = ConvertIA16ToRGBA(pPal[bhi^1]); } else { if( tinfo.tileNo>=0 ) *pDst = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); else *pDst = Convert555ToRGBA(pPal[bhi^1]); } } else if( tinfo.Format == TXT_FMT_IA ) *pDst = ConvertIA4ToRGBA(b>>4); else // if( tinfo.Format == TXT_FMT_I ) *pDst = ConvertI4ToRGBA(b>>4); if( bIgnoreAlpha ) *pDst |= 0xFF000000; } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2, idx++) { // two pixels at a time uint8 b = pByteSrc[idx^nFiddle]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) ) { if( tinfo.TLutFmt == TLUT_FMT_IA16 ) { if( tinfo.tileNo>=0 ) { pDst[0] = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); pDst[1] = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(blo<<2)]); } else { pDst[0] = ConvertIA16ToRGBA(pPal[bhi^1]); pDst[1] = ConvertIA16ToRGBA(pPal[blo^1]); } } else { if( tinfo.tileNo>=0 ) { pDst[0] = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); pDst[1] = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(blo<<2)]); } else { pDst[0] = Convert555ToRGBA(pPal[bhi^1]); pDst[1] = Convert555ToRGBA(pPal[blo^1]); } } } else if( tinfo.Format == TXT_FMT_IA ) { pDst[0] = ConvertIA4ToRGBA(b>>4); pDst[1] = ConvertIA4ToRGBA(b&0xF); } else // if( tinfo.Format == TXT_FMT_I ) { pDst[0] = ConvertI4ToRGBA(b>>4); pDst[1] = ConvertI4ToRGBA(b&0xF); } if( bIgnoreAlpha ) { pDst[0] |= 0xFF000000; pDst[1] |= 0xFF000000; } pDst+=2; } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } void Convert8b(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); if( tinfo.Format <= TXT_FMT_CI ) bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); Tile &tile = gRDP.tiles[tinfo.tileNo]; uint8 *pByteSrc; if( tinfo.tileNo >= 0 ) { pByteSrc = (uint8*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; } else { pByteSrc = (uint8*)(tinfo.pPhysicalAddress); } for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 nFiddle; if( tinfo.tileNo < 0 ) { if (tinfo.bSwapped) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; } else { nFiddle = 3; } } else { nFiddle = ( y&1 )? 0x4 : 0; } int idx = tinfo.tileNo>=0? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) { uint8 b = pByteSrc[idx^nFiddle]; if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) ) { if( tinfo.TLutFmt == TLUT_FMT_IA16 ) { if( tinfo.tileNo>=0 ) *pDst = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+(b<<2)]); else *pDst = ConvertIA16ToRGBA(pPal[b^1]); } else { if( tinfo.tileNo>=0 ) *pDst = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+(b<<2)]); else *pDst = Convert555ToRGBA(pPal[b^1]); } } else if( tinfo.Format == TXT_FMT_IA ) { uint8 I = FourToEight[(b & 0xf0)>>4]; uint8 * pByteDst = (uint8*)pDst; pByteDst[0] = I; pByteDst[1] = I; pByteDst[2] = I; pByteDst[3] = FourToEight[(b & 0x0f) ]; } else // if( tinfo.Format == TXT_FMT_I ) { uint8 * pByteDst = (uint8*)pDst; pByteDst[0] = b; pByteDst[1] = b; pByteDst[2] = b; pByteDst[3] = b; } if( bIgnoreAlpha ) { *pDst |= 0xFF000000; } pDst++; } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } void Convert16b(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; Tile &tile = gRDP.tiles[tinfo.tileNo]; uint16 *pWordSrc; if( tinfo.tileNo >= 0 ) pWordSrc = (uint16*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; else pWordSrc = (uint16*)(tinfo.pPhysicalAddress); for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); uint32 nFiddle; if( tinfo.tileNo < 0 ) { if (tinfo.bSwapped) { if ((y&1) == 0) nFiddle = 0x1; else nFiddle = 0x3; } else { nFiddle = 0x1; } } else { nFiddle = ( y&1 )? 0x2 : 0; } int idx = tinfo.tileNo>=0? tile.dwLine*4*y : (((y+tinfo.TopToLoad) * tinfo.Pitch)>>1) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) { uint16 w = pWordSrc[idx^nFiddle]; uint16 w2 = tinfo.tileNo>=0? ((w>>8)|(w<<8)) : w; if( tinfo.Format == TXT_FMT_RGBA ) { dwDst[x] = Convert555ToRGBA(w2); } else if( tinfo.Format == TXT_FMT_YUV ) { } else if( tinfo.Format >= TXT_FMT_IA ) { uint8 * pByteDst = (uint8*)&dwDst[x]; *pByteDst++ = (uint8)(w2 >> 8); *pByteDst++ = (uint8)(w2 >> 8); *pByteDst++ = (uint8)(w2 >> 8); *pByteDst++ = (uint8)(w2 & 0xFF); } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } mupen64plus-video-rice-src-2.0/src/ConvertImage.h0000644000000000000000000002216712165031100020034 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __CONVERTIMAGE_H__ #define __CONVERTIMAGE_H__ #include "typedefs.h" #include "Texture.h" #include "TextureManager.h" static const uint8 OneToEight[2] = { 0x00, // 0 -> 00 00 00 00 0xff // 1 -> 11 11 11 11 }; static const uint8 OneToFour[2] = { 0x00, // 0 -> 00 00 0x0f // 1 -> 11 11 }; static const uint8 TwoToEight[4] = { 0x00, // 00 -> 00 00 00 00 0x55, // 01 -> 01 01 01 01 0xaa, // 10 -> 10 10 10 10 0xff // 11 -> 11 11 11 11 }; static const uint8 TwoToFour[4] = { 0x0, // 00 -> 00 00 0x5, // 01 -> 01 01 0xa, // 10 -> 10 10 0xf // 11 -> 11 11 }; static const uint8 ThreeToEight[8] = { 0x00, // 000 -> 00 00 00 00 0x24, // 001 -> 00 10 01 00 0x49, // 010 -> 01 00 10 01 0x6d, // 011 -> 01 10 11 01 0x92, // 100 -> 10 01 00 10 0xb6, // 101 -> 10 11 01 10 0xdb, // 110 -> 11 01 10 11 0xff // 111 -> 11 11 11 11 }; static const uint8 ThreeToFour[8] = { 0x0, // 000 -> 00 00 00 00 0x2, // 001 -> 00 10 01 00 0x4, // 010 -> 01 00 10 01 0x6, // 011 -> 01 10 11 01 0x9, // 100 -> 10 01 00 10 0xb, // 101 -> 10 11 01 10 0xd, // 110 -> 11 01 10 11 0xf // 111 -> 11 11 11 11 }; static const uint8 FourToEight[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; static const uint16 FourToSixteen[16] = { 0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888, 0x9999, 0xaaaa, 0xbbbb, 0xcccc, 0xdddd, 0xeeee, 0xffff }; static const uint8 FiveToEight[32] = { 0x00, // 00000 -> 00000000 0x08, // 00001 -> 00001000 0x10, // 00010 -> 00010000 0x18, // 00011 -> 00011000 0x21, // 00100 -> 00100001 0x29, // 00101 -> 00101001 0x31, // 00110 -> 00110001 0x39, // 00111 -> 00111001 0x42, // 01000 -> 01000010 0x4a, // 01001 -> 01001010 0x52, // 01010 -> 01010010 0x5a, // 01011 -> 01011010 0x63, // 01100 -> 01100011 0x6b, // 01101 -> 01101011 0x73, // 01110 -> 01110011 0x7b, // 01111 -> 01111011 0x84, // 10000 -> 10000100 0x8c, // 10001 -> 10001100 0x94, // 10010 -> 10010100 0x9c, // 10011 -> 10011100 0xa5, // 10100 -> 10100101 0xad, // 10101 -> 10101101 0xb5, // 10110 -> 10110101 0xbd, // 10111 -> 10111101 0xc6, // 11000 -> 11000110 0xce, // 11001 -> 11001110 0xd6, // 11010 -> 11010110 0xde, // 11011 -> 11011110 0xe7, // 11100 -> 11100111 0xef, // 11101 -> 11101111 0xf7, // 11110 -> 11110111 0xff // 11111 -> 11111111 }; #define RGBA5551_RedMask (0xF800) #define RGBA5551_GreenMask (0x07C0) #define RGBA5551_BlueMask (0x003E) #define RGBA5551_AlphaMask (0x0001) #define RGBA5551_RedShift 11 #define RGBA5551_GreenShift 6 #define RGBA5551_BlueShift 1 #define RGBA5551_AlphaShift 0 #define RGBA565_RedMask (0xF800) #define RGBA565_GreenMask (0x07E0) #define RGBA565_BlueMask (0x001F) #define RGBA565_RedShift 11 #define RGBA565_GreenShift 5 #define RGBA565_BlueShift 0 inline uint16 ConvertRGBTo555(uint8 red, uint8 grn, uint8 blu) { return (uint16)(((uint16)(red >> 3) << RGBA5551_RedShift) | ((uint16)(grn >> 3) << RGBA5551_GreenShift) | ((uint16)(blu >> 3) << RGBA5551_BlueShift) | ((uint16)(1) << RGBA5551_AlphaShift)); } inline uint16 ConvertRGBTo565(uint8 red, uint8 grn, uint8 blu) { return (uint16)(((uint16)(red >> 3) << RGBA565_RedShift) | ((uint16)(grn >> 2) << RGBA565_GreenShift) | ((uint16)(blu >> 3) << RGBA565_BlueShift)); } inline uint16 Convert555To565(uint16 w555) { // Probably a faster method by fudging the low bits.. uint8 red = FiveToEight[(w555&RGBA5551_RedMask) >> RGBA5551_RedShift]; uint8 grn = FiveToEight[(w555&RGBA5551_GreenMask)>> RGBA5551_GreenShift]; uint8 blu = FiveToEight[(w555&RGBA5551_BlueMask) >> RGBA5551_BlueShift]; return ConvertRGBTo565(red, grn, blu); } #define R4G4B4A4_MAKE(r,g,b,a) ((uint16)(((a) << 12) | ((r)<< 8) | ((g)<<4) | (b))) inline uint32 Convert555ToRGBA(uint16 w555) { uint32 dwRed = FiveToEight[(w555&RGBA5551_RedMask) >> RGBA5551_RedShift]; uint32 dwGreen = FiveToEight[(w555&RGBA5551_GreenMask)>> RGBA5551_GreenShift]; uint32 dwBlue = FiveToEight[(w555&RGBA5551_BlueMask) >> RGBA5551_BlueShift]; uint32 dwAlpha = (w555&RGBA5551_AlphaMask) ? 0xFF : 0x00; return COLOR_RGBA(dwRed, dwGreen, dwBlue, dwAlpha); } inline uint16 Convert555ToR4G4B4A4(uint16 w555) { uint8 dwRed = ((w555&RGBA5551_RedMask) >> RGBA5551_RedShift)>>1; uint8 dwGreen = ((w555&RGBA5551_GreenMask)>> RGBA5551_GreenShift)>>1; uint8 dwBlue = ((w555&RGBA5551_BlueMask) >> RGBA5551_BlueShift)>>1; uint8 dwAlpha = (w555&RGBA5551_AlphaMask) ? 0xF : 0x0; return R4G4B4A4_MAKE(dwRed, dwGreen, dwBlue, dwAlpha); } inline uint32 ConvertIA4ToRGBA(uint8 IA4) { uint32 I = ThreeToEight[(IA4 & 0x0F) >> 1]; uint32 A = OneToEight[(IA4 & 0x01)]; return COLOR_RGBA(I, I, I, A); } inline uint16 ConvertIA4ToR4G4B4A4(uint8 IA4) { uint32 I = ThreeToFour[(IA4 & 0x0F) >> 1]; uint32 A = OneToFour[(IA4 & 0x01)]; return R4G4B4A4_MAKE(I, I, I, A); } inline uint32 ConvertI4ToRGBA(uint8 I4) { uint32 I = FourToEight[I4 & 0x0F]; return COLOR_RGBA(I, I, I, I); } inline uint16 ConvertI4ToR4G4B4A4(uint8 I4) { return FourToSixteen[I4 & 0x0F]; } inline uint32 ConvertIA16ToRGBA(uint16 wIA) { uint32 dwIntensity = (wIA >> 8) & 0xFF; uint32 dwAlpha = (wIA ) & 0xFF; return COLOR_RGBA(dwIntensity, dwIntensity, dwIntensity, dwAlpha); } inline uint16 ConvertIA16ToR4G4B4A4(uint16 wIA) { uint16 dwIntensity = (wIA >> 12) & 0x0F; uint16 dwAlpha = (wIA >> 4) & 0x0F; return R4G4B4A4_MAKE(dwIntensity, dwIntensity, dwIntensity, dwAlpha); } extern int g_convk0,g_convk1,g_convk2,g_convk3,g_convk4,g_convk5; extern float g_convc0,g_convc1,g_convc2,g_convc3,g_convc4,g_convc5; uint32 ConvertYUV16ToR8G8B8(int Y, int U, int V); uint16 ConvertYUV16ToR4G4B4(int Y, int U, int V); typedef void ( * ConvertFunction )( CTexture * p_texture, const TxtrInfo & ti ); void ConvertRGBA16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertRGBA32(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertIA4(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertIA8(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertIA16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertI4(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertI8(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI4( CTexture *pTexture, const TxtrInfo & ti ); void ConvertCI8( CTexture *pTexture, const TxtrInfo & ti ); void ConvertCI4_RGBA16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI4_IA16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI8_RGBA16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI8_IA16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertYUV(CTexture *pTexture, const TxtrInfo &tinfo); // 16 a4r4g4b4 void ConvertRGBA16_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertRGBA32_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertIA4_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertIA8_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertIA16_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertI4_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertI8_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI4_16( CTexture *pTexture, const TxtrInfo & ti ); void ConvertCI8_16( CTexture *pTexture, const TxtrInfo & ti ); void ConvertCI4_RGBA16_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI4_IA16_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI8_RGBA16_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI8_IA16_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertYUV_16(CTexture *pTexture, const TxtrInfo &tinfo); void Convert4b(CTexture *pTexture, const TxtrInfo &tinfo); void Convert8b(CTexture *pTexture, const TxtrInfo &tinfo); void Convert16b(CTexture *pTexture, const TxtrInfo &tinfo); void Convert4b_16(CTexture *pTexture, const TxtrInfo &tinfo); void Convert8b_16(CTexture *pTexture, const TxtrInfo &tinfo); void Convert16b_16(CTexture *pTexture, const TxtrInfo &tinfo); #endif mupen64plus-video-rice-src-2.0/src/ConvertImage16.cpp0000644000000000000000000011367212165031100020540 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Config.h" #include "ConvertImage.h" #include "RenderBase.h" // Still to be swapped: // IA16 ConvertFunction gConvertFunctions_16_FullTMEM[ 8 ][ 4 ] = { // 4bpp 8bpp 16bpp 32bpp { Convert4b_16, Convert8b_16, Convert16b_16, ConvertRGBA32_16 }, // RGBA { NULL, NULL, ConvertYUV_16, NULL }, // YUV { Convert4b_16, Convert8b_16, NULL, NULL }, // CI { Convert4b_16, Convert8b_16, Convert16b_16, NULL }, // IA { Convert4b_16, Convert8b_16, Convert16b_16, NULL }, // I { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL } // ? }; ConvertFunction gConvertFunctions_16[ 8 ][ 4 ] = { // 4bpp 8bpp 16bpp 32bpp { ConvertCI4_16, ConvertCI8_16, ConvertRGBA16_16, ConvertRGBA32_16 }, // RGBA { NULL, NULL, ConvertYUV_16, NULL }, // YUV { ConvertCI4_16, ConvertCI8_16, NULL, NULL }, // CI { ConvertIA4_16, ConvertIA8_16, ConvertIA16_16, NULL }, // IA { ConvertI4_16, ConvertI8_16, ConvertRGBA16_16, NULL }, // I { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL } // ? }; ConvertFunction gConvertTlutFunctions_16[ 8 ][ 4 ] = { // 4bpp 8bpp 16bpp 32bpp { ConvertCI4_16, ConvertCI8_16, ConvertRGBA16_16, ConvertRGBA32_16 }, // RGBA { NULL, NULL, ConvertYUV_16, NULL }, // YUV { ConvertCI4_16, ConvertCI8_16, NULL, NULL }, // CI { ConvertCI4_16, ConvertCI8_16, ConvertIA16_16, NULL }, // IA { ConvertCI4_16, ConvertCI8_16, ConvertRGBA16_16, NULL }, // I { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL } // ? }; extern bool conkerSwapHack; void ConvertRGBA16_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 x, y; uint32 nFiddle; // Copy of the base pointer uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x2; else nFiddle = 0x2 | 0x4; // dwDst points to start of destination row uint16 * wDst = (uint16 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); // DWordOffset points to the current dword we're looking at // (process 2 pixels at a time). May be a problem if we don't start on even pixel uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (x = 0; x < tinfo.WidthToLoad; x++) { uint16 w = *(uint16 *)&pByteSrc[dwWordOffset ^ nFiddle]; wDst[x] = Convert555ToR4G4B4A4(w); // Increment word offset to point to the next two pixels dwWordOffset += 2; } } } else { for (y = 0; y < tinfo.HeightToLoad; y++) { // dwDst points to start of destination row uint16 * wDst = (uint16 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); // DWordOffset points to the current dword we're looking at // (process 2 pixels at a time). May be a problem if we don't start on even pixel uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (x = 0; x < tinfo.WidthToLoad; x++) { uint16 w = *(uint16 *)&pByteSrc[dwWordOffset ^ 0x2]; wDst[x] = Convert555ToR4G4B4A4(w); // Increment word offset to point to the next two pixels dwWordOffset += 2; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } void ConvertRGBA32_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 * pSrc = (uint32*)(tinfo.pPhysicalAddress); if (!pTexture->StartUpdate(&dInfo)) return; if( options.bUseFullTMEM ) { Tile &tile = gRDP.tiles[tinfo.tileNo]; uint32 *pWordSrc; if( tinfo.tileNo >= 0 ) { pWordSrc = (uint32*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 * dwDst = (uint16 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); uint32 nFiddle = ( y&1 )? 0x2 : 0; int idx = tile.dwLine*4*y; for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) { uint32 w = pWordSrc[idx^nFiddle]; uint8* psw = (uint8*)&w; dwDst[x] = R4G4B4A4_MAKE( (psw[0]>>4), (psw[1]>>4), (psw[2]>>4), (psw[3]>>4)); } } } } else { if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint8 *pS = (uint8 *)pSrc + (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { *pDst++ = R4G4B4A4_MAKE((pS[3]>>4), // Red (pS[2]>>4), // Green (pS[1]>>4), // Blue (pS[0]>>4)); // Alpha pS+=4; } } else { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint8 *pS = (uint8 *)pSrc + (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4); int n; n = 0; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { *pDst++ = R4G4B4A4_MAKE((pS[(n^0x8) + 3]>>4), // Red (pS[(n^0x8) + 2]>>4), // Green (pS[(n^0x8) + 1]>>4), // Blue (pS[(n^0x8) + 0]>>4)); // Alpha n += 4; } } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint8 *pS = (uint8 *)pSrc + (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { *pDst++ = R4G4B4A4_MAKE((pS[3]>>4), // Red (pS[2]>>4), // Green (pS[1]>>4), // Blue (pS[0]>>4)); // Alpha pS+=4; } } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // E.g. Dear Mario text // Copy, Score etc void ConvertIA4_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); // For odd lines, swap words too if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; // This may not work if X is not even? uint32 dwByteOffset = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad/2); // Do two pixels at a time for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; // Even *pDst++ = R4G4B4A4_MAKE(ThreeToFour[(b & 0xE0) >> 5], ThreeToFour[(b & 0xE0) >> 5], ThreeToFour[(b & 0xE0) >> 5], OneToFour[(b & 0x10) >> 4]); // Odd *pDst++ = R4G4B4A4_MAKE(ThreeToFour[(b & 0x0E) >> 1], ThreeToFour[(b & 0x0E) >> 1], ThreeToFour[(b & 0x0E) >> 1], OneToFour[(b & 0x01)] ); dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); // This may not work if X is not even? uint32 dwByteOffset = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad/2); // Do two pixels at a time for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ 0x3]; // Even *pDst++ = R4G4B4A4_MAKE(ThreeToFour[(b & 0xE0) >> 5], ThreeToFour[(b & 0xE0) >> 5], ThreeToFour[(b & 0xE0) >> 5], OneToFour[(b & 0x10) >> 4]); // Odd *pDst++ = R4G4B4A4_MAKE(ThreeToFour[(b & 0x0E) >> 1], ThreeToFour[(b & 0x0E) >> 1], ThreeToFour[(b & 0x0E) >> 1], OneToFour[(b & 0x01)] ); dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // E.g Mario's head textures void ConvertIA8_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { // For odd lines, swap words too if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint16 *pDst = (uint16 *)((uint8*)dInfo.lpSurface + y * dInfo.lPitch); // Points to current byte uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; *pDst++ = R4G4B4A4_MAKE( ((b&0xf0)>>4),((b&0xf0)>>4),((b&0xf0)>>4),(b&0x0f)); dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); // Points to current byte uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ 0x3]; *pDst++ = R4G4B4A4_MAKE(((b&0xf0)>>4),((b&0xf0)>>4),((b&0xf0)>>4),(b&0x0f)); dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // E.g. camera's clouds, shadows void ConvertIA16_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; if (!pTexture->StartUpdate(&dInfo)) return; for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); // Points to current word uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint16 w = *(uint16 *)&pByteSrc[dwWordOffset^0x2]; uint8 i = (uint8)(w >> 12); uint8 a = (uint8)(w & 0xFF); *pDst++ = R4G4B4A4_MAKE(i, i, i, (a>>4)); dwWordOffset += 2; } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // Used by MarioKart void ConvertI4_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); // Might not work with non-even starting X uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); // For odd lines, swap words too if( !conkerSwapHack || (y&4) == 0 ) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; } else { if ((y%2) == 1) nFiddle = 0x3; else nFiddle = 0x7; } for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; // Even //*pDst++ = R4G4B4A4_MAKE(b>>4, b>>4, b>>4, b>>4); *pDst++ = FourToSixteen[(b & 0xF0)>>4]; // Odd //*pDst++ = R4G4B4A4_MAKE(b & 0x0f, b & 0x0f, b & 0x0f, b & 0x0f); *pDst++ = FourToSixteen[b & 0x0f]; dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; // Might not work with non-even starting X uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ 0x3]; // Even //*pDst++ = R4G4B4A4_MAKE(b>>4, b>>4, b>>4, b>>4); *pDst++ = FourToEight[(b & 0xF0)>>4]; // Odd //*pDst++ = R4G4B4A4_MAKE(b & 0x0f, b & 0x0f, b & 0x0f, b & 0x0f); *pDst++ = FourToEight[b & 0x0f]; dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // Used by MarioKart void ConvertI8_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; long long pSrc = (long long) (tinfo.pPhysicalAddress); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = *(uint8*)((pSrc+dwByteOffset)^nFiddle); *pDst++ = R4G4B4A4_MAKE(b>>4, b>>4, b>>4, b>>4); dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = *(uint8*)((pSrc+dwByteOffset)^0x3); *pDst++ = R4G4B4A4_MAKE(b>>4, b>>4, b>>4, b>>4); dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // Used by Starfox intro void ConvertCI4_RGBA16_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); uint16 * pPal = (uint16 *)tinfo.PalAddress; if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint16 * pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = Convert555ToR4G4B4A4(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = Convert555ToR4G4B4A4(pPal[blo^1]); // Remember palette is in different endian order! pDst+=2; dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 * pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ 0x3]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = Convert555ToR4G4B4A4(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = Convert555ToR4G4B4A4(pPal[blo^1]); // Remember palette is in different endian order! pDst+=2; dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } //***************************************************************************** // Convert CI4 images. We need to switch on the palette type //***************************************************************************** void ConvertCI4_16( CTexture * p_texture, const TxtrInfo & tinfo ) { if ( tinfo.TLutFmt == TLUT_FMT_RGBA16 ) { ConvertCI4_RGBA16_16( p_texture, tinfo ); } else if ( tinfo.TLutFmt == TLUT_FMT_IA16 ) { ConvertCI4_IA16_16( p_texture, tinfo ); } } //***************************************************************************** // Convert CI8 images. We need to switch on the palette type //***************************************************************************** void ConvertCI8_16( CTexture * p_texture, const TxtrInfo & tinfo ) { if ( tinfo.TLutFmt == TLUT_FMT_RGBA16 ) { ConvertCI8_RGBA16_16( p_texture, tinfo ); } else if ( tinfo.TLutFmt == TLUT_FMT_IA16 ) { ConvertCI8_IA16_16( p_texture, tinfo ); } } // Used by Starfox intro void ConvertCI4_IA16_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); uint16 * pPal = (uint16 *)tinfo.PalAddress; if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint16 * pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = ConvertIA16ToR4G4B4A4(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = ConvertIA16ToR4G4B4A4(pPal[blo^1]); // Remember palette is in different endian order! pDst += 2; dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 * pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ 0x3]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = ConvertIA16ToR4G4B4A4(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = ConvertIA16ToR4G4B4A4(pPal[blo^1]); // Remember palette is in different endian order! pDst+=2; dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // Used by MarioKart for Cars etc void ConvertCI8_RGBA16_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); uint16 * pPal = (uint16 *)tinfo.PalAddress; if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint16 *pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; *pDst++ = Convert555ToR4G4B4A4(pPal[b^1]); // Remember palette is in different endian order! dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ 0x3]; *pDst++ = Convert555ToR4G4B4A4(pPal[b^1]); // Remember palette is in different endian order! dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } // Used by MarioKart for Cars etc void ConvertCI8_IA16_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); uint16 * pPal = (uint16 *)tinfo.PalAddress; if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint16 *pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; *pDst++ = ConvertIA16ToR4G4B4A4(pPal[b^1]); // Remember palette is in different endian order! dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ 0x3]; *pDst++ = ConvertIA16ToR4G4B4A4(pPal[b^1]); // Remember palette is in different endian order! dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } void ConvertYUV_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; uint32 x, y; uint32 nFiddle; if( options.bUseFullTMEM ) { Tile &tile = gRDP.tiles[tinfo.tileNo]; uint16 * pSrc; if( tinfo.tileNo >= 0 ) pSrc = (uint16*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; else pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; for (y = 0; y < tinfo.HeightToLoad; y++) { nFiddle = ( y&1 )? 0x4 : 0; int dwWordOffset = tinfo.tileNo>=0? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); uint16 * wDst = (uint16 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); for (x = 0; x < tinfo.WidthToLoad/2; x++) { int y0 = *(uint8*)&pByteSrc[(dwWordOffset+1)^nFiddle]; int y1 = *(uint8*)&pByteSrc[(dwWordOffset+3)^nFiddle]; int u0 = *(uint8*)&pByteSrc[(dwWordOffset )^nFiddle]; int v0 = *(uint8*)&pByteSrc[(dwWordOffset+2)^nFiddle]; wDst[x*2+0] = ConvertYUV16ToR4G4B4(y0,u0,v0); wDst[x*2+1] = ConvertYUV16ToR4G4B4(y1,u0,v0); dwWordOffset += 4; } } } else { // Copy of the base pointer uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; if (tinfo.bSwapped) { for (y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x2; else nFiddle = 0x2 | 0x4; // dwDst points to start of destination row uint16 * wDst = (uint16 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); // DWordOffset points to the current dword we're looking at // (process 2 pixels at a time). May be a problem if we don't start on even pixel uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (x = 0; x < tinfo.WidthToLoad/2; x++) { uint32 y0 = *(uint8*)&pByteSrc[(dwWordOffset+1)^nFiddle]; uint32 y1 = *(uint8*)&pByteSrc[(dwWordOffset+3)^nFiddle]; uint32 u0 = *(uint8*)&pByteSrc[(dwWordOffset )^nFiddle]; uint32 v0 = *(uint8*)&pByteSrc[(dwWordOffset+2)^nFiddle]; wDst[x*2+0] = ConvertYUV16ToR4G4B4(y0,u0,v0); wDst[x*2+1] = ConvertYUV16ToR4G4B4(y1,u0,v0); dwWordOffset += 4; } } } else { for (y = 0; y < tinfo.HeightToLoad; y++) { // dwDst points to start of destination row uint16 * wDst = (uint16 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); // DWordOffset points to the current dword we're looking at // (process 2 pixels at a time). May be a problem if we don't start on even pixel uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (x = 0; x < tinfo.WidthToLoad/2; x++) { uint32 y0 = *(uint8*)&pByteSrc[(dwWordOffset+1)^3]; uint32 y1 = *(uint8*)&pByteSrc[(dwWordOffset+3)^3]; uint32 u0 = *(uint8*)&pByteSrc[(dwWordOffset )^3]; uint32 v0 = *(uint8*)&pByteSrc[(dwWordOffset+2)^3]; wDst[x*2+0] = ConvertYUV16ToR4G4B4(y0,u0,v0); wDst[x*2+1] = ConvertYUV16ToR4G4B4(y1,u0,v0); dwWordOffset += 4; } } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } uint16 ConvertYUV16ToR4G4B4(int Y, int U, int V) { uint32 A=1; uint32 R1 = Y + g_convk0 * V; uint32 G1 = Y + g_convk1 * U + g_convk2 * V; uint32 B1 = Y + g_convk3 * U; uint32 R = (R1 - g_convk4) * g_convk5 + R1; uint32 G = (G1 - g_convk4) * g_convk5 + G1; uint32 B = (B1 - g_convk4) * g_convk5 + B1; return (uint16)R4G4B4A4_MAKE((R>>4), (G>>4), (B>>4), 0xF*A); } // Used by Starfox intro void Convert4b_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); if( tinfo.Format <= TXT_FMT_CI ) bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); Tile &tile = gRDP.tiles[tinfo.tileNo]; uint8 *pByteSrc = tinfo.tileNo >= 0 ? (uint8*)&g_Tmem.g_Tmem64bit[tile.dwTMem] : (uint8*)(tinfo.pPhysicalAddress); for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 * pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 nFiddle; if( tinfo.tileNo < 0 ) { if (tinfo.bSwapped) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; } else { nFiddle = 3; } } else { nFiddle = ( y&1 )? 0x4 : 0; } int idx = tinfo.tileNo>=0 ? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2, idx++) { uint8 b = pByteSrc[idx^nFiddle]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) ) { if( tinfo.TLutFmt == TLUT_FMT_IA16 ) { if( tinfo.tileNo>=0 ) { pDst[0] = ConvertIA16ToR4G4B4A4(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); pDst[1] = ConvertIA16ToR4G4B4A4(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(blo<<2)]); } else { pDst[0] = ConvertIA16ToR4G4B4A4(pPal[bhi^1]); pDst[1] = ConvertIA16ToR4G4B4A4(pPal[blo^1]); } } else { if( tinfo.tileNo>=0 ) { pDst[0] = Convert555ToR4G4B4A4(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); pDst[1] = Convert555ToR4G4B4A4(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(blo<<2)]); } else { pDst[0] = Convert555ToR4G4B4A4(pPal[bhi^1]); pDst[1] = Convert555ToR4G4B4A4(pPal[blo^1]); } } } else if( tinfo.Format == TXT_FMT_IA ) { pDst[0] = ConvertIA4ToR4G4B4A4(b>>4); pDst[1] = ConvertIA4ToR4G4B4A4(b&0xF); } else //if( tinfo.Format == TXT_FMT_I ) { pDst[0] = ConvertI4ToR4G4B4A4(b>>4); pDst[1] = ConvertI4ToR4G4B4A4(b&0xF); } if( bIgnoreAlpha ) { pDst[0] |= 0xF000; pDst[1] |= 0xF000; } pDst+=2; } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } void Convert8b_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); if( tinfo.Format <= TXT_FMT_CI ) bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); Tile &tile = gRDP.tiles[tinfo.tileNo]; uint8 *pByteSrc; if( tinfo.tileNo >= 0 ) pByteSrc = (uint8*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; else pByteSrc = (uint8*)(tinfo.pPhysicalAddress); for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 * pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 nFiddle; if( tinfo.tileNo < 0 ) { if (tinfo.bSwapped) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; } else { nFiddle = 3; } } else { nFiddle = ( y&1 )? 0x4 : 0; } int idx = tinfo.tileNo>=0? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) { uint8 b = pByteSrc[idx^nFiddle]; if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) ) { if( tinfo.TLutFmt == TLUT_FMT_IA16 ) { if( tinfo.tileNo>=0 ) *pDst = ConvertIA16ToR4G4B4A4(g_Tmem.g_Tmem16bit[0x400+(b<<2)]); else *pDst = ConvertIA16ToR4G4B4A4(pPal[b^1]); } else { if( tinfo.tileNo>=0 ) *pDst = Convert555ToR4G4B4A4(g_Tmem.g_Tmem16bit[0x400+(b<<2)]); else *pDst = Convert555ToR4G4B4A4(pPal[b^1]); } } else if( tinfo.Format == TXT_FMT_IA ) { *pDst = R4G4B4A4_MAKE( ((b&0xf0)>>4),((b&0xf0)>>4),((b&0xf0)>>4),(b&0x0f)); } else //if( tinfo.Format == TXT_FMT_I ) { *pDst = R4G4B4A4_MAKE(b>>4, b>>4, b>>4, b>>4); } if( bIgnoreAlpha ) { *pDst |= 0xFF000000; } pDst++; } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } void Convert16b_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; Tile &tile = gRDP.tiles[tinfo.tileNo]; uint16 *pWordSrc; if( tinfo.tileNo >= 0 ) pWordSrc = (uint16*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; else pWordSrc = (uint16*)(tinfo.pPhysicalAddress); for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 * dwDst = (uint16 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); uint32 nFiddle; if( tinfo.tileNo < 0 ) { if (tinfo.bSwapped) { if ((y&1) == 0) nFiddle = 0x1; else nFiddle = 0x3; } else { nFiddle = 0x1; } } else { nFiddle = ( y&1 )? 0x2 : 0; } int idx = tinfo.tileNo>=0? tile.dwLine*4*y : (((y+tinfo.TopToLoad) * tinfo.Pitch)>>1) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) { uint16 w = pWordSrc[idx^nFiddle]; uint16 w2 = tinfo.tileNo>=0? ((w>>8)|(w<<8)) : w; if( tinfo.Format == TXT_FMT_RGBA ) { dwDst[x] = Convert555ToR4G4B4A4(w2); } else if( tinfo.Format == TXT_FMT_YUV ) { } else if( tinfo.Format >= TXT_FMT_IA ) { uint8 i = (uint8)(w2 >> 12); uint8 a = (uint8)(w2 & 0xFF); dwDst[x] = R4G4B4A4_MAKE(i, i, i, (a>>4)); } } } pTexture->EndUpdate(&dInfo); pTexture->SetOthersVariables(); } mupen64plus-video-rice-src-2.0/src/CritSect.h0000644000000000000000000000233612165031100017165 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if !defined(CRITSECT_H) #define CRITSECT_H #include class CCritSect { public: CCritSect() { cs = SDL_CreateMutex(); locked = 0; } ~CCritSect() { SDL_DestroyMutex(cs); } void Lock() { SDL_LockMutex(cs); locked = 1; } void Unlock() { locked = 0; SDL_UnlockMutex(cs); } bool IsLocked() { return (locked != 0); } protected: SDL_mutex *cs; int locked; }; #endif // !defined(CRITSECT_H) mupen64plus-video-rice-src-2.0/src/Debugger.cpp0000644000000000000000000005414712165031100017533 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define M64P_PLUGIN_PROTOTYPES 1 #include "m64p_plugin.h" #include "typedefs.h" #ifndef DEBUGGER void __cdecl DebuggerAppendMsg(const char * Message, ...) {} #else void DumpMatrix2(const Matrix &mtx, const char* prompt); bool debuggerWinOpened = false; bool debuggerDrawRenderTexture = false; int debuggerDrawRenderTextureNo = 0; bool logCombiners = false; bool logWarning = true; bool logTriangles = false; bool logMatrix = false; bool logVertex = false; bool logTextures = false; bool logTextureBuffer = false; bool logToScreen = true; bool logToFile = false; bool logUcodes = false; bool logMicrocode = false; bool logFog = false; bool logDetails = false; FILE *logFp = NULL; bool debuggerEnableTexture=true; bool debuggerEnableZBuffer=true; bool debuggerEnableCullFace=true; bool debuggerEnableTestTris=true; bool debuggerEnableAlphaTest=true; bool debuggerContinueWithUnknown=false; bool debuggerPause = false; bool pauseAtNext = true; int eventToPause = NEXT_FRAME; int debuggerPauseCount = 340; int countToPause = 1; bool debuggerDropCombiners=false; bool debuggerDropGeneralCombiners=false; bool debuggerDropDecodedMux=false; bool debuggerDropCombinerInfos=false; char msgBuf[0x20000+2]; bool msgBufUpdated = false; extern FiddledVtx * g_pVtxBase; uint32 CachedTexIndex = 0; const char* otherNexts[] = { "Frame", "Flush Tri", "TextRect", "Triangle", "Set CImg", "ObjTxt Cmd", "Obj BG", "Sprite2D", "FillRect", "DList", "Ucode", "Texture Buffer", "Matrix Cmd", "Vertex Cmd", "New Texture", "Set Texture", "Mux", "Set Light", "Set Mode Cmd", "Set Prim Color", "Texture Cmd", "Unknown Ops", "Scale Image", "LoadTlut", "Ucode Switching", }; int numberOfNextOthers = sizeof(otherNexts)/sizeof(char*); const char* thingsToDump[] = { "Cur Texture RGBA", "Cur+1 Texture RGBA", "Colors", "Memory At", "Mux", "Simple Mux", "Other Modes", "Texture #", "Tile #", "VI Regs", "Cur Txt to file", "Cur+1 Txt to file", "Cur Texture RGB", "Cur Texture Alpha", "Cur+1 Texture RGB", "Cur+1 Texture Alpha", "Light Info", "Tlut", "Obj Tlut", "Vertexes", "Cached Texture", "Next Texture", "Prev Texture", "Dlist At", "Matrix At", "Combined Matrix", "World Top Matrix", "Projection Matrix", "World Matrix #", "Frame Buffer in RDRAM", "BackBuffer", "TexBuffer #", }; int numberOfThingsToDump = sizeof(thingsToDump)/sizeof(char*); enum { DUMP_CUR_TEXTURE_RGBA, DUMP_CUR_1_TEXTURE_RGBA, DUMP_COLORS, DUMP_CONTENT_AT, DUMP_CUR_MUX, DUMP_SIMPLE_MUX, DUMP_OTHER_MODE, DUMP_TEXTURE_AT, DUMP_TILE_AT, DUMP_VI_REGS, DUMP_CUR_TEXTURE_TO_FILE, DUMP_CUR_1_TEXTURE_TO_FILE, DUMP_CUR_TEXTURE_RGB, DUMP_CUR_TEXTURE_ALPHA, DUMP_CUR_1_TEXTURE_RGB, DUMP_CUR_1_TEXTURE_ALPHA, DUMP_LIGHT, DUMP_TLUT, DUMP_OBJ_TLUT, DUMP_VERTEXES, DUMP_CACHED_TEX, DUMP_NEXT_TEX, DUMP_PREV_TEX, DUMP_DLIST_AT, DUMP_MATRIX_AT, DUMP_COMBINED_MATRIX, DUMP_WORLD_TOP_MATRIX, DUMP_PROJECTION_MATRIX, DUMP_WORLD_MATRIX_AT, DUMP_FRAME_BUFFER, DUMP_BACKBUFFER, DUMP_TEXBUFFER_AT, }; //--------------------------------------------------------------------- void DumpVIRegisters(void) { DebuggerAppendMsg("----VI Registers----\nSTATUS:\t%08X\nORIGIN:\t%08X\nWIDTH:\t%08X\n\ V_SYNC:\t%08X\nH_SYNC:\t%08X\nX_SCALE:\t%08X\nY_SCALE:\t%08X\n\ H_START:\t%08X\nV_START:\t%08X\nVI Width=%f(x %f), VI Height=%f(x %f)\n\n", *g_GraphicsInfo.VI_STATUS_REG, *g_GraphicsInfo.VI_ORIGIN_REG, *g_GraphicsInfo.VI_WIDTH_REG, *g_GraphicsInfo.VI_V_SYNC_REG, *g_GraphicsInfo.VI_H_SYNC_REG, *g_GraphicsInfo.VI_X_SCALE_REG, *g_GraphicsInfo.VI_Y_SCALE_REG, *g_GraphicsInfo.VI_H_START_REG, *g_GraphicsInfo.VI_V_START_REG, windowSetting.fViWidth,windowSetting.fMultX, windowSetting.fViHeight,windowSetting.fMultY); DebuggerAppendMsg("Scissor: x0=%d y0=%d x1=%d y1=%d mode=%d", gRDP.scissor.left, gRDP.scissor.top, gRDP.scissor.right, gRDP.scissor.bottom, gRDP.scissor.mode); DebuggerAppendMsg("Effective scissor: x0=%d y0=%d x1=%d y1=%d", gRSP.real_clip_scissor_left, gRSP.real_clip_scissor_top, gRSP.real_clip_scissor_right, gRSP.real_clip_scissor_bottom); DebuggerAppendMsg("Clipping: (%d) left=%f top=%f right=%f bottom=%f", gRSP.clip_ratio_posx, gRSP.real_clip_ratio_negx , gRSP.real_clip_ratio_negy, gRSP.real_clip_ratio_posx, gRSP.real_clip_ratio_posy); DebuggerAppendMsg("Viewport: left=%d top=%d right=%d bottom=%d", gRSP.nVPLeftN, gRSP.nVPTopN , gRSP.nVPRightN, gRSP.nVPBottomN); DebuggerAppendMsg("Current CImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_CI.dwAddr, pszImgFormat[g_CI.dwFormat], pszImgSize[g_CI.dwSize], g_CI.dwWidth); DebuggerAppendMsg("Current ZImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_ZI.dwAddr, pszImgFormat[g_ZI.dwFormat], pszImgSize[g_ZI.dwSize], g_ZI.dwWidth); } void DumpVertexArray(void) { DebuggerAppendMsg("----Vertexes----\n"); try { for( int i=0; i<32; i++ ) { FiddledVtx &v = g_pVtxBase[i]; DebuggerAppendMsg("[%d] x=%d,y=%d,z=%d -- r=%d,g=%d,b=%d,a=%d\n", i, v.x, v.y, v.z, v.rgba.r, v.rgba.g, v.rgba.b, v.rgba.a); DebuggerAppendMsg("\tx=%f,y=%f,z=%f,rhw=%f\n", g_vecProjected[i].x, g_vecProjected[i].y, g_vecProjected[i].z, g_vecProjected[i].w); } } catch(...) { DebuggerAppendMsg("Invalid memory pointer of vertex array\n"); } } void DumpHex(uint32 rdramAddr, int count); uint32 StrToHex(char *HexStr); void DumpTileInfo(uint32 dwTile) { const char *pszOnOff[2] = {"Off", "On"}; DebuggerAppendMsg("Tile: %d\nFmt: %s/%s Line:%d (Pitch %d) TMem:0x%04x Palette:%d\n", dwTile, pszImgFormat[gRDP.tiles[dwTile].dwFormat], pszImgSize[gRDP.tiles[dwTile].dwSize], gRDP.tiles[dwTile].dwLine, gRDP.tiles[dwTile].dwPitch, gRDP.tiles[dwTile].dwTMem, gRDP.tiles[dwTile].dwPalette); DebuggerAppendMsg("S: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x\n", pszOnOff[gRDP.tiles[dwTile].bClampS],pszOnOff[gRDP.tiles[dwTile].bMirrorS], gRDP.tiles[dwTile].dwMaskS, gRDP.tiles[dwTile].dwShiftS); DebuggerAppendMsg("T: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x\n", pszOnOff[gRDP.tiles[dwTile].bClampT],pszOnOff[gRDP.tiles[dwTile].bMirrorT], gRDP.tiles[dwTile].dwMaskT, gRDP.tiles[dwTile].dwShiftT); DebuggerAppendMsg("(%d,%d) -> (%d,%d), hilite [%d, %d]\n", gRDP.tiles[dwTile].sl, gRDP.tiles[dwTile].tl, gRDP.tiles[dwTile].sh, gRDP.tiles[dwTile].th, gRDP.tiles[dwTile].hilite_sl,gRDP.tiles[dwTile].hilite_tl); } void DumpTexture(int tex, TextureChannel channel = TXT_RGB ) { CRender::GetRender()->DrawTexture(tex, channel); } void DumpRenderTexture(int tex=-1) { if( CDeviceBuilder::GetBuilder()->GetGeneralDeviceType() == DIRECTX_DEVICE ) { g_pFrameBufferManager->DisplayRenderTexture(tex); } else { debuggerDrawRenderTextureNo = tex; debuggerDrawRenderTexture = true; } } void DumpTextureToFile(int tex, TextureChannel channel = TXT_RGB) { CRender::GetRender()->SaveTextureToFile(tex, channel,false); } void DumpTlut(uint16* palAddr) { for( uint32 i=0; i<0x100; i+=8 ) { DebuggerAppendMsg("0x%4X 0x%4X 0x%4X 0x%4X 0x%4X 0x%4X 0x%4X 0x%4X ", g_wRDPTlut[i], g_wRDPTlut[i+1], g_wRDPTlut[i+2], g_wRDPTlut[i+2], g_wRDPTlut[i+4], g_wRDPTlut[i+5], g_wRDPTlut[i+6], g_wRDPTlut[i+7]); } } extern char ucodeNames_GBI1[256]; extern char ucodeNames_GBI2[256]; void DumpDlistAt(uint32 dwPC) { uint32 word0, word1, opcode; char *name; switch( gRSP.ucode ) { case 2: case 10: //case 8: name=ucodeNames_GBI2; break; default: name=ucodeNames_GBI1; } DebuggerAppendMsg("\n\n"); //if( dwPC>100 ) dwPC -= 40; for( uint32 i=0; i<20; i++) { word0 = g_pRDRAMu32[(dwPC>>2)+0]; word1 = g_pRDRAMu32[(dwPC>>2)+1]; opcode = word0>>24; DebuggerAppendMsg("%08X: %08X, %08X - %s", dwPC, word0, word1, name[opcode] ); dwPC+=8; } DebuggerAppendMsg("\n\n"); } void DumpMatrixAt(uint32 dwPC) { Matrix mat; const float fRecip = 1.0f / 65536.0f; for (uint32 dwI = 0; dwI < 4; dwI++) { for (uint32 dwJ = 0; dwJ < 4; dwJ++) { int nDataHi = *(short *)(g_pRDRAMu8 + ((dwPC+(dwI<<3)+(dwJ<<1) )^0x2)); int nDataLo = *(uint16 *)(g_pRDRAMu8 + ((dwPC+(dwI<<3)+(dwJ<<1) + 32)^0x2)); mat.m[dwI][dwJ] = (float)((nDataHi << 16) | nDataLo) * fRecip; } } TRACE0("Dump Matrix in Memory"); DebuggerAppendMsg( " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n", mat.m[0][0], mat.m[0][1], mat.m[0][2], mat.m[0][3], mat.m[1][0], mat.m[1][1], mat.m[1][2], mat.m[1][3], mat.m[2][0], mat.m[2][1], mat.m[2][2], mat.m[2][3], mat.m[3][0], mat.m[3][1], mat.m[3][2], mat.m[3][3]); } // High static const char *alphadithertypes[4] = {"Pattern", "NotPattern", "Noise", "Disable"}; static const char *rgbdithertype[4] = {"MagicSQ", "Bayer", "Noise", "Disable"}; static const char *convtype[8] = {"Conv", "?", "?", "?", "?", "FiltConv", "Filt", "?"}; static const char *filtertype[4] = {"Point", "?", "Bilinear", "Average"}; static const char *cycletype[4] = {"1Cycle", "2Cycle", "Copy", "Fill"}; static const char *alphacomptype[4] = {"None", "Threshold", "?", "Dither"}; static const char * szCvgDstMode[4] = { "Clamp", "Wrap", "Full", "Save" }; static const char * szZMode[4] = { "Opa", "Inter", "XLU", "Decal" }; static const char * szZSrcSel[2] = { "Pixel", "Primitive" }; static const char * sc_szBlClr[4] = { "In", "Mem", "Bl", "Fog" }; static const char * sc_szBlA1[4] = { "AIn", "AFog", "AShade", "0" }; static const char * sc_szBlA2[4] = { "1-A", "AMem", "1", "0" }; void DumpOtherMode() { uint16 blender = gRDP.otherMode.blender; RDP_BlenderSetting &bl = *(RDP_BlenderSetting*)(&(blender)); DebuggerAppendMsg( "Other Modes"); DebuggerAppendMsg( "\talpha_compare:\t%s", alphacomptype[ gRDP.otherMode.alpha_compare ]); DebuggerAppendMsg( "\tdepth_source:\t%s", szZSrcSel[ gRDP.otherMode.depth_source ]); DebuggerAppendMsg( "\taa_en:\t\t%d", gRDP.otherMode.aa_en ); DebuggerAppendMsg( "\tz_cmp:\t\t%d", gRDP.otherMode.z_cmp ); DebuggerAppendMsg( "\tz_upd:\t\t%d", gRDP.otherMode.z_upd ); DebuggerAppendMsg( "\tim_rd:\t\t%d", gRDP.otherMode.im_rd ); DebuggerAppendMsg( "\tclr_on_cvg:\t%d", gRDP.otherMode.clr_on_cvg ); DebuggerAppendMsg( "\tcvg_dst:\t\t%s", szCvgDstMode[ gRDP.otherMode.cvg_dst ] ); DebuggerAppendMsg( "\tzmode:\t\t%s", szZMode[ gRDP.otherMode.zmode ] ); DebuggerAppendMsg( "\tcvg_x_alpha:\t%d", gRDP.otherMode.cvg_x_alpha ); DebuggerAppendMsg( "\talpha_cvg_sel:\t%d", gRDP.otherMode.alpha_cvg_sel ); DebuggerAppendMsg( "\tforce_bl:\t\t%d", gRDP.otherMode.force_bl ); DebuggerAppendMsg( "\ttex_edge:\t\t%d", gRDP.otherMode.tex_edge ); DebuggerAppendMsg( "\tblender:\t\t%04x - Cycle1:\t%s * %s + %s * %s\n\t\t\tCycle2:\t%s * %s + %s * %s", gRDP.otherMode.blender, sc_szBlClr[bl.c1_m1a], sc_szBlA1[bl.c1_m1b], sc_szBlClr[bl.c1_m2a], sc_szBlA2[bl.c1_m2b], sc_szBlClr[bl.c2_m1a], sc_szBlA1[bl.c2_m1b], sc_szBlClr[bl.c2_m2a], sc_szBlA2[bl.c2_m2b]); DebuggerAppendMsg( "\tblend_mask:\t%d", gRDP.otherMode.blend_mask ); DebuggerAppendMsg( "\talpha_dither:\t%s", alphadithertypes[ gRDP.otherMode.alpha_dither ] ); DebuggerAppendMsg( "\trgb_dither:\t\t%s", rgbdithertype[ gRDP.otherMode.rgb_dither ] ); DebuggerAppendMsg( "\tcomb_key:\t%s", gRDP.otherMode.key_en ? "Key" : "None" ); DebuggerAppendMsg( "\ttext_conv:\t\t%s", convtype[ gRDP.otherMode.text_conv ] ); DebuggerAppendMsg( "\ttext_filt:\t\t%s", filtertype[ gRDP.otherMode.text_filt ] ); DebuggerAppendMsg( "\ttext_tlut:\t\t%s", textluttype[ gRDP.otherMode.text_tlut ] ); DebuggerAppendMsg( "\ttext_lod:\t\t%s", gRDP.otherMode.text_lod ? "Yes": "No" ); DebuggerAppendMsg( "\ttext_detail:\t\t%s", gRDP.otherMode.text_detail ? "Yes": "No" ); DebuggerAppendMsg( "\ttext_sharpen:\t\t%s", gRDP.otherMode.text_sharpen ? "Yes": "No" ); DebuggerAppendMsg( "\ttext_persp:\t%s", gRDP.otherMode.text_persp ? "On" : "Off" ); DebuggerAppendMsg( "\tcycle_type:\t%s", cycletype[ gRDP.otherMode.cycle_type ] ); DebuggerAppendMsg( "\tpipeline:\t\t%s", gRDP.otherMode.atomic_prim ? "1Primitive" : "NPrimitive" ); DebuggerAppendMsg("\n\nSP render flags:"); DebuggerAppendMsg("\tCull mode: %s%s", gRSP.bCullFront?"Cull Front":"", gRSP.bCullBack?" Cull Back":""); DebuggerAppendMsg("\tShade mode: %d", gRSP.shadeMode); DebuggerAppendMsg("\tFog: %s", gRSP.bFogEnabled?"enabled":"disabled"); DebuggerAppendMsg("\tZbuffer in SP: %s", gRSP.bZBufferEnabled?"enabled":"disabled"); DebuggerAppendMsg("\tLighting: %s", gRSP.bLightingEnable?"enabled":"disabled"); DebuggerAppendMsg("\\Number of lights: %d", gRSPnumLights); DebuggerAppendMsg("\tTexture Gen: %s", gRSP.bTextureGen?"enabled":"disabled"); DebuggerAppendMsg("\tTexture Gen Linear: %s", (gRDP.geometryMode & G_TEXTURE_GEN_LINEAR)?"enabled":"disabled"); } void DumpCachedTexture(uint32 index) { TxtrCacheEntry *p = gTextureManager.GetCachedTexture(index); if( p != NULL ) { char filename[80]; sprintf(filename,"\\Texture%d_rgb", index); CRender::GetRender()->SaveTextureToFile(*(p->pTexture), filename, TXT_RGB); DebuggerAppendMsg("Display cached texture #%d of %d\n", index, gTextureManager.GetNumOfCachedTexture()); DebuggerAppendMsg("W:%d, H:%d, RealW:%d, RealH:%d, D3DW:%d, D3DH: %d", p->ti.WidthToCreate, p->ti.HeightToCreate, p->ti.WidthToLoad, p->ti.HeightToLoad, p->pTexture->m_dwCreatedTextureWidth, p->pTexture->m_dwCreatedTextureHeight); DebuggerAppendMsg("ScaledS:%s, ScaledT:%s", p->pTexture->m_bScaledS?"T":"F", p->pTexture->m_bScaledT?"T":"F"); } else { DebuggerAppendMsg("No cached texture at index = %d\n", index); } } extern uint32 gObjTlutAddr; void DumpInfo(int thingToDump) { switch(thingToDump) { case DUMP_COLORS: DebuggerAppendMsg("----Colors----\nPrim Color:\t%08X\nEnv Color:\t%08X\n" "Fill Color:\t%08X\nFog Color:\t%08X\n" "Prim Depth:\t%f\nPrim LOD Frac:\t%08X\n", GetPrimitiveColor(), GetEnvColor(), gRDP.fillColor, CRender::GetRender()->GetFogColor(), GetPrimitiveDepth(), GetLODFrac()); break; case DUMP_CUR_MUX: CRender::GetRender()->m_pColorCombiner->DisplayMuxString(); break; case DUMP_LIGHT: DebuggerAppendMsg("----Light Colors----\nNumber of Lights: %d\n",GetNumLights()); for( uint32 i=0; im_pColorCombiner->DisplaySimpleMuxString(); break; case DUMP_OTHER_MODE: DumpOtherMode(); break; case DUMP_FRAME_BUFFER: CRender::GetRender()->DrawFrameBuffer(true); break; case DUMP_CONTENT_AT: { } break; case DUMP_DLIST_AT: { } break; case DUMP_MATRIX_AT: { } break; case DUMP_NEXT_TEX: CachedTexIndex++; if( CachedTexIndex >= gTextureManager.GetNumOfCachedTexture() ) { CachedTexIndex = 0; } DumpCachedTexture(CachedTexIndex); break; case DUMP_PREV_TEX: CachedTexIndex--; if( CachedTexIndex < 0 || CachedTexIndex >= gTextureManager.GetNumOfCachedTexture() ) CachedTexIndex = 0; DumpCachedTexture(CachedTexIndex); break; case DUMP_CACHED_TEX: DumpCachedTexture(CachedTexIndex); break; case DUMP_TEXBUFFER_AT: { } break; case DUMP_COMBINED_MATRIX: DumpMatrix2(gRSPworldProject,"Combined Matrix"); break; case DUMP_WORLD_TOP_MATRIX: DumpMatrix2(gRSP.modelviewMtxs[gRSP.modelViewMtxTop],"World Top Matrix"); break; case DUMP_WORLD_MATRIX_AT: { } break; case DUMP_PROJECTION_MATRIX: DumpMatrix2(gRSP.projectionMtxs[gRSP.projectionMtxTop],"Projection Top Matrix"); break; } } void SetLogToFile(bool log) { if( log ) { if( logFp == NULL ) { logFp = fopen("\\RiceVideo.log", "at"); } } else { if( logFp != NULL ) { fclose(logFp); logFp = NULL; } } } void __cdecl DebuggerAppendMsg(const char * Message, ...) { if( !logToScreen && !logToFile ) return; char Msg[5000]; va_list ap; va_start( ap, Message ); vsprintf( Msg, Message, ap ); va_end( ap ); if( Msg[strlen(Msg)-1]!='\n' ) strcat(Msg,"\n"); if( logToScreen ) { DebugMessage(M64MSG_INFO, "Rice Debug: %s", Msg); } if( logToFile ) { fprintf(logFp, "%s\n", Msg); } } void DebuggerPause() { while( debuggerPause ) { if( debuggerDrawRenderTexture ) { g_pFrameBufferManager->DisplayRenderTexture(debuggerDrawRenderTextureNo); debuggerDrawRenderTexture = false; } usleep(100 * 1000); debuggerPause = false; } } void __cdecl LOG_UCODE(const char* szFormat, ...) { if( logUcodes) { char Msg[400]; va_list va; va_start(va, szFormat); vsprintf( Msg, szFormat, va ); va_end(va); DebuggerAppendMsg("%s\n", Msg); } } void DumpHex(uint32 rdramAddr, int count) { rdramAddr &= 0xFFFFFFF0; uint32 *ptr = (uint32 *)((rdramAddr&(g_dwRamSize-1))+g_pRDRAMu8); for( int i=0; i<(count+3)/4; i++) { DebuggerAppendMsg("%08X: %08X, %08X, %08X, %08X\n", rdramAddr+i*16, ptr[i*4], ptr[i*4+1], ptr[i*4+2], ptr[i*4+3]); } DebuggerAppendMsg("\n"); } uint32 StrToHex(char *HexStr) { uint32 temp = 0; for(uint32 k = 0; k < strlen(HexStr); k++) { if(HexStr[k] <= '9' && HexStr[k] >= '0') { temp = temp << 4; temp += HexStr[k] - '0'; } else if(HexStr[k] <= 'F' && HexStr[k] >= 'A') { temp = temp << 4; temp += HexStr[k] - 'A' + 10; } else if(HexStr[k] <= 'f' && HexStr[k] >= 'a') { temp = temp << 4; temp += HexStr[k] - 'a' + 10; } else { return(temp); } } return(temp); } void DEBUGGER_PAUSE_COUNT_N(uint32 val) { if (eventToPause == (int)val) { if(debuggerPauseCount>0) debuggerPauseCount--; if(debuggerPauseCount==0) { CGraphicsContext::Get()->UpdateFrame(); debuggerPause = true; } } } void DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(uint32 val) { if(eventToPause == (int)val) { if(debuggerPauseCount>0) debuggerPauseCount--; if(debuggerPauseCount==0) { debuggerPauseCount = countToPause; debuggerPause = true; } } } void DumpMatrix2(const Matrix &mat, const char* prompt) { DebuggerAppendMsg(prompt); DebuggerAppendMsg( " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n", mat.m[0][0], mat.m[0][1], mat.m[0][2], mat.m[0][3], mat.m[1][0], mat.m[1][1], mat.m[1][2], mat.m[1][3], mat.m[2][0], mat.m[2][1], mat.m[2][2], mat.m[2][3], mat.m[3][0], mat.m[3][1], mat.m[3][2], mat.m[3][3]); } void DumpMatrix(const Matrix &mat, const char* prompt) { if( pauseAtNext && logMatrix ) { DumpMatrix2(mat, prompt); } } #endif mupen64plus-video-rice-src-2.0/src/Debugger.h0000644000000000000000000001703312165031100017171 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if !defined(DEBUGGER_H) #define DEBUGGER_H #include "typedefs.h" #if defined(DEBUGGER) // Debugger.h : header file // ///////////////////////////////////////////////////////////////////////////// // CDebugger dialog extern bool debuggerWinOpened; extern bool logCombiners; extern bool logTriangles; extern bool logVertex; extern bool logWarning; extern bool logTextures; extern bool logTextureBuffer; extern bool logMatrix; extern bool logToScreen; extern bool logToFile; extern bool logUcodes; extern bool logMicrocode; extern bool logFog; extern bool logDetails; extern bool debuggerEnableTexture; extern bool debuggerEnableZBuffer; extern bool debuggerEnableCullFace; extern bool debuggerEnableTestTris; extern bool debuggerEnableAlphaTest; extern bool debuggerContinueWithUnknown; extern bool debuggerPause; extern bool pauseAtNext; extern int eventToPause; extern int debuggerPauseCount; extern int countToPause; extern bool debuggerDropCombiners; extern bool debuggerDropGeneralCombiners; extern bool debuggerDropDecodedMux; extern bool debuggerDropCombinerInfos; enum { NEXT_FRAME, NEXT_FLUSH_TRI, NEXT_TEXTRECT, NEXT_TRIANGLE, NEXT_SET_CIMG, NEXT_OBJ_TXT_CMD, NEXT_OBJ_BG, NEXT_SPRITE_2D, NEXT_FILLRECT, NEXT_DLIST, NEXT_UCODE, NEXT_RENDER_TEXTURE, NEXT_MATRIX_CMD, NEXT_VERTEX_CMD, NEXT_NEW_TEXTURE, NEXT_SET_TEXTURE, NEXT_MUX, NEXT_SET_LIGHT, NEXT_SET_MODE_CMD, NEXT_SET_PRIM_COLOR, NEXT_TEXTURE_CMD, NEXT_UNKNOWN_OP, NEXT_SCALE_IMG, NEXT_LOADTLUT, NEXT_SWITCH_UCODE, }; void DebuggerPause(); void __cdecl DebuggerAppendMsg(const char * Message, ...); void DumpHex(uint32 rdramAddr, int count); void DumpMatrix(const Matrix &mtx, const char* prompt); //Some common used macros #define DEBUG_DUMP_VERTEXES(str, v0, v1, v2) \ if( (pauseAtNext && (eventToPause == NEXT_TRIANGLE || eventToPause == NEXT_FLUSH_TRI)) && logTriangles ) \ { \ DebuggerAppendMsg("%s:%d(%08X),%d(%08X),%d(%08X)\n", (str),\ (v0), GetVertexDiffuseColor((v0)), \ (v1), GetVertexDiffuseColor((v1)), \ (v2), GetVertexDiffuseColor((v2))); \ } #define DEBUGGER_IF(op) if(op) #define DEBUGGER_PAUSE(op) if(pauseAtNext && eventToPause == op){pauseAtNext = false;CGraphicsContext::Get()->UpdateFrame(); debuggerPause = true;} extern void DEBUGGER_PAUSE_COUNT_N(uint32 event); extern void DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(uint32 val); #define DebuggerPauseCountN DEBUGGER_PAUSE_COUNT_N #define DEBUGGER_PAUSE_AND_DUMP(op,dumpfuc) \ if(pauseAtNext && eventToPause == op) \ { pauseAtNext = false;debuggerPause = true; CGraphicsContext::Get()->UpdateFrame(); dumpfuc;} #define DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(op,dumpfuc) \ if(pauseAtNext && eventToPause == op) \ { pauseAtNext = false;debuggerPause = true; dumpfuc;} #define DEBUGGER_PAUSE_AND_DUMP_COUNT_N(op,dumpfuc) \ if(pauseAtNext && eventToPause == op) \ { if( debuggerPauseCount > 0 ) debuggerPauseCount--; if( debuggerPauseCount == 0 ){pauseAtNext = false;debuggerPause = true; CGraphicsContext::Get()->UpdateFrame(); dumpfuc;}} #define DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N(cond,dumpfuc) \ if(pauseAtNext && (cond) ) \ { if( debuggerPauseCount > 0 ) debuggerPauseCount--; if( debuggerPauseCount == 0 ){pauseAtNext = false;debuggerPause = true; CGraphicsContext::Get()->UpdateFrame(); dumpfuc;}} void RDP_NOIMPL_Real(const char* op,uint32,uint32) ; #define RSP_RDP_NOIMPL RDP_NOIMPL_Real #define DEBUGGER_IF_DUMP(cond, dumpfunc) {if(cond) {dumpfunc}} #define TXTRBUF_DUMP(dumpfunc) DEBUGGER_IF_DUMP((logTextureBuffer), dumpfunc) #define TXTRBUF_DETAIL_DUMP(dumpfunc) DEBUGGER_IF_DUMP((logTextureBuffer&&logDetails), dumpfunc) #define TXTRBUF_OR_CI_DUMP(dumpfunc) DEBUGGER_IF_DUMP((logTextureBuffer || (pauseAtNext && eventToPause == NEXT_SET_CIMG)), dumpfunc) #define TXTRBUF_OR_CI_DETAIL_DUMP(dumpfunc) DEBUGGER_IF_DUMP(((logTextureBuffer || (pauseAtNext && eventToPause == NEXT_SET_CIMG))&&logDetails), dumpfunc) #define VTX_DUMP(dumpfunc) DEBUGGER_IF_DUMP((logVertex && pauseAtNext), dumpfunc) #define TRI_DUMP(dumpfunc) DEBUGGER_IF_DUMP((logTriangles && pauseAtNext), dumpfunc) #define LIGHT_DUMP(dumpfunc) DEBUGGER_IF_DUMP((eventToPause == NEXT_SET_LIGHT && pauseAtNext), dumpfunc) #define WARNING(dumpfunc) DEBUGGER_IF_DUMP(logWarning, dumpfunc) #define FOG_DUMP(dumpfunc) DEBUGGER_IF_DUMP(logFog, dumpfunc) #define LOG_TEXTURE(dumpfunc) DEBUGGER_IF_DUMP((logTextures || (pauseAtNext && eventToPause==NEXT_TEXTURE_CMD) ), dumpfunc) #define DEBUGGER_ONLY_IF DEBUGGER_IF_DUMP #define DEBUGGER_ONLY(func) {func} #define TRACE0(arg0) {DebuggerAppendMsg(arg0);} #define TRACE1(arg0,arg1) {DebuggerAppendMsg(arg0,arg1);} #define TRACE2(arg0,arg1,arg2) {DebuggerAppendMsg(arg0,arg1,arg2);} #define TRACE3(arg0,arg1,arg2,arg3) {DebuggerAppendMsg(arg0,arg1,arg2,arg3);} #define TRACE4(arg0,arg1,arg2,arg3,arg4) {DebuggerAppendMsg(arg0,arg1,arg2,arg3,arg4);} #define TRACE5(arg0,arg1,arg2,arg3,arg4,arg5) {DebuggerAppendMsg(arg0,arg1,arg2,arg3,arg4,arg5);} #define DEBUG_TRIANGLE(dumpfunc) { if(pauseAtNext && eventToPause==NEXT_TRIANGLE ) { eventToPause = NEXT_FLUSH_TRI; debuggerPause = true; DEBUGGER_PAUSE(NEXT_FLUSH_TRI); dumpfunc} } #else #define DEBUG_DUMP_VERTEXES(str, v0, v1, v2) #define DEBUGGER_IF(op) #define DEBUGGER_PAUSE(op) #define DEBUGGER_PAUSE_COUNT_N(op) #define DEBUGGER_PAUSE_AND_DUMP(op,dumpfuc) #define DebuggerPauseCountN DEBUGGER_PAUSE_COUNT_N #define DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N(cond,dumpfuc) #define DEBUGGER_PAUSE_AND_DUMP_COUNT_N(op,dumpfuc) #define DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(op) #define DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(op,dumpfuc) #define RSP_RDP_NOIMPL(a,b,c) void __cdecl DebuggerAppendMsg(const char * Message, ...); #define DumpHex(rdramAddr, count) #define DEBUGGER_IF_DUMP(cond, dumpfunc) #define TXTRBUF_DUMP(dumpfunc) #define TXTRBUF_DETAIL_DUMP(dumpfunc) #define TXTRBUF_OR_CI_DUMP(dumpfunc) #define TXTRBUF_OR_CI_DETAIL_DUMP(dumpfunc) #define VTX_DUMP(dumpfunc) #define TRI_DUMP(dumpfunc) #define LIGHT_DUMP(dumpfunc) #define WARNING(dumpfunc) #define FOG_DUMP(dumpfunc) #define LOG_TEXTURE(dumpfunc) #define DEBUGGER_ONLY_IF DEBUGGER_IF_DUMP #define DEBUGGER_ONLY(func) #define DumpMatrix(a,b) #define TRACE0(arg0) {} #define TRACE1(arg0,arg1) {} #define TRACE2(arg0,arg1,arg2) {} #define TRACE3(arg0,arg1,arg2,arg3) {} #define TRACE4(arg0,arg1,arg2,arg3,arg4) {} #define TRACE5(arg0,arg1,arg2,arg3,arg4,arg5) {} #define DEBUG_TRIANGLE(arg0) {} #endif #endif // !defined(DEBUGGER_H) mupen64plus-video-rice-src-2.0/src/DecodedMux.cpp0000644000000000000000000013725712165031100020034 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "GeneralCombiner.h" #include "Combiner.h" #include "Config.h" #include "RenderBase.h" #define ALLOW_USE_TEXTURE_FOR_CONSTANTS static const uint8 sc_Mux32[32] = { MUX_COMBINED, MUX_TEXEL0, MUX_TEXEL1, MUX_PRIM, MUX_SHADE, MUX_ENV, MUX_1, MUX_COMBINED|MUX_ALPHAREPLICATE, MUX_TEXEL0|MUX_ALPHAREPLICATE, MUX_TEXEL1|MUX_ALPHAREPLICATE, MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, MUX_ENV|MUX_ALPHAREPLICATE, MUX_LODFRAC, MUX_PRIMLODFRAC, MUX_K5, // Actually k5 MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK, MUX_0 }; static const uint8 sc_Mux16[16] = { MUX_COMBINED, MUX_TEXEL0, MUX_TEXEL1, MUX_PRIM, MUX_SHADE, MUX_ENV, MUX_1, MUX_COMBALPHA, MUX_TEXEL0|MUX_ALPHAREPLICATE, MUX_TEXEL1|MUX_ALPHAREPLICATE, MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, MUX_ENV|MUX_ALPHAREPLICATE, MUX_LODFRAC, MUX_PRIMLODFRAC, MUX_0 }; static const uint8 sc_Mux8[8] = { MUX_COMBINED, MUX_TEXEL0, MUX_TEXEL1, MUX_PRIM, MUX_SHADE, MUX_ENV, MUX_1, MUX_0 }; const char * translatedCombTypes[] = { "0", "1", "COMBINED", "TEXEL0", "TEXEL1", "PRIM", "SHADE", "ENV", "COMBALPHA", "T0_ALPHA_wrong", "T1_ALPHA_wrong", "PRIM_ALPHA_wrong", "SHADE_ALPHA_wrong", "ENV_ALPHA_wrong", "LODFRAC", "PRIMLODFRAC", "K5", "UNK", "FACTOR_PRIM_MINUS_ENV", "FACTOR_ENV_MINUS_PRIM", "FACTOR_1_MINUS_PRIM", "FACTOR_0_MINUS_PRIM", "FACTOR_1_MINUS_ENV", "FACTOR_0_MINUS_ENV", "FACTOR_1_MINUS_PRIMALPHA", "FACTOR_1_MINUS_ENVALPHA", "FACTOR_HALF", "PRIM_X_PRIMALPHA", "1_MINUS_PRIM_X_ENV_PLUS_PRIM", "ENV_X_PRIM", "PRIM_X_1_MINUS_ENV", "PRIM_X_PRIM", "ENV_X_ENV", }; const char* muxTypeStrs[] = { "CM_FMT_TYPE_NOT_USED", "CM_FMT_TYPE1_D", "CM_FMT_TYPE2_A_ADD_D", "CM_FMT_TYPE3_A_MOD_C", "CM_FMT_TYPE4_A_SUB_B", "CM_FMT_TYPE5_A_MOD_C_ADD_D", "CM_FMT_TYPE6_A_LERP_B_C", "CM_FMT_TYPE7_A_SUB_B_ADD_D", "CM_FMT_TYPE8_A_SUB_B_MOD_C", "CM_FMT_TYPE9_A_B_C_D", "CM_FMT_TYPE_NOT_CHECKED", }; void DecodedMux::Decode(uint32 dwMux0, uint32 dwMux1) { m_dwMux0 = dwMux0; m_dwMux1 = dwMux1; aRGB0 = uint8((dwMux0>>20)&0x0F); // c1 c1 // a0 bRGB0 = uint8((dwMux1>>28)&0x0F); // c1 c2 // b0 cRGB0 = uint8((dwMux0>>15)&0x1F); // c1 c3 // c0 dRGB0 = uint8((dwMux1>>15)&0x07); // c1 c4 // d0 aA0 = uint8((dwMux0>>12)&0x07); // c1 a1 // Aa0 bA0 = uint8((dwMux1>>12)&0x07); // c1 a2 // Ab0 cA0 = uint8((dwMux0>>9 )&0x07); // c1 a3 // Ac0 dA0 = uint8((dwMux1>>9 )&0x07); // c1 a4 // Ad0 aRGB1 = uint8((dwMux0>>5 )&0x0F); // c2 c1 // a1 bRGB1 = uint8((dwMux1>>24)&0x0F); // c2 c2 // b1 cRGB1 = uint8((dwMux0 )&0x1F); // c2 c3 // c1 dRGB1 = uint8((dwMux1>>6 )&0x07); // c2 c4 // d1 aA1 = uint8((dwMux1>>21)&0x07); // c2 a1 // Aa1 bA1 = uint8((dwMux1>>3 )&0x07); // c2 a2 // Ab1 cA1 = uint8((dwMux1>>18)&0x07); // c2 a3 // Ac1 dA1 = uint8((dwMux1 )&0x07); // c2 a4 // Ad1 //This fuction will translate the decode mux info further, so we can use //the decode data better. //Will translate A,B,C,D to unified presentation aRGB0 = sc_Mux16[aRGB0]; bRGB0 = sc_Mux16[bRGB0]; cRGB0 = sc_Mux32[cRGB0]; dRGB0 = sc_Mux8[dRGB0]; aA0 = sc_Mux8[aA0]; bA0 = sc_Mux8[bA0]; cA0 = sc_Mux8[cA0]; dA0 = sc_Mux8[dA0]; aRGB1 = sc_Mux16[aRGB1]; bRGB1 = sc_Mux16[bRGB1]; cRGB1 = sc_Mux32[cRGB1]; dRGB1 = sc_Mux8[dRGB1]; aA1 = sc_Mux8[aA1]; bA1 = sc_Mux8[bA1]; cA1 = sc_Mux8[cA1]; dA1 = sc_Mux8[dA1]; m_bShadeIsUsed[1] = isUsedInAlphaChannel(MUX_SHADE); m_bShadeIsUsed[0] = isUsedInColorChannel(MUX_SHADE); m_bTexel0IsUsed = isUsed(MUX_TEXEL0); m_bTexel1IsUsed = isUsed(MUX_TEXEL1); m_dwShadeColorChannelFlag = 0; m_dwShadeAlphaChannelFlag = 0; m_ColorTextureFlag[0] = 0; m_ColorTextureFlag[1] = 0; } int DecodedMux::Count(uint8 val, int cycle, uint8 mask) { uint8* pmux = m_bytes; int count=0; int start=0; int end=16; if( cycle >= 0 ) { start = cycle*4; end = start+4; } for( int i=start; i=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED; } else if( (m.b == MUX_0 && m.c == MUX_1 && m.d == MUX_0 ) || ( m.c == MUX_1 && m.b==m.d ) ) { splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D m.d = m.a; m.a = m.b = m.c = MUX_0; if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED; } else if( m.a == MUX_1 && m.b == MUX_0 && m.d == MUX_0 ) { splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D m.d = m.c; m.a = m.b = m.c = MUX_0; if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED; } else if( m.a == MUX_1 && m.c == MUX_1 && m.d == MUX_0 && do_complement ) { splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D m.d = m.b^MUX_COMPLEMENT; m.a = m.b = m.c = MUX_0; if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED; } if( splitType[i] == CM_FMT_TYPE_NOT_USED ) continue; if( splitType[i] == CM_FMT_TYPE_D ) { if( (i == N64Cycle0RGB || i == N64Cycle0Alpha) && splitType[i+2]!=CM_FMT_TYPE_NOT_USED ) //Cycle 1's Color or Alpha { uint8 saveD = m.d; for( int j=0; j<4; j++ ) { if( (m_bytes[j+i*4+8]&MUX_MASK) == MUX_COMBINED ) { m_bytes[j+i*4+8] = saveD|(m_bytes[j+i*4+8]&0xC0); //Replace cycle's CMB with D from cycle 1 } } m_dWords[i] = m_dWords[i+2]; splitType[i+2]=CM_FMT_TYPE_NOT_USED; m_dWords[i+2] = 0x02000000; i=i-1; // Throw the first cycle result away, use 2nd cycle for the 1st cycle // and then redo the 1st cycle continue; } if( (i==2 || i == 3) && (m.d&MUX_MASK) == MUX_COMBINED ) { splitType[i] = CM_FMT_TYPE_NOT_USED; } continue; } //Type 2: A+D ' ADD //B=0, C=1 = A+D //A=1, B=0 = C+D splitType[i] = CM_FMT_TYPE_A_ADD_D; //All Type 2 will be changed to = A+D if( m.b == MUX_0 && m.c == MUX_1 ) { if( m.d == MUX_TEXEL0 || m.d == MUX_TEXEL1 ) swap(m.a, m.d); if( m.a == MUX_COMBINED ) swap(m.a, m.d); continue; } if( m.a == MUX_1 && m.b == MUX_0 ) { m.a = m.c; //Change format A+D m.c = MUX_1; if( m.d == MUX_TEXEL0 || m.d == MUX_TEXEL1 ) swap(m.a, m.d); continue; } //Type 3: A*C //B=0, D=0 = A*C //A=1, D=0 = (1-A)*C splitType[i] = CM_FMT_TYPE_A_MOD_C; //A*C if( m.b == MUX_0 && m.d == MUX_0 ) { if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c); if( m.a == MUX_COMBINED ) swap(m.a, m.c); continue; } if( m.a == MUX_1 && m.d == MUX_0 && do_complement ) { m.a = m.b^MUX_COMPLEMENT; m.b = MUX_0; if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c); if( m.a == MUX_COMBINED ) swap(m.a, m.c); continue; } //Type 4: A-B ' SUB //C=1, D=0 = A-B splitType[i] = CM_FMT_TYPE_A_SUB_B; //A-B if( m.c == MUX_1 && m.d == MUX_0 ) { continue; } //Type 5: A*C+D , ' MULTIPLYADD //B=0 = A*C+D //A=1 = (1-B) * C + D splitType[i] = CM_FMT_TYPE_A_MOD_C_ADD_D; if( m.b == MUX_0 ) { if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c); if( m.a == MUX_COMBINED ) swap(m.a, m.c); continue; } if( m.a == MUX_1 && m.b!=m.d && do_complement ) { m.a = m.b^MUX_COMPLEMENT; m.b = MUX_0; if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c); if( m.a == MUX_COMBINED ) swap(m.a, m.c); continue; } //Type 6: (A-B)*C+B Map to LERP, or BLENDALPHA //D==B splitType[i] = CM_FMT_TYPE_A_LERP_B_C; if( m.b == m.d ) { continue; } //Type 7: A-B+D //C=1 = A-B+D splitType[i] = CM_FMT_TYPE_A_SUB_B_ADD_D; if( m.c == MUX_1 ) { if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c); continue; } //Type 8: (A-B)*C splitType[i] = CM_FMT_TYPE_A_SUB_B_MOD_C; if( m.d == MUX_0 ) { continue; } if( m.c == m.d && do_complement ) // (A-B)*C+C ==> (A + B|C ) * C { m.d = MUX_0; m.b |= MUX_COMPLEMENT; continue; } if( m.a == m.d ) { splitType[i] = CM_FMT_TYPE_A_B_C_A; continue; } //Type 9: (A-B)*C+D splitType[i] = CM_FMT_TYPE_A_B_C_D; } if( (splitType[0] == CM_FMT_TYPE_D && splitType[2]!= CM_FMT_TYPE_NOT_USED ) || //Cycle 1 Color (isUsedInCycle(MUX_COMBINED,1,COLOR_CHANNEL) == false && isUsedInCycle(MUX_COMBINED,1,ALPHA_CHANNEL) == false && splitType[2]!= CM_FMT_TYPE_NOT_USED) ) { //Replace cycle 1 color with cycle 2 color because we have already replace cycle2's cmb aRGB0 = aRGB1; bRGB0 = bRGB1; cRGB0 = cRGB1; dRGB0 = dRGB1; aRGB1 = MUX_0; bRGB1 = MUX_0; cRGB1 = MUX_0; dRGB1 = MUX_COMBINED; splitType[0] = splitType[2]; splitType[2] = CM_FMT_TYPE_NOT_USED; } if( (splitType[1] == CM_FMT_TYPE_D && splitType[3]!= CM_FMT_TYPE_NOT_USED ) || //Cycle 2 Alpha ( isUsedInCycle(MUX_COMBINED,1,ALPHA_CHANNEL) == false && isUsedInCycle(MUX_COMBINED|MUX_ALPHAREPLICATE,1,COLOR_CHANNEL,MUX_MASK_WITH_ALPHA) == false && splitType[3]!= CM_FMT_TYPE_NOT_USED) ) { //Replace cycle 1 alpha with cycle 2 alpha because we have already replace cycle2's cmb aA0 = aA1; bA0 = bA1; cA0 = cA1; dA0 = dA1; aA1 = MUX_0; bA1 = MUX_0; cA1 = MUX_0; dA1 = MUX_COMBINED; splitType[1] = splitType[3]; splitType[3] = CM_FMT_TYPE_NOT_USED; } if( splitType[0] == CM_FMT_TYPE_A_MOD_C && splitType[2] == CM_FMT_TYPE_A_ADD_D ) { m_n64Combiners[0].d = (m_n64Combiners[2].a & MUX_MASK) == MUX_COMBINED ? m_n64Combiners[2].d : m_n64Combiners[2].a; splitType[0] = CM_FMT_TYPE_A_MOD_C_ADD_D; splitType[2] = CM_FMT_TYPE_NOT_USED; m_n64Combiners[2].a = MUX_0; m_n64Combiners[2].c = MUX_0; m_n64Combiners[2].d = MUX_COMBINED; } if( splitType[1] == CM_FMT_TYPE_A_MOD_C && splitType[3] == CM_FMT_TYPE_A_ADD_D ) { m_n64Combiners[1].d = (m_n64Combiners[3].a & MUX_MASK) == MUX_COMBINED ? m_n64Combiners[3].d : m_n64Combiners[3].a; splitType[1] = CM_FMT_TYPE_A_MOD_C_ADD_D; splitType[3] = CM_FMT_TYPE_NOT_USED; m_n64Combiners[3].a = MUX_0; m_n64Combiners[3].c = MUX_0; m_n64Combiners[3].d = MUX_COMBINED; } mType = max(max(max(splitType[0], splitType[1]),splitType[2]),splitType[3]); } const char* MuxGroupStr[4] = { "Color0", "Alpha0", "Color1", "Alpha1", }; char* DecodedMux::FormatStr(uint8 val, char *buf) { if( val == CM_IGNORE_BYTE ) { strcpy(buf," "); } else { strcpy(buf, translatedCombTypes[val&MUX_MASK]); if( val&MUX_ALPHAREPLICATE ) strcat(buf,"|A"); if( val&MUX_COMPLEMENT ) strcat(buf,"|C"); if( val&MUX_NEG ) strcat(buf,"|N"); } return buf; } void DecodedMux::Display(bool simplified,FILE *fp) { DecodedMux decodedMux; DecodedMux *mux; if( simplified ) { mux = this; } else { decodedMux.Decode(m_dwMux0, m_dwMux1); mux = &decodedMux; } char buf0[30]; char buf1[30]; char buf2[30]; char buf3[30]; for( int i=0; i<2; i++ ) { for(int j=0;j<2;j++) { N64CombinerType &m = mux->m_n64Combiners[i+2*j]; if( fp ) { fprintf(fp,"%s: (%s - %s) * %s + %s\n", MuxGroupStr[i+2*j], FormatStr(m.a,buf0), FormatStr(m.b,buf1), FormatStr(m.c,buf2), FormatStr(m.d,buf3)); } else { DebuggerAppendMsg("%s: (%s - %s) * %s + %s\n", MuxGroupStr[i+2*j], FormatStr(m.a,buf0), FormatStr(m.b,buf1), FormatStr(m.c,buf2), FormatStr(m.d,buf3)); } } } } int DecodedMux::HowManyConstFactors() { int n=0; if( isUsed(MUX_PRIM) ) n++; if( isUsed(MUX_ENV) ) n++; if( isUsed(MUX_LODFRAC) ) n++; if( isUsed(MUX_PRIMLODFRAC) ) n++; return n; } int DecodedMux::HowManyTextures() { int n=0; if( isUsed(MUX_TEXEL0) ) n++; if( isUsed(MUX_TEXEL1) ) n++; return n; } int DecodedMux::CountTexels(void) { int count=0; for( int i=0; i<4; i++ ) { N64CombinerType &m = m_n64Combiners[i]; count = max(count, ::CountTexel1Cycle(m)); if( count == 2 ) break; } return count; } void DecodedMux::ReplaceVal(uint8 val1, uint8 val2, int cycle, uint8 mask) { int start = 0; int end = 16; if( cycle >= 0 ) { start = cycle*4; end = start+4; } uint8* pmux = m_bytes; for( int i=start; im_maxConstants; if( !isUsedInColorChannel(MUX_SHADE) && (forceToUsed || max(splitType[0], splitType[2]) >= CM_FMT_TYPE_A_MOD_C_ADD_D) ) { int countEnv = Count(MUX_ENV, N64Cycle0RGB, mask) + Count(MUX_ENV, N64Cycle1RGB, mask); int countPrim = Count(MUX_PRIM, N64Cycle0RGB, mask) + Count(MUX_PRIM, N64Cycle1RGB, mask); if( countEnv+countPrim > 0 ) { if( countPrim >= countEnv ) { //TRACE0("Use Shade for PRIM in color channel"); ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle0RGB); ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle1RGB); m_dwShadeColorChannelFlag = MUX_PRIM; } else if( countEnv>0 ) { //TRACE0("Use Shade for ENV in color channel"); ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle0RGB); ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle1RGB); m_dwShadeColorChannelFlag = MUX_ENV; } if( isUsedInColorChannel(MUX_SHADE|MUX_ALPHAREPLICATE, mask) ) { m_dwShadeAlphaChannelFlag = m_dwShadeColorChannelFlag; ReplaceVal((uint8)m_dwShadeColorChannelFlag, MUX_SHADE, N64Cycle0Alpha); ReplaceVal((uint8)m_dwShadeColorChannelFlag, MUX_SHADE, N64Cycle1Alpha); doAlphaChannel = false; } } } if( doAlphaChannel && !isUsedInAlphaChannel(MUX_SHADE) && !isUsedInColorChannel(MUX_SHADE|MUX_ALPHAREPLICATE,MUX_MASK_WITH_ALPHA)) { int countEnv = Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) + Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask); int countPrim = Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) + Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask); if( forceToUsed || max(splitType[1], splitType[3]) >= CM_FMT_TYPE_A_MOD_C_ADD_D || (max(splitType[0], splitType[2]) >= CM_FMT_TYPE_A_MOD_C_ADD_D && countEnv+countPrim > 0 ) ) { countEnv = Count(MUX_ENV, N64Cycle0Alpha) + Count(MUX_ENV, N64Cycle1Alpha) + Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) + Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask); countPrim = Count(MUX_PRIM, N64Cycle0Alpha) + Count(MUX_PRIM, N64Cycle1Alpha) + Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) + Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask); if( countEnv+countPrim > 0 ) { if( countPrim>0 && m_dwShadeColorChannelFlag == MUX_PRIM ) { //TRACE0("Use Shade for PRIM in alpha channel"); ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle0Alpha); ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle1Alpha); ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask); ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask); m_dwShadeAlphaChannelFlag = MUX_PRIM; } else if( countEnv>0 && m_dwShadeColorChannelFlag == MUX_ENV ) { //TRACE0("Use Shade for PRIM in alpha channel"); ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle0Alpha); ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle1Alpha); ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask); ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask); m_dwShadeAlphaChannelFlag = MUX_ENV; } else if( countPrim >= countEnv ) { //TRACE0("Use Shade for PRIM in alpha channel"); ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle0Alpha); ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle1Alpha); ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask); ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask); m_dwShadeAlphaChannelFlag = MUX_PRIM; } else if( countEnv>0 ) { //TRACE0("Use Shade for ENV in alpha channel"); ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle0Alpha); ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle1Alpha); ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask); ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask); m_dwShadeAlphaChannelFlag = MUX_ENV; } } } } } void DecodedMux::UseTextureForConstant(void) { int numofconst = HowManyConstFactors(); int numOftex = HowManyTextures(); if( numofconst > m_maxConstants && numOftex < m_maxTextures ) { // We can use a texture for a constant for( int i=0; i<2 && numofconst > m_maxConstants ; i++ ) { if( isUsed(MUX_TEXEL0+i) ) { continue; // can not use this texture } if( isUsed(MUX_PRIM) ) { ReplaceVal(MUX_PRIM, MUX_TEXEL0+i); m_ColorTextureFlag[i] = MUX_PRIM; numofconst--; continue; } if( isUsed(MUX_ENV) ) { ReplaceVal(MUX_ENV, MUX_TEXEL0+i); m_ColorTextureFlag[i] = MUX_ENV; numofconst--; continue; } if( isUsed(MUX_LODFRAC) ) { ReplaceVal(MUX_LODFRAC, MUX_TEXEL0+i); m_ColorTextureFlag[i] = MUX_LODFRAC; numofconst--; continue; } if( isUsed(MUX_PRIMLODFRAC) ) { ReplaceVal(MUX_PRIMLODFRAC, MUX_TEXEL0+i); m_ColorTextureFlag[i] = MUX_PRIMLODFRAC; numofconst--; continue; } } } } void DecodedMuxForOGL14V2::UseTextureForConstant(void) { bool envused = isUsed(MUX_ENV); bool lodused = isUsed(MUX_LODFRAC); int numofconst = 0; if( envused ) numofconst++; if( lodused ) numofconst++; int numOftex = HowManyTextures(); if( numofconst > 0 && numOftex < 2 ) { // We can use a texture for a constant for( int i=0; i<2 && numofconst > 0 ; i++ ) { if( isUsed(MUX_TEXEL0+i) ) { continue; // can not use this texture } if( envused ) { ReplaceVal(MUX_ENV, MUX_TEXEL0+i); m_ColorTextureFlag[i] = MUX_ENV; numofconst--; envused = false; continue; } if( isUsed(MUX_LODFRAC) ) { ReplaceVal(MUX_LODFRAC, MUX_TEXEL0+i); m_ColorTextureFlag[i] = MUX_LODFRAC; numofconst--; continue; } if( isUsed(MUX_PRIMLODFRAC) ) { ReplaceVal(MUX_PRIMLODFRAC, MUX_TEXEL0+i); m_ColorTextureFlag[i] = MUX_PRIMLODFRAC; numofconst--; continue; } } } } #ifdef DEBUGGER extern const char *translatedCombTypes[]; void DecodedMux::DisplayMuxString(const char *prompt) { DebuggerAppendMsg("//Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName); Display(false); TRACE0("\n"); } void DecodedMux::DisplaySimpliedMuxString(const char *prompt) { DebuggerAppendMsg("//Simplied Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName); DebuggerAppendMsg("Simplied DWORDs=%08X, %08X, %08X, %08X", m_dWords[0],m_dWords[1],m_dWords[2],m_dWords[3]); Display(true); DebuggerAppendMsg("Simplfied type: %s", muxTypeStrs[mType]); if( m_dwShadeColorChannelFlag != 0 ) { if( m_dwShadeColorChannelFlag == MUX_ENV ) TRACE0("Shade = ENV in color channel") else if( m_dwShadeColorChannelFlag == MUX_PRIM ) TRACE0("Shade = PRIM in color channel") else if( m_dwShadeColorChannelFlag == MUX_LODFRAC ) TRACE0("Shade = MUX_LODFRAC in color channel") else if( m_dwShadeColorChannelFlag == MUX_PRIMLODFRAC ) TRACE0("Shade = MUX_PRIMLODFRAC in color channel") else DisplayConstantsWithShade(m_dwShadeColorChannelFlag,COLOR_CHANNEL); } if( m_dwShadeAlphaChannelFlag != 0 ) { if( m_dwShadeAlphaChannelFlag == MUX_ENV ) TRACE0("Shade = ENV in alpha channel") else if( m_dwShadeAlphaChannelFlag == MUX_PRIM ) TRACE0("Shade = PRIM in alpha channel") else if( m_dwShadeAlphaChannelFlag == MUX_LODFRAC ) TRACE0("Shade = MUX_LODFRAC in alpha channel") else if( m_dwShadeAlphaChannelFlag == MUX_PRIMLODFRAC ) TRACE0("Shade = MUX_PRIMLODFRAC in alpha channel") else DisplayConstantsWithShade(m_dwShadeAlphaChannelFlag,ALPHA_CHANNEL); } for( int i=0; i<2; i++ ) { if( m_ColorTextureFlag[i] != 0 ) { if( m_ColorTextureFlag[i] == MUX_ENV ) TRACE1("Tex %d = ENV", i) else if( m_ColorTextureFlag[i] == MUX_PRIM ) TRACE1("Tex %d = PRIM", i) else if( m_ColorTextureFlag[i] == MUX_LODFRAC ) TRACE1("Tex %d = MUX_LODFRAC", i) else if( m_ColorTextureFlag[i] == MUX_PRIMLODFRAC ) TRACE1("Tex %d = MUX_PRIMLODFRAC", i) } } TRACE0("\n"); } void DecodedMux::DisplayConstantsWithShade(uint32 flag,CombineChannel channel) { DebuggerAppendMsg("Shade = %08X in %s channel",flag,channel==COLOR_CHANNEL?"color":"alpha"); } #else extern const char *translatedCombTypes[]; void DecodedMux::LogMuxString(const char *prompt, FILE *fp) { fprintf(fp,"//Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName); Display(false,fp); TRACE0("\n"); } void DecodedMux::LogSimpliedMuxString(const char *prompt, FILE *fp) { fprintf(fp,"//Simplied Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName); fprintf(fp,"Simplied DWORDs=%08X, %08X, %08X, %08X\n", m_dWords[0],m_dWords[1],m_dWords[2],m_dWords[3]); Display(true,fp); fprintf(fp,"Simplfied type: %s", muxTypeStrs[mType]); if( m_dwShadeColorChannelFlag != 0 ) { if( m_dwShadeColorChannelFlag == MUX_ENV ) TRACE0("Shade = ENV in color channel") else if( m_dwShadeColorChannelFlag == MUX_PRIM ) TRACE0("Shade = PRIM in color channel") else if( m_dwShadeColorChannelFlag == MUX_LODFRAC ) TRACE0("Shade = MUX_LODFRAC in color channel") else if( m_dwShadeColorChannelFlag == MUX_PRIMLODFRAC ) TRACE0("Shade = MUX_PRIMLODFRAC in color channel") else LogConstantsWithShade(m_dwShadeColorChannelFlag,COLOR_CHANNEL,fp); } if( m_dwShadeAlphaChannelFlag != 0 ) { if( m_dwShadeAlphaChannelFlag == MUX_ENV ) TRACE0("Shade = ENV in alpha channel") else if( m_dwShadeAlphaChannelFlag == MUX_PRIM ) TRACE0("Shade = PRIM in alpha channel") else if( m_dwShadeAlphaChannelFlag == MUX_LODFRAC ) TRACE0("Shade = MUX_LODFRAC in alpha channel") else if( m_dwShadeAlphaChannelFlag == MUX_PRIMLODFRAC ) TRACE0("Shade = MUX_PRIMLODFRAC in alpha channel") else LogConstantsWithShade(m_dwShadeAlphaChannelFlag,ALPHA_CHANNEL,fp); } for( int i=0; i<2; i++ ) { if( m_ColorTextureFlag[i] != 0 ) { if( m_ColorTextureFlag[i] == MUX_ENV ) TRACE1("Tex %d = ENV", i) else if( m_ColorTextureFlag[i] == MUX_PRIM ) TRACE1("Tex %d = PRIM", i) else if( m_ColorTextureFlag[i] == MUX_LODFRAC ) TRACE1("Tex %d = MUX_LODFRAC", i) else if( m_ColorTextureFlag[i] == MUX_PRIMLODFRAC ) TRACE1("Tex %d = MUX_PRIMLODFRAC", i) } } TRACE0("\n"); } void DecodedMux::LogConstantsWithShade(uint32 flag,CombineChannel channel, FILE *fp) { fprintf(fp,"Shade = %08X in %s channel",flag,channel==COLOR_CHANNEL?"color":"alpha"); } #endif void DecodedMux::To_AB_Add_CD_Format(void) // Use by TNT,Geforce { // This function should be called after calling reformat // This function will not be called by default, can be called optionally // by TNT/Geforce combiner compilers for( int i=0; i<2; i++ ) { N64CombinerType &m0 = m_n64Combiners[i]; N64CombinerType &m1 = m_n64Combiners[i+2]; switch( splitType[i] ) { case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D can not map very well in 1 stage if( splitType[i+2] == CM_FMT_TYPE_NOT_USED ) { m1.a = m0.d; m1.d = MUX_COMBINED; splitType[i+2] = CM_FMT_TYPE_A_ADD_D; m0.d = MUX_0; splitType[i] = CM_FMT_TYPE_A_SUB_B; } else if( splitType[i+2] == CM_FMT_TYPE_A_MOD_C ) { if( (m1.c&MUX_MASK) == MUX_COMBINED ) swap(m1.a, m1.c); m1.b = m1.d = m1.c; m1.c = (m0.d | (m1.a & (~MUX_MASK))); splitType[i+2] = CM_FMT_TYPE_AB_ADD_CD; m0.d = MUX_0; splitType[i] = CM_FMT_TYPE_A_SUB_B; } break; case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C can not map very well in 1 stage m0.d = m0.b; m0.b = m0.c; splitType[i] = CM_FMT_TYPE_AB_SUB_CD; break; case CM_FMT_TYPE_A_ADD_B_MOD_C: // = (A+B)*C can not map very well in 1 stage m0.d = m0.b; m0.b = m0.c; splitType[i] = CM_FMT_TYPE_AB_ADD_CD; break; case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D case CM_FMT_TYPE_A_B_C_A: // = (A-B)*C+D if( splitType[i+2] == CM_FMT_TYPE_NOT_USED ) { m1.a = m0.d; m1.d = MUX_COMBINED; splitType[i+2] = CM_FMT_TYPE_A_ADD_D; m0.d = m0.b; m0.b = m0.c; splitType[i] = CM_FMT_TYPE_AB_SUB_CD; } else if( splitType[i+2] == CM_FMT_TYPE_A_MOD_C ) { if( (m1.c&MUX_MASK) == MUX_COMBINED ) swap(m1.a, m1.c); m1.b = m1.d = m1.c; m1.c = (m0.d | (m1.a & (~MUX_MASK))); splitType[i+2] = CM_FMT_TYPE_AB_ADD_CD; m0.d = m0.b; m0.b = m0.c; splitType[i] = CM_FMT_TYPE_AB_ADD_CD; } break; default: break; } } } void DecodedMux::To_AB_Add_C_Format(void) // Use by ATI Radeon { // This function should be called after calling reformat // This function will not be called by default, can be called optionally // by ATI combiner compilers } void DecodedMux::CheckCombineInCycle1(void) { if( isUsedInCycle(MUX_COMBINED,0,COLOR_CHANNEL) ) { ReplaceVal(MUX_COMBINED, MUX_SHADE, 0); } if( isUsedInCycle(MUX_COMBALPHA,0,COLOR_CHANNEL) ) { ReplaceVal(MUX_COMBALPHA, MUX_SHADE|MUX_ALPHAREPLICATE, 0); } if( isUsedInCycle(MUX_COMBINED,0,ALPHA_CHANNEL) ) { if( cA0 == MUX_COMBINED && cRGB0 == MUX_LODFRAC && bRGB0 == dRGB0 && bA0 == dA0 ) { cA0 = MUX_LODFRAC; } else { ReplaceVal(MUX_COMBINED, MUX_SHADE, 1); } } if( isUsedInCycle(MUX_COMBALPHA,0,ALPHA_CHANNEL) ) { ReplaceVal(MUX_COMBALPHA, MUX_SHADE, 1); } } void DecodedMux::SplitComplexStages() { for( int i=0; i<2; i++) // Color channel and alpha channel { if( splitType[i+2] != CM_FMT_TYPE_NOT_USED ) continue; N64CombinerType &m = m_n64Combiners[i]; N64CombinerType &m2 = m_n64Combiners[i+2]; switch( splitType[i] ) { case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D can mapped to MULTIPLYADD(arg1,arg2,arg0) m2.a = m.d; m2.d = MUX_COMBINED; m2.c = MUX_1; m2.b = 0; splitType[i+2] = CM_FMT_TYPE_A_ADD_D; m.d = MUX_0; splitType[i] = CM_FMT_TYPE_A_MOD_C; break; case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D can not map very well in 1 stage m2.a = m.d; m2.d = MUX_COMBINED; m2.c = MUX_1; m2.b=0; splitType[i+2] = CM_FMT_TYPE_A_ADD_D; m.d = MUX_0; splitType[i] = CM_FMT_TYPE_A_SUB_B; break; case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C can not map very well in 1 stage m2.a = m.c; m2.c = MUX_COMBINED; m2.d = m2.b=0; splitType[i+2] = CM_FMT_TYPE_A_MOD_C; m.c = MUX_1; splitType[i] = CM_FMT_TYPE_A_SUB_B; break; case CM_FMT_TYPE_A_ADD_B_MOD_C: // = (A+B)*C can not map very well in 1 stage m2.a = m.c; m2.c = MUX_COMBINED; m2.d = m2.b = 0; splitType[i+2] = CM_FMT_TYPE_A_MOD_C; m.c = MUX_1; m.d = m.b; m.b = MUX_0; splitType[i] = CM_FMT_TYPE_A_ADD_D; break; case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D can not map very well in 1 stage m2.a = m.d; m2.d = MUX_COMBINED; m2.c = MUX_1; m2.b = 0; splitType[i+2] = CM_FMT_TYPE_A_ADD_D; m.d = MUX_0; splitType[i] = CM_FMT_TYPE_A_SUB_B_MOD_C; break; case CM_FMT_TYPE_A_B_C_A: // = (A-B)*C+A can not map very well in 1 stage m2.a = m.d; m2.d = MUX_COMBINED; m2.c = MUX_1; m2.b = 0; splitType[i+2] = CM_FMT_TYPE_A_ADD_D; m.d = MUX_0; splitType[i] = CM_FMT_TYPE_A_SUB_B_MOD_C; break; default: break; } } //Reformat(); //UseShadeForConstant(); } void DecodedMux::ConvertLODFracTo0() { ReplaceVal(MUX_LODFRAC,MUX_0); ReplaceVal(MUX_PRIMLODFRAC,MUX_0); } void DecodedMux::Hack(void) { if( options.enableHackForGames == HACK_FOR_TONYHAWK ) { if( gRSP.curTile == 1 ) { ReplaceVal(MUX_TEXEL1, MUX_TEXEL0); } } else if( options.enableHackForGames == HACK_FOR_ZELDA || options.enableHackForGames == HACK_FOR_ZELDA_MM) { if( m_dwMux1 == 0xfffd9238 && m_dwMux0 == 0x00ffadff ) { ReplaceVal(MUX_TEXEL1, MUX_TEXEL0); } else if( m_dwMux1 == 0xff5bfff8 && m_dwMux0 == 0x00121603 ) { // The Zelda road trace ReplaceVal(MUX_TEXEL1, MUX_0); } } else if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS ) { if( m_dwMux1 == 0xffebdbc0 && m_dwMux0 == 0x00ffb9ff ) { // Player shadow //m_decodedMux.dRGB0 = MUX_TEXEL0; //m_decodedMux.dRGB1 = MUX_COMBINED; cA1 = MUX_TEXEL0; } } else if( options.enableHackForGames == HACK_FOR_MARIO_GOLF ) { // Hack for Mario Golf if( m_dwMux1 == 0xf1ffca7e || m_dwMux0 == 0x00115407 ) { // The grass ReplaceVal(MUX_TEXEL0, MUX_TEXEL1); } } else if( options.enableHackForGames == HACK_FOR_TOPGEARRALLY ) { //Mux=0x00317e025ffef3fa Used in TOP GEAR RALLY //Color0: (PRIM - ENV) * TEXEL1 + ENV //Color1: (COMBINED - 0) * TEXEL1 + 0 //Alpha0: (0 - 0) * 0 + TEXEL0 //Alpha1: (0 - 0) * 0 + TEXEL1 if( m_dwMux1 == 0x5ffef3fa || m_dwMux0 == 0x00317e02 ) { // The grass //ReplaceVal(MUX_TEXEL0, MUX_TEXEL1); dA1 = MUX_COMBINED; //aA1 = MUX_COMBINED; //cA1 = MUX_TEXEL1; //dA1 = MUX_0; cRGB1 = MUX_TEXEL0; } } } mupen64plus-video-rice-src-2.0/src/DecodedMux.h0000644000000000000000000001613012165031100017463 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _DECODEDMUX_H_ #define _DECODEDMUX_H_ #include #include #include "typedefs.h" #include "CombinerDefs.h" typedef enum { N64Cycle0RGB=0, N64Cycle0Alpha=1, N64Cycle1RGB=2, N64Cycle1Alpha=3, } N64StageNumberType; typedef union { struct { uint32 dwMux0; uint32 dwMux1; }; uint64 Mux64; } MuxType; typedef struct { MuxType ori_mux; MuxType simple_mux; } SimpleMuxMapType; class DecodedMux { public: union { struct { uint8 aRGB0; uint8 bRGB0; uint8 cRGB0; uint8 dRGB0; uint8 aA0; uint8 bA0; uint8 cA0; uint8 dA0; uint8 aRGB1; uint8 bRGB1; uint8 cRGB1; uint8 dRGB1; uint8 aA1; uint8 bA1; uint8 cA1; uint8 dA1; }; uint8 m_bytes[16]; uint32 m_dWords[4]; N64CombinerType m_n64Combiners[4]; }; union { struct { uint32 m_dwMux0; uint32 m_dwMux1; }; uint64 m_u64Mux; }; CombinerFormatType splitType[4]; CombinerFormatType mType; uint32 m_dwShadeColorChannelFlag; uint32 m_dwShadeAlphaChannelFlag; uint32 m_ColorTextureFlag[2]; // I may use a texture to represent a constant color // when there are more constant colors are used than // the system can support bool m_bShadeIsUsed[2]; // 0 for color channel, 1 for alpha channel bool m_bTexel0IsUsed; bool m_bTexel1IsUsed; int m_maxConstants; // OpenGL 1.1 does not really support a constant color in combiner // must use shade for constants; int m_maxTextures; // 1 or 2 void Decode(uint32 dwMux0, uint32 dwMux1); virtual void Hack(void); bool isUsed(uint8 fac, uint8 mask=MUX_MASK); bool isUsedInAlphaChannel(uint8 fac, uint8 mask=MUX_MASK); bool isUsedInColorChannel(uint8 fac, uint8 mask=MUX_MASK); bool isUsedInCycle(uint8 fac, int cycle, CombineChannel channel, uint8 mask=MUX_MASK); bool isUsedInCycle(uint8 fac, int cycle, uint8 mask=MUX_MASK); uint32 GetCycle(int cycle, CombineChannel channel); uint32 GetCycle(int cycle); CombinerFormatType GetCombinerFormatType(uint32 cycle); void Display(bool simplified=true, FILE *fp=NULL); static char* FormatStr(uint8 val, char *buf); void CheckCombineInCycle1(void); virtual void Simplify(void); virtual void Reformat(bool do_complement = true); virtual void To_AB_Add_CD_Format(void); // Use by TNT,Geforce virtual void To_AB_Add_C_Format(void); // Use by ATI Radeon virtual void MergeShadeWithConstants(void); virtual void MergeShadeWithConstantsInChannel(CombineChannel channel); virtual void MergeConstants(void); virtual void UseShadeForConstant(void); virtual void UseTextureForConstant(void); void ConvertComplements(); int HowManyConstFactors(); int HowManyTextures(); void MergeConstFactors(); virtual void SplitComplexStages(); // Only used if the combiner supports more than 1 stages void ConvertLODFracTo0(); void ReplaceVal(uint8 val1, uint8 val2, int cycle= -1, uint8 mask = MUX_MASK); void Replace1Val(uint8 &val1, const uint8 val2, uint8 mask = MUX_MASK) { val1 &= (~mask); val1 |= val2; } int CountTexels(void); int Count(uint8 val, int cycle= -1, uint8 mask = MUX_MASK); #ifdef DEBUGGER void DisplayMuxString(const char *prompt); void DisplaySimpliedMuxString(const char *prompt); void DisplayConstantsWithShade(uint32 flag,CombineChannel channel); #else void DisplayMuxString(const char *prompt) {} void DisplaySimpliedMuxString(const char *prompt){} void DisplayConstantsWithShade(uint32 flag,CombineChannel channel){} void LogMuxString(const char *prompt, FILE *fp); void LogSimpliedMuxString(const char *prompt, FILE *fp); void LogConstantsWithShade(uint32 flag,CombineChannel channel, FILE *fp); #endif virtual DecodedMux& operator=(const DecodedMux& mux) { m_dWords[0] = mux.m_dWords[0]; m_dWords[1] = mux.m_dWords[1]; m_dWords[2] = mux.m_dWords[2]; m_dWords[3] = mux.m_dWords[3]; m_u64Mux = mux.m_u64Mux; splitType[0] = mux.splitType[0]; splitType[1] = mux.splitType[1]; splitType[2] = mux.splitType[2]; splitType[3] = mux.splitType[3]; mType = mux.mType; m_dwShadeColorChannelFlag = mux.m_dwShadeColorChannelFlag; m_dwShadeAlphaChannelFlag = mux.m_dwShadeAlphaChannelFlag; m_bShadeIsUsed[0] = mux.m_bShadeIsUsed[0]; m_bShadeIsUsed[1] = mux.m_bShadeIsUsed[1]; m_bTexel0IsUsed = mux.m_bTexel0IsUsed; m_bTexel1IsUsed = mux.m_bTexel1IsUsed; m_maxConstants = mux.m_maxConstants; m_maxTextures = mux.m_maxTextures; m_ColorTextureFlag[0] = mux.m_ColorTextureFlag[0]; m_ColorTextureFlag[1] = mux.m_ColorTextureFlag[1]; return *this; } static inline bool IsConstFactor(uint8 val) { uint8 v = val&MUX_MASK; return( v == MUX_0 || v == MUX_1 || v == MUX_PRIM || v == MUX_ENV || v == MUX_LODFRAC || v == MUX_PRIMLODFRAC ); } DecodedMux() { memset(m_bytes, 0, sizeof(m_bytes)); mType=CM_FMT_TYPE_NOT_CHECKED; for( int i=0; i<4; i++ ) { splitType[i] = CM_FMT_TYPE_NOT_CHECKED; } m_maxConstants = 1; m_maxTextures = 2; } virtual ~DecodedMux() {} }; class DecodedMuxForPixelShader : public DecodedMux { public: virtual void Simplify(void); void SplitComplexStages() {}; }; class DecodedMuxForSemiPixelShader : public DecodedMux { public: void Reset(void); }; class DecodedMuxForOGL14V2 : public DecodedMuxForPixelShader { public: virtual void Simplify(void); void UseTextureForConstant(void); }; typedef struct { bool bFurtherFormatForOGL2; bool bUseShadeForConstants; bool bUseTextureForConstants; bool bUseMoreThan2TextureForConstants; bool bReformatToAB_CD; bool bAllowHack; bool bAllowComplimentary; bool bCheckCombineInCycle1; bool bSetLODFracTo0; bool bMergeShadeWithConstants; bool bSplitComplexStage; bool bReformatAgainWithTwoTexels; } MuxConverterOptions; #endif mupen64plus-video-rice-src-2.0/src/DeviceBuilder.cpp0000644000000000000000000002707412165031100020514 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "osal_opengl.h" #include "DeviceBuilder.h" #include "FrameBuffer.h" #include "OGLCombiner.h" #include "OGLDebug.h" #include "OGLExtRender.h" #include "OGLGraphicsContext.h" #include "OGLTexture.h" #if SDL_VIDEO_OPENGL #include "OGLCombinerNV.h" #include "OGLCombinerTNT2.h" #include "OGLExtensions.h" #include "OGLFragmentShaders.h" #elif SDL_VIDEO_OPENGL_ES2 #include "OGLES2FragmentShaders.h" #endif //======================================================================== CDeviceBuilder* CDeviceBuilder::m_pInstance=NULL; SupportedDeviceType CDeviceBuilder::m_deviceType = DIRECTX_DEVICE; SupportedDeviceType CDeviceBuilder::m_deviceGeneralType = DIRECTX_DEVICE; CDeviceBuilder* CDeviceBuilder::GetBuilder(void) { if( m_pInstance == NULL ) CreateBuilder(m_deviceType); return m_pInstance; } void CDeviceBuilder::SelectDeviceType(SupportedDeviceType type) { if( type != m_deviceType && m_pInstance != NULL ) { DeleteBuilder(); } CDeviceBuilder::m_deviceType = type; switch(type) { case OGL_DEVICE: case OGL_1_1_DEVICE: case OGL_1_2_DEVICE: case OGL_1_3_DEVICE: case OGL_1_4_DEVICE: case OGL_1_4_V2_DEVICE: case OGL_TNT2_DEVICE: case NVIDIA_OGL_DEVICE: case OGL_FRAGMENT_PROGRAM: CDeviceBuilder::m_deviceGeneralType = OGL_DEVICE; break; default: break; } } SupportedDeviceType CDeviceBuilder::GetDeviceType(void) { return CDeviceBuilder::m_deviceType; } SupportedDeviceType CDeviceBuilder::GetGeneralDeviceType(void) { return CDeviceBuilder::m_deviceGeneralType; } CDeviceBuilder* CDeviceBuilder::CreateBuilder(SupportedDeviceType type) { if( m_pInstance == NULL ) { switch( type ) { case OGL_DEVICE: case OGL_1_1_DEVICE: case OGL_1_2_DEVICE: case OGL_1_3_DEVICE: case OGL_1_4_DEVICE: case OGL_1_4_V2_DEVICE: case OGL_TNT2_DEVICE: case NVIDIA_OGL_DEVICE: case OGL_FRAGMENT_PROGRAM: m_pInstance = new OGLDeviceBuilder(); break; default: DebugMessage(M64MSG_ERROR, "CreateBuilder: unknown OGL device type"); exit(1); } SAFE_CHECK(m_pInstance); } return m_pInstance; } void CDeviceBuilder::DeleteBuilder(void) { delete m_pInstance; m_pInstance = NULL; } CDeviceBuilder::CDeviceBuilder() : m_pRender(NULL), m_pGraphicsContext(NULL), m_pColorCombiner(NULL), m_pAlphaBlender(NULL) { } CDeviceBuilder::~CDeviceBuilder() { DeleteGraphicsContext(); DeleteRender(); DeleteColorCombiner(); DeleteAlphaBlender(); } void CDeviceBuilder::DeleteGraphicsContext(void) { if( m_pGraphicsContext != NULL ) { delete m_pGraphicsContext; CGraphicsContext::g_pGraphicsContext = m_pGraphicsContext = NULL; } SAFE_DELETE(g_pFrameBufferManager); } void CDeviceBuilder::DeleteRender(void) { if( m_pRender != NULL ) { delete m_pRender; CRender::g_pRender = m_pRender = NULL; CRender::gRenderReferenceCount = 0; } } void CDeviceBuilder::DeleteColorCombiner(void) { if( m_pColorCombiner != NULL ) { delete m_pColorCombiner; m_pColorCombiner = NULL; } } void CDeviceBuilder::DeleteAlphaBlender(void) { if( m_pAlphaBlender != NULL ) { delete m_pAlphaBlender; m_pAlphaBlender = NULL; } } //======================================================================== CGraphicsContext * OGLDeviceBuilder::CreateGraphicsContext(void) { if( m_pGraphicsContext == NULL ) { m_pGraphicsContext = new COGLGraphicsContext(); SAFE_CHECK(m_pGraphicsContext); CGraphicsContext::g_pGraphicsContext = m_pGraphicsContext; } g_pFrameBufferManager = new FrameBufferManager; return m_pGraphicsContext; } CRender * OGLDeviceBuilder::CreateRender(void) { if( m_pRender == NULL ) { if( CGraphicsContext::g_pGraphicsContext == NULL && CGraphicsContext::g_pGraphicsContext->Ready() ) { DebugMessage(M64MSG_ERROR, "Can not create ColorCombiner before creating and initializing GraphicsContext"); m_pRender = NULL; SAFE_CHECK(m_pRender); } COGLGraphicsContext &context = *((COGLGraphicsContext*)CGraphicsContext::g_pGraphicsContext); if( context.m_bSupportMultiTexture ) { // OGL extension render m_pRender = new COGLExtRender(); } else { // Basic OGL Render m_pRender = new OGLRender(); } SAFE_CHECK(m_pRender); CRender::g_pRender = m_pRender; } return m_pRender; } CTexture * OGLDeviceBuilder::CreateTexture(uint32 dwWidth, uint32 dwHeight, TextureUsage usage) { COGLTexture *txtr = new COGLTexture(dwWidth, dwHeight, usage); if( txtr->m_pTexture == NULL ) { delete txtr; TRACE0("Cannot create new texture, out of video memory"); return NULL; } else return txtr; } CColorCombiner * OGLDeviceBuilder::CreateColorCombiner(CRender *pRender) { if( m_pColorCombiner == NULL ) { if( CGraphicsContext::g_pGraphicsContext == NULL && CGraphicsContext::g_pGraphicsContext->Ready() ) { DebugMessage(M64MSG_ERROR, "Can not create ColorCombiner before creating and initializing GraphicsContext"); } else { m_deviceType = (SupportedDeviceType)options.OpenglRenderSetting; #if SDL_VIDEO_OPENGL if (m_deviceType == NVIDIA_OGL_DEVICE && !bNvidiaExtensionsSupported) { DebugMessage(M64MSG_WARNING, "Your video card does not support Nvidia OpenGL extensions. Falling back to auto device."); m_deviceType = OGL_DEVICE; } if( m_deviceType == OGL_DEVICE ) // Best fit { GLint maxUnit = 2; COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,&maxUnit); OPENGL_CHECK_ERRORS; if( pcontext->IsExtensionSupported("GL_ARB_fragment_program") ) { m_pColorCombiner = new COGL_FragmentProgramCombiner(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: Fragment Program"); } else if( pcontext->IsExtensionSupported("GL_NV_texture_env_combine4") || pcontext->IsExtensionSupported("GL_NV_register_combiners") ) { m_pColorCombiner = new COGLColorCombinerNvidia(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: NVidia"); } else if( pcontext->IsExtensionSupported("GL_NV_texture_env_combine4") ) { m_pColorCombiner = new COGLColorCombinerTNT2(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: TNT2"); } else if( pcontext->IsExtensionSupported("GL_EXT_texture_env_combine") || pcontext->IsExtensionSupported("GL_ARB_texture_env_combine") ) { if( pcontext->IsExtensionSupported("GL_ARB_texture_env_crossbar") ) { if( maxUnit > 2 ) { m_pColorCombiner = new COGLColorCombiner4v2(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: OGL 1.4 version 2"); } else { m_pColorCombiner = new COGLColorCombiner4(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: OGL 1.4"); } } else { if( maxUnit > 2 ) { m_pColorCombiner = new COGLColorCombiner4v2(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: OGL 1.4 version 2 (w/o env crossbar)"); } else { m_pColorCombiner = new COGLColorCombiner2(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: OGL 1.2/1.3"); } } } else { m_pColorCombiner = new COGLColorCombiner(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: Basic OGL"); } } else { switch(m_deviceType) { case OGL_1_1_DEVICE: m_pColorCombiner = new COGLColorCombiner(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: Basic OGL"); break; case OGL_1_2_DEVICE: case OGL_1_3_DEVICE: m_pColorCombiner = new COGLColorCombiner2(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: OGL 1.2/1.3"); break; case OGL_1_4_DEVICE: m_pColorCombiner = new COGLColorCombiner4(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: OGL 1.4"); break; case OGL_1_4_V2_DEVICE: m_pColorCombiner = new COGLColorCombiner4v2(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: OGL 1.4 Version 2"); break; case OGL_TNT2_DEVICE: m_pColorCombiner = new COGLColorCombinerTNT2(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: TNT2"); break; case NVIDIA_OGL_DEVICE: m_pColorCombiner = new COGLColorCombinerNvidia(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: Nvidia"); break; case OGL_FRAGMENT_PROGRAM: m_pColorCombiner = new COGL_FragmentProgramCombiner(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: Fragment Program"); break; default: break; } } #elif SDL_VIDEO_OPENGL_ES2 m_pColorCombiner = new COGL_FragmentProgramCombiner(pRender); DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: Fragment Program"); #endif } SAFE_CHECK(m_pColorCombiner); } return m_pColorCombiner; } CBlender * OGLDeviceBuilder::CreateAlphaBlender(CRender *pRender) { if( m_pAlphaBlender == NULL ) { m_pAlphaBlender = new COGLBlender(pRender); SAFE_CHECK(m_pAlphaBlender); } return m_pAlphaBlender; } mupen64plus-video-rice-src-2.0/src/DeviceBuilder.h0000644000000000000000000000507112165031100020152 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _DEVICE_BUILDER_H #define _DEVICE_BUILDER_H #include "Blender.h" #include "Combiner.h" #include "Config.h" #include "GraphicsContext.h" #include "TextureManager.h" //======================================================================== class CDeviceBuilder { public: virtual CGraphicsContext * CreateGraphicsContext(void)=0; virtual CRender * CreateRender(void)=0; virtual CTexture * CreateTexture(uint32 dwWidth, uint32 dwHeight, TextureUsage usage = AS_NORMAL)=0; virtual CColorCombiner * CreateColorCombiner(CRender *pRender)=0; virtual CBlender * CreateAlphaBlender(CRender *pRender)=0; void DeleteGraphicsContext(void); void DeleteRender(void); void DeleteColorCombiner(void); void DeleteAlphaBlender(void); static void DeleteBuilder(void); static CDeviceBuilder* GetBuilder(void); static void SelectDeviceType(SupportedDeviceType type); static SupportedDeviceType GetDeviceType(void); static SupportedDeviceType GetGeneralDeviceType(void); static SupportedDeviceType m_deviceGeneralType; protected: CDeviceBuilder(); virtual ~CDeviceBuilder(); static CDeviceBuilder* CreateBuilder(SupportedDeviceType type); static SupportedDeviceType m_deviceType; static CDeviceBuilder* m_pInstance; CRender* m_pRender; CGraphicsContext* m_pGraphicsContext; CColorCombiner* m_pColorCombiner; CBlender* m_pAlphaBlender; }; class OGLDeviceBuilder : public CDeviceBuilder { friend class CDeviceBuilder; public: CGraphicsContext * CreateGraphicsContext(void); CRender * CreateRender(void); CTexture * CreateTexture(uint32 dwWidth, uint32 dwHeight, TextureUsage usage = AS_NORMAL); CColorCombiner * CreateColorCombiner(CRender *pRender); CBlender * CreateAlphaBlender(CRender *pRender); protected: OGLDeviceBuilder() {}; virtual ~OGLDeviceBuilder() {}; }; #endif mupen64plus-video-rice-src-2.0/src/DirectXDecodedMux.cpp0000644000000000000000000001315612165031100021306 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Combiner.h" #include "DirectXDecodedMux.h" #include #ifdef min #undef min #endif #ifdef max #undef max #endif //This function is called after Reformat to handel two texels in 1 cycle, D3D can not handle //two texels in a single stage, the texels must be splited into multiple stages void CDirectXDecodedMux::ReformatAgainWithTwoTexels(void) { if( CountTexels() < 2 ) return; for( int i=0; i<2; i++ ) { N64CombinerType &m = m_n64Combiners[i]; if( CountTexel1Cycle(m) < 2 ) { continue; //1st cycle does not have two texels, do nothing here } else { N64CombinerType &m2 = m_n64Combiners[i+2]; if( splitType[i] == CM_FMT_TYPE_A_MOD_C ) //Texel0*Texel1 { if( splitType[i+2] == CM_FMT_TYPE_NOT_USED ) { //Change Texel1*Texel0 to (SEL(tex1), MOD(tex0)) m.d = m.a; m.a = MUX_0; m2.a = m.c; m2.c = MUX_COMBINED; m2.d = m2.b = MUX_0; m.c = MUX_0; splitType[i+2] = CM_FMT_TYPE_A_MOD_C; splitType[i] = CM_FMT_TYPE_D; } else if( splitType[i+2] == CM_FMT_TYPE_A_MOD_C ) { if( m2.a == MUX_COMBINED ) { swap(m2.a, m2.c); } if( m2.a != MUX_TEXEL0 && m2.a != MUX_TEXEL1 ) { //cool, we can swap m2.a to cycle1 and swap texel from cycle 1 to cycle 2 swap(m.a, m2.a); } else { if( m.a == m2.a ) { swap(m.c, m2.a); } else { swap(m.a, m2.a); } } } else if( splitType[i+2] == CM_FMT_TYPE_A_MOD_C_ADD_D ) { if( m2.a == MUX_COMBINED ) { swap(m2.a, m2.c); } if( m2.c == MUX_COMBINED && m2.d != MUX_COMBINED ) { //Cycle1: texel0*texel1 //Cycle2: a*cmd+d if( m2.a != MUX_TEXEL0 && m2.a != MUX_TEXEL1 ) { //cool, we can swap m2.a to cycle1 and swap texel from cycle 1 to cycle 2 swap(m.a, m2.a); } else { if( m.a == m2.a ) { swap(m.c, m2.a); } else { swap(m.a, m2.a); } } } } else if( splitType[i] == CM_FMT_TYPE_A_ADD_D ) //Texel0+Texel1 { if( splitType[i+2] == CM_FMT_TYPE_NOT_USED ) { //Change Texel1*Texel0 to (SEL(tex1), MOD(tex0)) m2.a = m.d; m2.d = MUX_COMBINED; m2.b = m2.c = MUX_0; m.d = m.a; m.a = MUX_0; splitType[i+2] = CM_FMT_TYPE_A_ADD_D; splitType[i] = CM_FMT_TYPE_D; } else if( splitType[i+2] == CM_FMT_TYPE_A_ADD_D ) { if( m2.a == MUX_COMBINED ) { swap(m2.a, m2.d); } if( m2.a != MUX_TEXEL0 && m2.a != MUX_TEXEL1 ) { swap(m2.a, m.a); } else { if( m.a == m2.a ) { swap(m.d, m2.a); } else { swap(m.a, m2.a); } } } } } if( CountTexel1Cycle(m2) < 2 ) { continue; //2nd cycle does not have two texels } } } } void CDirectXDecodedMux::Reformat(bool do_complement) { DecodedMux::Reformat(do_complement); ReformatAgainWithTwoTexels(); mType = std::max(std::max(std::max(splitType[0], splitType[1]),splitType[2]),splitType[3]); } mupen64plus-video-rice-src-2.0/src/DirectXDecodedMux.h0000644000000000000000000000167712165031100020760 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "DecodedMux.h" #ifndef _DIRECTX_DECODEDMUX_H_ #define _DIRECTX_DECODEDMUX_H_ class CDirectXDecodedMux : public DecodedMux { void ReformatAgainWithTwoTexels(void); virtual void Reformat(bool do_complement = true); }; #endif mupen64plus-video-rice-src-2.0/src/ExtendedRender.h0000644000000000000000000000421412165031100020342 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _EXTENDED_RENDER_H_ #define _EXTENDED_RENDER_H_ #include "RSP_Parser.h" #include "RSP_S2DEX.h" // Define the render extension interface and provide empty implementation of // the render extension functions. // Real render can either implement or not implement these extended render functions // These extended render functions are in different groups: // - Group #1: Related to frame buffer // - Group #2: Related to 2D sprite // - Group #3: Related BG and ScaledBG class CExtendedRender { public: virtual ~CExtendedRender() {} virtual void DrawFrameBuffer(bool useVIreg=false, uint32 left=0, uint32 top=0, uint32 width=0, uint32 height=0) {}; virtual void LoadFrameBuffer(bool useVIreg=false, uint32 left=0, uint32 top=0, uint32 width=0, uint32 height=0) {}; virtual void LoadTxtrBufFromRDRAM(void) {}; virtual void LoadTxtrBufIntoTexture(void) {}; virtual void DrawSprite2D(Sprite2DInfo &info, uint32 ucode) {}; virtual void LoadSprite2D(Sprite2DInfo &info, uint32 ucode) {}; virtual void DrawSprite(uObjTxSprite &sprite, bool rectR = true) {}; virtual void DrawObjBG1CYC(uObjScaleBg &bg, bool scaled=true) {}; virtual void DrawObjBGCopy(uObjBg &info) {}; virtual void LoadObjBGCopy(uObjBg &info) {}; virtual void LoadObjBG1CYC(uObjScaleBg &info) {}; virtual void LoadObjSprite(uObjTxSprite &info, bool useTIAddr=false) {}; virtual void DrawText(const char* str, RECT *rect) {}; }; #endif mupen64plus-video-rice-src-2.0/src/FrameBuffer.cpp0000644000000000000000000022032512165031100020164 0ustar 00000000000000/* Copyright (C) 2005 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // =========================================================================== #include #include "ConvertImage.h" #include "DeviceBuilder.h" #include "FrameBuffer.h" #include "UcodeDefs.h" #include "RSP_Parser.h" #include "Render.h" extern TMEMLoadMapInfo g_tmemLoadAddrMap[0x200]; // Totally 4KB TMEM; // 0 keeps the most recent CI info // 1 keeps the frame buffer CI info which is being displayed now // 2 keeps the older frame buffer CI info. This can be used if we are using triple buffer /* Overview of framebuffer implementation 1) Check if backbuffer has changed, via different detection techniques 2) If changed, we copy the GFX card's backbuffer to main RAM 3) This is slow due to the reading process, not the writing */ RecentCIInfo g_RecentCIInfo[5]; RecentCIInfo *g_uRecentCIInfoPtrs[5] = { &g_RecentCIInfo[0], &g_RecentCIInfo[1], &g_RecentCIInfo[2], &g_RecentCIInfo[3], &g_RecentCIInfo[4], }; int numOfRecentCIInfos = 5; RecentViOriginInfo g_RecentVIOriginInfo[5]; uint32 dwBackBufferSavedAtFrame=0; RenderTextureInfo gRenderTextureInfos[20]; int numOfTxtBufInfos = sizeof(gRenderTextureInfos)/sizeof(RenderTextureInfo); RenderTextureInfo *g_pRenderTextureInfo = NULL; FrameBufferManager* g_pFrameBufferManager = NULL; bool LastCIIsNewCI=false; FrameBufferManager::FrameBufferManager() : m_isRenderingToTexture(false), m_curRenderTextureIndex(-1), m_lastTextureBufferIndex(-1) { } FrameBufferManager::~FrameBufferManager() { } void FrameBufferManager::CloseUp() { for( int i=0; i=0x20?1:0; return ((r>>3)<>3)<>3)<>7); } uint16 ConvertRGBATo555(uint32 color32) { return (uint16)((((color32>>19)&0x1F)<>11)&0x1F)<>3)&0x1F)<>31)));; } void FrameBufferManager::UpdateRecentCIAddr(SetImgInfo &ciinfo) { if( ciinfo.dwAddr == g_uRecentCIInfoPtrs[0]->dwAddr ) return; RecentCIInfo *temp; int i; for( i=1; idwAddr ) { temp = g_uRecentCIInfoPtrs[i]; for( int j=i; j>0; j-- ) { g_uRecentCIInfoPtrs[j] = g_uRecentCIInfoPtrs[j-1]; } break; } } if( i >= numOfRecentCIInfos ) { temp = g_uRecentCIInfoPtrs[4]; g_uRecentCIInfoPtrs[4] = g_uRecentCIInfoPtrs[3]; g_uRecentCIInfoPtrs[3] = g_uRecentCIInfoPtrs[2]; g_uRecentCIInfoPtrs[2] = g_uRecentCIInfoPtrs[1]; g_uRecentCIInfoPtrs[1] = g_uRecentCIInfoPtrs[0]; temp->dwCopiedAtFrame = 0; temp->bCopied = false; } g_uRecentCIInfoPtrs[0] = temp; // Fix me here for Mario Tennis temp->dwLastWidth = windowSetting.uViWidth; temp->dwLastHeight = windowSetting.uViHeight; temp->dwFormat = ciinfo.dwFormat; temp->dwAddr = ciinfo.dwAddr; temp->dwSize = ciinfo.dwSize; temp->dwWidth = ciinfo.dwWidth; temp->dwHeight = gRDP.scissor.bottom; temp->dwMemSize = (temp->dwWidth*temp->dwHeight/2)<dwSize; temp->bCopied = false; temp->lastUsedFrame = status.gDlistCount; temp->lastSetAtUcode = status.gUcodeCount; } /************************************************************************/ /* Mark the ciinfo entry that the ciinfo is used by VI origin register */ /* in another word, this is a real frame buffer, not a fake frame buffer*/ /* Fake frame buffers are never really used by VI origin */ /************************************************************************/ void FrameBufferManager::SetAddrBeDisplayed(uint32 addr) { uint32 viwidth = *g_GraphicsInfo.VI_WIDTH_REG; addr &= (g_dwRamSize-1); int i; for( i=0; idwAddr+2*viwidth == addr ) { g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame = status.gDlistCount; } else if( addr >= g_uRecentCIInfoPtrs[i]->dwAddr && addr < g_uRecentCIInfoPtrs[i]->dwAddr+0x1000 ) { g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame = status.gDlistCount; } } for( i=0; idwAddr == 0 ) continue; if( g_uRecentCIInfoPtrs[i]->dwAddr == addr ) { if( status.gDlistCount-g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame < 20 ) //if( g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame != 0 ) { return true; } else { TXTRBUF_DUMP(TRACE0("This is a new buffer address, the addr is never a displayed buffer");); return false; } } } for( i=0; i addr && (g_RecentVIOriginInfo[i].addr - addr)%width == 0 && (g_RecentVIOriginInfo[i].addr - addr)/width <= 4) { if( status.gDlistCount-g_RecentVIOriginInfo[i].FrameCount < 20 ) //if( g_RecentVIOriginInfo[i].FrameCount != 0 ) { return true; } else { TXTRBUF_DUMP(DebuggerAppendMsg("This is a new buffer address, the addr is never a displayed buffer");); return false; } } } } if( status.gDlistCount > 20 ) return false; else { TXTRBUF_DUMP({DebuggerAppendMsg("This is a new buffer address, the addr is never a displayed buffer");}); return true; } } int FrameBufferManager::FindRecentCIInfoIndex(uint32 addr) { for( int i=0; idwAddr <= addr && addr < g_uRecentCIInfoPtrs[i]->dwAddr+g_uRecentCIInfoPtrs[i]->dwMemSize ) { return i; } } return -1; } bool FrameBufferManager::IsDIaRenderTexture() { // Knowing g_CI and g_ZI //if( g_CI.dwWidth ) bool foundSetScissor=false; bool foundFillRect=false; bool foundSetFillColor=false; bool foundSetCImg=false; uint32 newFillColor = 0; uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction for( int i=0; i<10; i++ ) { uint32 w0 = *(uint32 *)(g_pRDRAMu8 + dwPC + i*8); uint32 w1 = *(uint32 *)(g_pRDRAMu8 + dwPC + 4 + i*8); if( (w0>>24) == RDP_SETSCISSOR ) { foundSetScissor = true; continue; } if( (w0>>24) == RDP_SETFILLCOLOR ) { foundSetFillColor = true; newFillColor = w1; continue; } if( (w0>>24) == RDP_FILLRECT ) { uint32 x0 = ((w1>>12)&0xFFF)/4; uint32 y0 = ((w1>>0 )&0xFFF)/4; uint32 x1 = ((w0>>12)&0xFFF)/4; if( x0 == 0 && y0 == 0 ) { if( x1 == g_CI.dwWidth ) { foundFillRect = true; continue; } if(x1 == (unsigned int)(g_CI.dwWidth-1)) { foundFillRect = true; continue; } } } if( (w0>>24) == RDP_TEXRECT ) { break; } if( (w0>>24) == RDP_SETCIMG ) { foundSetCImg = true; break; } } /* bool foundSetScissor=false; bool foundFillRect=false; bool foundSetFillColor=false; bool foundSetCImg=false; bool foundTxtRect=false; int ucodeLength=10; uint32 newFillColor; */ if( foundFillRect ) { if( foundSetFillColor ) { if( newFillColor != 0xFFFCFFFC ) return true; // this is a render_texture else return false; } if( gRDP.fillColor != 0x00FFFFF7 ) return true; // this is a render_texture else return false; // this is a normal ZImg } else if( foundSetFillColor && newFillColor == 0xFFFCFFFC && foundSetCImg ) { return false; } else { return true; } if( !foundSetCImg ) return true; if( foundSetScissor ) return true; } int FrameBufferManager::CheckAddrInBackBuffers(uint32 addr, uint32 memsize, bool copyToRDRAM) { int r = FindRecentCIInfoIndex(addr); if( r >= 0 ) { // Also check if the address is overwritten by a recent render_texture //int t = CheckAddrInRenderTextures(addr,false); int t =-1; for( int i=0; i=gRenderTextureInfos[i].CI_Info.dwAddr && addr < gRenderTextureInfos[i].CI_Info.dwAddr+bufMemSize) { if( g_uRecentCIInfoPtrs[r]->lastSetAtUcode < gRenderTextureInfos[i].updateAtUcodeCount ) { t = i; break; } } } if( t >= 0 ) return -1; } if( r >= 0 && status.gDlistCount - g_uRecentCIInfoPtrs[r]->lastUsedFrame <= 3 && g_uRecentCIInfoPtrs[r]->bCopied == false ) { DEBUGGER_IF_DUMP((logTextureBuffer&&r==1),TRACE2("Hit current front buffer at %08X, size=0x%X", addr, memsize)); DEBUGGER_IF_DUMP((logTextureBuffer&&r==0),TRACE2("Hit current back buffer at %08X, size=0x%X", addr, memsize)); DEBUGGER_IF_DUMP((logTextureBuffer&&r>1),TRACE2("Hit old back buffer at %08X, size=0x%X", addr, memsize)); SaveBackBuffer(r, NULL, true); } return r; } uint8 CIFindIndex(uint16 val) { for( int i=0; i<=0xFF; i++ ) { if( val == g_wRDPTlut[i] ) { return (uint8)i; } } return 0; } void TexRectToFrameBuffer_8b(uint32 dwXL, uint32 dwYL, uint32 dwXH, uint32 dwYH, float t0u0, float t0v0, float t0u1, float t0v1, uint32 dwTile) { // Copy the framebuffer texture into the N64 framebuffer memory // Used in Yoshi /* uint32 maxW = g_pRenderTextureInfo->CI_Info.dwWidth; uint32 maxH = maxW*3/4; if( status.dwTvSystem == TV_SYSTEM_PAL ) { maxH = maxW*9/11; } */ uint32 maxW = g_pRenderTextureInfo->N64Width; uint32 maxH = g_pRenderTextureInfo->N64Height; uint32 maxOff = maxW*maxH; TMEMLoadMapInfo &info = g_tmemLoadAddrMap[gRDP.tiles[dwTile].dwTMem]; uint32 dwWidth = dwXH-dwXL; uint32 dwHeight = dwYH-dwYL; float xScale = (t0u1-t0u0)/dwWidth; float yScale = (t0v1-t0v0)/dwHeight; uint8* dwSrc = g_pRDRAMu8 + info.dwLoadAddress; uint8* dwDst = g_pRDRAMu8 + g_pRenderTextureInfo->CI_Info.dwAddr; uint32 dwSrcPitch = gRDP.tiles[dwTile].dwPitch; uint32 dwDstPitch = g_pRenderTextureInfo->CI_Info.dwWidth; uint32 dwSrcOffX = gRDP.tiles[dwTile].hilite_sl; uint32 dwSrcOffY = gRDP.tiles[dwTile].hilite_tl; uint32 dwLeft = dwXL; uint32 dwTop = dwYL; dwWidth = min(dwWidth, maxW-dwLeft); dwHeight = min(dwHeight, maxH-dwTop); if( maxH <= dwTop ) return; for (uint32 y = 0; y < dwHeight; y++) { uint32 dwByteOffset = (uint32)(((y*yScale+dwSrcOffY) * dwSrcPitch) + dwSrcOffX); for (uint32 x = 0; x < dwWidth; x++) { if( (((y+dwTop)*dwDstPitch+x+dwLeft)^0x3) > maxOff ) { #ifdef DEBUGGER TRACE0("Warning: Offset exceeds limit"); #endif continue; } dwDst[((y+dwTop)*dwDstPitch+x+dwLeft)^0x3] = dwSrc[(uint32)(dwByteOffset+x*xScale) ^ 0x3]; } } TXTRBUF_DUMP(DebuggerAppendMsg("TexRect To FrameBuffer: X0=%d, Y0=%d, X1=%d, Y1=%d,\n\t\tfS0=%f, fT0=%f, fS1=%f, fT1=%f ", dwXL, dwYL, dwXH, dwYH, t0v0, t0v0, t0u1, t0v1);); } void TexRectToN64FrameBuffer_16b(uint32 x0, uint32 y0, uint32 width, uint32 height, uint32 dwTile) { // Copy the framebuffer texture into the N64 RDRAM framebuffer memory structure DrawInfo srcInfo; if( g_textures[dwTile].m_pCTexture->StartUpdate(&srcInfo) == false ) { DebuggerAppendMsg("Fail to lock texture:TexRectToN64FrameBuffer_16b" ); return; } uint32 n64CIaddr = g_CI.dwAddr; uint32 n64CIwidth = g_CI.dwWidth; for (uint32 y = 0; y < height; y++) { uint32* pSrc = (uint32*)((uint8*)srcInfo.lpSurface + y * srcInfo.lPitch); uint16* pN64Buffer = (uint16*)(g_pRDRAMu8+(n64CIaddr&(g_dwRamSize-1)))+(y+y0)*n64CIwidth; for (uint32 x = 0; x < width; x++) { pN64Buffer[x+x0] = ConvertRGBATo555(pSrc[x]); } } g_textures[dwTile].m_pCTexture->EndUpdate(&srcInfo); } #define FAST_CRC_CHECKING_INC_X 13 #define FAST_CRC_CHECKING_INC_Y 11 #define FAST_CRC_MIN_Y_INC 2 #define FAST_CRC_MIN_X_INC 2 #define FAST_CRC_MAX_X_INC 7 #define FAST_CRC_MAX_Y_INC 3 extern uint32 dwAsmHeight; extern uint32 dwAsmPitch; extern uint32 dwAsmdwBytesPerLine; extern uint32 dwAsmCRC; extern uint8* pAsmStart; uint32 CalculateRDRAMCRC(void *pPhysicalAddress, uint32 left, uint32 top, uint32 width, uint32 height, uint32 size, uint32 pitchInBytes ) { dwAsmCRC = 0; dwAsmdwBytesPerLine = ((width<=32 || (dwAsmdwBytesPerLine>>2)>=16)) { uint32 realWidthInDWORD = dwAsmdwBytesPerLine>>2; uint32 xinc = realWidthInDWORD / FAST_CRC_CHECKING_INC_X; if( xinc < FAST_CRC_MIN_X_INC ) { xinc = min(FAST_CRC_MIN_X_INC, width); } if( xinc > FAST_CRC_MAX_X_INC ) { xinc = FAST_CRC_MAX_X_INC; } uint32 yinc = height / FAST_CRC_CHECKING_INC_Y; if( yinc < FAST_CRC_MIN_Y_INC ) { yinc = min(FAST_CRC_MIN_Y_INC, height); } if( yinc > FAST_CRC_MAX_Y_INC ) { yinc = FAST_CRC_MAX_Y_INC; } uint32 pitch = pitchInBytes>>2; register uint32 *pStart = (uint32*)(pPhysicalAddress); pStart += (top * pitch) + (((left<>3); // The original assembly code had a bug in it (it incremented pStart by 'pitch' in bytes, not in dwords) // This C code implements the same algorithm as the ASM but without the bug uint32 y = 0; while (y < height) { uint32 x = 0; while (x < realWidthInDWORD) { dwAsmCRC = (dwAsmCRC << 4) + ((dwAsmCRC >> 28) & 15); dwAsmCRC += pStart[x]; x += xinc; dwAsmCRC += x; } dwAsmCRC ^= y; y += yinc; pStart += pitch; } } else { try { dwAsmdwBytesPerLine = ((width<>1); dwAsmHeight = height - 1; dwAsmPitch = pitchInBytes; #if defined(NO_ASM) uint32 pitch = pitchInBytes>>2; uint32* pStart = (uint32*)pPhysicalAddress; pStart += (top * pitch) + (((left<>3); int y = dwAsmHeight; while(y >= 0) { uint32 esi = 0; int x = dwAsmdwBytesPerLine - 4; while(x >= 0) { esi = *(uint32*)(pAsmStart + x); esi ^= x; dwAsmCRC = (dwAsmCRC << 4) + ((dwAsmCRC >> 28) & 15); dwAsmCRC += esi; x-=4; } esi ^= y; dwAsmCRC += esi; pAsmStart += dwAsmPitch; y--; } #elif !defined(__GNUC__) // !defined(NO_ASM) __asm { push eax push ebx push ecx push edx push esi mov ecx, pAsmStart; // = pStart mov edx, 0 // The CRC mov eax, dwAsmHeight // = y l2: mov ebx, dwAsmdwBytesPerLine // = x sub ebx, 4 l1: mov esi, [ecx+ebx] xor esi, ebx rol edx, 4 add edx, esi sub ebx, 4 jge l1 xor esi, eax add edx, esi add ecx, dwAsmPitch dec eax jge l2 mov dwAsmCRC, edx pop esi pop edx pop ecx pop ebx pop eax } #elif defined(__x86_64__) // defined(__GNUC__) && !defined(NO_ASM) asm volatile(" xorl %k2, %k2 \n" " movslq %k4, %q4 \n" "0: \n" " movslq %3, %%rbx \n" " sub $4, %%rbx \n" "1: \n" " movl (%0,%%rbx,1), %%eax \n" " xorl %%ebx, %%eax \n" " roll $4, %k2 \n" " addl %%eax, %k2 \n" " sub $4, %%rbx \n" " jge 1b \n" " xorl %k1, %%eax \n" " addl %%eax, %k2 \n" " add %q4, %0 \n" " decl %k1 \n" " jge 0b \n" : "+r"(pAsmStart), "+r"(dwAsmHeight), "=&r"(dwAsmCRC) : "m"(dwAsmdwBytesPerLine), "r"(dwAsmPitch) : "%rbx", "%rax", "memory", "cc" ); #elif !defined(__PIC__) // !defined(__x86_64__) && defined(__GNUC__) && !defined(NO_ASM) asm volatile("pusha \n" "mov %[pAsmStart], %%ecx \n" // = pStart "mov $0, %%edx \n" // The CRC "mov %[dwAsmHeight], %%eax \n" // = y "0: \n" //l2: "mov %[dwAsmdwBytesPerLine], %%ebx \n" // = x "sub $4, %%ebx \n" "1: \n" //l1: "mov (%%ecx,%%ebx), %%esi \n" "xor %%ebx, %%esi \n" "rol $4, %%edx \n" "add %%esi, %%edx \n" "sub $4, %%ebx \n" "jge 1b \n" //jge l1 "xor %%eax, %%esi \n" "add %%esi, %%edx \n" "add %[dwAsmPitch], %%ecx \n" "dec %%eax \n" "jge 0b \n" //jge l2 "mov %%edx, %[dwAsmCRC] \n" "popa \n" : [pAsmStart]"+m"(pAsmStart), [dwAsmHeight]"+m"(dwAsmHeight), [dwAsmCRC]"=m"(dwAsmCRC) : [dwAsmdwBytesPerLine]"m"(dwAsmdwBytesPerLine), [dwAsmPitch]"m"(dwAsmPitch) : "memory", "cc" ); #else // defined(__PIC__) && !defined(__x86_64__) && defined(__GNUC__) && !defined(NO_ASM) unsigned int saveEBX; unsigned int saveEAX; unsigned int saveECX; unsigned int saveEDX; unsigned int saveESI; unsigned int asmdwBytesPerLine = dwAsmdwBytesPerLine; unsigned int asmPitch = dwAsmPitch; unsigned int asmHeight = dwAsmHeight; unsigned int asmCRC; asm volatile("mov %%ebx, %2 \n" "mov %%eax, %5 \n" "mov %%ecx, %7 \n" "mov %%edx, %8 \n" "mov %%esi, %9 \n" "mov %0, %%ecx \n" // = pStart "mov $0, %%edx \n" // The CRC "mov %1, %%eax \n" // = y "0: \n" //l2: "mov %3, %%ebx \n" // = x "sub $4, %%ebx \n" "1: \n" //l1: "mov (%%ecx,%%ebx), %%esi \n" "xor %%ebx, %%esi \n" "rol $4, %%edx \n" "add %%esi, %%edx \n" "sub $4, %%ebx \n" "jge 1b \n" //jge l1 "xor %%eax, %%esi \n" "add %%esi, %%edx \n" "add %4, %%ecx \n" "dec %%eax \n" "jge 0b \n" //jge l2 "mov %2, %%ebx \n" "mov %%edx, %6 \n" "mov %5, %%eax \n" "mov %7, %%ecx \n" "mov %8, %%edx \n" "mov %9, %%esi \n" : : "m"(pAsmStart), "m"(asmHeight), "m"(saveEBX), "m"(asmdwBytesPerLine), "m"(asmPitch), "m"(saveEAX), "m"(asmCRC), "m"(saveECX), "m"(saveEDX), "m"(saveESI) : "memory", "cc" ); dwAsmCRC = asmCRC; #endif } catch(...) { TRACE0("Exception in texture CRC calculation"); } } return dwAsmCRC; } unsigned char CalculateMaxCI(void *pPhysicalAddress, uint32 left, uint32 top, uint32 width, uint32 height, uint32 size, uint32 pitchInBytes ) { uint32 x, y; unsigned char *buf; unsigned char val = 0; if( TXT_SIZE_8b == size ) { for( y = 0; y val ) val = buf[x]; if( val == 0xFF ) return 0xFF; } } } else { unsigned char val1,val2; left >>= 1; width >>= 1; for( y = 0; y>4; val2 = buf[x]&0xF; if( val1 > val ) val = val1; if( val2 > val ) val = val2; if( val == 0xF ) return 0xF; } } } return val; } bool FrameBufferManager::FrameBufferInRDRAMCheckCRC() { RecentCIInfo &p = *(g_uRecentCIInfoPtrs[0]); uint8 *pFrameBufferBase = (uint8*)(g_pRDRAMu8+p.dwAddr); uint32 pitch = (p.dwWidth << p.dwSize ) >> 1; uint32 crc = CalculateRDRAMCRC(pFrameBufferBase, 0, 0, p.dwWidth, p.dwHeight, p.dwSize, pitch); if( crc != p.dwCRC ) { p.dwCRC = crc; TRACE0("Frame Buffer CRC mismitch, it is modified by CPU"); return false; } else { return true; } } extern std::vector frameWriteRecord; void FrameBufferManager::FrameBufferWriteByCPU(uint32 addr, uint32 size) { if( !frameBufferOptions.bProcessCPUWrite ) return; //WARNING(TRACE2("Frame Buffer Write, addr=%08X, CI Addr=%08X", addr, g_CI.dwAddr)); status.frameWriteByCPU = TRUE; frameWriteRecord.push_back(addr&(g_dwRamSize-1)); } extern RECT frameWriteByCPURect; extern std::vector frameWriteByCPURects; extern RECT frameWriteByCPURectArray[20][20]; extern bool frameWriteByCPURectFlag[20][20]; #define FRAMEBUFFER_IN_BLOCK bool FrameBufferManager::ProcessFrameWriteRecord() { int size = frameWriteRecord.size(); if( size == 0 ) return false; int index = FindRecentCIInfoIndex(frameWriteRecord[0]); if( index == -1 ) { LOG_TEXTURE(TRACE1("Frame Buffer Write to non-record addr = %08X", frameWriteRecord[0])); frameWriteRecord.clear(); return false; } else { uint32 base = g_uRecentCIInfoPtrs[index]->dwAddr; uint32 uwidth = g_uRecentCIInfoPtrs[index]->dwWidth; uint32 uheight = g_uRecentCIInfoPtrs[index]->dwHeight; uint32 upitch = uwidth<<1; frameWriteByCPURect.left=uwidth-1; frameWriteByCPURect.top = uheight-1; frameWriteByCPURect.right=0; frameWriteByCPURect.bottom = 0; int x, y, off; for( int i=0; idwMemSize ) { y = off/upitch; x = (off - y*upitch)>>1; #ifdef FRAMEBUFFER_IN_BLOCK int xidx=x/32; int yidx=y/24; RECT &rect = frameWriteByCPURectArray[xidx][yidx]; if( !frameWriteByCPURectFlag[xidx][yidx] ) { rect.left=rect.right=x; rect.top=rect.bottom=y; frameWriteByCPURectFlag[xidx][yidx]=true; } else { if( x < rect.left ) rect.left = x; if( x > rect.right ) rect.right = x; if( y < rect.top ) rect.top = y; if( y > rect.bottom ) rect.bottom = y; } #else if( x < frameWriteByCPURect.left ) frameWriteByCPURect.left = x; if( x > frameWriteByCPURect.right ) frameWriteByCPURect.right = x; if( y < frameWriteByCPURect.top ) frameWriteByCPURect.top = y; if( y > frameWriteByCPURect.bottom ) frameWriteByCPURect.bottom = y; #endif } } frameWriteRecord.clear(); LOG_TEXTURE(TRACE4("Frame Buffer Write: Left=%d, Top=%d, Right=%d, Bottom=%d", frameWriteByCPURect.left, frameWriteByCPURect.top, frameWriteByCPURect.right, frameWriteByCPURect.bottom)); return true; } } void FrameBufferManager::FrameBufferReadByCPU( uint32 addr ) { ///return; // it does not work very well anyway if( !frameBufferOptions.bProcessCPURead ) return; addr &= (g_dwRamSize-1); int index = FindRecentCIInfoIndex(addr); if( index == -1 ) { // Check if this is the depth buffer uint32 size = 2*g_RecentCIInfo[0].dwWidth*g_RecentCIInfo[0].dwHeight; addr &= 0x3FFFFFFF; if( addr >= g_ZI.dwAddr && addr < g_ZI.dwAddr + size ) { TXTRBUF_OR_CI_DUMP(TRACE1("Depth Buffer read, reported by emulator, addr=%08X", addr)); } else { return; } } if( status.gDlistCount - g_uRecentCIInfoPtrs[index]->lastUsedFrame > 3 ) { // Ok, we don't have this frame anymore return; } //TXTRBUF_OR_CI_DUMP(TRACE1("FB Read By CPU at %08X", addr)); if( g_uRecentCIInfoPtrs[index]->bCopied ) return; //if( addr != g_uRecentCIInfoPtrs[index]->dwAddr ) return; TXTRBUF_OR_CI_DUMP(TRACE1("Frame Buffer read, reported by emulator, addr=%08X", addr)); uint32 size = 0x1000 - addr%0x1000; CheckAddrInBackBuffers(addr, size, true); DEBUGGER_IF_DUMP(pauseAtNext,{TRACE0("Frame Buffer read");}); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE, {DebuggerAppendMsg("Paused after setting Frame Buffer read:\n Cur CI Addr: 0x%08x, Fmt: %s Size: %s Width: %d", g_CI.dwAddr, pszImgFormat[g_CI.dwFormat], pszImgSize[g_CI.dwSize], g_CI.dwWidth);}); } extern RECT frameWriteByCPURect; extern std::vector frameWriteByCPURects; extern RECT frameWriteByCPURectArray[20][20]; extern bool frameWriteByCPURectFlag[20][20]; #define FRAMEBUFFER_IN_BLOCK void FrameBufferManager::UpdateFrameBufferBeforeUpdateFrame() { if( (frameBufferOptions.bProcessCPUWrite && status.frameWriteByCPU ) || (frameBufferOptions.bLoadBackBufFromRDRAM && !FrameBufferInRDRAMCheckCRC() ) ) // Checks if frame buffer has been modified by CPU // Only happens to Dr. Mario { if( frameBufferOptions.bProcessCPUWrite ) { if( ProcessFrameWriteRecord() ) { #ifdef FRAMEBUFFER_IN_BLOCK int i,j; for( i=0; i<20; i++) { for( j=0; j<20; j++ ) { if( frameWriteByCPURectFlag[i][j] ) { CRender::GetRender()->DrawFrameBuffer(false, frameWriteByCPURectArray[i][j].left, frameWriteByCPURectArray[i][j].top, frameWriteByCPURectArray[i][j].right-frameWriteByCPURectArray[i][j].left+1, frameWriteByCPURectArray[i][j].bottom-frameWriteByCPURectArray[i][j].top+1); } } } for( i=0; i<20; i++) { for( j=0; j<20; j++ ) { if( frameWriteByCPURectFlag[i][j] ) { ClearN64FrameBufferToBlack(frameWriteByCPURectArray[i][j].left, frameWriteByCPURectArray[i][j].top, frameWriteByCPURectArray[i][j].right-frameWriteByCPURectArray[i][j].left+1, frameWriteByCPURectArray[i][j].bottom-frameWriteByCPURectArray[i][j].top+1); frameWriteByCPURectFlag[i][j] = false; } } } //memset(frameWriteByCPURectArray, 0, sizeof(frameWriteByCPURectArray)); //memset(frameWriteByCPURectFlag, 0, sizeof(frameWriteByCPURectFlag)); #else CRender::GetRender()->DrawFrameBuffer(false, frameWriteByCPURect.left, frameWriteByCPURect.top, frameWriteByCPURect.right-frameWriteByCPURect.left, frameWriteByCPURect.bottom-frameWriteByCPURect.top); ClearN64FrameBufferToBlack(frameWriteByCPURect.left, frameWriteByCPURect.top, frameWriteByCPURect.right-frameWriteByCPURect.left+1, frameWriteByCPURect.bottom-frameWriteByCPURect.top+1); /* int size = frameWriteByCPURects.size(); for( int i=0; iDrawFrameBuffer(false, frameWriteByCPURects[i].left, frameWriteByCPURects[i].top, frameWriteByCPURects[i].right-frameWriteByCPURects[i].left, frameWriteByCPURects[i].bottom-frameWriteByCPURects[i].top); ClearN64FrameBufferToBlack(frameWriteByCPURects[i].left, frameWriteByCPURects[i].top, frameWriteByCPURects[i].right-frameWriteByCPURects[i].left+1, frameWriteByCPURects[i].bottom-frameWriteByCPURects[i].top+1); } frameWriteByCPURects.clear(); */ #endif } status.frameWriteByCPU = FALSE; } else { if (CRender::IsAvailable()) { RecentCIInfo &p = *(g_uRecentCIInfoPtrs[0]); CRender::GetRender()->DrawFrameBuffer(false, 0,0,p.dwWidth,p.dwHeight); ClearN64FrameBufferToBlack(); } } } } uint32 FrameBufferManager::ComputeCImgHeight(SetImgInfo &info, uint32 &height) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction for( int i=0; i<10; i++ ) { uint32 w0 = *(uint32 *)(g_pRDRAMu8 + dwPC + i*8); uint32 w1 = *(uint32 *)(g_pRDRAMu8 + dwPC + 4 + i*8); if( (w0>>24) == RDP_SETSCISSOR ) { height = ((w1>>0 )&0xFFF)/4; TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height)); return RDP_SETSCISSOR; } if( (w0>>24) == RDP_FILLRECT ) { uint32 x0 = ((w1>>12)&0xFFF)/4; uint32 y0 = ((w1>>0 )&0xFFF)/4; uint32 x1 = ((w0>>12)&0xFFF)/4; uint32 y1 = ((w0>>0 )&0xFFF)/4; if( x0 == 0 && y0 == 0 ) { if( x1 == info.dwWidth ) { height = y1; TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height)); return RDP_FILLRECT; } if(x1 == (unsigned int)(info.dwWidth-1)) { height = y1+1; TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height)); return RDP_FILLRECT; } } } if( (w0>>24) == RDP_SETCIMG ) { goto step2; } if( (w0>>24) == RDP_SETCIMG ) { goto step2; } } if( gRDP.scissor.left == 0 && gRDP.scissor.top == 0 && (unsigned int)gRDP.scissor.right == info.dwWidth ) { height = gRDP.scissor.bottom; TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height)); return RDP_SETSCISSOR+1; } step2: TXTRBUF_DETAIL_DUMP(TRACE0("Not sure about buffer height")); height = info.dwWidth*3/4; if( status.dwTvSystem == TV_SYSTEM_PAL ) { height = info.dwWidth*9/11; } if( gRDP.scissor.bottom < (int)height && gRDP.scissor.bottom != 0 ) { height = gRDP.scissor.bottom; } if( info.dwAddr + height*info.dwWidth*info.dwSize >= g_dwRamSize ) { height = info.dwWidth*3/4; if( status.dwTvSystem == TV_SYSTEM_PAL ) { height = info.dwWidth*9/11; } if( gRDP.scissor.bottom < (int)height && gRDP.scissor.bottom != 0 ) { height = gRDP.scissor.bottom; } if( info.dwAddr + height*info.dwWidth*info.dwSize >= g_dwRamSize ) { height = ( g_dwRamSize - info.dwAddr ) / info.dwWidth; } } TXTRBUF_DETAIL_DUMP(TRACE1("render_texture height = %d", height)); return 0; } int FrameBufferManager::CheckRenderTexturesWithNewCI(SetImgInfo &CIinfo, uint32 height, bool byNewTxtrBuf) { int matchidx = -1; uint32 memsize = ((height*CIinfo.dwWidth)>>1)<>1)< CIinfo.dwAddr && info.CI_Info.dwAddr < CIinfo.dwAddr + memsize) covered = true; else if( info.CI_Info.dwAddr+memsize2 > CIinfo.dwAddr && info.CI_Info.dwAddr+memsize2 < CIinfo.dwAddr + memsize) covered = true; else if( CIinfo.dwAddr > info.CI_Info.dwAddr && CIinfo.dwAddr < info.CI_Info.dwAddr + memsize2 ) covered = true; else if( CIinfo.dwAddr+ memsize > info.CI_Info.dwAddr && CIinfo.dwAddr+ memsize < info.CI_Info.dwAddr + memsize2 ) covered = true; } if( covered ) { //SAFE_DELETE(info.psurf); if( info.pRenderTexture->IsBeingRendered() ) { TRACE0("Error, covering a render_texture which is being rendered"); TRACE3("New addrr=%08X, width=%d, height=%d", CIinfo.dwAddr, CIinfo.dwWidth, height ); TRACE3("Old addrr=%08X, width=%d, height=%d", info.CI_Info.dwAddr, info.N64Width, info.N64Height ); } info.isUsed = false; TXTRBUF_DUMP(TRACE5("Delete txtr buf %d at %08X, covered by new CI at %08X, Width=%d, Height=%d", i, info.CI_Info.dwAddr, CIinfo.dwAddr, CIinfo.dwWidth, height )); SAFE_DELETE(info.pRenderTexture); info.txtEntry.pTexture = NULL; continue; } } return matchidx; } extern RecentCIInfo *g_uRecentCIInfoPtrs[5]; RenderTextureInfo newRenderTextureInfo; int FrameBufferManager::FindASlot(void) { int idx; // Find an empty slot bool found = false; for( int i=0; iN64Height);}); } int FrameBufferManager::SetBackBufferAsRenderTexture(SetImgInfo &CIinfo, int ciInfoIdx) { // MUDLORD: // OK, heres the drill! // // We set the graphics card's back buffer's contents as a render_texure // This is done due to how the current framebuffer implementation detects // changes to the backbuffer memory pointer and then we do a texture // copy. This might be slow since it doesnt use hardware auxillary buffers RenderTextureInfo tempRenderTextureInfo; memcpy(&(tempRenderTextureInfo.CI_Info), &CIinfo, sizeof(SetImgInfo)); tempRenderTextureInfo.N64Width = g_uRecentCIInfoPtrs[ciInfoIdx]->dwLastWidth; tempRenderTextureInfo.N64Height = g_uRecentCIInfoPtrs[ciInfoIdx]->dwLastHeight; tempRenderTextureInfo.knownHeight = true; tempRenderTextureInfo.maxUsedHeight = 0; tempRenderTextureInfo.bufferWidth = windowSetting.uDisplayWidth; tempRenderTextureInfo.bufferHeight = windowSetting.uDisplayHeight; tempRenderTextureInfo.scaleX = tempRenderTextureInfo.bufferWidth / float(tempRenderTextureInfo.N64Width); tempRenderTextureInfo.scaleY = tempRenderTextureInfo.bufferHeight / float(tempRenderTextureInfo.N64Height); status.bFrameBufferIsDrawn = false; status.bFrameBufferDrawnByTriangles = false; tempRenderTextureInfo.updateAtFrame = status.gDlistCount; tempRenderTextureInfo.updateAtUcodeCount = status.gUcodeCount; // Checking against previous render_texture infos //uint32 memsize = ((tempRenderTextureInfo.N64Height*tempRenderTextureInfo.N64Width)>>1)<= 0) ? matchidx : FindASlot(); if( gRenderTextureInfos[idxToUse].pRenderTexture == NULL || matchidx < 0 ) { gRenderTextureInfos[idxToUse].pRenderTexture = new COGLRenderTexture(tempRenderTextureInfo.bufferWidth, tempRenderTextureInfo.bufferHeight, &gRenderTextureInfos[idxToUse], AS_BACK_BUFFER_SAVE); } // Need to set all variables for gRenderTextureInfos[idxToUse] CRenderTexture *pRenderTexture = gRenderTextureInfos[idxToUse].pRenderTexture; memcpy(&gRenderTextureInfos[idxToUse], &tempRenderTextureInfo, sizeof(RenderTextureInfo) ); gRenderTextureInfos[idxToUse].pRenderTexture = pRenderTexture; gRenderTextureInfos[idxToUse].isUsed = true; gRenderTextureInfos[idxToUse].txtEntry.pTexture = pRenderTexture->m_pTexture; gRenderTextureInfos[idxToUse].txtEntry.txtrBufIdx = idxToUse+1; TXTRBUF_DUMP(TRACE2("Set back buf as render_texture %d, addr=%08X", idxToUse, CIinfo.dwAddr)); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE, {DebuggerAppendMsg("Paused after setting render_texture:\nAddr: 0x%08x, Fmt: %s Size: %s Width: %d, Height:%d", CIinfo.dwAddr, pszImgFormat[CIinfo.dwFormat], pszImgSize[CIinfo.dwSize], CIinfo.dwWidth, g_pRenderTextureInfo->N64Height);}); return idxToUse; } void FrameBufferManager::CloseRenderTexture(bool toSave) { if( m_curRenderTextureIndex < 0 ) return; status.bHandleN64RenderTexture = false; if( status.bDirectWriteIntoRDRAM ) { // TODO: Implement } else { RestoreNormalBackBuffer(); if( !toSave || !status.bFrameBufferIsDrawn || !status.bFrameBufferDrawnByTriangles ) { TXTRBUF_DUMP(TRACE0("Closing render_texture without save");); SAFE_DELETE(gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture); gRenderTextureInfos[m_curRenderTextureIndex].isUsed = false; TXTRBUF_DUMP(TRACE1("Delete render_texture %d",m_curRenderTextureIndex);); } else { TXTRBUF_DUMP(TRACE1("Closing render_texture %d", m_curRenderTextureIndex);); StoreRenderTextureToRDRAM(); if( frameBufferOptions.bRenderTextureWriteBack ) { SAFE_DELETE(gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture); gRenderTextureInfos[m_curRenderTextureIndex].isUsed = false; TXTRBUF_DUMP(TRACE1("Delete render_texture %d after writing back to RDRAM",m_curRenderTextureIndex);); } else { g_pRenderTextureInfo->crcInRDRAM = ComputeRenderTextureCRCInRDRAM(m_curRenderTextureIndex); g_pRenderTextureInfo->crcCheckedAtFrame = status.gDlistCount; } } } SetScreenMult(windowSetting.uDisplayWidth/windowSetting.fViWidth, windowSetting.uDisplayHeight/windowSetting.fViHeight); CRender::g_pRender->UpdateClipRectangle(); CRender::g_pRender->ApplyScissorWithClipRatio(); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE, { DebuggerAppendMsg("Paused after saving render_texture %d:\nAddr: 0x%08x, Fmt: %s Size: %s Width: %d", m_curRenderTextureIndex, g_pRenderTextureInfo->CI_Info.dwAddr, pszImgFormat[g_pRenderTextureInfo->CI_Info.dwFormat], pszImgSize[g_pRenderTextureInfo->CI_Info.dwSize], g_pRenderTextureInfo->CI_Info.dwWidth); }); } void FrameBufferManager::ClearN64FrameBufferToBlack(uint32 left, uint32 top, uint32 width, uint32 height) { RecentCIInfo &p = *(g_uRecentCIInfoPtrs[0]); uint16 *frameBufferBase = (uint16*)(g_pRDRAMu8+p.dwAddr); uint32 pitch = p.dwWidth; if( width == 0 || height == 0 ) { uint32 len = p.dwHeight*p.dwWidth*p.dwSize; if( p.dwSize == TXT_SIZE_4b ) len = (p.dwHeight*p.dwWidth)>>1; memset(frameBufferBase, 0, len); } else { for( uint32 y=0; yUpdateFrame(); RecentCIInfo *info = g_uRecentCIInfoPtrs[i]; StoreBackBufferToRDRAM( info->dwAddr, info->dwFormat, info->dwSize, info->dwWidth, info->dwHeight, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, addr, 0x1000-addr%0x1000); TRACE1("Copy back for CI Addr=%08X", info->dwAddr); } } // We do these checks to see if a render_texture operation is occurring... void FrameBufferManager::CheckRenderTextureCRCInRDRAM(void) { for( int i=0; iIsBeingRendered() ) continue; if( gRenderTextureInfos[i].crcCheckedAtFrame < status.gDlistCount ) { uint32 crc = ComputeRenderTextureCRCInRDRAM(i); if( gRenderTextureInfos[i].crcInRDRAM != crc ) { // RDRAM has been modified by CPU core TXTRBUF_DUMP(TRACE2("Delete txtr buf %d at %08X, CRC in RDRAM changed", i, gRenderTextureInfos[i].CI_Info.dwAddr )); SAFE_DELETE(gRenderTextureInfos[i].pRenderTexture); gRenderTextureInfos[i].isUsed = false; continue; } else { gRenderTextureInfos[i].crcCheckedAtFrame = status.gDlistCount; } } } } // Check render_texture memory addresses int FrameBufferManager::CheckAddrInRenderTextures(uint32 addr, bool checkcrc) { for( int i=0; iIsBeingRendered() ) continue; uint32 bufHeight = gRenderTextureInfos[i].knownHeight ? gRenderTextureInfos[i].N64Height : gRenderTextureInfos[i].maxUsedHeight; uint32 bufMemSize = gRenderTextureInfos[i].CI_Info.dwSize*gRenderTextureInfos[i].N64Width*bufHeight; if( addr >=gRenderTextureInfos[i].CI_Info.dwAddr && addr < gRenderTextureInfos[i].CI_Info.dwAddr+bufMemSize) { if(checkcrc) { // Check the CRC in RDRAM if( gRenderTextureInfos[i].crcCheckedAtFrame < status.gDlistCount ) { uint32 crc = ComputeRenderTextureCRCInRDRAM(i); if( gRenderTextureInfos[i].crcInRDRAM != crc ) { // RDRAM has been modified by CPU core TRACE3("Buf %d CRC in RDRAM changed from %08X to %08X", i, gRenderTextureInfos[i].crcInRDRAM, crc ); TXTRBUF_DUMP(TRACE2("Delete txtr buf %d at %08X, crcInRDRAM failed.", i, gRenderTextureInfos[i].CI_Info.dwAddr )); SAFE_DELETE(gRenderTextureInfos[i].pRenderTexture); gRenderTextureInfos[i].isUsed = false; continue; } else { gRenderTextureInfos[i].crcCheckedAtFrame = status.gDlistCount; } } } TXTRBUF_DUMP(TRACE2("Loading texture addr = %08X from txtr buf %d", addr, i)); return i; } } return -1; } // Load texture from render_texture buffer void FrameBufferManager::LoadTextureFromRenderTexture(TxtrCacheEntry* pEntry, int infoIdx) { if( infoIdx < 0 || infoIdx >= numOfTxtBufInfos ) { infoIdx = CheckAddrInRenderTextures(pEntry->ti.Address); } if( infoIdx >= 0 && gRenderTextureInfos[infoIdx].isUsed && gRenderTextureInfos[infoIdx].pRenderTexture ) { TXTRBUF_DUMP(TRACE1("Loading from render_texture %d", infoIdx)); gRenderTextureInfos[infoIdx].pRenderTexture->LoadTexture(pEntry); } } void FrameBufferManager::RestoreNormalBackBuffer() { if( m_curRenderTextureIndex >= 0 && m_curRenderTextureIndex < numOfTxtBufInfos ) { if( gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture ) gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture->SetAsRenderTarget(false); m_isRenderingToTexture = false; m_lastTextureBufferIndex = m_curRenderTextureIndex; } if( !status.bFrameBufferIsDrawn || !status.bFrameBufferDrawnByTriangles ) { gRenderTextureInfos[m_curRenderTextureIndex].isUsed = false; TXTRBUF_DUMP(TRACE2("Delete txtr buf %d at %08X, it is never rendered", m_curRenderTextureIndex, gRenderTextureInfos[m_curRenderTextureIndex].CI_Info.dwAddr )); SAFE_DELETE(gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture); } } uint32 FrameBufferManager::ComputeRenderTextureCRCInRDRAM(int infoIdx) { if( infoIdx >= numOfTxtBufInfos || infoIdx < 0 || !gRenderTextureInfos[infoIdx].isUsed ) return 0; RenderTextureInfo &info = gRenderTextureInfos[infoIdx]; uint32 height = info.knownHeight ? info.N64Height : info.maxUsedHeight; uint8 *pAddr = (uint8*)(g_pRDRAMu8+info.CI_Info.dwAddr); uint32 pitch = (info.N64Width << info.CI_Info.dwSize ) >> 1; return CalculateRDRAMCRC(pAddr, 0, 0, info.N64Width, height, info.CI_Info.dwSize, pitch); } // Activates texture buffer for drawing void FrameBufferManager::ActiveTextureBuffer(void) { status.bCIBufferIsRendered = true; if( status.bHandleN64RenderTexture ) { // Checking against previous render_texture infos int matchidx = -1; //uint32 memsize = ((newRenderTextureInfo.N64Height*newRenderTextureInfo.N64Width)>>1)<= 0 ) { // Reuse the matched slot idxToUse = matchidx; } else { idxToUse = FindASlot(); } if( gRenderTextureInfos[idxToUse].pRenderTexture == NULL || matchidx < 0 ) { int w = newRenderTextureInfo.bufferWidth; if( newRenderTextureInfo.knownHeight == RDP_SETSCISSOR && newRenderTextureInfo.CI_Info.dwAddr == g_ZI.dwAddr ) { w = gRDP.scissor.right; } gRenderTextureInfos[idxToUse].pRenderTexture = new COGLRenderTexture(w, newRenderTextureInfo.bufferHeight, &gRenderTextureInfos[idxToUse], AS_RENDER_TARGET); } // Need to set all variables for gRenderTextureInfos[idxToUse] CRenderTexture *pRenderTexture = gRenderTextureInfos[idxToUse].pRenderTexture; memcpy(&gRenderTextureInfos[idxToUse], &newRenderTextureInfo, sizeof(RenderTextureInfo) ); gRenderTextureInfos[idxToUse].pRenderTexture = pRenderTexture; gRenderTextureInfos[idxToUse].isUsed = true; gRenderTextureInfos[idxToUse].txtEntry.pTexture = pRenderTexture->m_pTexture; gRenderTextureInfos[idxToUse].txtEntry.txtrBufIdx = idxToUse+1; g_pRenderTextureInfo = &gRenderTextureInfos[idxToUse]; // Active the render_texture if( m_curRenderTextureIndex >= 0 && gRenderTextureInfos[m_curRenderTextureIndex].isUsed && gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture ) { gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture->SetAsRenderTarget(false); m_isRenderingToTexture = false; } if( gRenderTextureInfos[idxToUse].pRenderTexture->SetAsRenderTarget(true) ) { m_isRenderingToTexture = true; //Clear(CLEAR_COLOR_AND_DEPTH_BUFFER,0x80808080,1.0f); if( frameBufferOptions.bFillRectNextTextureBuffer ) CGraphicsContext::g_pGraphicsContext->Clear(CLEAR_COLOR_BUFFER,gRDP.fillColor,1.0f); else if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS && g_pRenderTextureInfo->N64Width > 64 && g_pRenderTextureInfo->N64Width < 300 ) { CGraphicsContext::g_pGraphicsContext->Clear(CLEAR_COLOR_BUFFER,0,1.0f); } else if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS && g_pRenderTextureInfo->N64Width < 64 && g_pRenderTextureInfo->N64Width > 32 ) { CGraphicsContext::g_pGraphicsContext->Clear(CLEAR_COLOR_BUFFER,0,1.0f); } m_curRenderTextureIndex = idxToUse; status.bDirectWriteIntoRDRAM = false; //SetScreenMult(1, 1); SetScreenMult(gRenderTextureInfos[m_curRenderTextureIndex].scaleX, gRenderTextureInfos[m_curRenderTextureIndex].scaleY); CRender::g_pRender->UpdateClipRectangle(); // If needed, draw RDRAM into the render_texture //if( frameBufferOptions.bLoadRDRAMIntoRenderTexture ) //{ // CRender::GetRender()->LoadTxtrBufFromRDRAM(); //} } else { if( CDeviceBuilder::m_deviceGeneralType == DIRECTX_DEVICE ) { TRACE1("Error to set Render Target: %d", idxToUse); TRACE1("Addr = %08X", gRenderTextureInfos[idxToUse].CI_Info.dwAddr); TRACE2("Width = %d, Height=%d", gRenderTextureInfos[idxToUse].N64Width, gRenderTextureInfos[idxToUse].N64Height); } } TXTRBUF_DUMP(TRACE2("Rendering to render_texture %d, addr=%08X", idxToUse, g_CI.dwAddr)); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE, {DebuggerAppendMsg("Paused after activating render_texture:\nAddr: 0x%08x, Fmt: %s Size: %s Width: %d, Height:%d", g_CI.dwAddr, pszImgFormat[g_CI.dwFormat], pszImgSize[g_CI.dwSize], g_CI.dwWidth, g_pRenderTextureInfo->N64Height);}); } else { UpdateRecentCIAddr(g_CI); CheckRenderTexturesWithNewCI(g_CI,gRDP.scissor.bottom,false); } } #define SAVE_CI {g_CI.dwAddr = newCI.dwAddr;g_CI.dwFormat = newCI.dwFormat;g_CI.dwSize = newCI.dwSize;g_CI.dwWidth = newCI.dwWidth;g_CI.bpl=newCI.bpl;} // Sets CI address for framebuffer copies void FrameBufferManager::Set_CI_addr(SetImgInfo &newCI) { bool wasDrawingTextureBuffer = status.bN64IsDrawingTextureBuffer; status.bN64IsDrawingTextureBuffer = ( newCI.dwSize != TXT_SIZE_16b || newCI.dwFormat != TXT_FMT_RGBA || newCI.dwWidth < 200 || ( newCI.dwAddr != g_ZI.dwAddr && newCI.dwWidth != 512 && !g_pFrameBufferManager->HasAddrBeenDisplayed(newCI.dwAddr, newCI.dwWidth)) ); status.bN64FrameBufferIsUsed = status.bN64IsDrawingTextureBuffer; if( !wasDrawingTextureBuffer && g_CI.dwAddr == g_ZI.dwAddr && status.bCIBufferIsRendered ) { TXTRBUF_DUMP(TRACE0("ZI is rendered")); if( options.enableHackForGames != HACK_FOR_CONKER && g_uRecentCIInfoPtrs[0]->bCopied == false ) { // Conker is not actually using a backbuffer g_pFrameBufferManager->UpdateRecentCIAddr(g_CI); if( status.leftRendered != -1 && status.topRendered != -1 && status.rightRendered != -1 && status.bottomRendered != -1 ) { RECT rect={status.leftRendered,status.topRendered,status.rightRendered,status.bottomRendered}; g_pFrameBufferManager->SaveBackBuffer(0,&rect); } else { g_pFrameBufferManager->SaveBackBuffer(0,NULL); } } } frameBufferOptions.bFillRectNextTextureBuffer = false; if( g_CI.dwAddr == newCI.dwAddr && status.bHandleN64RenderTexture && (g_CI.dwFormat != newCI.dwFormat || g_CI.dwSize != newCI.dwSize || g_CI.dwWidth != newCI.dwWidth ) ) { // Mario Tennis player shadow g_pFrameBufferManager->CloseRenderTexture(true); if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS ) frameBufferOptions.bFillRectNextTextureBuffer = true; // Hack for Mario Tennis } SAVE_CI; if( g_CI.dwAddr == g_ZI.dwAddr && !status.bN64IsDrawingTextureBuffer ) { if( g_pFrameBufferManager->IsDIaRenderTexture() ) { status.bN64IsDrawingTextureBuffer = true; status.bN64FrameBufferIsUsed = status.bN64IsDrawingTextureBuffer; } } status.bCIBufferIsRendered = false; status.leftRendered = status.topRendered = status.rightRendered = status.bottomRendered = -1; if( currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_CI_CHANGE && !status.bN64IsDrawingTextureBuffer ) { if( status.curRenderBuffer == 0 ) { status.curRenderBuffer = g_CI.dwAddr; } else if( status.curRenderBuffer != g_CI.dwAddr ) { status.curDisplayBuffer = status.curRenderBuffer; CGraphicsContext::Get()->UpdateFrame(); status.curRenderBuffer = g_CI.dwAddr; DEBUGGER_IF_DUMP(pauseAtNext,{DebuggerAppendMsg("Screen Update because CI change to %08X, Display Buf=%08X", status.curRenderBuffer, status.curDisplayBuffer);}); } } if( frameBufferOptions.bAtEachFrameUpdate && !status.bHandleN64RenderTexture ) { if( status.curRenderBuffer != g_CI.dwAddr ) { if( status.gDlistCount%(currentRomOptions.N64FrameBufferWriteBackControl+1) == 0 ) { g_pFrameBufferManager->StoreBackBufferToRDRAM(status.curRenderBuffer, newCI.dwFormat, newCI.dwSize, windowSetting.uViWidth, windowSetting.uViHeight, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); } } //status.curDisplayBuffer = status.curRenderBuffer; status.curRenderBuffer = g_CI.dwAddr; } switch( currentRomOptions.N64RenderToTextureEmuType ) { case TXT_BUF_NONE: if( status.bHandleN64RenderTexture ) g_pFrameBufferManager->CloseRenderTexture(false); status.bHandleN64RenderTexture = false; // Don't handle N64 render_texture stuffs if( !status.bN64IsDrawingTextureBuffer ) g_pFrameBufferManager->UpdateRecentCIAddr(g_CI); break; default: if( status.bHandleN64RenderTexture ) { #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_RENDER_TEXTURE ) { pauseAtNext = TRUE; eventToPause = NEXT_RENDER_TEXTURE; } #endif g_pFrameBufferManager->CloseRenderTexture(true); } status.bHandleN64RenderTexture = status.bN64IsDrawingTextureBuffer; if( status.bHandleN64RenderTexture ) { if( options.enableHackForGames != HACK_FOR_BANJO_TOOIE ) { g_pFrameBufferManager->SetRenderTexture(); } } else { #ifdef DEBUGGER if( g_CI.dwWidth == 512 && pauseAtNext && (eventToPause==NEXT_OBJ_BG || eventToPause==NEXT_SET_CIMG) ) { DebuggerAppendMsg("Warning SetCImg: new Addr=0x%08X, fmt:%s size=%sb, Width=%d\n", g_CI.dwAddr, pszImgFormat[newCI.dwFormat], pszImgSize[newCI.dwSize], newCI.dwWidth); } #endif //g_pFrameBufferManager->UpdateRecentCIAddr(g_CI); // Delay this until the CI buffer is actally drawn } break; } TXTRBUF_DUMP(TRACE4("SetCImg : Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_CI.dwAddr, pszImgFormat[newCI.dwFormat], pszImgSize[newCI.dwSize], newCI.dwWidth)); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG, { DebuggerAppendMsg("Pause after SetCImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_CI.dwAddr, pszImgFormat[newCI.dwFormat], pszImgSize[newCI.dwSize], newCI.dwWidth); } ); } void FrameBufferManager::StoreRenderTextureToRDRAM(int infoIdx) { if( !frameBufferOptions.bRenderTextureWriteBack ) return; if( infoIdx < 0 ) infoIdx = m_lastTextureBufferIndex; if( !gRenderTextureInfos[infoIdx].pRenderTexture ) return; if( gRenderTextureInfos[infoIdx].pRenderTexture->IsBeingRendered() ) { TXTRBUF_DUMP(TRACE1("Cannot SaveTextureBuffer %d, it is being rendered", infoIdx)); return; } gRenderTextureInfos[infoIdx].pRenderTexture->StoreToRDRAM(infoIdx); } //does FB copy to N64 RDAM structure void FrameBufferManager::CopyBufferToRDRAM(uint32 addr, uint32 fmt, uint32 siz, uint32 width, uint32 height, uint32 bufWidth, uint32 bufHeight, uint32 startaddr, uint32 memsize, uint32 pitch, TextureFmt bufFmt, void *buffer, uint32 bufPitch) { uint32 startline=0; if( startaddr == 0xFFFFFFFF ) startaddr = addr; startline = (startaddr-addr)/siz/pitch; if( startline >= height ) { //TRACE0("Warning: check me"); startline = height; } uint32 endline = height; if( memsize != 0xFFFFFFFF ) { endline = (startaddr+memsize-addr)/siz; if( endline % pitch == 0 ) endline /= pitch; else endline = endline/pitch+1; } if( endline > height ) { endline = height; } if( memsize != 0xFFFFFFFF ) { TXTRBUF_DUMP(DebuggerAppendMsg("Start at: 0x%X, from line %d to %d", startaddr-addr, startline, endline);); } int indexes[600]; { float sx; int sx0; float ratio = bufWidth/(float)width; for( uint32 j=0; jIsBeingRendered() ) { TRACE1("Render texture %d is being rendered, cannot display", infoIdx); } else { TRACE1("Texture buffer %d:", infoIdx); TRACE1("Addr=%08X", gRenderTextureInfos[infoIdx].CI_Info.dwAddr); TRACE2("Width=%d, Created Height=%d", gRenderTextureInfos[infoIdx].N64Width,gRenderTextureInfos[infoIdx].N64Height); TRACE2("Fmt=%d, Size=%d", gRenderTextureInfos[infoIdx].CI_Info.dwFormat,gRenderTextureInfos[infoIdx].CI_Info.dwSize); } } else { TRACE1("Texture buffer %d is not used", infoIdx); } } #endif // Saves backbuffer // this is the core to the current framebuffer code // We need to save backbuffer when changed by framebuffer // so that we can use it for framebuffer effects void FrameBufferManager::SaveBackBuffer(int ciInfoIdx, RECT* pSrcRect, bool forceToSaveToRDRAM) { RecentCIInfo &ciInfo = *g_uRecentCIInfoPtrs[ciInfoIdx]; if( ciInfoIdx == 1 ) // to save the current front buffer { CGraphicsContext::g_pGraphicsContext->UpdateFrame(true); } if( frameBufferOptions.bWriteBackBufToRDRAM || forceToSaveToRDRAM ) { uint32 width = ciInfo.dwWidth; uint32 height = ciInfo.dwHeight; if( ciInfo.dwWidth == *g_GraphicsInfo.VI_WIDTH_REG && ciInfo.dwWidth != windowSetting.uViWidth ) { width = windowSetting.uViWidth; height = windowSetting.uViHeight; } StoreBackBufferToRDRAM( ciInfo.dwAddr, ciInfo.dwFormat, ciInfo.dwSize, width, height, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); g_uRecentCIInfoPtrs[ciInfoIdx]->bCopied = true; if( ciInfoIdx == 1 ) // to save the current front buffer { CGraphicsContext::g_pGraphicsContext->UpdateFrame(true); } return; } SetImgInfo tempinfo; tempinfo.dwAddr = ciInfo.dwAddr; tempinfo.dwFormat = ciInfo.dwFormat; tempinfo.dwSize = ciInfo.dwSize; tempinfo.dwWidth = ciInfo.dwWidth; int idx = SetBackBufferAsRenderTexture(tempinfo, ciInfoIdx); CopyBackBufferToRenderTexture(idx, ciInfo, pSrcRect); gRenderTextureInfos[idx].crcCheckedAtFrame = status.gDlistCount; gRenderTextureInfos[idx].crcInRDRAM = ComputeRenderTextureCRCInRDRAM(idx); DEBUGGER_IF_DUMP((logTextureBuffer&&pSrcRect==NULL),TRACE1("SaveBackBuffer at 0x%08X", ciInfo.dwAddr)); DEBUGGER_IF_DUMP((logTextureBuffer&&pSrcRect),TRACE5("SaveBackBuffer at 0x%08X, {%d,%d -%d,%d)", ciInfo.dwAddr, pSrcRect->left,pSrcRect->top,pSrcRect->right,pSrcRect->bottom)); DEBUGGER_IF_DUMP(( pauseAtNext && eventToPause == NEXT_RENDER_TEXTURE),{g_pFrameBufferManager->DisplayRenderTexture(idx);}); g_uRecentCIInfoPtrs[ciInfoIdx]->bCopied = true; } mupen64plus-video-rice-src-2.0/src/FrameBuffer.h0000644000000000000000000001370512165031100017633 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _FRAME_BUFFER_H_ #define _FRAME_BUFFER_H_ #include "typedefs.h" #include "RenderTexture.h" #include "TextureManager.h" typedef int SURFFORMAT; extern void TexRectToN64FrameBuffer_16b(uint32 x0, uint32 y0, uint32 width, uint32 height, uint32 dwTile); extern void TexRectToFrameBuffer_8b(uint32 dwXL, uint32 dwYL, uint32 dwXH, uint32 dwYH, float t0u0, float t0v0, float t0u1, float t0v1, uint32 dwTile); class FrameBufferManager { friend class CGraphicsContext; friend class CDXGraphicsContext; public: FrameBufferManager(); virtual ~FrameBufferManager(); void Initialize(); void CloseUp(); void Set_CI_addr(SetImgInfo &newCI); void UpdateRecentCIAddr(SetImgInfo &ciinfo); void SetAddrBeDisplayed(uint32 addr); bool HasAddrBeenDisplayed(uint32 addr, uint32 width); int FindRecentCIInfoIndex(uint32 addr); bool IsDIaRenderTexture(); int CheckAddrInRenderTextures(uint32 addr, bool checkcrc = true); uint32 ComputeRenderTextureCRCInRDRAM(int infoIdx); void CheckRenderTextureCRCInRDRAM(void); int CheckRenderTexturesWithNewCI(SetImgInfo &CIinfo, uint32 height, bool byNewTxtrBuf); virtual void ClearN64FrameBufferToBlack(uint32 left=0, uint32 top=0, uint32 width=0, uint32 height=0); virtual int SetBackBufferAsRenderTexture(SetImgInfo &CIinfo, int ciInfoIdx); void LoadTextureFromRenderTexture(TxtrCacheEntry* pEntry, int infoIdx); void UpdateFrameBufferBeforeUpdateFrame(); virtual void RestoreNormalBackBuffer(); // restore the normal back buffer virtual void CopyBackToFrameBufferIfReadByCPU(uint32 addr); virtual void SetRenderTexture(void); virtual void CloseRenderTexture(bool toSave); virtual void ActiveTextureBuffer(void); int IsAddrInRecentFrameBuffers(uint32 addr); int CheckAddrInBackBuffers(uint32 addr, uint32 memsize, bool copyToRDRAM = false); uint8 CIFindIndex(uint16 val); uint32 ComputeCImgHeight(SetImgInfo &info, uint32 &height); int FindASlot(void); bool ProcessFrameWriteRecord(); void FrameBufferWriteByCPU(uint32 addr, uint32 size); void FrameBufferReadByCPU( uint32 addr ); bool FrameBufferInRDRAMCheckCRC(); void StoreRenderTextureToRDRAM(int infoIdx = -1); virtual bool IsRenderingToTexture() {return m_isRenderingToTexture;} // Device dependent functions virtual void SaveBackBuffer(int ciInfoIdx, RECT* pRect=NULL, bool forceToSaveToRDRAM = false); // Copy the current back buffer to temp buffer virtual void CopyBackBufferToRenderTexture(int idx, RecentCIInfo &ciInfo, RECT* pRect=NULL) {} // Copy the current back buffer to temp buffer virtual void CopyBufferToRDRAM(uint32 addr, uint32 fmt, uint32 siz, uint32 width, uint32 height, uint32 bufWidth, uint32 bufHeight, uint32 startaddr, uint32 memsize, uint32 pitch, TextureFmt bufFmt, void *surf, uint32 bufPitch); virtual void StoreBackBufferToRDRAM(uint32 addr, uint32 fmt, uint32 siz, uint32 width, uint32 height, uint32 bufWidth, uint32 bufHeight, uint32 startaddr=0xFFFFFFFF, uint32 memsize=0xFFFFFFFF, uint32 pitch=0, SURFFORMAT surf_fmt=SURFFMT_A8R8G8B8) {} #ifdef DEBUGGER virtual void DisplayRenderTexture(int infoIdx = -1); #endif protected: bool m_isRenderingToTexture; int m_curRenderTextureIndex; int m_lastTextureBufferIndex; }; class DXFrameBufferManager : public FrameBufferManager { virtual ~DXFrameBufferManager() {} public: // Device dependent functions virtual void CopyBackBufferToRenderTexture(int idx, RecentCIInfo &ciInfo, RECT* pRect=NULL); // Copy the current back buffer to temp buffer virtual void StoreBackBufferToRDRAM(uint32 addr, uint32 fmt, uint32 siz, uint32 width, uint32 height, uint32 bufWidth, uint32 bufHeight, uint32 startaddr=0xFFFFFFFF, uint32 memsize=0xFFFFFFFF, uint32 pitch=0, SURFFORMAT surf_fmt=SURFFMT_A8R8G8B8); }; class OGLFrameBufferManager : public FrameBufferManager { virtual ~OGLFrameBufferManager() {} public: // Device dependent functions virtual void CopyBackBufferToRenderTexture(int idx, RecentCIInfo &ciInfo, RECT* pRect=NULL); // Copy the current back buffer to temp buffer virtual void StoreBackBufferToRDRAM(uint32 addr, uint32 fmt, uint32 siz, uint32 width, uint32 height, uint32 bufWidth, uint32 bufHeight, uint32 startaddr=0xFFFFFFFF, uint32 memsize=0xFFFFFFFF, uint32 pitch=0, SURFFORMAT surf_fmt=SURFFMT_A8R8G8B8); }; extern RenderTextureInfo gRenderTextureInfos[]; extern RenderTextureInfo newRenderTextureInfo; #define NEW_TEXTURE_BUFFER extern RenderTextureInfo g_ZI_saves[2]; extern RenderTextureInfo *g_pRenderTextureInfo; extern FrameBufferManager* g_pFrameBufferManager; extern RecentCIInfo g_RecentCIInfo[]; extern RecentViOriginInfo g_RecentVIOriginInfo[]; extern RenderTextureInfo gRenderTextureInfos[]; extern int numOfTxtBufInfos; extern RecentCIInfo *g_uRecentCIInfoPtrs[5]; extern uint8 RevTlutTable[0x10000]; extern uint32 CalculateRDRAMCRC(void *pAddr, uint32 left, uint32 top, uint32 width, uint32 height, uint32 size, uint32 pitchInBytes ); extern uint16 ConvertRGBATo555(uint8 r, uint8 g, uint8 b, uint8 a); extern uint16 ConvertRGBATo555(uint32 color32); extern void InitTlutReverseLookup(void); #endif mupen64plus-video-rice-src-2.0/src/GeneralCombiner.cpp0000644000000000000000000013167312165031100021043 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "GeneralCombiner.h" #include "Combiner.h" #include "Debugger.h" extern const int numOf3StageCombiners; extern const int numOf2StageCombiners; extern GeneralCombinerInfo CombinerTable2Stages[]; extern GeneralCombinerInfo CombinerTable3Stages[]; CGeneralCombiner::CGeneralCombiner() { m_lastGeneralIndex=0; m_ppGeneralDecodedMux=NULL; m_bTxtOpAdd=true; m_bTxtOpSub=false; m_bTxtOpLerp=false; m_bTxtOpAddSmooth=false; m_bTxtOpBlendCurAlpha=false; m_bTxtOpBlendDifAlpha=true; m_bTxtOpBlendFacAlpha=false; m_bTxtOpBlendTxtAlpha=true; m_bTxtOpMulAdd=false; m_dwGeneralMaxStages=2; } bool isTex(uint32 val) { return ( (val&MUX_MASK) == MUX_TEXEL0 || (val&MUX_MASK) == MUX_TEXEL1 ); } int toTex(uint32 val) { return (val&MUX_MASK)-MUX_TEXEL0; } bool isComb(uint32 val) { return (val&MUX_MASK)==MUX_COMBINED; } #ifdef DEBUGGER const char* BlendFuncStr[] = { "Enable both", "Disable alpha", "Disable color", "Disable both", "Color one", "Alpha one", }; const char* cmopstrs[] = { "Sel", "Mod", "Add", "Sub", "Lerp", "AddSmooth", "BlCurA", "BlDifA", "BlFacA", "BlTexA", "MulAdd", }; void CGeneralCombiner::General_DisplayBlendingStageInfo(GeneralCombinerInfo &gci) { char str1[30],str2[30],str3[30]; DebuggerAppendMsg("\nStages:%d, Alpha:%s, Factor:%s, Specular:%s Dif Color:0x%X Dif Alpha:0x%X\n", gci.nStages, BlendFuncStr[gci.blendingFunc], DecodedMux::FormatStr((uint8)gci.TFactor,str1), DecodedMux::FormatStr((uint8)gci.specularPostOp,str2), gci.m_dwShadeColorChannelFlag, gci.m_dwShadeAlphaChannelFlag); for( int i=0; im_n64Combiners[curN64Stage]; StageOperate *op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); if( ( m.d == MUX_0 || m.d == MUX_1 ) && curN64Stage==1 ) { //if( m.d == MUX_0 ) // gci.blendingFunc = DISABLE_COLOR; //if( m.d == MUX_1 ) // gci.blendingFunc = DISABLE_ALPHA; op->op = CM_REPLACE; op->Arg1 = MUX_COMBINED; op->Arg2 = CM_IGNORE; op->Arg0 = CM_IGNORE; } else { if( isTex(m.d) ) Check1TxtrForAlpha(curN64Stage, curStage, gci, toTex(m.d)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op = CM_REPLACE; op->Arg1 = m.d; op->Arg2 = CM_IGNORE; op->Arg0 = CM_IGNORE; } if( !gci.stages[curStage].bTextureUsed ) gci.stages[curStage].dwTexture = GetTexelNumber(m); textureUsedInStage[curStage][curN64Stage%2] = IsTxtrUsed(m); return curStage; } int CGeneralCombiner::GenCI_Type_A_MOD_C(int curN64Stage, int curStage, GeneralCombinerInfo &gci, uint32 dxop) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; StageOperate *op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); if( CountTexel1Cycle(m) == 2 ) { // As we can not use both texture in one stage // we split them to two stages // Stage1: SELECT txt1 // Stage2: MOD txt2 if( gci.stages[curStage].bTextureUsed && gci.stages[curStage].dwTexture != (unsigned int)toTex(m.a) ) swap(m.a,m.c); op->op =CM_REPLACE; op->Arg1 = m.a; op->Arg2 = CM_IGNORE; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = toTex(m.a); textureUsedInStage[curStage][curN64Stage%2] = true; NextStage(curStage); Check1TxtrForAlpha(curN64Stage, curStage, gci, toTex(m.c)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op =dxop; op->Arg1 = (m.c); op->Arg2 = MUX_COMBINED; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = toTex(m.c); textureUsedInStage[curStage][curN64Stage%2] = true; } else { if( CountTexel1Cycle(m) == 1) { Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); } op->op = dxop; op->Arg1 = (m.a); op->Arg2 = (m.c); op->Arg0 = CM_IGNORE; if( !gci.stages[curStage].bTextureUsed ) gci.stages[curStage].dwTexture = GetTexelNumber(m); textureUsedInStage[curStage][curN64Stage%2] = IsTxtrUsed(m); } return curStage; } int CGeneralCombiner::GenCI_Type_A_ADD_D(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { uint32 opToUse = m_bTxtOpAdd?CM_ADD:CM_MODULATE; N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; swap(m.c, m.d); curStage = GenCI_Type_A_MOD_C(curN64Stage, curStage, gci, opToUse); swap(m.c, m.d); return curStage; } int CGeneralCombiner::GenCI_Type_A_SUB_B(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; if( !m_bTxtOpSub ) { swap(m.c, m.b); curStage = GenCI_Type_A_MOD_C(curN64Stage, curStage, gci); swap(m.c, m.b); return curStage; } StageOperate *op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); if( CountTexel1Cycle(m) == 2 ) { Check1TxtrForAlpha(curN64Stage, curStage, gci, toTex(m.b)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op =CM_REPLACE; op->Arg1 = (m.b); op->Arg2 = CM_IGNORE; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = toTex(m.b); textureUsedInStage[curStage][curN64Stage%2] = true; NextStage(curStage); Check1TxtrForAlpha(curN64Stage, curStage, gci, toTex(m.a)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op =CM_SUBTRACT; op->Arg1 = (m.a); op->Arg2 = MUX_COMBINED; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = toTex(m.a); textureUsedInStage[curStage][curN64Stage%2] = true; } else { if( CountTexel1Cycle(m) == 1) { Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); } op->op = CM_SUBTRACT; op->Arg1 = (m.a); op->Arg2 = (m.b); op->Arg0 = CM_IGNORE; if( !gci.stages[curStage].bTextureUsed ) gci.stages[curStage].dwTexture = GetTexelNumber(m); textureUsedInStage[curStage][curN64Stage%2] = IsTxtrUsed(m); } return curStage; } int CGeneralCombiner::GenCI_Type_A_MOD_C_ADD_D(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; StageOperate *op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); if( !m_bTxtOpMulAdd ) { N64CombinerType save = m; m.d = MUX_0; curStage = GenCI_Type_A_MOD_C(curN64Stage, curStage, gci); m = save; m.c = MUX_0; m.a = MUX_COMBINED; NextStage(curStage); curStage = GenCI_Type_A_ADD_D(curN64Stage, curStage, gci); m = save; return curStage; } if( CountTexel1Cycle(m) == 2 ) { if( !gci.stages[curStage].bTextureUsed ) { gci.stages[curStage].dwTexture = 0; gci.stages[curStage].bTextureUsed = true; } op->op = CM_REPLACE; op->Arg2 = CM_IGNORE; op->Arg0 = CM_IGNORE; op->Arg1 = MUX_TEXEL0 + gci.stages[curStage].dwTexture ; N64CombinerType m2 = m; uint8* vals = (uint8*)&m2; for( int i=0; i<4; i++ ) { if( (unsigned int)(vals[i]&MUX_MASK) == MUX_TEXEL0 + gci.stages[curStage].dwTexture ) { vals[i] = MUX_COMBINED | (vals[i]&0xe0); } } NextStage(curStage); Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m2)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op = CM_MULTIPLYADD; op->Arg1 = m2.a; op->Arg2 = m2.c; op->Arg0 = m2.d; if( !gci.stages[curStage].bTextureUsed ) gci.stages[curStage].dwTexture = GetTexelNumber(m2); textureUsedInStage[curStage][curN64Stage%2] = IsTxtrUsed(m2); } else { Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op = CM_MULTIPLYADD; op->Arg1 = (m.a); op->Arg2 = (m.c); op->Arg0 = (m.d); if( !gci.stages[curStage].bTextureUsed ) gci.stages[curStage].dwTexture = GetTexelNumber(m); textureUsedInStage[curStage][curN64Stage%2] = IsTxtrUsed(m); } return curStage; } int CGeneralCombiner::GenCI_Type_A_LERP_B_C(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; StageOperate *op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); N64CombinerType save = m; if( CountTexel1Cycle(m) == 2 ) { // There are two textures int texToUse = CheckWhichTexToUseInThisStage(curN64Stage, curStage, gci); op->op =CM_REPLACE; op->Arg1 = (MUX_TEXEL0+texToUse); op->Arg2 = CM_IGNORE; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = texToUse; textureUsedInStage[curStage][curN64Stage%2] = true; (*m_ppGeneralDecodedMux)->ReplaceVal(MUX_TEXEL0+texToUse, MUX_COMBINED, curN64Stage); NextStage(curStage); Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); } // Now we have only 1 texture left Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); if( m.a == MUX_1 ) { op->op = CM_ADDSMOOTH; op->Arg1 = (m.b); op->Arg2 = (m.c); op->Arg0 = CM_IGNORE; } else if( m.a == MUX_0 ) { op->op = CM_MODULATE; m.a = 0; op->Arg1 = (m.b); op->Arg2 = (m.c^MUX_COMPLEMENT); op->Arg0 = CM_IGNORE; } else { if( ((m.c&MUX_ALPHAREPLICATE) || (curN64Stage%2)==1 || m_bTxtOpLerp == false) && ((m.c&MUX_MASK)==MUX_SHADE || (m.c&MUX_MASK)==MUX_COMBINED || (m.c&MUX_MASK)==MUX_TEXEL0 || (m.c&MUX_MASK)==MUX_TEXEL1 ) ) { if( curN64Stage == 2 && (m.c&MUX_ALPHAREPLICATE) == 0 ) { op->op = CM_MODULATE; op->Arg1 = m.b; op->Arg2 = m.c|MUX_COMPLEMENT; op->Arg0 = CM_IGNORE; resultIsGood = false; } else { if( (m.c&MUX_MASK)==MUX_SHADE ) { op->op = CM_BLENDDIFFUSEALPHA; } else if( (m.c&MUX_MASK) == MUX_COMBINED ) { op->op = CM_BLENDCURRENTALPHA; } else if( (m.c&MUX_MASK) == MUX_TEXEL0 ) { op->op = CM_BLENDTEXTUREALPHA; } else if( (m.c&MUX_MASK)==MUX_TEXEL1 ) { op->op = CM_BLENDTEXTUREALPHA; } else { op->op = CM_BLENDDIFFUSEALPHA; } op->Arg1 = (m.a); op->Arg2 = (m.b); op->Arg0 = m.c|MUX_ALPHAREPLICATE; } } else { if( ((m.c&MUX_ALPHAREPLICATE) || (curN64Stage%2)==1 || m_bTxtOpLerp == false) && ((((m.c&MUX_MASK)==MUX_ENV) || ((m.c&MUX_MASK)==MUX_PRIM)) )) { op->op = CM_BLENDFACTORALPHA; op->Arg1 = (m.a); op->Arg2 = (m.b); op->Arg0 = m.c|MUX_ALPHAREPLICATE; } else { op->op = CM_INTERPOLATE; op->Arg0 = (m.c); op->Arg1 = (m.a); op->Arg2 = (m.b); } } } gci.stages[curStage].dwTexture = GetTexelNumber(m); textureUsedInStage[curStage][curN64Stage%2] = IsTxtrUsed(m); m = save; return curStage; } int CGeneralCombiner::GenCI_Type_A_B_C_D(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; StageOperate *op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); N64CombinerType save = m; if( CountTexel1Cycle(m) == 2 ) { if( isTex(m.a) && !isTex(m.c) && curN64Stage == 0 && isTex(m.d) && toTex(m.a) != toTex(m.d) ) { if( m_dwGeneralMaxStages >= 4 ) { op->op = CM_SUBTRACT; op->Arg1 = m.a; op->Arg2 = m.b; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = toTex(m.a); textureUsedInStage[curStage][curN64Stage%2] = true; NextStage(curStage); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op = CM_MULTIPLYADD; op->Arg1 = MUX_COMBINED; op->Arg2 = m.c; op->Arg0 = m.d; gci.stages[curStage].dwTexture = toTex(m.d); textureUsedInStage[curStage][curN64Stage%2] = true; resultIsGood = true; } else { op->op = CM_MODULATE; op->Arg1 = m.a; op->Arg2 = m.c; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = toTex(m.a); textureUsedInStage[curStage][curN64Stage%2] = true; NextStage(curStage); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op = CM_ADD; op->Arg1 = MUX_COMBINED; op->Arg2 = m.d; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = toTex(m.d); textureUsedInStage[curStage][curN64Stage%2] = true; resultIsGood = false; } } else { // There are two textures int texToUse = CheckWhichTexToUseInThisStage(curN64Stage, curStage, gci); op->op =CM_REPLACE; op->Arg1 = (MUX_TEXEL0+texToUse); op->Arg2 = CM_IGNORE; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = texToUse; textureUsedInStage[curStage][curN64Stage%2] = true; (*m_ppGeneralDecodedMux)->ReplaceVal(MUX_TEXEL0+texToUse, MUX_COMBINED, curN64Stage); NextStage(curStage); Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); m.a = MUX_COMBINED; m.c = MUX_TEXEL0+(1-texToUse); m.b = m.d = 0; curStage = GenCI_Type_A_MOD_C(curN64Stage, curStage, gci); } } else if( CountTexel1Cycle(m) == 1 ) { if( m_dwGeneralMaxStages < 4 ) { Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m)); op->Arg1 = (MUX_TEXEL0+GetTexelNumber(m)); if( (*m_ppGeneralDecodedMux)->isUsedInCycle(MUX_SHADE, curN64Stage) ) { op->op =CM_MODULATE; op->Arg2 = MUX_SHADE; } else { op->op =CM_REPLACE; op->Arg2 = 0; } op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = GetTexelNumber(m); textureUsedInStage[curStage][curN64Stage%2] = true; } else { curStage = GenCI_Type_A_SUB_B_MOD_C(curN64Stage, curStage, gci); m.a = MUX_COMBINED; NextStage(curStage); curStage = GenCI_Type_A_ADD_D(curN64Stage, curStage, gci); } } else { m.d = 0; curStage = GenCI_Type_A_SUB_B_MOD_C(curN64Stage, curStage, gci); m = save; m.a = MUX_COMBINED; m.b = m.c = 0; NextStage(curStage); curStage = GenCI_Type_A_ADD_D(curN64Stage, curStage, gci); } m = save; return curStage; } int CGeneralCombiner::GenCI_Type_A_SUB_B_ADD_D(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; N64CombinerType save = m; m.d = MUX_0; curStage = GenCI_Type_A_SUB_B(curN64Stage, curStage, gci); m = save; m.a = MUX_COMBINED; m.b = MUX_0; NextStage(curStage); curStage = GenCI_Type_A_ADD_D(curN64Stage, curStage, gci); m = save; return curStage; } int CGeneralCombiner::GenCI_Type_A_ADD_B_MOD_C(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; N64CombinerType save = m; m.d = m.b; m.b = 0; curStage = GenCI_Type_A_ADD_D(curN64Stage, curStage, gci); m = save; m.b = MUX_0; m.a = MUX_COMBINED; NextStage(curStage); curStage = GenCI_Type_A_MOD_C(curN64Stage, curStage, gci); m = save; return curStage; } int CGeneralCombiner::GenCI_Type_A_B_C_A(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { // We can not do too much with this type, it is not a bad idea to use LERP to simplify it. //return GenCI_Type_A_LERP_B_C(curN64Stage, curStage, gci); return GenCI_Type_A_B_C_D(curN64Stage, curStage, gci); } int CGeneralCombiner::GenCI_Type_A_SUB_B_MOD_C(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; N64CombinerType save = m; m.c = MUX_0; curStage = GenCI_Type_A_SUB_B(curN64Stage, curStage, gci); m = save; m.b = MUX_0; m.a = MUX_COMBINED; NextStage(curStage); curStage = GenCI_Type_A_MOD_C(curN64Stage, curStage, gci); m = save; return curStage; } ///////////////////////////////////// // End of gci generating functions // ///////////////////////////////////// void CGeneralCombiner::SkipStage(StageOperate &op, int &curStage) { op.op = CM_REPLACE; op.Arg1 = MUX_COMBINED; op.Arg2 = CM_IGNORE; op.Arg0 = CM_IGNORE; NextStage(curStage); } void CGeneralCombiner::NextStage(int &curStage) { if( curStage < m_dwGeneralMaxStages-1 ) { curStage++; } else { curStage++; resultIsGood = false; TRACE0("Stage overflow"); } } void CGeneralCombiner::Check1TxtrForAlpha(int curN64Stage, int &curStage, GeneralCombinerInfo &gci, int tex) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; if( curN64Stage%2 && IsTxtrUsed(m) ) { while (curStagem_n64Combiners[curN64Stage]; if( curN64Stage%2 && IsTxtrUsed(m) ) { if( tex1 == tex2 ) { while (curStage m_dwGeneralMaxStages ) { resultIsGood = false; gci.nStages = m_dwGeneralMaxStages; } if( mux.m_ColorTextureFlag[0] != 0 || mux.m_ColorTextureFlag[1] != 0 ) { resultIsGood = false; } // The bResultIsGoodWithinStages is for Semi-Pixel shader combiner, don't move the code down gci.bResultIsGoodWithinStages = resultIsGood; if( mux.HowManyConstFactors() > 1 || gci.specularPostOp != MUX_0 || gci.blendingFunc != ENABLE_BOTH ) { gci.bResultIsGoodWithinStages = false; } if( gci.nStages > stages[0] ) // Color has less stages { for( int i=stages[0]; i stages[1] ) // Color has less stages { for( int i=stages[1]; i= m_dwGeneralMaxStages ) { extern int noOfTwoStages; extern GeneralCombinerInfo twostages[]; for( int k=0; km_dWords[0]; result.muxDWords[1] = (*m_ppGeneralDecodedMux)->m_dWords[1]; result.muxDWords[2] = (*m_ppGeneralDecodedMux)->m_dWords[2]; result.muxDWords[3] = (*m_ppGeneralDecodedMux)->m_dWords[3]; result.m_dwShadeAlphaChannelFlag = (*m_ppGeneralDecodedMux)->m_dwShadeAlphaChannelFlag; result.m_dwShadeColorChannelFlag = (*m_ppGeneralDecodedMux)->m_dwShadeColorChannelFlag; result.colorTextureFlag[0] = (*m_ppGeneralDecodedMux)->m_ColorTextureFlag[0]; result.colorTextureFlag[1] = (*m_ppGeneralDecodedMux)->m_ColorTextureFlag[1]; result.dwMux0 = (*m_ppGeneralDecodedMux)->m_dwMux0; result.dwMux1 = (*m_ppGeneralDecodedMux)->m_dwMux1; m_vCompiledCombinerStages.push_back(result); m_lastGeneralIndex = m_vCompiledCombinerStages.size()-1; return m_lastGeneralIndex; } int CGeneralCombiner::FindCompiledMux( ) { #ifdef DEBUGGER if( debuggerDropCombiners || debuggerDropGeneralCombiners ) { m_vCompiledCombinerStages.clear(); //m_dwLastMux0 = m_dwLastMux1 = 0; debuggerDropCombiners = false; debuggerDropGeneralCombiners = false; } #endif for( uint32 i=0; im_dwMux0 && m_vCompiledCombinerStages[i].dwMux1 == (*m_ppGeneralDecodedMux)->m_dwMux1 ) { m_lastGeneralIndex = i; return i; } } return -1; } bool LM_textureUsedInStage[8]; void CGeneralCombiner::LM_GenCI_Init(GeneralCombinerInfo &gci) { gci.specularPostOp=gci.TFactor=MUX_0; gci.blendingFunc = ENABLE_BOTH; for( int i=0; i<8; i++) { gci.stages[i].dwTexture = 0; LM_textureUsedInStage[i] = false; } } //#define fillstage(opr,a1,a2,a3) {op->op=opr;op->Arg1=a1;op->Arg2=a2;op->Arg0=a3;curStage++;} inline void FillStage(StageOperate &op, uint32 opr, uint32 a1, uint32 a2, uint32 a3) { op.op = opr; op.Arg1 = a1; op.Arg2 = a2; op.Arg0 = a3; } /************************************************************************/ /* New functions, will generate stages within stage limited */ /* and return the number of stages used. */ /************************************************************************/ int CGeneralCombiner::LM_GenCI_Type_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { int originalstage=curStage; StageOperate *op = ((StageOperate*)(&(gci.stages[curStage]))) + channel; if( checktexture && LM_Check1TxtrForAlpha(curStage, gci, m.d ) ) { if( limit > 1 ) { FillStage(*op,CM_REPLACE,MUX_COMBINED,CM_IGNORE,CM_IGNORE); curStage++; op = ((StageOperate*)(&(gci.stages[curStage]))) + channel; FillStage(*op,CM_REPLACE,m.d,CM_IGNORE,CM_IGNORE); } else { // It is not allowed to use two stages, what to do? // It should not happen anyway TRACE0("Check me here, at LM_GenCI_Type_D"); } } else { FillStage(*op,CM_REPLACE,m.d,CM_IGNORE,CM_IGNORE); } gci.stages[curStage].dwTexture = GetTexelNumber(m); LM_textureUsedInStage[curStage] = IsTxtrUsed(m); curStage++; return curStage-originalstage; } int CGeneralCombiner::LM_GenCI_Type_A_MOD_C(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci, uint32 dxop) { int originalstage=curStage; StageOperate *op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; int numberOfTex = CountTexel1Cycle(m); if( numberOfTex == 2 ) { // As we can not use both texture in one stage // we split them to two stages // Stage1: SELECT txt1 // Stage2: MOD txt2 if( checktexture ) { if( LM_Check1TxtrForAlpha(curStage, gci, m.a ) ) { FillStage(*op,CM_REPLACE,m.c,CM_IGNORE,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.c); LM_textureUsedInStage[curStage] = true; curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.a,MUX_COMBINED,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.a); LM_textureUsedInStage[curStage] = true; curStage++; } else { FillStage(*op,CM_REPLACE,m.a,CM_IGNORE,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.a); LM_textureUsedInStage[curStage] = true; curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.c,MUX_COMBINED,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.c); LM_textureUsedInStage[curStage] = true; curStage++; } } else { FillStage(*op,CM_REPLACE,m.a,CM_IGNORE,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.a); LM_textureUsedInStage[curStage] = true; curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.c,MUX_COMBINED,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.c); LM_textureUsedInStage[curStage] = true; curStage++; } } else if( numberOfTex == 1) { if( checktexture ) { if( isTex(m.a) ) { if( LM_Check1TxtrForAlpha(curStage, gci, m.a ) ) { FillStage(*op,CM_REPLACE,m.c,CM_IGNORE,CM_IGNORE); curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.a,MUX_COMBINED,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.a); LM_textureUsedInStage[curStage] = true; curStage++; } else { FillStage(*op,CM_REPLACE,m.a,CM_IGNORE,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.a); LM_textureUsedInStage[curStage] = true; curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.c,MUX_COMBINED,CM_IGNORE); curStage++; } } else { if( LM_Check1TxtrForAlpha(curStage, gci, m.c ) ) { FillStage(*op,CM_REPLACE,m.a,CM_IGNORE,CM_IGNORE); curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.c,MUX_COMBINED,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.c); LM_textureUsedInStage[curStage] = true; curStage++; } else { FillStage(*op,CM_REPLACE,m.c,CM_IGNORE,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.c); LM_textureUsedInStage[curStage] = true; curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.a,MUX_COMBINED,CM_IGNORE); curStage++; } } } else { if( isTex(m.a) ) { FillStage(*op,CM_REPLACE,m.a,CM_IGNORE,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.a); LM_textureUsedInStage[curStage] = true; curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.c,MUX_COMBINED,CM_IGNORE); curStage++; } else { FillStage(*op,CM_REPLACE,m.c,CM_IGNORE,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.c); LM_textureUsedInStage[curStage] = true; curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.a,MUX_COMBINED,CM_IGNORE); curStage++; } } } else { FillStage(*op,dxop,m.a,m.c,CM_IGNORE); curStage++; } return curStage-originalstage; } int CGeneralCombiner::LM_GenCI_Type_A_ADD_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_SUB_B(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_LERP_B_C(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_MOD_C_ADD_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_SUB_B_ADD_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_SUB_B_MOD_C(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_ADD_B_MOD_C(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_B_C_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_B_C_A(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_ParseDecodedMux() { return 0; } bool CGeneralCombiner::LM_Check1TxtrForAlpha(int curStage, GeneralCombinerInfo &gci, uint32 val ) { return !( isTex(val) && LM_textureUsedInStage[curStage] && gci.stages[curStage].dwTexture != (unsigned int)toTex(val) ); } void CGeneralCombiner::LM_SkipStage(StageOperate &op) { op.op = CM_REPLACE; op.Arg1 = MUX_COMBINED; op.Arg2 = CM_IGNORE; op.Arg0 = CM_IGNORE; } mupen64plus-video-rice-src-2.0/src/GeneralCombiner.h0000644000000000000000000002331212165031100020476 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GENERAL_COMBINER_H_ #define _GENERAL_COMBINER_H_ #include #include "DecodedMux.h" class GeneralCombineStage { public: StageOperate colorOp; StageOperate alphaOp; uint32 dwTexture; //Which texture to apply, 0 or 1 bool bTextureUsed; BOOL operator!=(const GeneralCombineStage & cs) const { return !(operator==(cs)); } BOOL operator==(const GeneralCombineStage & cs) const { return ( cs.colorOp.Arg1 == colorOp.Arg1 && cs.colorOp.Arg2 == colorOp.Arg2 && cs.colorOp.Arg0 == colorOp.Arg0 && cs.alphaOp.Arg1 == alphaOp.Arg1 && cs.alphaOp.Arg2 == alphaOp.Arg2 && cs.alphaOp.Arg0 == alphaOp.Arg0 && cs.colorOp.op == colorOp.op && cs.alphaOp.op == alphaOp.op && cs.dwTexture == dwTexture&& cs.bTextureUsed==bTextureUsed); } }; class GeneralCombinerInfo { public: uint32 muxDWords[4]; // Simplified Mux uint32 dwMux0; uint32 dwMux1; int nStages; BlendingFunc blendingFunc; uint32 TFactor; uint32 m_dwShadeColorChannelFlag; uint32 m_dwShadeAlphaChannelFlag; uint32 specularPostOp; uint32 colorTextureFlag[2]; GeneralCombineStage stages[8]; bool bResultIsGoodWithinStages; BOOL operator!=(const GeneralCombinerInfo & sci) const { return !(operator==(sci)); } BOOL operator==(const GeneralCombinerInfo & sci) const { int i; if (sci.nStages != nStages) return FALSE; if (sci.blendingFunc != blendingFunc) return FALSE; for (i = 0; i < nStages; i++) { if (sci.stages[i] != stages[i]) return FALSE; } if( sci.TFactor != TFactor ) return FALSE; if( sci.specularPostOp != specularPostOp ) return FALSE; if( sci.m_dwShadeColorChannelFlag != m_dwShadeColorChannelFlag ) return FALSE; if( sci.m_dwShadeAlphaChannelFlag != m_dwShadeAlphaChannelFlag ) return FALSE; if( sci.colorTextureFlag[0] != colorTextureFlag[0] ) return FALSE; if( sci.colorTextureFlag[1] != colorTextureFlag[1] ) return FALSE; return TRUE; } }; enum CombinerOp { CM_REPLACE, CM_MODULATE, CM_ADD, CM_SUBTRACT, CM_INTERPOLATE, // == LERP in DirectX, INTERPOLATE = OpenGL CM_ADDSMOOTH, // For DirectX only, for OpenGL, use INTERPOLATE CM_BLENDCURRENTALPHA, // For DirectX only, for OpenGL, use INTERPOLATE CM_BLENDDIFFUSEALPHA, // For DirectX only, for OpenGL, use INTERPOLATE CM_BLENDFACTORALPHA, // For DirectX only, for OpenGL, use INTERPOLATE CM_BLENDTEXTUREALPHA, // For DirectX only, for OpenGL, use INTERPOLATE CM_MULTIPLYADD, // For DirectX only }; #define CM_IGNORE 0 #define CM_IGNORE_BYTE 0xFF /************************************************************************/ /* This general combiner class is designed for general DirectX combiner */ /* and OpenGL 1.2/1.3 combiner. Such combiners have the following */ /* limitions and conditions: */ /* */ /* - Supporting at least 2 textures */ /* - Supporting at least 2 combiner stages */ /* - At each combiner stages, only 1 texture can be used */ /* - Supporting only 1 constant color */ /* - Supporting more or less texture combine operations, depending */ /* on devices caps */ /* */ /* Before using this class, device caps boolean flags must be set */ /* externally by owner of the class object (or a subclass object). */ /* */ /* */ /************************************************************************/ class CGeneralCombiner { protected: CGeneralCombiner(); int FindCompiledMux(); int ParseDecodedMux(); void ParseDecodedMuxForConstants(GeneralCombinerInfo &res); int SaveParserResult(GeneralCombinerInfo &result); int m_lastGeneralIndex; DecodedMux **m_ppGeneralDecodedMux; /* * Texture ops flags */ bool m_bTxtOpAdd; bool m_bTxtOpSub; bool m_bTxtOpLerp; // LERP is for DirectX, INTERPOLATE is for OpenGL bool m_bTxtOpAddSmooth; // For DirectX only, for OpenGL, use INTERPOLATE bool m_bTxtOpBlendCurAlpha; // For DirectX only, for OpenGL, use INTERPOLATE bool m_bTxtOpBlendDifAlpha; // For DirectX only, for OpenGL, use INTERPOLATE bool m_bTxtOpBlendFacAlpha; // For DirectX only, for OpenGL, use INTERPOLATE bool m_bTxtOpBlendTxtAlpha; // For DirectX only, for OpenGL, use INTERPOLATE bool m_bTxtOpMulAdd; // For DirectX only int m_dwGeneralMaxStages; std::vector m_vCompiledCombinerStages; protected: // combiner info generating functions void GenCI_Init(GeneralCombinerInfo &ci); void SkipStage(StageOperate &op, int &curStage); void NextStage(int &curStage); void Check1TxtrForAlpha(int curN64Stage, int &curStage, GeneralCombinerInfo &ci, int tex); int Check2TxtrForAlpha(int curN64Stage, int &curStage, GeneralCombinerInfo &ci, int tex1, int tex2); int CheckWhichTexToUseInThisStage(int curN64Stage, int curStage, GeneralCombinerInfo &ci); int GenCI_Type_D(int curN64Stage, int curStage, GeneralCombinerInfo &ci); int GenCI_Type_A_MOD_C(int curN64Stage, int curStage, GeneralCombinerInfo &ci, uint32 dxop=CM_MODULATE); int GenCI_Type_A_ADD_D(int curN64Stage, int curStage, GeneralCombinerInfo &ci); int GenCI_Type_A_SUB_B(int curN64Stage, int curStage, GeneralCombinerInfo &ci); int GenCI_Type_A_LERP_B_C(int curN64Stage, int curStage, GeneralCombinerInfo &ci); int GenCI_Type_A_MOD_C_ADD_D(int curN64Stage, int curStage, GeneralCombinerInfo &ci); int GenCI_Type_A_SUB_B_ADD_D(int curN64Stage, int curStage, GeneralCombinerInfo &ci); int GenCI_Type_A_SUB_B_MOD_C(int curN64Stage, int curStage, GeneralCombinerInfo &ci); int GenCI_Type_A_ADD_B_MOD_C(int curN64Stage, int curStage, GeneralCombinerInfo &ci); int GenCI_Type_A_B_C_D(int curN64Stage, int curStage, GeneralCombinerInfo &ci); int GenCI_Type_A_B_C_A(int curN64Stage, int curStage, GeneralCombinerInfo &ci); // New functions, generate stages within the stage limition // And return the number of stages used // channel = 0 for color channel // channel = 1 for alpha channel // checktexture = true, need to use if texture matching in the stage // checktexture = false, no check, just use any texture in the stage (since this stage hasn't been used) int LM_GenCI_Type_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &ci); int LM_GenCI_Type_A_MOD_C(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &ci, uint32 dxop=CM_MODULATE); int LM_GenCI_Type_A_ADD_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &ci); int LM_GenCI_Type_A_SUB_B(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &ci); int LM_GenCI_Type_A_LERP_B_C(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &ci); int LM_GenCI_Type_A_MOD_C_ADD_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &ci); int LM_GenCI_Type_A_SUB_B_ADD_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &ci); int LM_GenCI_Type_A_SUB_B_MOD_C(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &ci); int LM_GenCI_Type_A_ADD_B_MOD_C(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &ci); int LM_GenCI_Type_A_B_C_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &ci); int LM_GenCI_Type_A_B_C_A(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &ci); void LM_GenCI_Init(GeneralCombinerInfo &ci); int LM_ParseDecodedMux(); bool LM_Check1TxtrForAlpha(int curStage, GeneralCombinerInfo &ci, uint32 val); void LM_SkipStage(StageOperate &op); bool IsTextureUsedInStage(GeneralCombineStage &stage); #ifdef DEBUGGER void General_DisplayBlendingStageInfo(GeneralCombinerInfo &ci); #endif }; #endif mupen64plus-video-rice-src-2.0/src/GraphicsContext.cpp0000644000000000000000000000610012165031100021076 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define M64P_PLUGIN_PROTOTYPES 1 #include "m64p_plugin.h" #include "m64p_vidext.h" #include "FrameBuffer.h" #include "OGLGraphicsContext.h" #include "Video.h" CGraphicsContext* CGraphicsContext::g_pGraphicsContext = NULL; bool CGraphicsContext::m_deviceCapsIsInitialized = false; bool CGraphicsContext::needCleanScene = false; int CGraphicsContext::m_maxFSAA = 16; int CGraphicsContext::m_maxAnisotropy = 16; CGraphicsContext * CGraphicsContext::Get(void) { return CGraphicsContext::g_pGraphicsContext; } CGraphicsContext::CGraphicsContext() : m_supportTextureMirror(false), m_bReady(false), m_bActive(false), m_bWindowed(true) { } CGraphicsContext::~CGraphicsContext() { g_pFrameBufferManager->CloseUp(); } uint32 CGraphicsContext::m_dwWindowStyle=0; // Saved window style for mode switches uint32 CGraphicsContext::m_dwWindowExStyle=0; // Saved window style for mode switches uint32 CGraphicsContext::m_dwStatusWindowStyle=0; // Saved window style for mode switches void CGraphicsContext::InitWindowInfo() { } bool CGraphicsContext::Initialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed) { m_bWindowed = (bWindowed != 0); g_pFrameBufferManager->Initialize(); return true; } bool CGraphicsContext::ResizeInitialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed ) { return true; } void CGraphicsContext::CleanUp() { m_bActive = false; m_bReady = false; } int __cdecl SortFrequenciesCallback( const void* arg1, const void* arg2 ) { unsigned int* p1 = (unsigned int*)arg1; unsigned int* p2 = (unsigned int*)arg2; if( *p1 < *p2 ) return -1; else if( *p1 > *p2 ) return 1; else return 0; } int __cdecl SortResolutionsCallback( const void* arg1, const void* arg2 ) { unsigned int* p1 = (unsigned int*)arg1; unsigned int* p2 = (unsigned int*)arg2; if( *p1 < *p2 ) return -1; else if( *p1 > *p2 ) return 1; else { if( p1[1] < p2[1] ) return -1; else if( p1[1] > p2[1] ) return 1; else return 0; } } // This is a static function, will be called when the plugin DLL is initialized void CGraphicsContext::InitDeviceParameters(void) { // To initialze device parameters for OpenGL COGLGraphicsContext::InitDeviceParameters(); } mupen64plus-video-rice-src-2.0/src/GraphicsContext.h0000644000000000000000000000564412165031100020557 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef GFXCONTEXT_H #define GFXCONTEXT_H #include "typedefs.h" #include "CritSect.h" enum ClearFlag { CLEAR_COLOR_BUFFER=0x01, CLEAR_DEPTH_BUFFER=0x02, CLEAR_COLOR_AND_DEPTH_BUFFER=0x03, }; typedef struct { uint32 addr; //N64 RDRAM address uint32 size; //N64 buffer size uint32 format; //N64 format uint32 width; uint32 height; } TextureBufferShortInfo; // This class basically provides an extra level of security for our // multithreaded code. Threads can Grab the CGraphicsContext to prevent // other threads from changing/releasing any of the pointers while it is // running. // It is based on CCritSect for Lock() and Unlock() class CGraphicsContext : public CCritSect { friend class CDeviceBuilder; public: bool Ready() { return m_bReady; } bool IsWindowed() {return m_bWindowed;} virtual bool Initialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed ); virtual bool ResizeInitialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed ); virtual void CleanUp(); virtual void Clear(ClearFlag flags, uint32 color=0xFF000000, float depth=1.0f) = 0; virtual void UpdateFrame(bool swaponly=false) = 0; virtual int ToggleFullscreen()=0; // return 0 as the result is windowed static void InitWindowInfo(); static void InitDeviceParameters(); bool m_supportTextureMirror; public: static int m_maxFSAA; static int m_maxAnisotropy; protected: static uint32 m_dwWindowStyle; // Saved window style for mode switches static uint32 m_dwWindowExStyle; // Saved window style for mode switches static uint32 m_dwStatusWindowStyle; // Saved window style for mode switches static bool m_deviceCapsIsInitialized; bool m_bReady; bool m_bActive; bool m_bWindowed; RECT m_rcWindowBounds; char m_strDeviceStats[256]; virtual ~CGraphicsContext(); CGraphicsContext(); public: static CGraphicsContext *g_pGraphicsContext; static CGraphicsContext * Get(void); inline const char* GetDeviceStr() {return m_strDeviceStats;} static bool needCleanScene; }; #endif mupen64plus-video-rice-src-2.0/src/IColor.h0000644000000000000000000001130112165031100016624 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ICOLOR_H_ #define _ICOLOR_H_ #ifndef min #define min(a,b) ((a) < (b) ? (a) : (b)) #endif #ifndef max #define max(a,b) ((a) > (b) ? (a) : (b)) #endif class IColor { public: uint8 r; uint8 g; uint8 b; uint8 a; IColor(COLOR rgba) { *((COLOR*)this) = rgba; } IColor() { *((COLOR*)this) = 0; } IColor(XCOLOR &rgba) { *((COLOR*)this) = (unsigned int) rgba; } inline IColor operator = (const IColor &sec) const { *((COLOR*)this) = *((COLOR*)&sec); return *this; } inline IColor operator = (COLOR col) const { *((COLOR*)this) = col; return *this; } inline IColor operator + (const IColor &sec) const { IColor newc; newc.r = (uint8)min((unsigned int) r + (unsigned int) sec.r, 0xFF); newc.g = (uint8)min((unsigned int) g + (unsigned int) sec.g, 0xFF); newc.b = (uint8)min((unsigned int) b + (unsigned int) sec.b, 0xFF); newc.a = (uint8)min((unsigned int) a + (unsigned int) sec.a, 0xFF); return newc; } inline IColor operator - (const IColor &sec) const { IColor newc; newc.r = max(int(r)-int(sec.r),0); newc.g = max(int(g)-int(sec.g),0); newc.b = max(int(b)-int(sec.b),0); newc.a = max(int(a)-int(sec.a),0); return newc; } inline IColor operator * (const IColor &sec) const { IColor newc; newc.r = (uint8)min((unsigned int) r * (unsigned int) sec.r / 256,255); newc.g = (uint8)min((unsigned int) g * (unsigned int) sec.g / 256,255); newc.b = (uint8)min((unsigned int) b * (unsigned int) sec.b / 256,255); newc.a = (uint8)min((unsigned int) a * (unsigned int) sec.a / 256,255); return newc; } inline IColor& operator += (const IColor &sec) { r = uint8(min((unsigned int) r + (unsigned int) sec.r, 255)); g = uint8(min((unsigned int) g + (unsigned int) sec.g, 255)); b = uint8(min((unsigned int) b + (unsigned int) sec.b, 255)); a = uint8(min((unsigned int) a + (unsigned int) sec.a, 255)); return *this; } inline IColor& operator -= (const IColor &sec) { r = uint8(max(int(r)-int(sec.r),0)); g = uint8(max(int(g)-int(sec.g),0)); b = uint8(max(int(b)-int(sec.b),0)); a = uint8(max(int(a)-int(sec.a),0)); return *this; } inline IColor& operator *= (const IColor &sec) { r = uint8(min((unsigned int) r * (unsigned int) sec.r / 256,255)); g = uint8(min((unsigned int) g * (unsigned int) sec.g / 256,255)); b = uint8(min((unsigned int) b * (unsigned int) sec.b / 256,255)); a = uint8(min((unsigned int) a * (unsigned int) sec.a / 256,255)); return *this; } inline IColor& operator += (XCOLOR val) { IColor newc(val); return this->operator += (newc); } inline IColor& operator -= (XCOLOR val) { IColor newc(val); return this->operator-=(newc); } inline IColor& operator *= (XCOLOR val) { IColor newc(val); return this->operator*=(newc); } inline IColor operator + (XCOLOR val) const { IColor newc(val); return this->operator+(newc); } inline IColor operator - (XCOLOR val) const { IColor newc(val); return this->operator-(newc); } inline IColor operator * (XCOLOR val) const { IColor newc(val); return this->operator*(newc); } inline operator COLOR() const { return *((COLOR*)this); } inline operator XCOLOR() const { XCOLOR rgba; rgba.r = (float)r/256.0f; rgba.g = (float)g/256.0f; rgba.b = (float)b/256.0f; rgba.a = (float)a/256.0f; return rgba; } inline void Complement() { r = 0xFF-r; g = 0xFF-g; b = 0xFF-b; a = 0xFF-a; } inline void AlphaReplicate() { r=g=b=a; } }; #endif mupen64plus-video-rice-src-2.0/src/OGLCombiner.cpp0000644000000000000000000002773712165031100020114 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - OGLCombiner.cpp * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2003 Rice1964 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "osal_opengl.h" #include "OGLCombiner.h" #include "OGLDebug.h" #include "OGLRender.h" #include "OGLGraphicsContext.h" #include "OGLDecodedMux.h" #include "OGLTexture.h" //======================================================================== uint32 DirectX_OGL_BlendFuncMaps [] = { GL_SRC_ALPHA, //Nothing GL_ZERO, //BLEND_ZERO = 1, GL_ONE, //BLEND_ONE = 2, GL_SRC_COLOR, //BLEND_SRCCOLOR = 3, GL_ONE_MINUS_SRC_COLOR, //BLEND_INVSRCCOLOR = 4, GL_SRC_ALPHA, //BLEND_SRCALPHA = 5, GL_ONE_MINUS_SRC_ALPHA, //BLEND_INVSRCALPHA = 6, GL_DST_ALPHA, //BLEND_DESTALPHA = 7, GL_ONE_MINUS_DST_ALPHA, //BLEND_INVDESTALPHA = 8, GL_DST_COLOR, //BLEND_DESTCOLOR = 9, GL_ONE_MINUS_DST_COLOR, //BLEND_INVDESTCOLOR = 10, GL_SRC_ALPHA_SATURATE, //BLEND_SRCALPHASAT = 11, GL_SRC_ALPHA_SATURATE, //BLEND_BOTHSRCALPHA = 12, GL_SRC_ALPHA_SATURATE, //BLEND_BOTHINVSRCALPHA = 13, }; //======================================================================== COGLColorCombiner::COGLColorCombiner(CRender *pRender) : CColorCombiner(pRender), m_pOGLRender((OGLRender*)pRender), m_bSupportAdd(false), m_bSupportSubtract(false) { m_pDecodedMux = new COGLDecodedMux; m_pDecodedMux->m_maxConstants = 0; m_pDecodedMux->m_maxTextures = 1; } COGLColorCombiner::~COGLColorCombiner() { delete m_pDecodedMux; m_pDecodedMux = NULL; } bool COGLColorCombiner::Initialize(void) { m_bSupportAdd = false; m_bSupportSubtract = false; m_supportedStages = 1; m_bSupportMultiTexture = false; COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); if( pcontext->IsExtensionSupported(OSAL_GL_ARB_TEXTURE_ENV_ADD) || pcontext->IsExtensionSupported("GL_EXT_texture_env_add") ) { m_bSupportAdd = true; } if( pcontext->IsExtensionSupported("GL_EXT_blend_subtract") ) { m_bSupportSubtract = true; } return true; } void COGLColorCombiner::DisableCombiner(void) { m_pOGLRender->DisableMultiTexture(); glEnable(GL_BLEND); OPENGL_CHECK_ERRORS; glBlendFunc(GL_ONE, GL_ZERO); OPENGL_CHECK_ERRORS; if( m_bTexelsEnable ) { COGLTexture* pTexture = g_textures[gRSP.curTile].m_pCOGLTexture; if( pTexture ) { m_pOGLRender->EnableTexUnit(0,TRUE); m_pOGLRender->BindTexture(pTexture->m_dwTextureName, 0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); OPENGL_CHECK_ERRORS; m_pOGLRender->SetAllTexelRepeatFlag(); } #ifdef DEBUGGER else { DebuggerAppendMsg("Check me, texture is NULL but it is enabled"); } #endif } else { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); OPENGL_CHECK_ERRORS; m_pOGLRender->EnableTexUnit(0,FALSE); } } void COGLColorCombiner::InitCombinerCycleCopy(void) { m_pOGLRender->DisableMultiTexture(); m_pOGLRender->EnableTexUnit(0,TRUE); COGLTexture* pTexture = g_textures[gRSP.curTile].m_pCOGLTexture; if( pTexture ) { m_pOGLRender->BindTexture(pTexture->m_dwTextureName, 0); m_pOGLRender->SetTexelRepeatFlags(gRSP.curTile); } #ifdef DEBUGGER else { DebuggerAppendMsg("Check me, texture is NULL"); } #endif glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); OPENGL_CHECK_ERRORS; } void COGLColorCombiner::InitCombinerCycleFill(void) { m_pOGLRender->DisableMultiTexture(); m_pOGLRender->EnableTexUnit(0,FALSE); } void COGLColorCombiner::InitCombinerCycle12(void) { m_pOGLRender->DisableMultiTexture(); if( !m_bTexelsEnable ) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); OPENGL_CHECK_ERRORS; m_pOGLRender->EnableTexUnit(0,FALSE); return; } #if SDL_VIDEO_OPENGL uint32 mask = 0x1f; COGLTexture* pTexture = g_textures[gRSP.curTile].m_pCOGLTexture; if( pTexture ) { m_pOGLRender->EnableTexUnit(0,TRUE); m_pOGLRender->BindTexture(pTexture->m_dwTextureName, 0); m_pOGLRender->SetAllTexelRepeatFlag(); } #ifdef DEBUGGER else { DebuggerAppendMsg("Check me, texture is NULL"); } #endif bool texIsUsed = m_pDecodedMux->isUsed(MUX_TEXEL0); bool shadeIsUsedInColor = m_pDecodedMux->isUsedInCycle(MUX_SHADE, 0, COLOR_CHANNEL); bool texIsUsedInColor = m_pDecodedMux->isUsedInCycle(MUX_TEXEL0, 0, COLOR_CHANNEL); if( texIsUsed ) { // Parse the simplified the mux, because the OGL 1.1 combiner function is so much // limited, we only parse the 1st N64 combiner setting and only the RGB part N64CombinerType & comb = m_pDecodedMux->m_n64Combiners[0]; switch( m_pDecodedMux->mType ) { case CM_FMT_TYPE_NOT_USED: case CM_FMT_TYPE_D: // = A glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); OPENGL_CHECK_ERRORS; break; case CM_FMT_TYPE_A_ADD_D: // = A+D if( shadeIsUsedInColor && texIsUsedInColor ) { if( m_bSupportAdd ) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); else glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); } else if( texIsUsedInColor ) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } else glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); OPENGL_CHECK_ERRORS; break; case CM_FMT_TYPE_A_SUB_B: // = A-B if( shadeIsUsedInColor && texIsUsedInColor ) { if( m_bSupportSubtract ) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_SUBTRACT_ARB); else glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); } else if( texIsUsedInColor ) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } else glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); OPENGL_CHECK_ERRORS; break; case CM_FMT_TYPE_A_MOD_C: // = A*C case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D if( shadeIsUsedInColor && texIsUsedInColor ) { if( ((comb.c & mask) == MUX_SHADE && !(comb.c&MUX_COMPLEMENT)) || ((comb.a & mask) == MUX_SHADE && !(comb.a&MUX_COMPLEMENT)) ) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); else glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } else if( texIsUsedInColor ) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } else glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); OPENGL_CHECK_ERRORS; break; case CM_FMT_TYPE_A_LERP_B_C: // = A*C+D if( (comb.b&mask) == MUX_SHADE && (comb.c&mask)==MUX_TEXEL0 && ((comb.a&mask)==MUX_PRIM||(comb.a&mask)==MUX_ENV)) { float *fv; if( (comb.a&mask)==MUX_PRIM ) { fv = GetPrimitiveColorfv(); } else { fv = GetEnvColorfv(); } glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,fv); OPENGL_CHECK_ERRORS; glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); OPENGL_CHECK_ERRORS; break; } default: // = (A-B)*C+D if( shadeIsUsedInColor ) { if( ((comb.c & mask) == MUX_SHADE && !(comb.c&MUX_COMPLEMENT)) || ((comb.a & mask) == MUX_SHADE && !(comb.a&MUX_COMPLEMENT)) ) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); else glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } else { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } OPENGL_CHECK_ERRORS; break; } } else { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); OPENGL_CHECK_ERRORS; } #endif } void COGLBlender::NormalAlphaBlender(void) { glEnable(GL_BLEND); OPENGL_CHECK_ERRORS; glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); OPENGL_CHECK_ERRORS; } void COGLBlender::DisableAlphaBlender(void) { glEnable(GL_BLEND); OPENGL_CHECK_ERRORS; glBlendFunc(GL_ONE, GL_ZERO); OPENGL_CHECK_ERRORS; } void COGLBlender::BlendFunc(uint32 srcFunc, uint32 desFunc) { glBlendFunc(DirectX_OGL_BlendFuncMaps[srcFunc], DirectX_OGL_BlendFuncMaps[desFunc]); OPENGL_CHECK_ERRORS; } void COGLBlender::Enable() { glEnable(GL_BLEND); OPENGL_CHECK_ERRORS; } void COGLBlender::Disable() { glDisable(GL_BLEND); OPENGL_CHECK_ERRORS; } void COGLColorCombiner::InitCombinerBlenderForSimpleTextureDraw(uint32 tile) { m_pOGLRender->DisableMultiTexture(); if( g_textures[tile].m_pCTexture ) { m_pOGLRender->EnableTexUnit(0,TRUE); glBindTexture(GL_TEXTURE_2D, ((COGLTexture*)(g_textures[tile].m_pCTexture))->m_dwTextureName); OPENGL_CHECK_ERRORS; } m_pOGLRender->SetAllTexelRepeatFlag(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); OPENGL_CHECK_ERRORS; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); OPENGL_CHECK_ERRORS; glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering OPENGL_CHECK_ERRORS; glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering OPENGL_CHECK_ERRORS; glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); OPENGL_CHECK_ERRORS; m_pOGLRender->SetAlphaTestEnable(FALSE); } #ifdef DEBUGGER extern const char *translatedCombTypes[]; void COGLColorCombiner::DisplaySimpleMuxString(void) { TRACE0("\nSimplified Mux\n"); m_pDecodedMux->DisplaySimpliedMuxString("Used"); } #endif mupen64plus-video-rice-src-2.0/src/OGLCombiner.h0000644000000000000000000000512112165031100017540 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - OGLCombiner.h * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2002 Rice1964 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef _OGL_COMBINER_H_ #define _OGL_COMBINER_H_ #include "Blender.h" #include "Combiner.h" class OGLRender; class COGLColorCombiner : public CColorCombiner { public: bool Initialize(void); void InitCombinerBlenderForSimpleTextureDraw(uint32 tile=0); protected: friend class OGLDeviceBuilder; void DisableCombiner(void); void InitCombinerCycleCopy(void); void InitCombinerCycleFill(void); void InitCombinerCycle12(void); COGLColorCombiner(CRender *pRender); ~COGLColorCombiner(); OGLRender *m_pOGLRender; bool m_bSupportAdd; bool m_bSupportSubtract; #ifdef DEBUGGER void DisplaySimpleMuxString(void); #endif }; class COGLBlender : public CBlender { public: void NormalAlphaBlender(void); void DisableAlphaBlender(void); void BlendFunc(uint32 srcFunc, uint32 desFunc); void Enable(); void Disable(); protected: friend class OGLDeviceBuilder; COGLBlender(CRender *pRender) : CBlender(pRender), m_pOGLRender((OGLRender*)pRender) {}; ~COGLBlender() {}; OGLRender *m_pOGLRender; }; #endif mupen64plus-video-rice-src-2.0/src/OGLCombinerNV.cpp0000644000000000000000000011456112165031100020350 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "OGLExtensions.h" #include "OGLCombinerNV.h" #include "OGLRender.h" #include "OGLGraphicsContext.h" //======================================================================== #define MUX_E_F (MUX_PRIMLODFRAC+1) #define MUX_SPARE1 (MUX_E_F+1) #define MUX_SECONDARY_COLOR (MUX_SPARE1+1) #define MUX_NOT_USED MUX_ERR #define MUX_COMBINED_SIGNED (MUX_SECONDARY_COLOR+1) //Use only by Nvidia register combiner typedef struct { GLenum input; GLenum mapping; GLenum componentUsage; }RGBMapType; RGBMapType RGBmap1[] = { {GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_0 = 0, {GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB}, //MUX_1, = ZERO NEG {GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_COMBINED, {GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_TEXEL0, {GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_TEXEL1, {GL_CONSTANT_COLOR0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_PRIM, {GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_SHADE, {GL_CONSTANT_COLOR1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_ENV, {GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA}, //MUX_COMBALPHA, {GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA}, //MUX_T0_ALPHA, {GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA}, //MUX_T1_ALPHA, {GL_CONSTANT_COLOR0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA}, //MUX_PRIM_ALPHA, {GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA}, //MUX_SHADE_ALPHA, {GL_CONSTANT_COLOR1_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA}, //MUX_ENV_ALPHA, {GL_CONSTANT_COLOR1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_LODFRAC, {GL_CONSTANT_COLOR1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_PRIMLODFRAC, {GL_E_TIMES_F_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_E_F, {GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_SPARE1, {GL_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB}, //MUX_SECONDARY_COLOR, {GL_SPARE0_NV, GL_SIGNED_IDENTITY_NV, GL_RGB}, //MUX_COMBINED_SIGNED, }; //======================================================================== COGLColorCombinerNvidia::COGLColorCombinerNvidia(CRender *pRender) : COGLColorCombiner4(pRender) { m_bNVSupported = false; delete m_pDecodedMux; m_pDecodedMux = new COGLDecodedMux; m_pDecodedMux->m_maxConstants=2; } COGLColorCombinerNvidia::~COGLColorCombinerNvidia() { m_vCompiledSettings.clear(); } bool COGLColorCombinerNvidia::Initialize(void) { m_bNVSupported = false; if( COGLColorCombiner4::Initialize() ) { m_bSupportMultiTexture = true; COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); if( pcontext->IsExtensionSupported("GL_NV_texture_env_combine4") || pcontext->IsExtensionSupported("GL_NV_register_combiners") ) { m_bNVSupported = true; glEnable(GL_REGISTER_COMBINERS_NV); return true; } else { DebugMessage(M64MSG_ERROR, "Your video card does not support Nvidia OpenGL extension combiner"); glDisable(GL_REGISTER_COMBINERS_NV); return false; } } glDisable(GL_REGISTER_COMBINERS_NV); return false; } void COGLColorCombinerNvidia::InitCombinerCycle12(void) { if( !m_bNVSupported ) {COGLColorCombiner4::InitCombinerCycle12(); return;} glEnable(GL_REGISTER_COMBINERS_NV); #ifdef DEBUGGER if( debuggerDropCombiners ) { m_vCompiledSettings.clear(); m_dwLastMux0 = m_dwLastMux1 = 0; debuggerDropCombiners = false; } #endif m_pOGLRender->EnableMultiTexture(); bool combinerIsChanged = false; if( m_pDecodedMux->m_dwMux0 != m_dwLastMux0 || m_pDecodedMux->m_dwMux1 != m_dwLastMux1 || m_lastIndex < 0 ) { combinerIsChanged = true; m_lastIndex = FindCompiledMux(); if( m_lastIndex < 0 ) // Can not found { NVRegisterCombinerParserType result; ParseDecodedMux(result); m_lastIndex= SaveParserResult(result); } m_dwLastMux0 = m_pDecodedMux->m_dwMux0; m_dwLastMux1 = m_pDecodedMux->m_dwMux1; GenerateNVRegisterCombinerSetting(m_lastIndex); } m_pOGLRender->SetAllTexelRepeatFlag(); if( m_bCycleChanged || combinerIsChanged || gRDP.texturesAreReloaded || gRDP.colorsAreReloaded ) { gRDP.texturesAreReloaded = false; if( m_bCycleChanged || combinerIsChanged ) { GenerateNVRegisterCombinerSettingConstants(m_lastIndex); GenerateNVRegisterCombinerSetting(m_lastIndex); ApplyFogAtFinalStage(); } else if( gRDP.colorsAreReloaded ) { GenerateNVRegisterCombinerSettingConstants(m_lastIndex); } gRDP.colorsAreReloaded = false; } } void COGLColorCombinerNvidia::ParseDecodedMux(NVRegisterCombinerParserType &result) // Compile the decodedMux into NV register combiner setting { //int stagesForRGB=0; //int stagesForAlpha=0; //int stages=0; COGLDecodedMux &mux = *(COGLDecodedMux*)m_pDecodedMux; mux.To_AB_Add_CD_Format(); result.stagesUsed=0; if( StagesNeedToUse(mux, N64Cycle0RGB) == 0 ) { // Nothing to be done for RGB ByPassGeneralStage(result.s1rgb); ByPassGeneralStage(result.s2rgb); ByPassFinalStage(result.finalrgb); } else if( StagesNeedToUse(mux, N64Cycle0RGB) == 1 ) { result.stagesUsed = 1; Parse1Mux(mux, N64Cycle0RGB, result.s1rgb); if( StagesNeedToUse(mux, N64Cycle1RGB) == 0 ) { ByPassGeneralStage(result.s2rgb); ByPassFinalStage(result.finalrgb); } else { result.stagesUsed = 2; Parse1MuxForStage2AndFinalStage(mux, N64Cycle1RGB, result.s2rgb, result.finalrgb); } } else { result.stagesUsed = 2; Parse1Mux2Stages(mux, N64Cycle0RGB, result.s1rgb, result.s2rgb); Parse1MuxForFinalStage(mux, N64Cycle1RGB, result.finalrgb); } // Debug texel1 /* if( m_pDecodedMux->m_bTexel0IsUsed && m_pDecodedMux->m_bTexel1IsUsed ) { result.finalrgb.a = MUX_TEXEL0; result.finalrgb.b = MUX_TEXEL1; result.finalrgb.c = MUX_0; result.finalrgb.d = MUX_0; } */ if( StagesNeedToUse(mux, N64Cycle0Alpha) == 0 ) { // Nothing to be done for Alpha ByPassGeneralStage(result.s1alpha); ByPassGeneralStage(result.s2alpha); ByPassFinalStage(result.finalalpha); } else if( Parse1Mux2Stages(mux, N64Cycle0Alpha, result.s1alpha, result.s2alpha) == 1 ) { // Only 1 NV stage is used if( result.stagesUsed == 0 ) result.stagesUsed = 1; if( StagesNeedToUse(mux, N64Cycle1Alpha) == 0 ) { ByPassGeneralStage(result.s2alpha); } else { Parse1Mux(mux, N64Cycle1Alpha, result.s2alpha); result.stagesUsed = 2; } } else { // The 1st is used 2 stages, skip the 2nd N64 alpha setting result.stagesUsed = 2; result.s2alpha.a=MUX_COMBINED; result.s2alpha.b=MUX_1; result.s2alpha.c=m_pDecodedMux->m_n64Combiners[N64Cycle0Alpha].d; result.s2alpha.d=MUX_1; } // Parse Alpha setting, alpha does not have a final stage ByPassFinalStage(result.finalalpha); ParseDecodedMuxForConstant(result); } void COGLColorCombinerNvidia::ParseDecodedMuxForConstant(NVRegisterCombinerParserType &result) { result.constant0 = MUX_0; result.constant1 = MUX_0; bool const0Used=false; bool const1Used=false; if( m_pDecodedMux->isUsed(MUX_PRIM) ) { result.constant0 = MUX_PRIM; const0Used = true; } if( m_pDecodedMux->isUsed(MUX_ENV) ) { if( const0Used ) { result.constant1 = MUX_ENV; const1Used = true; } else { result.constant0 = MUX_ENV; const0Used = true; } } if( m_pDecodedMux->isUsed(MUX_LODFRAC) && !const1Used ) { if( !const1Used ) { result.constant1 = MUX_LODFRAC; const1Used = true; } else if( !const0Used ) { result.constant0 = MUX_LODFRAC; const0Used = true; } } if( m_pDecodedMux->isUsed(MUX_PRIMLODFRAC) && !const1Used ) { if( !const1Used ) { result.constant1 = MUX_PRIMLODFRAC; const1Used = true; } else if( !const0Used ) { result.constant0 = MUX_PRIMLODFRAC; const0Used = true; } } } int COGLColorCombinerNvidia::StagesNeedToUse(COGLDecodedMux &mux, N64StageNumberType stage) { N64CombinerType &m = mux.m_n64Combiners[stage]; switch(mux.splitType[stage]) { case CM_FMT_TYPE_NOT_USED: return 0; case CM_FMT_TYPE_D: // = A ==> can be done in 1 NV stage case CM_FMT_TYPE_A_ADD_D: // = A+D ==> can be done in 1 NV stage case CM_FMT_TYPE_A_MOD_C: // = A*C ==> can be done in 1 NV stage case CM_FMT_TYPE_A_SUB_B: // = A-B ==> can be done in 1 NV stage case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D ==> can be done in 1 NV stage case CM_FMT_TYPE_A_LERP_B_C: // = (A-B)*C+B ==> can be done in 1 NV stage case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C ==> can be done in 1 NV stage case CM_FMT_TYPE_AB_ADD_CD: // = AB+CD case CM_FMT_TYPE_AB_SUB_CD: // = AB-CD return 1; case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D ==> can not be done in 1 stage if( m.a == m.d ) // = 2A-B, simply it to A-B, in fact,we can do 2A-B with NV register combiner return 1; else // Need two NV stages for this N64 combiner return 2; case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D ==> can not be done in 1 stage default: //if( m.a == m.d ) // = (A-B)*C+A = A(C+1)-B*C = A-B*C // return 1; //else if( m.d == m.c ) // = (A-B)*C+C = A*C+(1-B)*C return 1; else // = (A-B)*C+D, need two NV stages return 2; } } bool isTex(uint8 val) { if( (val&MUX_MASK) == MUX_TEXEL0 || (val&MUX_MASK) == MUX_TEXEL1 ) return true; else return false; } int COGLColorCombinerNvidia::Parse1Mux(COGLDecodedMux &mux, N64StageNumberType stage, NVGeneralCombinerType &res) // Compile the decodedMux into NV register combiner setting { // Parse 1 N64 combiner, generate result and return how many NV stage is needed. // result will be put into only 1 NV stage, not the 2nd one even if 2nd one is needed. // The caller of this function will handle the 2nd NV stage if it is needed // Up to here, the m_pDecodedMux is already simplied, N64 stage 1 and stage 2 have been // adjusted so stage1 is almost always complicated than stage 2 // The stage type in decodedMux is still in (A-B)*C+D format // we need to parser and translate it to A*B+C*D format for NV register general combiner // and to A*D+(1-A)*C+D format for the NV final combiner // Remember that N64 has two stages, NV has two general combiner stages and 1 final combiner stage // NV should be able to simulate exactly all possible N64 combiner settings /* CM_FMT_TYPE1_D, // = A ==> can be done in 1 NV stage CM_FMT_TYPE2_A_ADD_D, // = A+D ==> can be done in 1 NV stage CM_FMT_TYPE3_A_MOD_C, // = A*C ==> can be done in 1 NV stage CM_FMT_TYPE4_A_SUB_B, // = A-B ==> can be done in 1 NV stage CM_FMT_TYPE5_A_MOD_C_ADD_D, // = A*C+D ==> can be done in 1 NV stage CM_FMT_TYPE6_A_LERP_B_C, // = (A-B)*C+B ==> can be done in 1 NV stage CM_FMT_TYPE8_A_SUB_B_MOD_C, // = (A-B)*C ==> can be done in 1 NV stage CM_FMT_TYPE7_A_SUB_B_ADD_D, // = A-B+C ==> can not be done in 1 stage CM_FMT_TYPE9_A_B_C_D, // = (A-B)*C+D ==> can not be done in 1 stage the last two ones, since we can neither do it in the final stage, if the 1st N64 stage happen to be one of the two types and have used the two NV general combiners, and if the 2nd N64 combiner happens to be one of the two types as well, then we have to simplify the N64 combiner so to implement it. In such as case, the N64 combiners are too complicated, we just do what either as we can to implement it. Use UNSIGNED_INVERT of ZERO ==> ONE // If the 1st N64 stage can not be done in 1 NV stage, then we will do 1st N64 stage // by using 2 NV general combiner stages, and the 2nd N64 stage by using the NV final // combiner stage. // RGB channel and alpha channel is the same in the general combiner, but different in // the final combiner. In fact, final combiner does not do anything for alpha channel // so alpha channel setting of both N64 combiner must be implemented by the two NV general // combiner If we can not implement the two alpha setting in 2 NV combiner stages, we will do what either as we can. */ N64CombinerType &m = mux.m_n64Combiners[stage]; switch(mux.splitType[stage]) { case CM_FMT_TYPE_NOT_USED: res.a=MUX_0; res.b=MUX_0; res.c=MUX_0; res.d=MUX_0; return 0; break; case CM_FMT_TYPE_D: // = A ==> can be done in 1 NV stage res.a=m.d; res.b=MUX_1; res.c=MUX_0; res.d=MUX_0; return 1; break; case CM_FMT_TYPE_A_ADD_D: // = A+D ==> can be done in 1 NV stage res.a=m.a; res.b=MUX_1; res.c=m.d; res.d=MUX_1; return 1; break; case CM_FMT_TYPE_A_MOD_C: // = A*C ==> can be done in 1 NV stage res.a=m.a; res.b=m.c; res.c=MUX_0; res.d=MUX_0; return 1; break; case CM_FMT_TYPE_A_SUB_B: // = A-B ==> can be done in 1 NV stage res.a=m.a; res.b=MUX_1; res.c=m.b|MUX_NEG; res.d=MUX_1; return 1; break; case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D ==> can be done in 1 NV stage res.a=m.a; res.b=m.c; res.c=m.d; res.d=MUX_1; return 1; break; case CM_FMT_TYPE_A_LERP_B_C: // = (A-B)*C+B ==> can be done in 1 NV stage // = AC+(1-C)B res.a=m.a; res.b=m.c; res.c=m.c^MUX_COMPLEMENT; res.d=m.b; return 1; break; case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C ==> can be done in 1 NV stage res.a=m.a; res.b=m.c; res.c=m.b|MUX_NEG; res.d=m.c; return 1; break; case CM_FMT_TYPE_AB_ADD_CD: // = AB+CD res.a = m.a; res.b = m.b; res.c = m.c; res.d = m.d; return 1; break; case CM_FMT_TYPE_AB_SUB_CD: // = AB-CD res.a = m.a; res.b = m.b; res.c = m.c|MUX_NEG; res.d = m.d; return 1; break; case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D ==> can not be done in 1 stage if( m.a == m.d ) // = 2A-B, simply it to A-B, in fact,we can do 2A-B with NV register combiner { res.a=m.a; res.b=MUX_1; res.c=m.b|MUX_NEG; res.d=MUX_1; return 1; } else // Need two NV stages for this N64 combiner { // Stage 1: R1=A-B res.a=m.a; res.b=MUX_1; if( isTex(res.b) || !isTex(res.d) ) { res.c=m.b|MUX_NEG; res.d=MUX_1; } else { res.c=m.d; res.d=MUX_1; } return 2; } break; case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D ==> can not be done in 1 stage default: if( m.a == m.d ) // = (A-B)*C+A = A(C+1)-B*C = A-B*C { res.a=m.a; res.b=m.c; res.c=m.b|MUX_NEG; res.d=m.c; return 1; } else if( m.d == m.c ) // = (A-B)*C+C = A*C+(1-B)*C { res.a=m.a; res.b=m.c; res.c=m.b^MUX_COMPLEMENT; res.d=m.c; return 1; } else // = (A-B)*C+D, need two NV stages { // Stage 1: R1=(A-B)*C = AC-BC if( isTex(m.d) ) { // = A*C+D res.a=m.a; res.b=m.c; res.c=m.d; res.d=MUX_1; } else { // = (A-B)*C = A*C - B*C res.a=m.a; res.b=m.c; res.c=m.b|MUX_NEG; res.d=m.c; } return 2; } break; } } int COGLColorCombinerNvidia::Parse1Mux2Stages(COGLDecodedMux &mux, N64StageNumberType stage, NVGeneralCombinerType &res, NVGeneralCombinerType &res2) { N64CombinerType &m = mux.m_n64Combiners[stage]; switch(mux.splitType[stage]) { case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D ==> can not be done in 1 stage if( m.a != m.d ) // = 2A-B, simply it to A-B, in fact,we can do 2A-B with NV register combiner { // Stage 1: R1=A-B res.a=m.a; res.b=MUX_1; res.c=m.b|MUX_NEG; res.d=MUX_1; res2.a=MUX_COMBINED_SIGNED; res2.b=MUX_1; res2.c=m.d; res2.d=MUX_1; return 2; } break; case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D ==> can not be done in 1 stage case CM_FMT_TYPE_A_B_C_A: // = (A-B)*C+D ==> can not be done in 1 stage //if( m.a != m.d && m.d != m.c ) { // Stage 1: R1=(A-B)*C = AC-BC res.a=m.a; res.b=m.c; res.c=m.b|MUX_NEG; res.d=m.c; res2.a=MUX_COMBINED_SIGNED; res2.b=MUX_1; res2.c=m.d; res2.d=MUX_1; return 2; } break; default: break; } return Parse1Mux(mux, stage, res); } void COGLColorCombinerNvidia::Parse1MuxForFinalStage(COGLDecodedMux &mux, N64StageNumberType stage, NVFinalCombinerType &res) { N64CombinerType &m = mux.m_n64Combiners[stage]; // Final stage equation is: AB+(1-A)C+D switch(mux.splitType[stage]) { case CM_FMT_TYPE_NOT_USED: res.a=MUX_0; res.b=MUX_0; res.c=MUX_0; res.d=MUX_0; break; case CM_FMT_TYPE_D: // = A ==> can be done in 1 NV stage res.a=m.a; res.b=MUX_1; res.c=MUX_0; res.d=MUX_0; break; case CM_FMT_TYPE_A_ADD_D: // = A+D ==> can be done in 1 NV stage res.a=m.a; res.b=MUX_1; res.c=MUX_0; res.d=m.d; break; case CM_FMT_TYPE_A_MOD_C: // = A*C ==> can be done in 1 NV stage res.a=m.a; res.b=m.c; res.c=MUX_0; res.d=MUX_0; break; case CM_FMT_TYPE_A_SUB_B: // = A-B ==> can be done in 1 NV stage res.a=m.a; res.b=MUX_1; res.c=MUX_0; res.d=m.b|MUX_NEG; break; case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D ==> can be done in 1 NV stage res.a=m.a; res.b=m.c; res.c=MUX_0; res.d=m.d; break; case CM_FMT_TYPE_A_LERP_B_C: // = (A-B)*C+B ==> can be done in 1 NV stage // = AC+(1-B)C res.a = m.c; res.b = MUX_0; res.c = m.b; res.d = MUX_E_F; res.e = m.a; res.f = m.c; break; case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C ==> can be done in 1 NV stage res.a=m.c; res.b=m.a; res.c=m.b; res.d=m.b|MUX_NEG; break; case CM_FMT_TYPE_AB_ADD_CD: // = AB+CD res.a = m.a; res.b = m.b; res.e = m.c; res.f = m.d; res.c = MUX_0; res.d = MUX_E_F; break; case CM_FMT_TYPE_AB_SUB_CD: // = AB-CD res.a = m.a; res.b = m.b; res.e = m.c|MUX_NEG; res.f = m.d; res.c = MUX_0; res.d = MUX_E_F; break; case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D ==> can not be done in 1 stage if( m.a == m.d ) // = 2A-B, simply it to A-B, in fact,we can do 2A-B with NV register combiner { res.a=m.a; res.b=MUX_1; res.c=MUX_0; res.d=m.b|MUX_NEG; } else // Need two NV stages for this N64 combiner { TRACE0("NV Combiner parse, check me, not fully support this combiner"); // final combiner can not fully support this combiner setting // Stage 1: R1=A-B res.a=m.a; res.b=MUX_1; res.c=MUX_0; res.d=m.b|MUX_NEG; } break; case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D ==> can not be done in 1 stage default: if( m.a == m.d ) // = (A-B)*C+A = A(C+1)-B*C = A-B*C { /* res.a=m.c; res.b=m.b|MUX_NEG; res.c=MUX_0; res.d=m.a; */ res.a=m.c; res.b=m.a; res.c=m.b; res.d=MUX_0; } else if( m.d == m.c ) // = (A-B)*C+C = A*C+(1-B)*C { res.a=m.b; res.b=MUX_0; res.c=m.c; res.d=MUX_E_F; res.e=m.a; res.f=m.c; } else // = (A-B)*C+D, need two NV stages { TRACE0("NV Combiner parse, check me, not fully support this combiner"); // final combiner can not fully support this combiner setting // Stage 1: R1=(A-B)*C = AC-BC res.a=m.c; res.b=m.a; res.c=m.b; res.d=m.b|MUX_NEG; } break; } res.g=MUX_COMBINED; } int COGLColorCombinerNvidia::Parse1MuxForStage2AndFinalStage(COGLDecodedMux &mux, N64StageNumberType stage, NVGeneralCombinerType &res, NVFinalCombinerType &fres) { if( Parse1Mux(mux, stage, res) == 1 ) { ByPassFinalStage(fres); return 1; } else { ByPassFinalStage(fres); fres.a=MUX_COMBINED; fres.b=MUX_1; fres.d = mux.m_n64Combiners[stage].d; fres.g=MUX_COMBINED; return 2; } } void COGLColorCombinerNvidia::ByPassFinalStage(NVFinalCombinerType &fres) { fres.a=MUX_0; fres.b=MUX_0; fres.c=MUX_0; fres.d=MUX_COMBINED; fres.e=MUX_0; fres.f=MUX_0; fres.g=MUX_COMBINED; } void COGLColorCombinerNvidia::ByPassGeneralStage(NVGeneralCombinerType &res) { res.a=MUX_1; res.b=MUX_COMBINED; res.c=MUX_0; res.d=MUX_0; } int COGLColorCombinerNvidia::FindCompiledMux(void) { for( uint32 i=0; im_dwMux0 && m_vCompiledSettings[i].dwMux1 == m_pDecodedMux->m_dwMux1 ) return i; } return -1; } void COGLColorCombinerNvidia::GenerateNVRegisterCombinerSettingConstants(int index) { NVRegisterCombinerSettingType &info = m_vCompiledSettings[index]; uint8 consts[2] = {info.constant0,info.constant1}; float *pf; for( int i=0; i<2; i++ ) { switch( consts[i] ) { case MUX_PRIM: pf = GetPrimitiveColorfv(); pglCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV+i,pf); break; case MUX_ENV: pf = GetEnvColorfv(); pglCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV+i,pf); break; case MUX_LODFRAC: case MUX_PRIMLODFRAC: { float frac = gRDP.primLODFrac / 255.0f; float tempf[4] = {frac,frac,frac,frac}; pglCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV+i,tempf); break; } } } } void COGLColorCombinerNvidia::GenerateNVRegisterCombinerSetting(int index) { if( index < 0 || index >= (int)m_vCompiledSettings.size() ) { TRACE0("NV Register combiner, vector index out of range"); return; } NVRegisterCombinerSettingType &info = m_vCompiledSettings[index]; pglCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV,info.numOfStages); uint32 i; if( info.numOfStages > 0 ) { for( i=0; i<4; i++ ) { pglCombinerInputNV(GL_COMBINER0_NV, GL_RGB, info.stage1RGB[i].variable, info.stage1RGB[i].input, info.stage1RGB[i].mapping, info.stage1RGB[i].componentUsage ); } for( i=0; i<4; i++ ) { pglCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, info.stage1Alpha[i].variable, info.stage1Alpha[i].input, info.stage1Alpha[i].mapping, info.stage1Alpha[i].componentUsage ); } pglCombinerOutputNV(GL_COMBINER0_NV, GL_RGB, info.stage1outputRGB.abOutput, info.stage1outputRGB.cdOutput, info.stage1outputRGB.sumOutput, info.stage1outputRGB.scale, info.stage1outputRGB.bias, info.stage1outputRGB.abDotProduct, info.stage1outputRGB.cdDotProduct, info.stage1outputRGB.muxSum); pglCombinerOutputNV(GL_COMBINER0_NV, GL_ALPHA, info.stage2outputAlpha.abOutput, info.stage2outputAlpha.cdOutput, info.stage2outputAlpha.sumOutput, info.stage2outputAlpha.scale, info.stage2outputAlpha.bias, info.stage2outputAlpha.abDotProduct, info.stage2outputAlpha.cdDotProduct, info.stage2outputAlpha.muxSum); if( info.numOfStages > 1 ) { for( i=0; i<4; i++ ) { pglCombinerInputNV(GL_COMBINER1_NV, GL_RGB, info.stage2RGB[i].variable, info.stage2RGB[i].input, info.stage2RGB[i].mapping, info.stage2RGB[i].componentUsage ); } for( i=0; i<4; i++ ) { pglCombinerInputNV(GL_COMBINER1_NV, GL_ALPHA, info.stage2Alpha[i].variable, info.stage2Alpha[i].input, info.stage2Alpha[i].mapping, info.stage2Alpha[i].componentUsage ); } pglCombinerOutputNV(GL_COMBINER1_NV, GL_RGB, info.stage2outputRGB.abOutput, info.stage2outputRGB.cdOutput, info.stage2outputRGB.sumOutput, info.stage2outputRGB.scale, info.stage2outputRGB.bias, info.stage2outputRGB.abDotProduct, info.stage2outputRGB.cdDotProduct, info.stage2outputRGB.muxSum); pglCombinerOutputNV(GL_COMBINER1_NV, GL_ALPHA, info.stage2outputAlpha.abOutput, info.stage2outputAlpha.cdOutput, info.stage2outputAlpha.sumOutput, info.stage2outputAlpha.scale, info.stage2outputAlpha.bias, info.stage2outputAlpha.abDotProduct, info.stage2outputAlpha.cdDotProduct, info.stage2outputAlpha.muxSum); } } for( i=0; i<7; i++ ) { pglFinalCombinerInputNV(info.finalStage[i].variable, info.finalStage[i].input, info.finalStage[i].mapping, info.finalStage[i].componentUsage ); } } GLenum COGLColorCombinerNvidia::ConstMap(uint8 c) { switch(c) { case MUX_0: return GL_ZERO; case MUX_1: return GL_ZERO; case MUX_COMBINED: case MUX_TEXEL0: case MUX_TEXEL1: case MUX_PRIM: case MUX_SHADE: case MUX_ENV: case MUX_COMBALPHA: case MUX_T0_ALPHA: case MUX_T1_ALPHA: case MUX_PRIM_ALPHA: case MUX_SHADE_ALPHA: case MUX_ENV_ALPHA: case MUX_LODFRAC: case MUX_PRIMLODFRAC: break; } return GL_ZERO; } void Set1Variable(GLenum variable, uint8 val, NVCombinerInputType &record, const NVRegisterCombinerParserType &result, bool forRGB=true) { record.variable = variable; record.componentUsage = RGBmap1[val&MUX_MASK].componentUsage; record.input = RGBmap1[val&MUX_MASK].input; record.mapping = RGBmap1[val&MUX_MASK].mapping; switch( val&MUX_MASK ) { case MUX_PRIM: case MUX_ENV: case MUX_PRIMLODFRAC: case MUX_LODFRAC: if( (val&MUX_MASK) == result.constant0 ) { record.input = GL_CONSTANT_COLOR0_NV; } else if( (val&MUX_MASK) == result.constant1 ) { record.input = GL_CONSTANT_COLOR1_NV; } else { record.input = GL_ZERO; } break; } if( val&MUX_NEG ) { record.mapping = GL_SIGNED_NEGATE_NV; } else if( val == MUX_1 ) { record.mapping = GL_UNSIGNED_INVERT_NV; } else if( val & MUX_COMPLEMENT ) { record.mapping = GL_UNSIGNED_INVERT_NV; } if( val & MUX_ALPHAREPLICATE || !forRGB ) { record.componentUsage = GL_ALPHA; } } int COGLColorCombinerNvidia::SaveParserResult(const NVRegisterCombinerParserType &result) { NVRegisterCombinerSettingType save; // Stage 1 RGB Set1Variable(GL_VARIABLE_A_NV, result.s1rgb.a, save.stage1RGB[0], result); Set1Variable(GL_VARIABLE_B_NV, result.s1rgb.b, save.stage1RGB[1], result); Set1Variable(GL_VARIABLE_C_NV, result.s1rgb.c, save.stage1RGB[2], result); Set1Variable(GL_VARIABLE_D_NV, result.s1rgb.d, save.stage1RGB[3], result); // Stage 1 Alpha Set1Variable(GL_VARIABLE_A_NV, result.s1alpha.a, save.stage1Alpha[0], result, false); Set1Variable(GL_VARIABLE_B_NV, result.s1alpha.b, save.stage1Alpha[1], result, false); Set1Variable(GL_VARIABLE_C_NV, result.s1alpha.c, save.stage1Alpha[2], result, false); Set1Variable(GL_VARIABLE_D_NV, result.s1alpha.d, save.stage1Alpha[3], result, false); // Stage 2 RGB Set1Variable(GL_VARIABLE_A_NV, result.s2rgb.a, save.stage2RGB[0], result); Set1Variable(GL_VARIABLE_B_NV, result.s2rgb.b, save.stage2RGB[1], result); Set1Variable(GL_VARIABLE_C_NV, result.s2rgb.c, save.stage2RGB[2], result); Set1Variable(GL_VARIABLE_D_NV, result.s2rgb.d, save.stage2RGB[3], result); // Stage 2 Alpha Set1Variable(GL_VARIABLE_A_NV, result.s2alpha.a, save.stage2Alpha[0], result, false); Set1Variable(GL_VARIABLE_B_NV, result.s2alpha.b, save.stage2Alpha[1], result, false); Set1Variable(GL_VARIABLE_C_NV, result.s2alpha.c, save.stage2Alpha[2], result, false); Set1Variable(GL_VARIABLE_D_NV, result.s2alpha.d, save.stage2Alpha[3], result, false); // Final Stage RGB Set1Variable(GL_VARIABLE_A_NV, result.finalrgb.a, save.finalStage[0], result); Set1Variable(GL_VARIABLE_B_NV, result.finalrgb.b, save.finalStage[1], result); Set1Variable(GL_VARIABLE_C_NV, result.finalrgb.c, save.finalStage[2], result); Set1Variable(GL_VARIABLE_D_NV, result.finalrgb.d, save.finalStage[3], result); Set1Variable(GL_VARIABLE_E_NV, result.finalrgb.e, save.finalStage[4], result); //save.finalStage[4].componentUsage = GL_ALPHA; Set1Variable(GL_VARIABLE_F_NV, result.finalrgb.f, save.finalStage[5], result); //save.finalStage[5].componentUsage = GL_ALPHA; Set1Variable(GL_VARIABLE_G_NV, result.finalrgb.g, save.finalStage[6], result); save.finalStage[6].componentUsage = GL_ALPHA; save.numOfStages = result.stagesUsed; save.dwMux0 = m_pDecodedMux->m_dwMux0; save.dwMux1 = m_pDecodedMux->m_dwMux1; save.stage1outputRGB.scale = GL_NONE; save.stage1outputRGB.sumOutput = GL_SPARE0_NV; save.stage1outputRGB.abDotProduct = GL_FALSE; save.stage1outputRGB.cdDotProduct = GL_FALSE; save.stage1outputRGB.abOutput = GL_SPARE1_NV; save.stage1outputRGB.cdOutput = GL_SECONDARY_COLOR_NV; save.stage1outputRGB.bias = GL_NONE; save.stage1outputRGB.muxSum = GL_FALSE; save.stage1outputAlpha.scale = GL_NONE; save.stage1outputAlpha.sumOutput = GL_SPARE0_NV; save.stage1outputAlpha.abDotProduct = GL_FALSE; save.stage1outputAlpha.cdDotProduct = GL_FALSE; save.stage1outputAlpha.abOutput = GL_SPARE1_NV; save.stage1outputAlpha.cdOutput = GL_SECONDARY_COLOR_NV; save.stage1outputAlpha.bias = GL_NONE; save.stage1outputAlpha.muxSum = GL_FALSE; save.stage2outputRGB.scale = GL_NONE; save.stage2outputRGB.sumOutput = GL_SPARE0_NV; save.stage2outputRGB.abDotProduct = GL_FALSE; save.stage2outputRGB.cdDotProduct = GL_FALSE; save.stage2outputRGB.abOutput = GL_SPARE1_NV; save.stage2outputRGB.cdOutput = GL_SECONDARY_COLOR_NV; save.stage2outputRGB.bias = GL_NONE; save.stage2outputRGB.muxSum = GL_FALSE; save.stage2outputAlpha.scale = GL_NONE; save.stage2outputAlpha.sumOutput = GL_SPARE0_NV; save.stage2outputAlpha.abDotProduct = GL_FALSE; save.stage2outputAlpha.cdDotProduct = GL_FALSE; save.stage2outputAlpha.abOutput = GL_SPARE1_NV; save.stage2outputAlpha.cdOutput = GL_SECONDARY_COLOR_NV; save.stage2outputAlpha.bias = GL_NONE; save.stage2outputAlpha.muxSum = GL_FALSE; save.constant0 = result.constant0; save.constant1 = result.constant1; #ifdef DEBUGGER memcpy(&(save.parseResult),&result, sizeof(result)); if( logCombiners ) { TRACE0("\nNew Mux:\n"); DisplayMuxString(); COGLColorCombiner::DisplaySimpleMuxString(); DisplayNVCombinerString(save); } #endif m_vCompiledSettings.push_back(save); return m_vCompiledSettings.size()-1; // Return the index of the last element } void COGLColorCombinerNvidia::DisableCombiner(void) { glDisable(GL_REGISTER_COMBINERS_NV); COGLColorCombiner4::DisableCombiner(); } void COGLColorCombinerNvidia::InitCombinerCycleCopy(void) { glDisable(GL_REGISTER_COMBINERS_NV); COGLColorCombiner4::InitCombinerCycleCopy(); } void COGLColorCombinerNvidia::InitCombinerCycleFill(void) { glDisable(GL_REGISTER_COMBINERS_NV); COGLColorCombiner4::InitCombinerCycleFill(); } void COGLColorCombinerNvidia::InitCombinerBlenderForSimpleTextureDraw(uint32 tile) { glDisable(GL_REGISTER_COMBINERS_NV); COGLColorCombiner::InitCombinerBlenderForSimpleTextureDraw(tile); } void COGLColorCombinerNvidia::ApplyFogAtFinalStage() { // If we need to enable fog at final stage, the current flag stage setting // will be affect, which means correct combiner setting at final stage is lost // in order to use fog if( glIsEnabled(GL_FOG) ) { // Use final stage as: cmb*fogfactor+fog*(1-fogfactor) pglFinalCombinerInputNV(GL_VARIABLE_A_NV, GL_FOG, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA ); pglFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB ); pglFinalCombinerInputNV(GL_VARIABLE_C_NV, GL_FOG, GL_UNSIGNED_IDENTITY_NV, GL_RGB ); pglFinalCombinerInputNV(GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB ); } } #ifdef DEBUGGER extern const char *translatedCombTypes[]; void COGLColorCombinerNvidia::DisplaySimpleMuxString(void) { COGLColorCombiner::DisplaySimpleMuxString(); TRACE0("\nNV Combiner setting\n"); uint32 index = FindCompiledMux(); if( index >= 0 ) { NVRegisterCombinerSettingType &record = m_vCompiledSettings[index]; DisplayNVCombinerString(record); } } char* FormatStrForFinalStage(uint8 val, char* buf) { if( (val&MUX_MASK) == MUX_E_F ) { strcpy(buf, "E_F"); return buf; } else return DecodedMux::FormatStr(val, buf); } void COGLColorCombinerNvidia::DisplayNVCombinerString(NVRegisterCombinerSettingType &record) { NVRegisterCombinerParserType &result = record.parseResult; char buf[2000]; char buf0[30]; char buf1[30]; char buf2[30]; char buf3[30]; char buf4[30]; char buf5[30]; char buf6[30]; buf[0]='\0'; TRACE0("\n\n"); TRACE0("\nNvidia combiner stages:\n"); DebuggerAppendMsg("//aRGB0:\t%s * %s + %s * %s\n", DecodedMux::FormatStr(result.s1rgb.a, buf0), DecodedMux::FormatStr(result.s1rgb.b, buf1), DecodedMux::FormatStr(result.s1rgb.c, buf2),DecodedMux::FormatStr(result.s1rgb.d, buf3)); DebuggerAppendMsg("//aA0:\t%s * %s + %s * %s\n", DecodedMux::FormatStr(result.s1alpha.a, buf0), DecodedMux::FormatStr(result.s1alpha.b, buf1), DecodedMux::FormatStr(result.s1alpha.c, buf2),DecodedMux::FormatStr(result.s1alpha.d, buf3)); if( record.numOfStages == 2 ) { DebuggerAppendMsg("//aRGB1:\t%s * %s + %s * %s\n", DecodedMux::FormatStr(result.s2rgb.a, buf0), DecodedMux::FormatStr(result.s2rgb.b, buf1), DecodedMux::FormatStr(result.s2rgb.c, buf2),DecodedMux::FormatStr(result.s2rgb.d, buf3)); DebuggerAppendMsg("//aA1:\t%s * %s + %s * %s\n", DecodedMux::FormatStr(result.s2alpha.a, buf0), DecodedMux::FormatStr(result.s2alpha.b, buf1), DecodedMux::FormatStr(result.s2alpha.c, buf2),DecodedMux::FormatStr(result.s2alpha.d, buf3)); } DebuggerAppendMsg("//Final:\t%s * %s + (1 - %s) * %s + %s\n\tE=%s, F=%s\n", FormatStrForFinalStage(result.finalrgb.a, buf0), FormatStrForFinalStage(result.finalrgb.b, buf1), FormatStrForFinalStage(result.finalrgb.a, buf2), FormatStrForFinalStage(result.finalrgb.c, buf3), FormatStrForFinalStage(result.finalrgb.d, buf4), FormatStrForFinalStage(result.finalrgb.e, buf5), FormatStrForFinalStage(result.finalrgb.f, buf6)); if( result.constant0 != MUX_0 ) { DebuggerAppendMsg("//Constant 0:\t%s\n", DecodedMux::FormatStr(result.constant0, buf0)); } if( result.constant1 != MUX_0 ) { DebuggerAppendMsg("//Constant 1:\t%s\n", DecodedMux::FormatStr(result.constant1, buf0)); } TRACE0("\n\n"); } #endif mupen64plus-video-rice-src-2.0/src/OGLCombinerNV.h0000644000000000000000000001165112165031100020011 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _OGL_COMBINER_NV_H_ #define _OGL_COMBINER_NV_H_ #include #include #include "OGLExtCombiner.h" #include "OGLDecodedMux.h" typedef struct { uint8 a; uint8 b; uint8 c; uint8 d; } NVGeneralCombinerType; typedef struct { uint8 a; uint8 b; uint8 c; uint8 d; uint8 e; uint8 f; uint8 g; } NVFinalCombinerType; typedef struct { GLenum variable; GLenum input; GLenum mapping; GLenum componentUsage; } NVCombinerInputType; typedef struct { GLenum abOutput; GLenum cdOutput; GLenum sumOutput; GLenum scale; GLenum bias; GLboolean abDotProduct; GLboolean cdDotProduct; GLboolean muxSum; } NVCombinerOutputType; typedef struct { union { struct { NVGeneralCombinerType s1rgb; NVGeneralCombinerType s1alpha; NVGeneralCombinerType s2rgb; NVGeneralCombinerType s2alpha; NVFinalCombinerType finalrgb; NVFinalCombinerType finalalpha; }; struct { NVGeneralCombinerType generalCombiners[4]; NVFinalCombinerType finalCombiners[2]; }; }; int stagesUsed; uint8 constant0; uint8 constant1; } NVRegisterCombinerParserType; typedef struct { NVCombinerInputType stage1RGB[4]; NVCombinerInputType stage1Alpha[4]; NVCombinerOutputType stage1outputRGB; NVCombinerOutputType stage1outputAlpha; NVCombinerInputType stage2RGB[4]; NVCombinerInputType stage2Alpha[4]; NVCombinerOutputType stage2outputRGB; NVCombinerOutputType stage2outputAlpha; NVCombinerInputType finalStage[7]; int numOfStages; uint32 dwMux0; uint32 dwMux1; uint8 constant0; uint8 constant1; #ifdef DEBUGGER NVRegisterCombinerParserType parseResult; #endif } NVRegisterCombinerSettingType; class COGLColorCombinerNvidia : public COGLColorCombiner4 { public: bool Initialize(void); void InitCombinerBlenderForSimpleTextureDraw(uint32 tile=0); protected: friend class OGLDeviceBuilder; void InitCombinerCycle12(void); void DisableCombiner(void); void InitCombinerCycleCopy(void); void InitCombinerCycleFill(void); int FindCompiledMux(void); void GenerateNVRegisterCombinerSetting(int); void GenerateNVRegisterCombinerSettingConstants(int); // Compile the decodedMux into NV register combiner setting void ApplyFogAtFinalStage(); void ParseDecodedMux(NVRegisterCombinerParserType &result); // Compile the decodedMux into NV register combiner setting void ParseDecodedMuxForConstant(NVRegisterCombinerParserType &result); // Compile the decodedMux into NV register combiner setting int SaveParserResult(const NVRegisterCombinerParserType &result); int StagesNeedToUse(COGLDecodedMux &mux, N64StageNumberType stage); int Parse1Mux(COGLDecodedMux &mux, N64StageNumberType stage, NVGeneralCombinerType &res); // Compile the decodedMux into NV register combiner setting int Parse1Mux2Stages(COGLDecodedMux &mux, N64StageNumberType stage, NVGeneralCombinerType &res, NVGeneralCombinerType &res2); int Parse1MuxForStage2AndFinalStage(COGLDecodedMux &mux, N64StageNumberType stage, NVGeneralCombinerType &res, NVFinalCombinerType &fres); void Parse1MuxForFinalStage(COGLDecodedMux &mux, N64StageNumberType stage, NVFinalCombinerType &fres); void ByPassFinalStage(NVFinalCombinerType &fres); void ByPassGeneralStage(NVGeneralCombinerType &res); GLenum ConstMap(uint8 c); COGLColorCombinerNvidia(CRender *pRender); ~COGLColorCombinerNvidia(); std::vector m_vCompiledSettings; bool m_bNVSupported; // Is this NV OGL extension combiner supported by the video card driver? #ifdef DEBUGGER void DisplaySimpleMuxString(void); void DisplayNVCombinerString(NVRegisterCombinerSettingType &record); #endif }; #endif mupen64plus-video-rice-src-2.0/src/OGLCombinerTNT2.cpp0000644000000000000000000002630612165031100020553 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "OGLExtensions.h" #include "OGLCombinerTNT2.h" #include "OGLRender.h" #include "OGLGraphicsContext.h" #include "OGLTexture.h" //======================================================================== COGLColorCombinerTNT2::COGLColorCombinerTNT2(CRender *pRender) :COGLColorCombiner4(pRender) { m_bTNT2Supported=false; delete m_pDecodedMux; m_pDecodedMux = new COGLDecodedMux; m_ppDecodedMux = &m_pDecodedMux; } bool COGLColorCombinerTNT2::Initialize(void) { m_bTNT2Supported = false; if( COGLColorCombiner4::Initialize() ) { m_bSupportMultiTexture = true; COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); if( pcontext->IsExtensionSupported("GL_NV_texture_env_combine4") ) { m_bTNT2Supported = true; } else { DebugMessage(M64MSG_ERROR, "Your video card does not support OpenGL TNT2 extension combiner, you can only use the OpenGL Ext combiner functions"); } return true; } return false; } //======================================================================== void COGLColorCombinerTNT2::InitCombinerCycle12(void) { if( !m_bOGLExtCombinerSupported ) { COGLColorCombiner4::InitCombinerCycle12(); return;} #ifdef DEBUGGER if( debuggerDropCombiners ) { m_vCompiledTNTSettings.clear(); m_dwLastMux0 = m_dwLastMux1 = 0; debuggerDropCombiners = false; } #endif m_pOGLRender->EnableMultiTexture(); bool combinerIsChanged = false; if( m_pDecodedMux->m_dwMux0 != m_dwLastMux0 || m_pDecodedMux->m_dwMux1 != m_dwLastMux1 || m_lastIndex < 0 ) { combinerIsChanged = true; m_lastIndex = CNvTNTCombiner::FindCompiledMux(); if( m_lastIndex < 0 ) // Can not found { m_lastIndex = CNvTNTCombiner::ParseDecodedMux(); } m_dwLastMux0 = m_pDecodedMux->m_dwMux0; m_dwLastMux1 = m_pDecodedMux->m_dwMux1; } m_pOGLRender->SetAllTexelRepeatFlag(); if( m_bCycleChanged || combinerIsChanged || gRDP.texturesAreReloaded || gRDP.colorsAreReloaded ) { gRDP.texturesAreReloaded = false; if( m_bCycleChanged || combinerIsChanged ) { GenerateCombinerSettingConstants(m_lastIndex); GenerateCombinerSetting(m_lastIndex); } else if( gRDP.colorsAreReloaded ) { GenerateCombinerSettingConstants(m_lastIndex); } gRDP.colorsAreReloaded = false; } } const char* COGLColorCombinerTNT2::GetOpStr(GLenum op) { switch( op ) { case GL_ADD: return "MOD"; default: return "ADD_SIGNED"; } } #ifdef DEBUGGER void COGLColorCombinerTNT2::DisplaySimpleMuxString(void) { COGLColorCombiner::DisplaySimpleMuxString(); CNvTNTCombiner::DisplaySimpleMuxString(); } #endif //======================================================================== GLint COGLColorCombinerTNT2::RGBArgsMap[] = { GL_ZERO, //MUX_0 GL_ZERO, //MUX_1 GL_PREVIOUS_EXT, //MUX_COMBINED, GL_TEXTURE0_ARB, //MUX_TEXEL0, GL_TEXTURE1_ARB, //MUX_TEXEL1, GL_CONSTANT_EXT, //MUX_PRIM, GL_PRIMARY_COLOR_EXT, //MUX_SHADE, GL_CONSTANT_EXT, //MUX_ENV, GL_PREVIOUS_EXT, //MUX_COMBALPHA, GL_TEXTURE0_ARB, //MUX_T0_ALPHA, GL_TEXTURE1_ARB, //MUX_T1_ALPHA, GL_CONSTANT_EXT, //MUX_PRIM_ALPHA, GL_PRIMARY_COLOR_EXT, //MUX_SHADE_ALPHA, GL_CONSTANT_EXT, //MUX_ENV_ALPHA, GL_CONSTANT_EXT, //MUX_LODFRAC, GL_CONSTANT_EXT, //MUX_PRIMLODFRAC, GL_ZERO, //MUX_K5 GL_ZERO //MUX_UNK }; //======================================================================== GLint COGLColorCombinerTNT2::MapRGBArgs(uint8 arg) { return RGBArgsMap[arg&MUX_MASK]; } GLint COGLColorCombinerTNT2::MapRGBArgFlags(uint8 arg) { if( (arg & MUX_ALPHAREPLICATE) && (arg & MUX_COMPLEMENT) ) { return GL_ONE_MINUS_SRC_ALPHA; } else if( (arg & MUX_ALPHAREPLICATE) ) { if( arg == MUX_1 ) return GL_ONE_MINUS_SRC_ALPHA; else return GL_SRC_ALPHA; } else if(arg & MUX_COMPLEMENT || arg == MUX_1) { return GL_ONE_MINUS_SRC_COLOR; } else return GL_SRC_COLOR; } GLint COGLColorCombinerTNT2::MapAlphaArgs(uint8 arg) { return RGBArgsMap[arg&MUX_MASK]; } GLint COGLColorCombinerTNT2::MapAlphaArgFlags(uint8 arg) { if(arg & MUX_COMPLEMENT || arg == MUX_1) { return GL_ONE_MINUS_SRC_ALPHA; } else return GL_SRC_ALPHA; } //======================================================================== void COGLColorCombinerTNT2::GenerateCombinerSetting(int index) { TNT2CombinerSaveType &res = m_vCompiledTNTSettings[index]; // Texture unit 0 COGLTexture* pTexture = g_textures[gRSP.curTile].m_pCOGLTexture; COGLTexture* pTexture1 = g_textures[(gRSP.curTile+1)&7].m_pCOGLTexture; if( pTexture ) m_pOGLRender->BindTexture(pTexture->m_dwTextureName, 0); if( pTexture1 ) m_pOGLRender->BindTexture(pTexture1->m_dwTextureName, 1); // Texture unit 0 pglActiveTexture(GL_TEXTURE0_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV); m_pOGLRender->EnableTexUnit(0,TRUE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, res.unit1.rgbOp); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, res.unit1.alphaOp); if( res.unit1.rgbOp == GL_SUBTRACT_ARB ) { glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, MapRGBArgs(res.unit1.rgbArg0^MUX_COMPLEMENT)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, MapRGBArgFlags(res.unit1.rgbArg0^MUX_COMPLEMENT)); } else { glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, MapRGBArgs(res.unit1.rgbArg0)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, MapRGBArgFlags(res.unit1.rgbArg0)); } glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, MapRGBArgs(res.unit1.rgbArg1)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, MapRGBArgFlags(res.unit1.rgbArg1)); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, MapRGBArgs(res.unit1.rgbArg2)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, MapRGBArgFlags(res.unit1.rgbArg2)); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_EXT, MapRGBArgs(res.unit1.rgbArg3)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_EXT, MapRGBArgFlags(res.unit1.rgbArg3)); if( res.unit1.alphaOp == GL_SUBTRACT_ARB ) { glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, MapRGBArgs(res.unit1.alphaArg0^MUX_COMPLEMENT)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, MapAlphaArgFlags(res.unit1.alphaArg0^MUX_COMPLEMENT)); } else { glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, MapRGBArgs(res.unit1.alphaArg0)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, MapAlphaArgFlags(res.unit1.alphaArg0)); } glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, MapRGBArgs(res.unit1.alphaArg1)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, MapAlphaArgFlags(res.unit1.alphaArg1)); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, MapRGBArgs(res.unit1.alphaArg2)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, MapAlphaArgFlags(res.unit1.alphaArg2)); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_EXT, MapRGBArgs(res.unit1.rgbArg3)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_EXT, MapAlphaArgFlags(res.unit1.rgbArg3)); pglActiveTexture(GL_TEXTURE1_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV); if( m_maxTexUnits > 1 && res.numOfUnits > 1 ) { glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, res.unit2.rgbOp); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, res.unit2.alphaOp); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, MapRGBArgs(res.unit2.rgbArg0)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, MapRGBArgFlags(res.unit2.rgbArg0)); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, MapRGBArgs(res.unit2.rgbArg1)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, MapRGBArgFlags(res.unit2.rgbArg1)); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, MapRGBArgs(res.unit2.rgbArg2)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, MapRGBArgFlags(res.unit2.rgbArg2)); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_EXT, MapRGBArgs(res.unit2.rgbArg3)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_EXT, MapRGBArgFlags(res.unit2.rgbArg3)); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, MapRGBArgs(res.unit2.alphaArg0)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, MapAlphaArgFlags(res.unit2.alphaArg0)); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, MapRGBArgs(res.unit2.alphaArg1)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, MapAlphaArgFlags(res.unit2.alphaArg1)); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, MapRGBArgs(res.unit2.alphaArg2)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, MapAlphaArgFlags(res.unit2.alphaArg2)); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_EXT, MapRGBArgs(res.unit2.alphaArg3)); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_EXT, MapAlphaArgFlags(res.unit2.alphaArg3)); m_pOGLRender->EnableTexUnit(1,TRUE); } else { //m_pOGLRender->EnableTexUnit(1,FALSE); } } void COGLColorCombinerTNT2::GenerateCombinerSettingConstants(int index) { TNT2CombinerSaveType &res = m_vCompiledTNTSettings[index]; for( int i=0; i<2; i++ ) { float *fv; pglActiveTextureARB(GL_TEXTURE0_ARB+i); switch( res.units[i].constant & MUX_MASK ) { case MUX_PRIM: fv = GetPrimitiveColorfv(); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,fv); break; case MUX_ENV: fv = GetEnvColorfv(); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,fv); break; case MUX_LODFRAC: { float frac = gRDP.LODFrac / 255.0f; float tempf[4] = {frac,frac,frac,frac}; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,tempf); break; } case MUX_PRIMLODFRAC: { float frac = gRDP.primLODFrac / 255.0f; float tempf[4] = {frac,frac,frac,frac}; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,tempf); break; } } } } mupen64plus-video-rice-src-2.0/src/OGLCombinerTNT2.h0000644000000000000000000000367412165031100020223 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _OGL_COMBINER_TNT2_H_ #define _OGL_COMBINER_TNT2_H_ #include #define GL_SOURCE3_RGB_EXT 0x8583 #define GL_SOURCE3_ALPHA_EXT 0x858B #define GL_OPERAND3_RGB_EXT 0x8593 #define GL_OPERAND3_ALPHA_EXT 0x859B #include "OGLExtCombiner.h" #include "OGLDecodedMux.h" #include "CNvTNTCombiner.h" //======================================================================== class COGLColorCombinerTNT2 : public COGLColorCombiner4, CNvTNTCombiner { public: bool Initialize(void); protected: friend class OGLDeviceBuilder; void InitCombinerCycle12(void); virtual void GenerateCombinerSetting(int); virtual void GenerateCombinerSettingConstants(int); COGLColorCombinerTNT2(CRender *pRender); ~COGLColorCombinerTNT2() {} ; bool m_bTNT2Supported; // Is this NV OGL extension combiner supported by the video card driver? #ifdef DEBUGGER void DisplaySimpleMuxString(void); #endif private: virtual GLint MapRGBArgs(uint8 arg); static GLint MapRGBArgFlags(uint8 arg); virtual GLint MapAlphaArgs(uint8 arg); static GLint MapAlphaArgFlags(uint8 arg); static GLint RGBArgsMap[]; static const char* GetOpStr(GLenum op); }; #endif mupen64plus-video-rice-src-2.0/src/OGLDebug.h0000644000000000000000000000452412165031100017036 0ustar 00000000000000/* OGLDebug.h Copyright (C) 2009 Richard Goedeken This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if !defined(OPENGL_DEBUG_H) #define OPENGL_DEBUG_H #if defined(OPENGL_DEBUG) #define OPENGL_CHECK_ERRORS { const GLenum errcode = glGetError(); if (errcode != GL_NO_ERROR) fprintf(stderr, "OpenGL Error code %i in '%s' line %i\n", errcode, __FILE__, __LINE__-1); } #else #define OPENGL_CHECK_ERRORS #endif /* Dump client state (for informational purposes) int rval = 0; void *ptr; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &rval); printf("GL_ARRAY_BUFFER_BINDING: %i\n", rval); glGetPointerv(GL_COLOR_ARRAY_POINTER, &ptr); printf("GL_COLOR_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_COLOR_ARRAY), (int) ptr); glGetPointerv(GL_FOG_COORD_ARRAY_POINTER, &ptr); printf("GL_FOG_COORDINATE_ARRAY_EXT: %i (%lx)\n", (int) glIsEnabled(GL_FOG_COORDINATE_ARRAY_EXT), (int) ptr); glGetPointerv(GL_INDEX_ARRAY_POINTER, &ptr); printf("GL_INDEX_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_INDEX_ARRAY), (int) ptr); glGetPointerv(GL_NORMAL_ARRAY_POINTER, &ptr); printf("GL_NORMAL_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_NORMAL_ARRAY), (int) ptr); glGetPointerv(GL_SECONDARY_COLOR_ARRAY_POINTER, &ptr); printf("GL_SECONDARY_COLOR_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_SECONDARY_COLOR_ARRAY), (int) ptr); glGetPointerv(GL_TEXTURE_COORD_ARRAY_POINTER, &ptr); printf("GL_TEXTURE_COORD_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_TEXTURE_COORD_ARRAY), (int) ptr); glGetPointerv(GL_VERTEX_ARRAY_POINTER, &ptr); printf("GL_VERTEX_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_VERTEX_ARRAY), (int) ptr); */ #endif /* OPENGL_DEBUG_H */ mupen64plus-video-rice-src-2.0/src/OGLDecodedMux.cpp0000644000000000000000000000702612165031100020364 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "OGLDecodedMux.h" //======================================================================== void COGLDecodedMux::Simplify(void) { DecodedMux::Simplify(); } void COGLDecodedMux::Reformat(void) { DecodedMux::Reformat(); mType = max(max(max(splitType[0], splitType[1]),splitType[2]),splitType[3]); } void COGLExtDecodedMux::Simplify(void) //======================================================================== { COGLDecodedMux::Simplify(); FurtherFormatForOGL2(); Reformat(); // Reformat again } void COGLExtDecodedMux::FurtherFormatForOGL2(void) { // This function is used by OGL 1.2, no need to call this function // for Nvidia register combiner // And OGL 1.2 extension only supports 1 constant color, we can not use both PRIM and ENV // constant color, and we can not use SPECULAR color as the 2nd color. // To futher format the mux. // - For each stage, allow only 1 texel, change the 2nd texel in the same stage to MUX_SHADE // - Only allow 1 constant color. Count PRIM and ENV, left the most used one, and change // the 2nd one to MUX_SHADE if( Count(MUX_PRIM) >= Count(MUX_ENV) ) { ReplaceVal(MUX_ENV, MUX_PRIM); //ReplaceVal(MUX_ENV, MUX_SHADE); //ReplaceVal(MUX_ENV, MUX_1); //ReplaceVal(MUX_PRIM, MUX_0); } else { //ReplaceVal(MUX_PRIM, MUX_ENV); //ReplaceVal(MUX_PRIM, MUX_SHADE); ReplaceVal(MUX_PRIM, MUX_0); } /* // Because OGL 1.2, we may use more than 1 texture unit, but for each texture unit, // we can not use multitexture to do color combiner. Each combiner stage can only // use 1 texture. if( isUsed(MUX_TEXEL0) && isUsed(MUX_TEXEL1) ) { if( Count(MUX_TEXEL0,0)+Count(MUX_TEXEL0,1) >= Count(MUX_TEXEL1,0)+Count(MUX_TEXEL1,1) ) { ReplaceVal(MUX_TEXEL1, MUX_TEXEL0, 0); ReplaceVal(MUX_TEXEL1, MUX_TEXEL0, 1); } else { ReplaceVal(MUX_TEXEL0, MUX_TEXEL1, 0); ReplaceVal(MUX_TEXEL0, MUX_TEXEL1, 1); } if( Count(MUX_TEXEL0,2)+Count(MUX_TEXEL0,3) >= Count(MUX_TEXEL1,2)+Count(MUX_TEXEL1,3) ) { ReplaceVal(MUX_TEXEL1, MUX_TEXEL0, 2); ReplaceVal(MUX_TEXEL1, MUX_TEXEL0, 3); } else { ReplaceVal(MUX_TEXEL0, MUX_TEXEL1, 2); ReplaceVal(MUX_TEXEL0, MUX_TEXEL1, 3); } } */ } void COGLExtDecodedMuxTNT2::FurtherFormatForOGL2(void) { if( Count(MUX_PRIM) >= Count(MUX_ENV) ) { //ReplaceVal(MUX_ENV, MUX_PRIM); //ReplaceVal(MUX_ENV, MUX_SHADE); ReplaceVal(MUX_ENV, MUX_1); //ReplaceVal(MUX_PRIM, MUX_0); } else { //ReplaceVal(MUX_PRIM, MUX_ENV); //ReplaceVal(MUX_PRIM, MUX_SHADE); ReplaceVal(MUX_PRIM, MUX_0); } } mupen64plus-video-rice-src-2.0/src/OGLDecodedMux.h0000644000000000000000000000224312165031100020025 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "DecodedMux.h" #ifndef _OGL_DECODEDMUX_H_ #define _OGL_DECODEDMUX_H_ class COGLDecodedMux : public DecodedMux { protected: virtual void Simplify(void); virtual void Reformat(void); }; class COGLExtDecodedMux : public COGLDecodedMux { protected: virtual void FurtherFormatForOGL2(void); virtual void Simplify(void); }; class COGLExtDecodedMuxTNT2 : public COGLExtDecodedMux { protected: virtual void FurtherFormatForOGL2(void); }; #endif mupen64plus-video-rice-src-2.0/src/OGLES2FragmentShaders.cpp0000644000000000000000000007046512165031100021741 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "OGLDebug.h" #include "OGLES2FragmentShaders.h" #include "OGLRender.h" #include "OGLGraphicsContext.h" #include "OGLTexture.h" #define ALPHA_TEST " if(gl_FragColor.a < AlphaRef) discard; \n" //#define ALPHA_TEST GLuint vertexProgram = 9999; const char *vertexShader = "#version " GLSL_VERSION "\n" "attribute mediump vec4 aPosition; \n"\ "attribute lowp vec4 aColor; \n"\ "attribute lowp vec2 aTexCoord0; \n"\ "attribute lowp vec2 aTexCoord1; \n"\ "attribute lowp vec2 aAtlasTransform; \n"\ " \n"\ "uniform lowp vec2 FogMinMax; \n"\ " \n"\ "varying lowp float vFactor; \n"\ "varying lowp vec4 vShadeColor; \n"\ "varying mediump vec2 vTexCoord0; \n"\ "varying lowp vec2 vTexCoord1; \n"\ "varying lowp float vFog; \n"\ " \n"\ "void main() \n"\ "{ \n"\ "gl_Position = aPosition; //gl_Position.z = max(0.0,gl_Position.z); \n"\ "vShadeColor = aColor; \n"\ "vTexCoord0 = aTexCoord0; \n"\ "vTexCoord1 = aTexCoord1; \n"\ "vFog = clamp((FogMinMax[1] - (gl_Position.z/aPosition.w))/(FogMinMax[1]-FogMinMax[0]),0.0,1.0); \n"\ " \n"\ "} \n"\ " \n"; const char *fragmentHeader = "#define saturate(x) clamp( x, 0.0, 1.0 ) \n"\ "precision lowp float; \n"\ "#ifdef NEED_TEX0 \n"\ "uniform sampler2D uTex0; \n"\ "#endif \n"\ " \n"\ "#ifdef NEED_TEX1 \n"\ "uniform sampler2D uTex1; \n"\ "#endif \n"\ " \n"\ "uniform vec4 EnvColor; \n"\ "uniform vec4 PrimColor; \n"\ "uniform vec4 EnvFrac; \n"\ "uniform vec4 PrimFrac; \n"\ "uniform float AlphaRef; \n"\ "uniform vec4 FogColor; \n"\ " \n"\ "varying lowp float vFactor; \n"\ "varying lowp vec4 vShadeColor; \n"\ "varying mediump vec2 vTexCoord0; \n"\ "varying lowp vec2 vTexCoord1; \n"\ "varying lowp float vFog; \n"\ " \n"\ "void main() \n"\ "{ \n"\ "vec4 comb,comb2; \n"\ " \n"\ "#ifdef NEED_TEX0 \n"\ "vec4 t0 = texture2D(uTex0,vTexCoord0); \n"\ "#endif \n"\ " \n"\ "#ifdef NEED_TEX1 \n"\ "vec4 t1 = texture2D(uTex1,vTexCoord1); \n"\ "#endif \n"; const char *fragmentFooter = " \n"\ "#ifdef FOG \n"\ "gl_FragColor.rgb = mix(FogColor.rgb,comb.rgb,vFog * step(0.5,1.0-FogColor.a)); \n"\ "gl_FragColor.a = comb.a; \n"\ "#else \n"\ "gl_FragColor = comb; \n"\ "#endif \n"\ " \n"\ "#ifdef ALPHA_TEST \n"\ ALPHA_TEST "#endif \n"\ " \n"\ " \n"\ " \n"\ " \n"\ "} \n"; //Fragment shader for InitCycleCopy const char *fragmentCopy = "#version " GLSL_VERSION "\n"\ "precision lowp float; \n"\ "uniform sampler2D uTex0; \n"\ "uniform float AlphaRef; \n"\ "varying lowp vec2 vTexCoord0; \n"\ "void main() \n"\ "{ \n"\ " gl_FragColor = texture2D(uTex0,vTexCoord0).bgra; \n"\ ALPHA_TEST "}"; GLuint copyProgram,copyAlphaLocation; //Fragment shader for InitCycleFill const char *fragmentFill = "#version " GLSL_VERSION "\n"\ "precision lowp float; \n" "uniform vec4 uColor; \n" "void main() \n" "{ \n" " gl_FragColor = uColor; \n" "}"; GLuint fillProgram,fillColorLocation; COGLFragmentShaderCombiner::COGLFragmentShaderCombiner(CRender *pRender) : COGLColorCombiner(pRender) { m_bShaderIsSupported = true; } COGLFragmentShaderCombiner::~COGLFragmentShaderCombiner() { } bool COGLFragmentShaderCombiner::Initialize(void) { if( !COGLColorCombiner::Initialize() ) return false; COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); // if( pcontext->IsExtensionSupported("GL_fragment_shader") ) // { m_bShaderIsSupported = true; // } return true; } void COGLFragmentShaderCombiner::InitCombinerCycle12(void) { } void COGLFragmentShaderCombiner::DisableCombiner(void) { COGLColorCombiner::DisableCombiner(); } void COGLFragmentShaderCombiner::InitCombinerCycleCopy(void) { COGLColorCombiner::InitCombinerCycleCopy(); } void COGLFragmentShaderCombiner::InitCombinerCycleFill(void) { COGLColorCombiner::InitCombinerCycleFill(); } void COGLFragmentShaderCombiner::InitCombinerBlenderForSimpleTextureDraw(uint32 tile) { COGLColorCombiner::InitCombinerBlenderForSimpleTextureDraw(tile); } #ifdef DEBUGGER void COGLFragmentShaderCombiner::DisplaySimpleMuxString(void) { COGLColorCombiner::DisplaySimpleMuxString(); } #endif COGL_FragmentProgramCombiner::COGL_FragmentProgramCombiner(CRender *pRender) : COGLColorCombiner4(pRender) { delete m_pDecodedMux; m_pDecodedMux = new DecodedMuxForPixelShader; m_bFragmentProgramIsSupported = true; m_AlphaRef = 0.0f; //Create shaders for fill and copy GLint success; GLuint vs,fs; copyProgram = glCreateProgram(); vs = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vs,1,&vertexShader,NULL); glCompileShader(vs); glGetShaderiv(vs,GL_COMPILE_STATUS,&success); if(!success) { char log[1024]; glGetShaderInfoLog(vs,1024,NULL,log); printf("%s\n",log); } fs = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fs,1,&fragmentCopy,NULL); glCompileShader(fs); glGetShaderiv(fs,GL_COMPILE_STATUS,&success); if(!success) { char log[1024]; glGetShaderInfoLog(fs,1024,NULL,log); printf("%s\n",log); } glAttachShader(copyProgram,vs); glAttachShader(copyProgram,fs); glBindAttribLocation(copyProgram,VS_TEXCOORD0,"aTexCoord0"); OPENGL_CHECK_ERRORS; glBindAttribLocation(copyProgram,VS_POSITION,"aPosition"); OPENGL_CHECK_ERRORS; glLinkProgram(copyProgram); copyAlphaLocation = glGetUniformLocation(copyProgram,"AlphaRef"); glGetProgramiv(copyProgram,GL_LINK_STATUS,&success); if(!success) { char log[1024]; glGetProgramInfoLog(copyProgram,1024,NULL,log); printf("%s\n",log); } glDeleteShader(fs); //Fill shader fs = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fs,1,&fragmentFill,NULL); glCompileShader(fs); glGetShaderiv(fs,GL_COMPILE_STATUS,&success); if(!success) { char log[1024]; glGetShaderInfoLog(fs,1024,NULL,log); printf("%s\n",log); } fillProgram = glCreateProgram(); glAttachShader(fillProgram,vs); glAttachShader(fillProgram,fs); glBindAttribLocation(fillProgram,VS_POSITION,"aPosition"); OPENGL_CHECK_ERRORS; glLinkProgram(fillProgram); fillColorLocation = glGetUniformLocation(fillProgram,"uColor"); glDeleteShader(fs); glDeleteShader(vs); } COGL_FragmentProgramCombiner::~COGL_FragmentProgramCombiner() { int size = m_vCompiledShaders.size(); for (int i=0; iIsExtensionSupported("GL_fragment_program") ) // { m_bFragmentProgramIsSupported = true; // } return true; } void COGL_FragmentProgramCombiner::DisableCombiner(void) { //glDisable(GL_FRAGMENT_PROGRAM); //OPENGL_CHECK_ERRORS; COGLColorCombiner4::DisableCombiner(); } void COGL_FragmentProgramCombiner::InitCombinerCycleCopy(void) { m_pOGLRender->DisableMultiTexture(); m_pOGLRender->EnableTexUnit(0,TRUE); glUseProgram(copyProgram); glUniform1f(copyAlphaLocation,m_AlphaRef); OPENGL_CHECK_ERRORS; glEnableVertexAttribArray(VS_POSITION); OPENGL_CHECK_ERRORS; glEnableVertexAttribArray(VS_TEXCOORD0); OPENGL_CHECK_ERRORS; glDisableVertexAttribArray(VS_COLOR); OPENGL_CHECK_ERRORS; glDisableVertexAttribArray(VS_TEXCOORD1); OPENGL_CHECK_ERRORS; COGLTexture* pTexture = g_textures[gRSP.curTile].m_pCOGLTexture; if( pTexture ) { m_pOGLRender->BindTexture(pTexture->m_dwTextureName, 0); m_pOGLRender->SetTexelRepeatFlags(gRSP.curTile); } } void COGL_FragmentProgramCombiner::InitCombinerCycleFill(void) { glUseProgram(fillProgram); glUniform4f(fillColorLocation,((gRDP.fillColor>>16)&0xFF)/255.0f,((gRDP.fillColor>>8)&0xFF)/255.0f,((gRDP.fillColor)&0xFF)/255.0f,((gRDP.fillColor>>24)&0xFF)/255.0f); OPENGL_CHECK_ERRORS; } #ifdef BGR_SHADER const char *muxToFP_Maps[][2] = { //color -- alpha {"vec3(0.0)", "0.0"}, //MUX_0 = 0, {"vec3(1.0)", "1.0"}, //MUX_1, {"comb.rgb", "comb.a"}, //MUX_COMBINED, {"t0.rgb", "t0.a"}, //MUX_TEXEL0, {"t1.rgb", "t1.a"}, //MUX_TEXEL1, {"PrimColor.rgb", "PrimColor.a"}, //MUX_PRIM, {"vShadeColor.rgb", "vShadeColor.a"}, //MUX_SHADE, {"EnvColor.rgb", "EnvColor.a"}, //MUX_ENV, {"comb.rgb", "comb.a"}, //MUX_COMBALPHA, {"t0.rgb", "t0.a"}, //MUX_T0_ALPHA, {"t1.rgb", "t1.a"}, //MUX_T1_ALPHA, {"PrimColor.rgb", "PrimColor.a"}, //MUX_PRIM_ALPHA, {"vShadeColor.rgb", "vShadeColor.a"}, //MUX_SHADE_ALPHA, {"EnvColor.rgb", "EnvColor.a"}, //MUX_ENV_ALPHA, {"EnvFrac.a", "EnvFrac.a"}, //MUX_LODFRAC, {"PrimFrac.a", "PrimFrac.a"}, //MUX_PRIMLODFRAC, {"vec3(1.0)", "1.0"}, //MUX_K5, {"vec3(1.0)", "1.0"}, //MUX_UNK, // Should not be used }; #else const char *muxToFP_Maps[][2] = { //color -- alpha {"vec3(0.0)", "0.0"}, //MUX_0 = 0, {"vec3(1.0)", "1.0"}, //MUX_1, {"comb.rgb", "comb.a"}, //MUX_COMBINED, {"t0.bgr", "t0.a"}, //MUX_TEXEL0, {"t1.bgr", "t1.a"}, //MUX_TEXEL1, {"PrimColor.rgb", "PrimColor.a"}, //MUX_PRIM, {"vShadeColor.rgb", "vShadeColor.a"}, //MUX_SHADE, {"EnvColor.rgb", "EnvColor.a"}, //MUX_ENV, {"comb.rgb", "comb.a"}, //MUX_COMBALPHA, {"t0.bgr", "t0.a"}, //MUX_T0_ALPHA, {"t1.bgr", "t1.a"}, //MUX_T1_ALPHA, {"PrimColor.rgb", "PrimColor.a"}, //MUX_PRIM_ALPHA, {"vShadeColor.rgb", "vShadeColor.a"}, //MUX_SHADE_ALPHA, {"EnvColor.rgb", "EnvColor.a"}, //MUX_ENV_ALPHA, {"EnvFrac.a", "EnvFrac.a"}, //MUX_LODFRAC, {"PrimFrac.a", "PrimFrac.a"}, //MUX_PRIMLODFRAC, {"vec3(1.0)", "1.0"}, //MUX_K5, {"vec3(1.0)", "1.0"}, //MUX_UNK, // Should not be used }; #endif char oglNewFP[4092]; char* MuxToOC(uint8 val) { // For color channel if( val&MUX_ALPHAREPLICATE ) return (char*)muxToFP_Maps[val&0x1F][1]; else return (char*)muxToFP_Maps[val&0x1F][0]; } char* MuxToOA(uint8 val) { // For alpha channel return (char*)muxToFP_Maps[val&0x1F][1]; } static void CheckFpVars(uint8 MuxVar, bool &bNeedT0, bool &bNeedT1) { MuxVar &= 0x1f; if (MuxVar == MUX_TEXEL0 || MuxVar == MUX_T0_ALPHA) bNeedT0 = true; if (MuxVar == MUX_TEXEL1 || MuxVar == MUX_T1_ALPHA) bNeedT1 = true; } void COGL_FragmentProgramCombiner::GenerateProgramStr() { DecodedMuxForPixelShader &mux = *(DecodedMuxForPixelShader*)m_pDecodedMux; mux.splitType[0] = mux.splitType[1] = mux.splitType[2] = mux.splitType[3] = CM_FMT_TYPE_NOT_CHECKED; m_pDecodedMux->Reformat(false); char tempstr[500], newFPBody[4092]; bool bNeedT0 = false, bNeedT1 = false, bNeedComb2 = false; newFPBody[0] = 0; for( int cycle=0; cycle<2; cycle++ ) { for( int channel=0; channel<2; channel++) { char* (*func)(uint8) = channel==0?MuxToOC:MuxToOA; char *dst = channel==0?(char*)"rgb":(char*)"a"; N64CombinerType &m = mux.m_n64Combiners[cycle*2+channel]; switch( mux.splitType[cycle*2+channel] ) { case CM_FMT_TYPE_NOT_USED: tempstr[0] = 0; break; case CM_FMT_TYPE_D: sprintf(tempstr, "comb.%s = %s;\n", dst, func(m.d)); CheckFpVars(m.d, bNeedT0, bNeedT1); break; case CM_FMT_TYPE_A_MOD_C: sprintf(tempstr, "comb.%s = %s * %s;\n", dst, func(m.a), func(m.c)); CheckFpVars(m.a, bNeedT0, bNeedT1); CheckFpVars(m.c, bNeedT0, bNeedT1); break; case CM_FMT_TYPE_A_ADD_D: sprintf(tempstr, "comb.%s = saturate(%s + %s);\n", dst, func(m.a), func(m.d)); CheckFpVars(m.a, bNeedT0, bNeedT1); CheckFpVars(m.d, bNeedT0, bNeedT1); break; case CM_FMT_TYPE_A_SUB_B: sprintf(tempstr, "comb.%s = %s - %s;\n", dst, func(m.a), func(m.b)); CheckFpVars(m.a, bNeedT0, bNeedT1); CheckFpVars(m.b, bNeedT0, bNeedT1); break; case CM_FMT_TYPE_A_MOD_C_ADD_D: sprintf(tempstr, "comb.%s = saturate(%s * %s + %s);\n", dst, func(m.a), func(m.c),func(m.d)); CheckFpVars(m.a, bNeedT0, bNeedT1); CheckFpVars(m.c, bNeedT0, bNeedT1); CheckFpVars(m.d, bNeedT0, bNeedT1); break; case CM_FMT_TYPE_A_LERP_B_C: //ARB ASM LERP and mix have different parameter ordering. //sprintf(tempstr, "comb.%s = saturate(mix(%s, %s, %s));\n", dst,func(m.a),func(m.b), func(m.c)); sprintf(tempstr, "comb.%s = (%s - %s) * %s + %s;\n", dst,func(m.a),func(m.b), func(m.c),func(m.b)); CheckFpVars(m.a, bNeedT0, bNeedT1); CheckFpVars(m.b, bNeedT0, bNeedT1); CheckFpVars(m.c, bNeedT0, bNeedT1); //sprintf(tempstr, "SUB comb.%s, %s, %s;\nMAD_SAT comb.%s, comb, %s, %s;\n", dst, func(m.a), func(m.b), dst, func(m.c), func(m.b)); break; default: sprintf(tempstr, "comb2.%s = %s - %s;\ncomb.%s = saturate(comb2.%s * %s + %s);\n", dst, func(m.a), func(m.b), dst,dst, func(m.c),func(m.d)); CheckFpVars(m.a, bNeedT0, bNeedT1); CheckFpVars(m.b, bNeedT0, bNeedT1); CheckFpVars(m.c, bNeedT0, bNeedT1); CheckFpVars(m.d, bNeedT0, bNeedT1); bNeedComb2 = true; break; } strcat(newFPBody, tempstr); } } oglNewFP[0] = 0; if (bNeedT0) strcat(oglNewFP, "#define NEED_TEX0\n"); if (bNeedT1) strcat(oglNewFP, "#define NEED_TEX1\n"); if(gRDP.bFogEnableInBlender && gRSP.bFogEnabled && options.fogMethod > 0) strcat(oglNewFP,"#define FOG"); strcat(oglNewFP, fragmentHeader); strcat(oglNewFP, newFPBody); strcat(oglNewFP, fragmentFooter); } int COGL_FragmentProgramCombiner::ParseDecodedMux() { if( !m_bFragmentProgramIsSupported ) return COGLColorCombiner4::ParseDecodedMux(); OGLShaderCombinerSaveType res; GLint success; if(vertexProgram == 9999) { vertexProgram = res.vertexShaderID = glCreateShader(GL_VERTEX_SHADER); glShaderSource(res.vertexShaderID, 1, &vertexShader,NULL); OPENGL_CHECK_ERRORS; glCompileShader(res.vertexShaderID); OPENGL_CHECK_ERRORS; } else { res.vertexShaderID = vertexProgram; } //Create 2 shaders, with and without alphatest GenerateProgramStr(); for(int alphaTest = 0;alphaTest < 2;alphaTest++) { res.fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); char* tmpShader = (char*)malloc(sizeof(char) * 4096); strcpy(tmpShader,"#version " GLSL_VERSION "\n"); if(alphaTest == 1) { strcat(tmpShader,"#define ALPHA_TEST\n"); } res.alphaTest = alphaTest == 1; strcat(tmpShader,oglNewFP); glShaderSource(res.fragmentShaderID, 1,(const char**) &tmpShader,NULL); free(tmpShader); OPENGL_CHECK_ERRORS; glCompileShader(res.fragmentShaderID); glGetShaderiv(res.fragmentShaderID, GL_COMPILE_STATUS, &success); if (!success) { char Log[1024]; GLint nLength; glGetShaderInfoLog(res.fragmentShaderID, 1024, &nLength, Log); printf("Error compiling shader!\n %s",oglNewFP); printf(Log); } res.programID = glCreateProgram(); glAttachShader(res.programID,res.vertexShaderID); glAttachShader(res.programID,res.fragmentShaderID); //Bind Attributes glBindAttribLocation(res.programID,VS_COLOR,"aColor"); OPENGL_CHECK_ERRORS; glBindAttribLocation(res.programID,VS_TEXCOORD0,"aTexCoord0"); OPENGL_CHECK_ERRORS; glBindAttribLocation(res.programID,VS_TEXCOORD1,"aTexCoord1"); OPENGL_CHECK_ERRORS; glBindAttribLocation(res.programID,VS_POSITION,"aPosition"); OPENGL_CHECK_ERRORS; glLinkProgram(res.programID); OPENGL_CHECK_ERRORS; glGetProgramiv(res.programID, GL_LINK_STATUS, &success); if (!success) { char Log[1024]; GLint nLength; glGetShaderInfoLog(res.fragmentShaderID, 1024, &nLength, Log); printf("Error linking program!\n"); printf("%s\n",Log); } glUseProgram(res.programID); OPENGL_CHECK_ERRORS; //Bind texture samplers GLint tex0 = glGetUniformLocation(res.programID,"uTex0"); GLint tex1 = glGetUniformLocation(res.programID,"uTex1"); if(tex0 != -1) glUniform1i(tex0,0); if(tex1 != -1) glUniform1i(tex1,1); //Bind Uniforms res.PrimColorLocation = glGetUniformLocation(res.programID,"PrimColor"); OPENGL_CHECK_ERRORS; res.EnvColorLocation = glGetUniformLocation(res.programID,"EnvColor"); OPENGL_CHECK_ERRORS; res.PrimFracLocation = glGetUniformLocation(res.programID,"PrimFrac"); OPENGL_CHECK_ERRORS; res.EnvFracLocation = glGetUniformLocation(res.programID,"EnvFrac"); OPENGL_CHECK_ERRORS; res.AlphaRefLocation = glGetUniformLocation(res.programID,"AlphaRef"); OPENGL_CHECK_ERRORS; res.FogColorLocation = glGetUniformLocation(res.programID,"FogColor"); OPENGL_CHECK_ERRORS; res.FogMinMaxLocation = glGetUniformLocation(res.programID,"FogMinMax"); OPENGL_CHECK_ERRORS; res.dwMux0 = m_pDecodedMux->m_dwMux0; res.dwMux1 = m_pDecodedMux->m_dwMux1; res.fogIsUsed = gRDP.bFogEnableInBlender && gRSP.bFogEnabled; m_vCompiledShaders.push_back(res); } m_lastIndex = m_vCompiledShaders.size()-2; return m_lastIndex; } void COGL_FragmentProgramCombiner::GenerateCombinerSetting(int index) { GLuint ID = m_vCompiledShaders[index].programID; glUseProgram(ID); glEnableVertexAttribArray(VS_POSITION); OPENGL_CHECK_ERRORS; glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); OPENGL_CHECK_ERRORS; glEnableVertexAttribArray(VS_TEXCOORD0); OPENGL_CHECK_ERRORS; glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u)); OPENGL_CHECK_ERRORS; glEnableVertexAttribArray(VS_TEXCOORD1); OPENGL_CHECK_ERRORS; glVertexAttribPointer(VS_TEXCOORD1,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[1].u)); OPENGL_CHECK_ERRORS; glEnableVertexAttribArray(VS_COLOR); OPENGL_CHECK_ERRORS; glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); OPENGL_CHECK_ERRORS; } void COGL_FragmentProgramCombiner::GenerateCombinerSettingConstants(int index) { OGLShaderCombinerSaveType prog = m_vCompiledShaders[index]; glUseProgram(prog.programID); float *pf; if(prog.EnvColorLocation != -1) { pf = GetEnvColorfv(); glUniform4fv(prog.EnvColorLocation,1, pf); OPENGL_CHECK_ERRORS; } if(prog.PrimColorLocation != -1) { pf = GetPrimitiveColorfv(); glUniform4fv(prog.PrimColorLocation,1, pf); OPENGL_CHECK_ERRORS; } if(prog.EnvFracLocation != -1) { float frac = gRDP.LODFrac / 255.0f; float tempf[4] = {frac,frac,frac,frac}; glUniform4fv(prog.EnvFracLocation,1, tempf); OPENGL_CHECK_ERRORS; } if(prog.PrimFracLocation != -1) { float frac2 = gRDP.primLODFrac / 255.0f; float tempf2[4] = {frac2,frac2,frac2,frac2}; glUniform4fv(prog.PrimFracLocation,1, tempf2); OPENGL_CHECK_ERRORS; } //if(prog.FogColorLocation != -1 && prog.FogMinMaxLocation != -1) //{ // //Pass fog colour and distance, use 0 alpha if fog disabled // glUniform4f(prog.FogColorLocation, gRDP.fvFogColor[0],gRDP.fvFogColor[1],gRDP.fvFogColor[2], // gRSP.bFogEnabled ? gRDP.fvFogColor[0] : 0.0f); // glUniform2f(prog.FogMinMaxLocation,gRSPfFogMin,gRSPfFogMax); //} if(prog.AlphaRefLocation != -1) glUniform1f(prog.AlphaRefLocation,m_AlphaRef); OPENGL_CHECK_ERRORS; } void COGL_FragmentProgramCombiner::UpdateFog(bool bEnable) { if(m_lastIndex < 0 || m_lastIndex >= m_vCompiledShaders.size()) return; OGLShaderCombinerSaveType prog = m_vCompiledShaders[m_lastIndex]; //if(bEnable) // DebugMessage(M64MSG_INFO,"Fog Color %x Min %f Max %f",gRDP.fogColor,gRSPfFogMin,gRSPfFogMax); if(prog.FogColorLocation != -1 && prog.FogMinMaxLocation != -1) { //Pass fog colour and distance, use 0 alpha if fog disabled glUniform4f(prog.FogColorLocation, gRDP.fvFogColor[0],gRDP.fvFogColor[1],gRDP.fvFogColor[2], bEnable ? gRDP.fvFogColor[0] : 0.0f); //glUniform4f(prog.FogColorLocation, 1.0f,0.3f,0.3f,1.0f); //OPENGL_CHECK_ERRORS; glUniform2f(prog.FogMinMaxLocation,gRSPfFogMin,gRSPfFogMax); OPENGL_CHECK_ERRORS; } } int COGL_FragmentProgramCombiner::FindCompiledMux() { #ifdef DEBUGGER if( debuggerDropCombiners ) { m_vCompiledShaders.clear(); //m_dwLastMux0 = m_dwLastMux1 = 0; debuggerDropCombiners = false; } #endif for( uint32 i=0; im_dwMux0 && m_vCompiledShaders[i].dwMux1 == m_pDecodedMux->m_dwMux1 && m_vCompiledShaders[i].fogIsUsed == (gRDP.bFogEnableInBlender && gRSP.bFogEnabled) && m_vCompiledShaders[i].alphaTest == m_AlphaRef > 0.0f) { return (int)i; } } return -1; } ////////////////////////////////////////////////////////////////////////// void COGL_FragmentProgramCombiner::InitCombinerCycle12(void) { if( !m_bFragmentProgramIsSupported ) { COGLColorCombiner4::InitCombinerCycle12(); return; } #ifdef DEBUGGER if( debuggerDropCombiners ) { UpdateCombiner(m_pDecodedMux->m_dwMux0,m_pDecodedMux->m_dwMux1); m_vCompiledShaders.clear(); m_dwLastMux0 = m_dwLastMux1 = 0; debuggerDropCombiners = false; } #endif m_pOGLRender->EnableMultiTexture(); bool combinerIsChanged = false; if( m_pDecodedMux->m_dwMux0 != m_dwLastMux0 || m_pDecodedMux->m_dwMux1 != m_dwLastMux1 || m_lastIndex < 0 ) { combinerIsChanged = true; m_lastIndex = FindCompiledMux(); if( m_lastIndex < 0 ) // Can not found { m_lastIndex = ParseDecodedMux(); } m_dwLastMux0 = m_pDecodedMux->m_dwMux0; m_dwLastMux1 = m_pDecodedMux->m_dwMux1; } GenerateCombinerSettingConstants(m_lastIndex); if( m_bCycleChanged || combinerIsChanged || gRDP.texturesAreReloaded || gRDP.colorsAreReloaded ) { if( m_bCycleChanged || combinerIsChanged ) { GenerateCombinerSettingConstants(m_lastIndex); GenerateCombinerSetting(m_lastIndex); } else if( gRDP.colorsAreReloaded ) { GenerateCombinerSettingConstants(m_lastIndex); } m_pOGLRender->SetAllTexelRepeatFlag(); gRDP.colorsAreReloaded = false; gRDP.texturesAreReloaded = false; } else { m_pOGLRender->SetAllTexelRepeatFlag(); } } #ifdef DEBUGGER void COGL_FragmentProgramCombiner::DisplaySimpleMuxString(void) { COGLColorCombiner::DisplaySimpleMuxString(); DecodedMuxForPixelShader &mux = *(DecodedMuxForPixelShader*)m_pDecodedMux; mux.Reformat(false); GenerateProgramStr(); //sprintf(oglNewFP, oglFP, // MuxToOC(mux.aRGB0), MuxToOC(mux.bRGB0), MuxToOC(mux.cRGB0), MuxToOC(mux.dRGB0), // MuxToOA(mux.aA0), MuxToOA(mux.bA0), MuxToOA(mux.cA0), MuxToOA(mux.dA0), // MuxToOC(mux.aRGB1), MuxToOC(mux.bRGB1), MuxToOC(mux.cRGB1), MuxToOC(mux.dRGB1), // MuxToOA(mux.aA1), MuxToOA(mux.bA1), MuxToOA(mux.cA1), MuxToOA(mux.dA1) // ); TRACE0("OGL Fragment Program:"); TRACE0(oglNewFP); } #endif mupen64plus-video-rice-src-2.0/src/OGLES2FragmentShaders.h0000644000000000000000000000523612165031100021400 0ustar 00000000000000/* Copyright (C) 2005 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _OGL_FRAGMENT_SHADER_H_ #define _OGL_FRAGMENT_SHADER_H_ #include #include "osal_opengl.h" #include "OGLCombiner.h" #include "OGLExtCombiner.h" #include "GeneralCombiner.h" typedef struct { uint32 dwMux0; uint32 dwMux1; bool fogIsUsed; bool alphaTest; GLuint fragmentShaderID; GLuint vertexShaderID; GLuint programID; GLint PrimColorLocation; GLint EnvColorLocation; GLint PrimFracLocation; GLint EnvFracLocation; GLint AlphaRefLocation; GLint FogColorLocation; GLint FogMinMaxLocation; } OGLShaderCombinerSaveType; class COGL_FragmentProgramCombiner : public COGLColorCombiner4 { public: bool Initialize(void); float m_AlphaRef; void UpdateFog(bool bEnable); protected: friend class OGLDeviceBuilder; void DisableCombiner(void); void InitCombinerCycleCopy(void); void InitCombinerCycleFill(void); void InitCombinerCycle12(void); COGL_FragmentProgramCombiner(CRender *pRender); ~COGL_FragmentProgramCombiner(); bool m_bFragmentProgramIsSupported; std::vector m_vCompiledShaders; private: virtual int ParseDecodedMux(); virtual void GenerateProgramStr(); int FindCompiledMux(); virtual void GenerateCombinerSetting(int index); virtual void GenerateCombinerSettingConstants(int index); #ifdef DEBUGGER void DisplaySimpleMuxString(void); #endif }; class COGLFragmentShaderCombiner : public COGLColorCombiner { public: bool Initialize(void); void InitCombinerBlenderForSimpleTextureDraw(uint32 tile=0); protected: friend class OGLDeviceBuilder; void DisableCombiner(void); void InitCombinerCycleCopy(void); void InitCombinerCycleFill(void); void InitCombinerCycle12(void); COGLFragmentShaderCombiner(CRender *pRender); ~COGLFragmentShaderCombiner(); bool m_bShaderIsSupported; #ifdef DEBUGGER void DisplaySimpleMuxString(void); #endif }; #endif mupen64plus-video-rice-src-2.0/src/OGLExtCombiner.cpp0000644000000000000000000011733112165031100020563 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "osal_opengl.h" #if SDL_VIDEO_OPENGL #include "OGLExtensions.h" #endif #include "OGLDebug.h" #include "OGLExtCombiner.h" #include "OGLExtRender.h" #include "OGLDecodedMux.h" #include "OGLGraphicsContext.h" #include "OGLTexture.h" #include "DirectXDecodedMux.h" #define GL_MODULATE_ADD_ATI 0x8744 #define GL_MODULATE_SUBTRACT_ATI 0x8746 //======================================================================== COGLColorCombiner4::COGLColorCombiner4(CRender *pRender) :COGLColorCombiner(pRender), m_maxTexUnits(0), m_lastIndex(-1), m_dwLastMux0(0), m_dwLastMux1(0) { m_bOGLExtCombinerSupported=false; m_bSupportModAdd_ATI = false; m_bSupportModSub_ATI = false; delete m_pDecodedMux; m_pDecodedMux = new COGLExtDecodedMux; } COGLColorCombiner4v2::COGLColorCombiner4v2(CRender *pRender) :COGLColorCombiner4(pRender) { delete m_pDecodedMux; m_pDecodedMux = new DecodedMuxForOGL14V2; } COGLColorCombiner2::COGLColorCombiner2(CRender *pRender) :COGLColorCombiner4(pRender) { delete m_pDecodedMux; m_pDecodedMux = new CDirectXDecodedMux; // Use Mux for DirectX because we support only 1 texture for each stage m_ppGeneralDecodedMux = &m_pDecodedMux; } ////////////////////////////////////////////////////////////////////////// bool COGLColorCombiner4::Initialize(void) { m_bOGLExtCombinerSupported = false; m_bSupportModAdd_ATI = false; m_bSupportModSub_ATI = false; m_maxTexUnits = 1; #if SDL_VIDEO_OPENGL if( COGLColorCombiner::Initialize() ) { m_bSupportMultiTexture = true; COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); if( pcontext->IsExtensionSupported("GL_EXT_texture_env_combine") || pcontext->IsExtensionSupported("GL_ARB_texture_env_combine") ) { m_bOGLExtCombinerSupported = true; glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,&m_maxTexUnits); OPENGL_CHECK_ERRORS; if( m_maxTexUnits > 8 ) m_maxTexUnits = 8; TRACE0("Starting Ogl 1.4 multitexture combiner" ); TRACE1("m_maxTexUnits = %d", m_maxTexUnits); if( pcontext->IsExtensionSupported("ATI_texture_env_combine3") ) { m_bSupportModAdd_ATI = true; m_bSupportModSub_ATI = true; } } else { DebugMessage(M64MSG_ERROR, "Your video card does not support OpenGL extension combiner, you can only use the basic OpenGL combiner functions"); } m_supportedStages = m_maxTexUnits; return true; } return false; #elif SDL_VIDEO_OPENGL_ES2 return true; #endif } bool COGLColorCombiner2::Initialize(void) { TRACE0("Starting Ogl 1.2/1.3 multitexture combiner" ); if( COGLColorCombiner4::Initialize() ) { // For general combiner flags m_dwGeneralMaxStages = m_supportedStages; m_bTxtOpAdd = m_bSupportAdd; m_bTxtOpSub = m_bSupportSubtract; m_bTxtOpLerp = true; m_bTxtOpAddSmooth = true; m_bTxtOpBlendCurAlpha = true; m_bTxtOpBlendDifAlpha = true; m_bTxtOpBlendFacAlpha = true; m_bTxtOpBlendTxtAlpha = true; m_bTxtOpMulAdd = m_bSupportModAdd_ATI; return true; } else { return false; } } //======================================================================== void COGLColorCombiner4::InitCombinerCycleFill(void) { for( int i=0; iEnableTexUnit(i,FALSE); } //pglActiveTexture(GL_TEXTURE0_ARB); //m_pOGLRender->EnableTexUnit(0,FALSE); //pglActiveTexture(GL_TEXTURE1_ARB); //m_pOGLRender->EnableTexUnit(1,FALSE); } ////////////////////////////////////////////////////////////////////////// void COGLColorCombiner4::InitCombinerCycle12(void) { if( !m_bOGLExtCombinerSupported ) { COGLColorCombiner::InitCombinerCycle12(); return; } #ifdef DEBUGGER if( debuggerDropCombiners ) { UpdateCombiner(m_pDecodedMux->m_dwMux0,m_pDecodedMux->m_dwMux1); m_vCompiledSettings.clear(); m_dwLastMux0 = m_dwLastMux1 = 0; debuggerDropCombiners = false; } #endif m_pOGLRender->EnableMultiTexture(); bool combinerIsChanged = false; if( m_pDecodedMux->m_dwMux0 != m_dwLastMux0 || m_pDecodedMux->m_dwMux1 != m_dwLastMux1 || m_lastIndex < 0 ) { combinerIsChanged = true; m_lastIndex = FindCompiledMux(); if( m_lastIndex < 0 ) // Can not found { m_lastIndex = ParseDecodedMux(); #ifdef DEBUGGER DisplaySimpleMuxString(); #endif } m_dwLastMux0 = m_pDecodedMux->m_dwMux0; m_dwLastMux1 = m_pDecodedMux->m_dwMux1; } if( m_bCycleChanged || combinerIsChanged || gRDP.texturesAreReloaded || gRDP.colorsAreReloaded ) { if( m_bCycleChanged || combinerIsChanged ) { GenerateCombinerSettingConstants(m_lastIndex); GenerateCombinerSetting(m_lastIndex); } else if( gRDP.colorsAreReloaded ) { GenerateCombinerSettingConstants(m_lastIndex); } m_pOGLRender->SetAllTexelRepeatFlag(); gRDP.colorsAreReloaded = false; gRDP.texturesAreReloaded = false; } else { m_pOGLRender->SetAllTexelRepeatFlag(); } } ////////////////////////////////////////////////////////////////////////// int COGLColorCombiner4::ParseDecodedMux() { #define nextUnit() {unitNo++;} #if SDL_VIDEO_OPENGL if( m_maxTexUnits<3) return ParseDecodedMux2Units(); OGLExtCombinerSaveType res; for( int k=0; k<8; k++ ) res.units[k].tex = -1; COGLDecodedMux &mux = *(COGLDecodedMux*)m_pDecodedMux; int unitNos[2]; for( int rgbalpha = 0; rgbalpha<2; rgbalpha++ ) { unitNos[rgbalpha] = 0; for( int cycle = 0; cycle<2; cycle++ ) { int &unitNo = unitNos[rgbalpha]; OGLExtCombinerType &unit = res.units[unitNo]; OGLExt1CombType &comb = unit.Combs[rgbalpha]; CombinerFormatType type = m_pDecodedMux->splitType[cycle*2+rgbalpha]; N64CombinerType &m = m_pDecodedMux->m_n64Combiners[cycle*2+rgbalpha]; comb.arg0 = comb.arg1 = comb.arg2 = CM_IGNORE_BYTE; switch( type ) { case CM_FMT_TYPE_NOT_USED: comb.arg0 = MUX_COMBINED; unit.ops[rgbalpha] = GL_REPLACE; nextUnit(); break; case CM_FMT_TYPE_D: // = A comb.arg0 = m.d; unit.ops[rgbalpha] = GL_REPLACE; nextUnit(); break; case CM_FMT_TYPE_A_ADD_D: // = A+D comb.arg0 = m.a; comb.arg1 = m.d; unit.ops[rgbalpha] = GL_ADD; nextUnit(); break; case CM_FMT_TYPE_A_SUB_B: // = A-B comb.arg0 = m.a; comb.arg1 = m.b; unit.ops[rgbalpha] = GL_SUBTRACT_ARB; nextUnit(); break; case CM_FMT_TYPE_A_MOD_C: // = A*C comb.arg0 = m.a; comb.arg1 = m.c; unit.ops[rgbalpha] = GL_MODULATE; nextUnit(); break; case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D if( m_bSupportModAdd_ATI ) { comb.arg0 = m.a; comb.arg2 = m.c; comb.arg1 = m.d; unit.ops[rgbalpha] = GL_MODULATE_ADD_ATI; nextUnit(); } else { if( unitNo < m_maxTexUnits-1 ) { comb.arg0 = m.a; comb.arg1 = m.c; unit.ops[rgbalpha] = GL_MODULATE; nextUnit(); res.units[unitNo].Combs[rgbalpha].arg0 = MUX_COMBINED; res.units[unitNo].Combs[rgbalpha].arg1 = m.d; res.units[unitNo].ops[rgbalpha] = GL_ADD; nextUnit(); } else { comb.arg0 = m.a; comb.arg1 = m.c; comb.arg2 = m.d; unit.ops[rgbalpha] = GL_INTERPOLATE_ARB; nextUnit(); } } break; case CM_FMT_TYPE_A_LERP_B_C: // = (A-B)*C+B comb.arg0 = m.a; comb.arg1 = m.b; comb.arg2 = m.c; unit.ops[rgbalpha] = GL_INTERPOLATE_ARB; nextUnit(); break; case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D if( unitNo < m_maxTexUnits-1 ) { comb.arg0 = m.a; comb.arg1 = m.b; unit.ops[rgbalpha] = GL_SUBTRACT_ARB; nextUnit(); res.units[unitNo].Combs[rgbalpha].arg0 = MUX_COMBINED; res.units[unitNo].Combs[rgbalpha].arg1 = m.d; res.units[unitNo].ops[rgbalpha] = GL_ADD; nextUnit(); } else { comb.arg0 = m.a; comb.arg1 = m.c; comb.arg2 = m.d; unit.ops[rgbalpha] = GL_INTERPOLATE_ARB; nextUnit(); } break; case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C if( unitNo < m_maxTexUnits-1 ) { comb.arg0 = m.a; comb.arg1 = m.b; unit.ops[rgbalpha] = GL_SUBTRACT_ARB; nextUnit(); res.units[unitNo].Combs[rgbalpha].arg0 = MUX_COMBINED; res.units[unitNo].Combs[rgbalpha].arg1 = m.c; res.units[unitNo].ops[rgbalpha] = GL_MODULATE; nextUnit(); } else { comb.arg0 = m.a; comb.arg1 = m.c; comb.arg2 = m.d; unit.ops[rgbalpha] = GL_INTERPOLATE_ARB; nextUnit(); } break; case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D default: if( unitNo < m_maxTexUnits-1 ) { comb.arg0 = m.a; comb.arg1 = m.b; unit.ops[rgbalpha] = GL_SUBTRACT_ARB; nextUnit(); if( m_bSupportModAdd_ATI ) { res.units[unitNo].Combs[rgbalpha].arg0 = MUX_COMBINED; res.units[unitNo].Combs[rgbalpha].arg2 = m.c; res.units[unitNo].Combs[rgbalpha].arg1 = m.d; res.units[unitNo].ops[rgbalpha] = GL_MODULATE_ADD_ATI; nextUnit(); } else { res.units[unitNo].Combs[rgbalpha].arg0 = m.a; res.units[unitNo].Combs[rgbalpha].arg1 = m.b; res.units[unitNo].Combs[rgbalpha].arg2 = m.c; res.units[unitNo].ops[rgbalpha] = GL_INTERPOLATE_ARB; nextUnit(); } } else { comb.arg0 = m.a; comb.arg1 = m.c; comb.arg2 = m.d; unit.ops[rgbalpha] = GL_INTERPOLATE_ARB; nextUnit(); } break; } } } res.numOfUnits = min(m_maxTexUnits, max(unitNos[0],unitNos[1])); if( unitNos[0]>m_maxTexUnits || unitNos[1]>m_maxTexUnits ) { TRACE0("Unit overflows"); } for( int j=0; j<2; j++ ) { if( unitNos[j]splitType[i]; N64CombinerType &m = m_pDecodedMux->m_n64Combiners[i]; comb.arg0 = comb.arg1 = comb.arg2 = MUX_0; switch( type ) { case CM_FMT_TYPE_NOT_USED: comb.arg0 = MUX_COMBINED; unit.ops[i%2] = GL_REPLACE; break; case CM_FMT_TYPE_D: // = A comb.arg0 = m.d; unit.ops[i%2] = GL_REPLACE; break; #if SDL_VIDEO_OPENGL case CM_FMT_TYPE_A_ADD_D: // = A+D comb.arg0 = m.a; comb.arg1 = m.d; unit.ops[i%2] = GL_ADD; break; case CM_FMT_TYPE_A_SUB_B: // = A-B comb.arg0 = m.a; comb.arg1 = m.b; unit.ops[i%2] = GL_SUBTRACT_ARB; break; case CM_FMT_TYPE_A_MOD_C: // = A*C comb.arg0 = m.a; comb.arg1 = m.c; unit.ops[i%2] = GL_MODULATE; break; case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D comb.arg0 = m.a; comb.arg1 = m.c; comb.arg2 = m.d; unit.ops[i%2] = GL_INTERPOLATE_ARB; break; case CM_FMT_TYPE_A_LERP_B_C: // = (A-B)*C+B comb.arg0 = m.a; comb.arg1 = m.b; comb.arg2 = m.c; unit.ops[i%2] = GL_INTERPOLATE_ARB; break; case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D // fix me, to use 2 texture units comb.arg0 = m.a; comb.arg1 = m.b; unit.ops[i%2] = GL_SUBTRACT_ARB; break; case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C // fix me, to use 2 texture units comb.arg0 = m.a; comb.arg1 = m.c; unit.ops[i%2] = GL_MODULATE; break; break; case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D #endif default: comb.arg0 = m.a; comb.arg1 = m.b; comb.arg2 = m.c; unit.ops[i%2] = GL_INTERPOLATE_ARB; break; } } if( m_pDecodedMux->splitType[2] == CM_FMT_TYPE_NOT_USED && m_pDecodedMux->splitType[3] == CM_FMT_TYPE_NOT_USED && !m_bTex1Enabled ) { res.numOfUnits = 1; } res.units[0].tex = 0; res.units[1].tex = 1; return SaveParsedResult(res); } const char* COGLColorCombiner4::GetOpStr(GLenum op) { switch( op ) { case GL_REPLACE: return "REPLACE"; #if SDL_VIDEO_OPENGL case GL_MODULATE: return "MOD"; case GL_ADD: return "ADD"; case GL_ADD_SIGNED_ARB: return "ADD_SIGNED"; case GL_INTERPOLATE_ARB: return "INTERPOLATE"; case GL_SUBTRACT_ARB: return "SUB"; #endif case GL_MODULATE_ADD_ATI: return "MULADD"; default: return "SUB"; } } int COGLColorCombiner4::SaveParsedResult(OGLExtCombinerSaveType &result) { result.dwMux0 = m_pDecodedMux->m_dwMux0; result.dwMux1 = m_pDecodedMux->m_dwMux1; for( int n=0; n= GL_TEXTURE0_ARB && val <= GL_TEXTURE7_ARB ) return true; else return false; } int COGLColorCombiner4v2::SaveParsedResult(OGLExtCombinerSaveType &result) { result.dwMux0 = m_pDecodedMux->m_dwMux0; result.dwMux1 = m_pDecodedMux->m_dwMux1; int n; for( n=0; nm_dwMux0 && m_vCompiledSettings[i].dwMux1 == m_pDecodedMux->m_dwMux1 ) return (int)i; } return -1; } //======================================================================== GLint COGLColorCombiner4::RGBArgsMap4[] = { #if SDL_VIDEO_OPENGL GL_PRIMARY_COLOR_ARB, //MUX_0 GL_PRIMARY_COLOR_ARB, //MUX_1 GL_PREVIOUS_ARB, //MUX_COMBINED, #endif GL_TEXTURE0_ARB, //MUX_TEXEL0, #if SDL_VIDEO_OPENGL GL_TEXTURE1_ARB, //MUX_TEXEL1, GL_CONSTANT_ARB, //MUX_PRIM, GL_PRIMARY_COLOR_ARB, //MUX_SHADE, GL_CONSTANT_ARB, //MUX_ENV, GL_PREVIOUS_ARB, //MUX_COMBALPHA, #endif GL_TEXTURE0_ARB, //MUX_T0_ALPHA, #if SDL_VIDEO_OPENGL GL_TEXTURE1_ARB, //MUX_T1_ALPHA, GL_CONSTANT_ARB, //MUX_PRIM_ALPHA, GL_PRIMARY_COLOR_ARB, //MUX_SHADE_ALPHA, GL_CONSTANT_ARB, //MUX_ENV_ALPHA, GL_CONSTANT_ARB, //MUX_LODFRAC, GL_CONSTANT_ARB, //MUX_PRIMLODFRAC, GL_PRIMARY_COLOR_ARB, //MUX_K5 GL_PRIMARY_COLOR_ARB //MUX_UNK #endif }; GLint COGLColorCombiner4v2::RGBArgsMap4v2[] = { #if SDL_VIDEO_OPENGL GL_PRIMARY_COLOR_ARB, //MUX_0 GL_PRIMARY_COLOR_ARB, //MUX_1 GL_PREVIOUS_ARB, //MUX_COMBINED, #endif GL_TEXTURE0_ARB, //MUX_TEXEL0, #if SDL_VIDEO_OPENGL GL_TEXTURE1_ARB, //MUX_TEXEL1, GL_CONSTANT_ARB, //MUX_PRIM, GL_PRIMARY_COLOR_ARB, //MUX_SHADE, GL_TEXTURE2_ARB, //MUX_ENV, //{GL_TEXTURE1_ARB, }, //MUX_ENV, GL_PREVIOUS_ARB, //MUX_COMBALPHA, GL_TEXTURE0_ARB, //MUX_T0_ALPHA, GL_TEXTURE1_ARB, //MUX_T1_ALPHA, GL_CONSTANT_ARB, //MUX_PRIM_ALPHA, GL_PRIMARY_COLOR_ARB, //MUX_SHADE_ALPHA, GL_TEXTURE2_ARB, //MUX_ENV_ALPHA, //{GL_TEXTURE1_ARB, }, //MUX_ENV_ALPHA, //{GL_TEXTURE3_ARB, }, //MUX_LODFRAC, //{GL_TEXTURE3_ARB, }, //MUX_PRIMLODFRAC, GL_TEXTURE1_ARB, //MUX_LODFRAC, GL_TEXTURE1_ARB, //MUX_PRIMLODFRAC, GL_PRIMARY_COLOR_ARB, //MUX_K5 GL_PRIMARY_COLOR_ARB //MUX_UNK #endif }; GLint COGLColorCombiner2::RGBArgsMap2[] = { #if SDL_VIDEO_OPENGL GL_PRIMARY_COLOR_ARB, //MUX_0 GL_PRIMARY_COLOR_ARB, //MUX_1 GL_PREVIOUS_ARB, //MUX_COMBINED, //{GL_TEXTURE, }, //MUX_TEXEL0, //{GL_TEXTURE, }, //MUX_TEXEL1, #endif GL_TEXTURE0_ARB, //MUX_TEXEL0, #if SDL_VIDEO_OPENGL GL_TEXTURE1_ARB, //MUX_TEXEL1, GL_CONSTANT_ARB, //MUX_PRIM, GL_PRIMARY_COLOR_ARB, //MUX_SHADE, GL_CONSTANT_ARB, //MUX_ENV, GL_PREVIOUS_ARB, //MUX_COMBALPHA, //{GL_TEXTURE, }, //MUX_T0_ALPHA, //{GL_TEXTURE, }, //MUX_T1_ALPHA, GL_TEXTURE0_ARB, //MUX_TEXEL0, GL_TEXTURE1_ARB, //MUX_TEXEL1, GL_CONSTANT_ARB, //MUX_PRIM_ALPHA, GL_PRIMARY_COLOR_ARB, //MUX_SHADE_ALPHA, GL_CONSTANT_ARB, //MUX_ENV_ALPHA, GL_CONSTANT_ARB, //MUX_LODFRAC, GL_CONSTANT_ARB, //MUX_PRIMLODFRAC, GL_PRIMARY_COLOR_ARB, //MUX_K5 GL_PRIMARY_COLOR_ARB //MUX_UNK #endif }; //======================================================================== GLint COGLColorCombiner4::MapRGBArgs(uint8 arg) { return RGBArgsMap4[arg&MUX_MASK]; } GLint COGLColorCombiner4v2::MapRGBArgs(uint8 arg) { return RGBArgsMap4v2[arg&MUX_MASK]; } GLint COGLColorCombiner2::MapRGBArgs(uint8 arg) { return RGBArgsMap2[arg&MUX_MASK]; } GLint COGLColorCombiner4::MapRGBArgFlags(uint8 arg) { if( (arg & MUX_ALPHAREPLICATE) && (arg & MUX_COMPLEMENT) ) { return GL_ONE_MINUS_SRC_ALPHA; } else if( (arg & MUX_ALPHAREPLICATE) ) { return GL_SRC_ALPHA; } else if(arg & MUX_COMPLEMENT) { return GL_ONE_MINUS_SRC_COLOR; } else return GL_SRC_COLOR; } GLint COGLColorCombiner4::MapAlphaArgs(uint8 arg) { return RGBArgsMap4[arg&MUX_MASK]; } GLint COGLColorCombiner4v2::MapAlphaArgs(uint8 arg) { return RGBArgsMap4v2[arg&MUX_MASK]; } GLint COGLColorCombiner2::MapAlphaArgs(uint8 arg) { return RGBArgsMap2[arg&MUX_MASK]; } GLint COGLColorCombiner4::MapAlphaArgFlags(uint8 arg) { if(arg & MUX_COMPLEMENT) { return GL_ONE_MINUS_SRC_ALPHA; } else return GL_SRC_ALPHA; } //======================================================================== void ApplyFor1Unit(OGLExtCombinerType &unit) { #if SDL_VIDEO_OPENGL glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit.rgbOp); OPENGL_CHECK_ERRORS; if( unit.rgbArg0 != CM_IGNORE_BYTE ) { glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, (unit.rgbArg0gl)); OPENGL_CHECK_ERRORS; glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, (unit.rgbFlag0gl)); OPENGL_CHECK_ERRORS; } if( unit.rgbArg1 != CM_IGNORE_BYTE ) { glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, (unit.rgbArg1gl)); OPENGL_CHECK_ERRORS; glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, (unit.rgbFlag1gl)); OPENGL_CHECK_ERRORS; } if( unit.rgbArg2 != CM_IGNORE_BYTE ) { glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, (unit.rgbArg2gl)); OPENGL_CHECK_ERRORS; glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, (unit.rgbFlag2gl)); OPENGL_CHECK_ERRORS; } if( unit.alphaArg0 != CM_IGNORE_BYTE ) { glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, (unit.alphaArg0gl)); OPENGL_CHECK_ERRORS; glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, (unit.alphaFlag0gl)); OPENGL_CHECK_ERRORS; } if( unit.alphaArg1 != CM_IGNORE_BYTE ) { glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, (unit.alphaArg1gl)); OPENGL_CHECK_ERRORS; glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, (unit.alphaFlag1gl)); OPENGL_CHECK_ERRORS; } if( unit.alphaArg2 != CM_IGNORE_BYTE ) { glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, (unit.alphaArg2gl)); OPENGL_CHECK_ERRORS; glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, (unit.alphaFlag2gl)); OPENGL_CHECK_ERRORS; } #endif } ////////////////////////////////////////////////////////////////////////// void COGLColorCombiner4::GenerateCombinerSetting(int index) { OGLExtCombinerSaveType &res = m_vCompiledSettings[index]; // Texture unit 0 COGLTexture* pTexture = NULL; COGLTexture* pTexture1 = NULL; if( m_bTex0Enabled || m_bTex1Enabled || gRDP.otherMode.cycle_type == CYCLE_TYPE_COPY ) { if( m_bTex0Enabled || gRDP.otherMode.cycle_type == CYCLE_TYPE_COPY ) { pTexture = g_textures[gRSP.curTile].m_pCOGLTexture; if( pTexture ) m_pOGLRender->BindTexture(pTexture->m_dwTextureName, 0); } if( m_bTex1Enabled ) { pTexture1 = g_textures[(gRSP.curTile+1)&7].m_pCOGLTexture; if( pTexture1 ) m_pOGLRender->BindTexture(pTexture1->m_dwTextureName, 1); } } for( int i=0; iEnableTexUnit(i,TRUE); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); OPENGL_CHECK_ERRORS; ApplyFor1Unit(res.units[i]); } if( res.numOfUnits < m_maxTexUnits ) { for( int i=res.numOfUnits; iDisBindTexture(0, i); m_pOGLRender->EnableTexUnit(i,FALSE); } } } void COGLColorCombiner4::GenerateCombinerSettingConstants(int index) { OGLExtCombinerSaveType &res = m_vCompiledSettings[index]; float *fv; float tempf[4]; bool isused = true; if( res.primIsUsed ) { fv = GetPrimitiveColorfv(); // CONSTANT COLOR } else if( res.envIsUsed ) { fv = GetEnvColorfv(); // CONSTANT COLOR } else if( res.lodFracIsUsed ) { float frac = gRDP.LODFrac / 255.0f; tempf[0] = tempf[1] = tempf[2] = tempf[3] = frac; fv = &tempf[0]; } else { isused = false; } if( isused ) { for( int i=0; iEnableTexUnit(2,TRUE); TxtrCacheEntry *pEntry = gTextureManager.GetConstantColorTexture(MUX_ENV); prender->SetCurrentTexture( (gRSP.curTile+2)%7, pEntry->pTexture, 4, 4, pEntry); prender->SetTexelRepeatFlags((gRSP.curTile+2)%7); } if( res.lodFracIsUsed) { int unit = 3; if( !res.envIsUsed ) unit = 2; // Set Texture unit 3 to LODFRAC pglActiveTexture(GL_TEXTURE0_ARB+unit); OPENGL_CHECK_ERRORS; prender->EnableTexUnit(unit,TRUE); TxtrCacheEntry *pEntry = gTextureManager.GetConstantColorTexture(MUX_LODFRAC); prender->SetCurrentTexture( (gRSP.curTile+unit)%7, pEntry->pTexture, 4, 4, pEntry); prender->SetTexelRepeatFlags((gRSP.curTile+unit)%7); } else { int unit = 3; if( !res.envIsUsed ) unit = 2; // Disable texture unit 3 pglActiveTexture(GL_TEXTURE0_ARB+unit); OPENGL_CHECK_ERRORS; prender->EnableTexUnit(unit,FALSE); prender->SetTextureToTextureUnitMap(-1,unit); } } GLenum GeneralToGLMaps[]= { GL_REPLACE, //CM_REPLACE, #if SDL_VIDEO_OPENGL GL_MODULATE, //CM_MODULATE, GL_ADD, //CM_ADD, GL_SUBTRACT_ARB, //CM_SUBTRACT, GL_INTERPOLATE_ARB, //CM_INTERPOLATE, GL_INTERPOLATE_ARB, //CM_ADDSMOOTH, GL_INTERPOLATE_ARB, //CM_BLENDCURRENTALPHA GL_INTERPOLATE_ARB, //CM_BLENDDIFFUSEALPHA GL_INTERPOLATE_ARB, //CM_BLENDFACTORALPHA, GL_INTERPOLATE_ARB, //CM_BLENDTEXTUREALPHA #endif GL_MODULATE_ADD_ATI, //CM_MULTIPLYADD, }; ////////////////////////////////////////////////////////////////////////// int COGLColorCombiner2::ParseDecodedMux() { //return COGLColorCombiner4::ParseDecodedMux(); int generalCombinerIndex = CGeneralCombiner::FindCompiledMux(); if( generalCombinerIndex < 0 ) // Can not found { generalCombinerIndex = CGeneralCombiner::ParseDecodedMux(); } GeneralCombinerInfo &generalRes = m_vCompiledCombinerStages[generalCombinerIndex]; OGLExtCombinerSaveType res; // Convert generalRes to OGLExtCombinerSaveType for( int unitNo=0; unitNoSetTextureToTextureUnitMap(res.units[i].tex,i); m_pOGLRender->EnableTexUnit(i,TRUE); COGLTexture* pTexture = g_textures[(gRSP.curTile+res.units[i].tex)&7].m_pCOGLTexture; if( pTexture ) m_pOGLRender->BindTexture(pTexture->m_dwTextureName, i); } /* else { m_pOGLRender->EnableTexUnit(i,TRUE); prender->SetTextureToTextureUnitMap(-1,i); //m_pOGLRender->EnableTexUnit(i,FALSE); //m_pOGLRender->DisBindTexture(0, i); } */ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); OPENGL_CHECK_ERRORS; ApplyFor1Unit(res.units[i]); } if( res.numOfUnits < m_maxTexUnits ) { for( int i=res.numOfUnits; iEnableTexUnit(i,FALSE); prender->SetTextureToTextureUnitMap(-1,i); } } } mupen64plus-video-rice-src-2.0/src/OGLExtCombiner.h0000644000000000000000000001307512165031100020230 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _OGLEXT_COMBINER_H_ #define _OGLEXT_COMBINER_H_ #include #include "osal_opengl.h" #include "OGLCombiner.h" #include "GeneralCombiner.h" typedef union { struct { uint8 arg0; uint8 arg1; uint8 arg2; }; uint8 args[3]; } OGLExt1CombType; typedef struct { union { struct { GLenum rgbOp; GLenum alphaOp; }; GLenum ops[2]; }; union { struct { uint8 rgbArg0; uint8 rgbArg1; uint8 rgbArg2; uint8 alphaArg0; uint8 alphaArg1; uint8 alphaArg2; }; struct { OGLExt1CombType rgbComb; OGLExt1CombType alphaComb; }; OGLExt1CombType Combs[2]; }; union { struct { GLint rgbArg0gl; GLint rgbArg1gl; GLint rgbArg2gl; }; GLint glRGBArgs[3]; }; union { struct { GLint rgbFlag0gl; GLint rgbFlag1gl; GLint rgbFlag2gl; }; GLint glRGBFlags[3]; }; union { struct { GLint alphaArg0gl; GLint alphaArg1gl; GLint alphaArg2gl; }; GLint glAlphaArgs[3]; }; union { struct { GLint alphaFlag0gl; GLint alphaFlag1gl; GLint alphaFlag2gl; }; GLint glAlphaFlags[3]; }; int tex; bool textureIsUsed; //float scale; //Will not be used } OGLExtCombinerType; typedef struct { uint32 dwMux0; uint32 dwMux1; OGLExtCombinerType units[8]; int numOfUnits; uint32 constantColor; // For 1.4 v2 combiner bool primIsUsed; bool envIsUsed; bool lodFracIsUsed; } OGLExtCombinerSaveType; //======================================================================== // OpenGL 1.4 combiner which support Texture Crossbar feature class COGLColorCombiner4 : public COGLColorCombiner { public: bool Initialize(void); protected: friend class OGLDeviceBuilder; void InitCombinerCycle12(void); void InitCombinerCycleFill(void); virtual void GenerateCombinerSetting(int index); virtual void GenerateCombinerSettingConstants(int index); virtual int ParseDecodedMux(); COGLColorCombiner4(CRender *pRender); ~COGLColorCombiner4() {}; bool m_bOGLExtCombinerSupported; // Is this OGL extension combiner supported by the video card driver? bool m_bSupportModAdd_ATI; bool m_bSupportModSub_ATI; GLint m_maxTexUnits; int m_lastIndex; uint32 m_dwLastMux0; uint32 m_dwLastMux1; #ifdef DEBUGGER void DisplaySimpleMuxString(void); #endif protected: virtual int SaveParsedResult(OGLExtCombinerSaveType &result); static GLint MapRGBArgFlags(uint8 arg); static GLint MapAlphaArgFlags(uint8 arg); std::vector m_vCompiledSettings; static GLint RGBArgsMap4[]; static const char* GetOpStr(GLenum op); private: virtual int ParseDecodedMux2Units(); virtual int FindCompiledMux(); virtual GLint MapRGBArgs(uint8 arg); virtual GLint MapAlphaArgs(uint8 arg); }; class COGLColorCombiner4v2 : public COGLColorCombiner4 { /************************************************************************ * Version 2 of OGL 1.4 combiner * Will support up to 4 texture units * Texture unit 0 and 1 are for N64 texture T0 and T1 * Texture unit 2 and 3 will be used to map constant colors * Constant color mapping: * OGL constant factor: MUX_PRIM * ARB_TEXTURE2: MUX_ENV * ARB_TEXTURE3: MUX_LODFRAC ************************************************************************/ protected: friend class OGLDeviceBuilder; virtual void GenerateCombinerSettingConstants(int index); virtual int SaveParsedResult(OGLExtCombinerSaveType &result); COGLColorCombiner4v2(CRender *pRender); ~COGLColorCombiner4v2() {}; static GLint RGBArgsMap4v2[]; private: virtual GLint MapRGBArgs(uint8 arg); virtual GLint MapAlphaArgs(uint8 arg); }; ////////////////////////////////////////////////////////////////////////// // OpenGL 1.2, 1.3 combiner which does not support Texture Crossbar feature class COGLColorCombiner2 : public COGLColorCombiner4, CGeneralCombiner { public: bool Initialize(void); #ifdef DEBUGGER void DisplaySimpleMuxString(void); #endif protected: friend class OGLDeviceBuilder; COGLColorCombiner2(CRender *pRender); ~COGLColorCombiner2() {}; private: virtual int ParseDecodedMux(); virtual void GenerateCombinerSetting(int index); virtual void GenerateCombinerSettingConstants(int index); virtual GLint MapRGBArgs(uint8 arg); virtual GLint MapAlphaArgs(uint8 arg); static GLint RGBArgsMap2[]; }; #endif mupen64plus-video-rice-src-2.0/src/OGLExtRender.cpp0000644000000000000000000002205012165031100020235 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "osal_opengl.h" #if SDL_VIDEO_OPENGL #include "OGLExtensions.h" #endif #include "OGLDebug.h" #include "OGLExtRender.h" #include "OGLTexture.h" void COGLExtRender::Initialize(void) { OGLRender::Initialize(); // Initialize multitexture glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,&m_maxTexUnits); OPENGL_CHECK_ERRORS; for( int i=0; i<8; i++ ) m_textureUnitMap[i] = -1; m_textureUnitMap[0] = 0; // T0 is usually using texture unit 0 m_textureUnitMap[1] = 1; // T1 is usually using texture unit 1 } void COGLExtRender::BindTexture(GLuint texture, int unitno) { if( m_bEnableMultiTexture ) { if( unitno < m_maxTexUnits ) { if( m_curBoundTex[unitno] != texture ) { pglActiveTexture(GL_TEXTURE0_ARB+unitno); OPENGL_CHECK_ERRORS; glBindTexture(GL_TEXTURE_2D,texture); OPENGL_CHECK_ERRORS; m_curBoundTex[unitno] = texture; } } } else { OGLRender::BindTexture(texture, unitno); } } void COGLExtRender::DisBindTexture(GLuint texture, int unitno) { if( m_bEnableMultiTexture ) { pglActiveTexture(GL_TEXTURE0_ARB+unitno); OPENGL_CHECK_ERRORS; glBindTexture(GL_TEXTURE_2D, 0); //Not to bind any texture OPENGL_CHECK_ERRORS; } else OGLRender::DisBindTexture(texture, unitno); } void COGLExtRender::TexCoord2f(float u, float v) { #if SDL_VIDEO_OPENGL if( m_bEnableMultiTexture ) { for( int i=0; i<8; i++ ) { if( m_textureUnitMap[i] >= 0 ) { pglMultiTexCoord2f(GL_TEXTURE0_ARB+i, u, v); } } } else { OGLRender::TexCoord2f(u,v); } #endif } void COGLExtRender::TexCoord(TLITVERTEX &vtxInfo) { #if SDL_VIDEO_OPENGL if( m_bEnableMultiTexture ) { for( int i=0; i<8; i++ ) { if( m_textureUnitMap[i] >= 0 ) { pglMultiTexCoord2fv(GL_TEXTURE0_ARB+i, &(vtxInfo.tcord[m_textureUnitMap[i]].u)); } } } else { OGLRender::TexCoord(vtxInfo); } #endif } void COGLExtRender::SetTexWrapS(int unitno,GLuint flag) { static GLuint mflag[8]; static GLuint mtex[8]; if( m_curBoundTex[unitno] != mtex[unitno] || mflag[unitno] != flag ) { mtex[unitno] = m_curBoundTex[0]; mflag[unitno] = flag; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, flag); OPENGL_CHECK_ERRORS; } } void COGLExtRender::SetTexWrapT(int unitno,GLuint flag) { static GLuint mflag[8]; static GLuint mtex[8]; if( m_curBoundTex[unitno] != mtex[unitno] || mflag[unitno] != flag ) { mtex[unitno] = m_curBoundTex[0]; mflag[unitno] = flag; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, flag); OPENGL_CHECK_ERRORS; } } extern UVFlagMap OGLXUVFlagMaps[]; void COGLExtRender::SetTextureUFlag(TextureUVFlag dwFlag, uint32 dwTile) { TileUFlags[dwTile] = dwFlag; if( !m_bEnableMultiTexture ) { OGLRender::SetTextureUFlag(dwFlag, dwTile); return; } int tex; if( dwTile == gRSP.curTile ) tex=0; else if( dwTile == ((gRSP.curTile+1)&7) ) tex=1; else { if( dwTile == ((gRSP.curTile+2)&7) ) tex=2; else if( dwTile == ((gRSP.curTile+3)&7) ) tex=3; else { TRACE2("Incorrect tile number for OGL SetTextureUFlag: cur=%d, tile=%d", gRSP.curTile, dwTile); return; } } for( int textureNo=0; textureNo<8; textureNo++) { if( m_textureUnitMap[textureNo] == tex ) { pglActiveTexture(GL_TEXTURE0_ARB+textureNo); OPENGL_CHECK_ERRORS; COGLTexture* pTexture = g_textures[(gRSP.curTile+tex)&7].m_pCOGLTexture; if( pTexture ) { EnableTexUnit(textureNo,TRUE); BindTexture(pTexture->m_dwTextureName, textureNo); } SetTexWrapS(textureNo, OGLXUVFlagMaps[dwFlag].realFlag); } } } void COGLExtRender::SetTextureVFlag(TextureUVFlag dwFlag, uint32 dwTile) { TileVFlags[dwTile] = dwFlag; if( !m_bEnableMultiTexture ) { OGLRender::SetTextureVFlag(dwFlag, dwTile); return; } int tex; if( dwTile == gRSP.curTile ) tex=0; else if( dwTile == ((gRSP.curTile+1)&7) ) tex=1; else { if( dwTile == ((gRSP.curTile+2)&7) ) tex=2; else if( dwTile == ((gRSP.curTile+3)&7) ) tex=3; else { TRACE2("Incorrect tile number for OGL SetTextureVFlag: cur=%d, tile=%d", gRSP.curTile, dwTile); return; } } for( int textureNo=0; textureNo<8; textureNo++) { if( m_textureUnitMap[textureNo] == tex ) { COGLTexture* pTexture = g_textures[(gRSP.curTile+tex)&7].m_pCOGLTexture; if( pTexture ) { EnableTexUnit(textureNo,TRUE); BindTexture(pTexture->m_dwTextureName, textureNo); } SetTexWrapT(textureNo, OGLXUVFlagMaps[dwFlag].realFlag); } } } void COGLExtRender::EnableTexUnit(int unitno, BOOL flag) { if( m_texUnitEnabled[unitno] != flag ) { m_texUnitEnabled[unitno] = flag; pglActiveTexture(GL_TEXTURE0_ARB+unitno); OPENGL_CHECK_ERRORS; if( flag == TRUE ) glEnable(GL_TEXTURE_2D); else glDisable(GL_TEXTURE_2D); OPENGL_CHECK_ERRORS; } } void COGLExtRender::ApplyTextureFilter() { static uint32 minflag[8], magflag[8]; static uint32 mtex[8]; int iMinFilter, iMagFilter; for( int i=0; i= -1 || tex <= 1)) m_textureUnitMap[unit] = tex; } mupen64plus-video-rice-src-2.0/src/OGLExtRender.h0000644000000000000000000000303212165031100017701 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _OGL_EXT_RENDER_H_ #define _OGL_EXT_RENDER_H_ #include "OGLRender.h" class COGLExtRender : public OGLRender { public: void Initialize(void); void BindTexture(GLuint texture, int unitno); void DisBindTexture(GLuint texture, int unitno); void TexCoord2f(float u, float v); void TexCoord(TLITVERTEX &vtxInfo); void SetTextureUFlag(TextureUVFlag dwFlag, uint32 tile); void SetTextureVFlag(TextureUVFlag dwFlag, uint32 tile); void EnableTexUnit(int unitno, BOOL flag); void SetTexWrapS(int unitno,GLuint flag); void SetTexWrapT(int unitno,GLuint flag); void ApplyTextureFilter(); void SetTextureToTextureUnitMap(int tex, int unit); protected: friend class OGLDeviceBuilder; COGLExtRender() {}; ~COGLExtRender() {}; GLint m_maxTexUnits; int m_textureUnitMap[8]; }; #endif mupen64plus-video-rice-src-2.0/src/OGLExtensions.cpp0000644000000000000000000001162712165031100020504 0ustar 00000000000000/* OGLExtensions.cpp Copyright (C) 2009 Richard Goedeken This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This source file contains code for assigning function pointers to some OpenGL functions */ /* This is only necessary because Windows does not contain development support for OpenGL versions beyond 1.1 */ #include #include "OGLExtensions.h" #include "Video.h" static void APIENTRY EmptyFunc(void) { return; } bool bNvidiaExtensionsSupported = false; PFUNCGLCOMBINERPARAMETERFVNVPROC pglCombinerParameterfvNV = (PFUNCGLCOMBINERPARAMETERFVNVPROC) EmptyFunc; PFUNCGLFINALCOMBINERINPUTNVPROC pglFinalCombinerInputNV = (PFUNCGLFINALCOMBINERINPUTNVPROC) EmptyFunc; PFUNCGLCOMBINEROUTPUTNVPROC pglCombinerOutputNV = (PFUNCGLCOMBINEROUTPUTNVPROC) EmptyFunc; PFUNCGLCOMBINERINPUTNVPROC pglCombinerInputNV = (PFUNCGLCOMBINERINPUTNVPROC) EmptyFunc; PFUNCGLCOMBINERPARAMETERINVPROC pglCombinerParameteriNV = (PFUNCGLCOMBINERPARAMETERINVPROC) EmptyFunc; PFUNCGLACTIVETEXTUREPROC pglActiveTexture = (PFUNCGLACTIVETEXTUREPROC) EmptyFunc; PFUNCGLACTIVETEXTUREARBPROC pglActiveTextureARB = (PFUNCGLACTIVETEXTUREARBPROC) EmptyFunc; PFUNCGLMULTITEXCOORD2FPROC pglMultiTexCoord2f = (PFUNCGLMULTITEXCOORD2FPROC) EmptyFunc; PFUNCGLMULTITEXCOORD2FVPROC pglMultiTexCoord2fv = (PFUNCGLMULTITEXCOORD2FVPROC) EmptyFunc; PFUNCGLDELETEPROGRAMSARBPROC pglDeleteProgramsARB = (PFUNCGLDELETEPROGRAMSARBPROC) EmptyFunc; PFUNCGLPROGRAMSTRINGARBPROC pglProgramStringARB = (PFUNCGLPROGRAMSTRINGARBPROC) EmptyFunc; PFUNCGLBINDPROGRAMARBPROC pglBindProgramARB = (PFUNCGLBINDPROGRAMARBPROC) EmptyFunc; PFUNCGLGENPROGRAMSARBPROC pglGenProgramsARB = (PFUNCGLGENPROGRAMSARBPROC) EmptyFunc; PFUNCGLPROGRAMENVPARAMETER4FVARBPROC pglProgramEnvParameter4fvARB = (PFUNCGLPROGRAMENVPARAMETER4FVARBPROC) EmptyFunc; PFUNCGLFOGCOORDPOINTEREXTPROC pglFogCoordPointerEXT = (PFUNCGLFOGCOORDPOINTEREXTPROC) EmptyFunc; PFUNCGLCLIENTACTIVETEXTUREARBPROC pglClientActiveTextureARB = (PFUNCGLCLIENTACTIVETEXTUREARBPROC) EmptyFunc; #define INIT_ENTRY_POINT(type, funcname) \ p##funcname = (type) CoreVideo_GL_GetProcAddress(#funcname); \ if (p##funcname == NULL) { DebugMessage(M64MSG_WARNING, \ "Couldn't get address of OpenGL function: '%s'", #funcname); p##funcname = (type) EmptyFunc; } void OGLExtensions_Init(void) { /* nvidia extensions are a special case */ bNvidiaExtensionsSupported = true; pglCombinerParameterfvNV = (PFUNCGLCOMBINERPARAMETERFVNVPROC) CoreVideo_GL_GetProcAddress("glCombinerParameterfvNV"); if (pglCombinerParameterfvNV == NULL) bNvidiaExtensionsSupported = false; pglFinalCombinerInputNV = (PFUNCGLFINALCOMBINERINPUTNVPROC) CoreVideo_GL_GetProcAddress("glFinalCombinerInputNV"); if (pglFinalCombinerInputNV == NULL) bNvidiaExtensionsSupported = false; pglCombinerOutputNV = (PFUNCGLCOMBINEROUTPUTNVPROC) CoreVideo_GL_GetProcAddress("glCombinerOutputNV"); if (pglCombinerOutputNV == NULL) bNvidiaExtensionsSupported = false; pglCombinerInputNV = (PFUNCGLCOMBINERINPUTNVPROC) CoreVideo_GL_GetProcAddress("glCombinerInputNV"); if (pglCombinerInputNV == NULL) bNvidiaExtensionsSupported = false; pglCombinerParameteriNV = (PFUNCGLCOMBINERPARAMETERINVPROC) CoreVideo_GL_GetProcAddress("glCombinerParameteriNV"); if (pglCombinerParameteriNV == NULL) bNvidiaExtensionsSupported = false; INIT_ENTRY_POINT(PFUNCGLACTIVETEXTUREPROC, glActiveTexture); INIT_ENTRY_POINT(PFUNCGLACTIVETEXTUREARBPROC, glActiveTextureARB); INIT_ENTRY_POINT(PFUNCGLMULTITEXCOORD2FPROC, glMultiTexCoord2f); INIT_ENTRY_POINT(PFUNCGLMULTITEXCOORD2FVPROC, glMultiTexCoord2fv); INIT_ENTRY_POINT(PFUNCGLDELETEPROGRAMSARBPROC, glDeleteProgramsARB); INIT_ENTRY_POINT(PFUNCGLPROGRAMSTRINGARBPROC, glProgramStringARB); INIT_ENTRY_POINT(PFUNCGLBINDPROGRAMARBPROC, glBindProgramARB); INIT_ENTRY_POINT(PFUNCGLGENPROGRAMSARBPROC, glGenProgramsARB); INIT_ENTRY_POINT(PFUNCGLPROGRAMENVPARAMETER4FVARBPROC, glProgramEnvParameter4fvARB); INIT_ENTRY_POINT(PFUNCGLFOGCOORDPOINTEREXTPROC, glFogCoordPointerEXT); INIT_ENTRY_POINT(PFUNCGLCLIENTACTIVETEXTUREARBPROC, glClientActiveTextureARB); } mupen64plus-video-rice-src-2.0/src/OGLExtensions.h0000644000000000000000000001016512165031100020145 0ustar 00000000000000/* OGLExtensions.h Copyright (C) 2009 Richard Goedeken This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This header file contains function pointers to some OpenGL functions */ /* This is only necessary because Windows does not contain development support for OpenGL versions beyond 1.1 */ #if !defined(OGL_EXTENSIONS_H) #define OGL_EXTENSIONS_H #include /* Just call this one function to load up the function pointers. */ void OGLExtensions_Init(void); /* The function pointer types are defined here because as of 2009 some OpenGL drivers under Linux do 'incorrect' things which mess up the SDL_opengl.h header, resulting in no function pointer typedefs at all, and thus compilation errors. */ typedef void (APIENTRYP PFUNCGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFUNCGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); typedef void (APIENTRYP PFUNCGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); typedef void (APIENTRYP PFUNCGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); typedef void (APIENTRYP PFUNCGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFUNCGLACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRYP PFUNCGLACTIVETEXTUREARBPROC) (GLenum texture); typedef void (APIENTRYP PFUNCGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t); typedef void (APIENTRYP PFUNCGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFUNCGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFUNCGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); typedef void (APIENTRYP PFUNCGLBINDPROGRAMARBPROC) (GLenum target, GLuint program); typedef void (APIENTRYP PFUNCGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs); typedef void (APIENTRYP PFUNCGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); typedef void (APIENTRYP PFUNCGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFUNCGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture); extern bool bNvidiaExtensionsSupported; extern PFUNCGLCOMBINERPARAMETERFVNVPROC pglCombinerParameterfvNV; extern PFUNCGLFINALCOMBINERINPUTNVPROC pglFinalCombinerInputNV; extern PFUNCGLCOMBINEROUTPUTNVPROC pglCombinerOutputNV; extern PFUNCGLCOMBINERINPUTNVPROC pglCombinerInputNV; extern PFUNCGLCOMBINERPARAMETERINVPROC pglCombinerParameteriNV; extern PFUNCGLACTIVETEXTUREPROC pglActiveTexture; extern PFUNCGLACTIVETEXTUREARBPROC pglActiveTextureARB; extern PFUNCGLMULTITEXCOORD2FPROC pglMultiTexCoord2f; extern PFUNCGLMULTITEXCOORD2FVPROC pglMultiTexCoord2fv; extern PFUNCGLDELETEPROGRAMSARBPROC pglDeleteProgramsARB; extern PFUNCGLPROGRAMSTRINGARBPROC pglProgramStringARB; extern PFUNCGLBINDPROGRAMARBPROC pglBindProgramARB; extern PFUNCGLGENPROGRAMSARBPROC pglGenProgramsARB; extern PFUNCGLPROGRAMENVPARAMETER4FVARBPROC pglProgramEnvParameter4fvARB; extern PFUNCGLFOGCOORDPOINTEREXTPROC pglFogCoordPointerEXT; extern PFUNCGLCLIENTACTIVETEXTUREARBPROC pglClientActiveTextureARB; #endif // OGL_EXTENSIONS_H mupen64plus-video-rice-src-2.0/src/OGLFragmentShaders.cpp0000644000000000000000000003620312165031100021417 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "OGLExtensions.h" #include "OGLDebug.h" #include "OGLFragmentShaders.h" #include "OGLRender.h" #include "OGLGraphicsContext.h" COGLFragmentShaderCombiner::COGLFragmentShaderCombiner(CRender *pRender) : COGLColorCombiner(pRender) { m_bShaderIsSupported = false; } COGLFragmentShaderCombiner::~COGLFragmentShaderCombiner() { } bool COGLFragmentShaderCombiner::Initialize(void) { if( !COGLColorCombiner::Initialize() ) return false; COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); if( pcontext->IsExtensionSupported("GL_ARB_fragment_shader") ) { m_bShaderIsSupported = true; } return true; } void COGLFragmentShaderCombiner::InitCombinerCycle12(void) { } void COGLFragmentShaderCombiner::DisableCombiner(void) { COGLColorCombiner::DisableCombiner(); } void COGLFragmentShaderCombiner::InitCombinerCycleCopy(void) { COGLColorCombiner::InitCombinerCycleCopy(); } void COGLFragmentShaderCombiner::InitCombinerCycleFill(void) { COGLColorCombiner::InitCombinerCycleFill(); } void COGLFragmentShaderCombiner::InitCombinerBlenderForSimpleTextureDraw(uint32 tile) { COGLColorCombiner::InitCombinerBlenderForSimpleTextureDraw(tile); } #ifdef DEBUGGER void COGLFragmentShaderCombiner::DisplaySimpleMuxString(void) { COGLColorCombiner::DisplaySimpleMuxString(); } #endif COGL_FragmentProgramCombiner::COGL_FragmentProgramCombiner(CRender *pRender) : COGLColorCombiner4(pRender) { delete m_pDecodedMux; m_pDecodedMux = new DecodedMuxForPixelShader; m_bFragmentProgramIsSupported = false; } COGL_FragmentProgramCombiner::~COGL_FragmentProgramCombiner() { int size = m_vCompiledShaders.size(); for (int i=0; iIsExtensionSupported("GL_ARB_fragment_program") ) { m_bFragmentProgramIsSupported = true; } return true; } void COGL_FragmentProgramCombiner::DisableCombiner(void) { glDisable(GL_FRAGMENT_PROGRAM_ARB); OPENGL_CHECK_ERRORS; COGLColorCombiner4::DisableCombiner(); } void COGL_FragmentProgramCombiner::InitCombinerCycleCopy(void) { glDisable(GL_FRAGMENT_PROGRAM_ARB); OPENGL_CHECK_ERRORS; COGLColorCombiner4::InitCombinerCycleCopy(); } void COGL_FragmentProgramCombiner::InitCombinerCycleFill(void) { glDisable(GL_FRAGMENT_PROGRAM_ARB); OPENGL_CHECK_ERRORS; COGLColorCombiner4::InitCombinerCycleFill(); } const char *muxToFP_Maps[][2] = { //color -- alpha {"0", "0"}, //MUX_0 = 0, {"1", "1"}, //MUX_1, {"comb", "comb.a"}, //MUX_COMBINED, {"t0", "t0.a"}, //MUX_TEXEL0, {"t1", "t1.a"}, //MUX_TEXEL1, {"program.env[2]", "program.env[2].a"}, //MUX_PRIM, {"fragment.color", "fragment.color.a"}, //MUX_SHADE, {"program.env[1]", "program.env[1].a"}, //MUX_ENV, {"comb.a", "comb.a"}, //MUX_COMBALPHA, {"t0.a", "t0.a"}, //MUX_T0_ALPHA, {"t1.a", "t1.a"}, //MUX_T1_ALPHA, {"primcolor.a", "primcolor.a"}, //MUX_PRIM_ALPHA, {"fragment.color.a", "fragment.color.a"}, //MUX_SHADE_ALPHA, {"envcolor.a", "envcolor.a"}, //MUX_ENV_ALPHA, {"program.env[3]", "program.env[3]"}, //MUX_LODFRAC, {"program.env[4]", "program.env[4]"}, //MUX_PRIMLODFRAC, {"1", "1"}, //MUX_K5, {"1", "1"}, //MUX_UNK, // Should not be used }; const char *oglFPTest = "!!ARBfp1.0\n" "#Declarations\n" "TEMP t0;\n" "TEMP t1;\n" "TEMP comb;\n" "TEMP comb2;\n" "\n" "ATTRIB coord0 = fragment.texcoord[0];\n" "ATTRIB coord1 = fragment.texcoord[1];\n" "ATTRIB shade = fragment.color;\n" "ATTRIB fogfactor = fragment.fogcoord;\n" "\n" "OUTPUT out = result.color;\n" "\n" "#Instructions\n" "TEX t0, coord0, texture[0], 2D;\n" "TEX t1, coord1, texture[1], 2D;\n" "\n" "MAD_SAT out, t0, program.env[1],program.env[0];\n" //"SUB comb.rgb, t0, 0;\n" //"MAD_SAT out.rgb, comb, program.env[1], 0;\n" //"SUB comb.a, t0, 0;\n" //"MAD_SAT out.a, comb, program.env[1], 0;\n" "END\n"; char oglNewFP[4092]; char* MuxToOC(uint8 val) { // For color channel if( val&MUX_ALPHAREPLICATE ) return (char*)muxToFP_Maps[val&0x1F][1]; else return (char*)muxToFP_Maps[val&0x1F][0]; } char* MuxToOA(uint8 val) { // For alpha channel return (char*)muxToFP_Maps[val&0x1F][0]; } static void CheckFpVars(uint8 MuxVar, bool &bNeedT0, bool &bNeedT1) { MuxVar &= 0x1f; if (MuxVar == MUX_TEXEL0 || MuxVar == MUX_T0_ALPHA) bNeedT0 = true; if (MuxVar == MUX_TEXEL1 || MuxVar == MUX_T1_ALPHA) bNeedT1 = true; } void COGL_FragmentProgramCombiner::GenerateProgramStr() { DecodedMuxForPixelShader &mux = *(DecodedMuxForPixelShader*)m_pDecodedMux; mux.splitType[0] = mux.splitType[1] = mux.splitType[2] = mux.splitType[3] = CM_FMT_TYPE_NOT_CHECKED; m_pDecodedMux->Reformat(false); char tempstr[500], newFPBody[4092]; bool bNeedT0 = false, bNeedT1 = false, bNeedComb2 = false; newFPBody[0] = 0; for( int cycle=0; cycle<2; cycle++ ) { for( int channel=0; channel<2; channel++) { char* (*func)(uint8) = channel==0?MuxToOC:MuxToOA; char *dst = channel==0?(char*)"rgb":(char*)"a"; N64CombinerType &m = mux.m_n64Combiners[cycle*2+channel]; switch( mux.splitType[cycle*2+channel] ) { case CM_FMT_TYPE_NOT_USED: tempstr[0] = 0; break; case CM_FMT_TYPE_D: sprintf(tempstr, "MOV comb.%s, %s;\n", dst, func(m.d)); CheckFpVars(m.d, bNeedT0, bNeedT1); break; case CM_FMT_TYPE_A_MOD_C: sprintf(tempstr, "MUL comb.%s, %s, %s;\n", dst, func(m.a), func(m.c)); CheckFpVars(m.a, bNeedT0, bNeedT1); CheckFpVars(m.c, bNeedT0, bNeedT1); break; case CM_FMT_TYPE_A_ADD_D: sprintf(tempstr, "ADD_SAT comb.%s, %s, %s;\n", dst, func(m.a), func(m.d)); CheckFpVars(m.a, bNeedT0, bNeedT1); CheckFpVars(m.d, bNeedT0, bNeedT1); break; case CM_FMT_TYPE_A_SUB_B: sprintf(tempstr, "SUB comb.%s, %s, %s;\n", dst, func(m.a), func(m.b)); CheckFpVars(m.a, bNeedT0, bNeedT1); CheckFpVars(m.b, bNeedT0, bNeedT1); break; case CM_FMT_TYPE_A_MOD_C_ADD_D: sprintf(tempstr, "MAD_SAT comb.%s, %s, %s, %s;\n", dst, func(m.a), func(m.c), func(m.d)); CheckFpVars(m.a, bNeedT0, bNeedT1); CheckFpVars(m.c, bNeedT0, bNeedT1); CheckFpVars(m.d, bNeedT0, bNeedT1); break; case CM_FMT_TYPE_A_LERP_B_C: sprintf(tempstr, "LRP_SAT comb.%s, %s, %s, %s;\n", dst, func(m.c), func(m.a), func(m.b)); CheckFpVars(m.a, bNeedT0, bNeedT1); CheckFpVars(m.b, bNeedT0, bNeedT1); CheckFpVars(m.c, bNeedT0, bNeedT1); //sprintf(tempstr, "SUB comb.%s, %s, %s;\nMAD_SAT comb.%s, comb, %s, %s;\n", dst, func(m.a), func(m.b), dst, func(m.c), func(m.b)); break; default: sprintf(tempstr, "SUB comb2.%s, %s, %s;\nMAD_SAT comb.%s, comb2, %s, %s;\n", dst, func(m.a), func(m.b), dst, func(m.c), func(m.d)); CheckFpVars(m.a, bNeedT0, bNeedT1); CheckFpVars(m.b, bNeedT0, bNeedT1); CheckFpVars(m.c, bNeedT0, bNeedT1); CheckFpVars(m.d, bNeedT0, bNeedT1); bNeedComb2 = true; break; } strcat(newFPBody, tempstr); } } strcpy(oglNewFP, "!!ARBfp1.0\n"); strcat(oglNewFP, "#Declarations\n"); if (gRDP.bFogEnableInBlender && gRSP.bFogEnabled) strcat(oglNewFP, "OPTION ARB_fog_linear;\n"); if (bNeedT0) strcat(oglNewFP, "TEMP t0;\n"); if (bNeedT1) strcat(oglNewFP, "TEMP t1;\n"); strcat(oglNewFP, "TEMP comb;\n"); if (bNeedComb2) strcat(oglNewFP, "TEMP comb2;\n"); strcat(oglNewFP, "#Instructions\n"); if (bNeedT0) strcat(oglNewFP, "TEX t0, fragment.texcoord[0], texture[0], 2D;\n"); if (bNeedT1) strcat(oglNewFP, "TEX t1, fragment.texcoord[1], texture[1], 2D;\n"); strcat(oglNewFP, "# N64 cycle 1, result is in comb\n"); strcat(oglNewFP, newFPBody); strcat(oglNewFP, "MOV result.color, comb;\n"); strcat(oglNewFP, "END\n\n"); } int COGL_FragmentProgramCombiner::ParseDecodedMux() { if( !m_bFragmentProgramIsSupported ) return COGLColorCombiner4::ParseDecodedMux(); OGLShaderCombinerSaveType res; pglGenProgramsARB( 1, &res.programID); OPENGL_CHECK_ERRORS; pglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, res.programID); OPENGL_CHECK_ERRORS; GenerateProgramStr(); pglProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(oglNewFP), oglNewFP); OPENGL_CHECK_ERRORS; //pglProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(oglFPTest), oglFPTest); if (glGetError() != 0) { GLint position; #ifdef DEBUGGER char *str = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB); #endif glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &position); if( position >= 0 ) { #ifdef DEBUGGER if( m_lastIndex >= 0 ) COGLColorCombiner4::DisplaySimpleMuxString(); DebugMessage(M64MSG_ERROR, "%s - %s", str, oglNewFP+position); #endif glDisable(GL_FRAGMENT_PROGRAM_ARB); return COGLColorCombiner4::ParseDecodedMux(); } } glEnable(GL_FRAGMENT_PROGRAM_ARB); OPENGL_CHECK_ERRORS; res.dwMux0 = m_pDecodedMux->m_dwMux0; res.dwMux1 = m_pDecodedMux->m_dwMux1; res.fogIsUsed = gRDP.bFogEnableInBlender && gRSP.bFogEnabled; m_vCompiledShaders.push_back(res); m_lastIndex = m_vCompiledShaders.size()-1; return m_lastIndex; } void COGL_FragmentProgramCombiner::GenerateCombinerSetting(int index) { GLuint ID = m_vCompiledShaders[index].programID; pglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, ID ); OPENGL_CHECK_ERRORS; glEnable(GL_FRAGMENT_PROGRAM_ARB); OPENGL_CHECK_ERRORS; } void COGL_FragmentProgramCombiner::GenerateCombinerSettingConstants(int index) { float *pf; pf = GetEnvColorfv(); pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 1, pf); OPENGL_CHECK_ERRORS; pf = GetPrimitiveColorfv(); pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 2, pf); OPENGL_CHECK_ERRORS; float frac = gRDP.LODFrac / 255.0f; float tempf[4] = {frac,frac,frac,frac}; pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 3, tempf); OPENGL_CHECK_ERRORS; float frac2 = gRDP.primLODFrac / 255.0f; float tempf2[4] = {frac2,frac2,frac2,frac2}; pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 4, tempf2); OPENGL_CHECK_ERRORS; float tempf3[4] = {0,0,0,0}; pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, tempf3); OPENGL_CHECK_ERRORS; pglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 6, tempf3); OPENGL_CHECK_ERRORS; } int COGL_FragmentProgramCombiner::FindCompiledMux() { #ifdef DEBUGGER if( debuggerDropCombiners ) { m_vCompiledShaders.clear(); //m_dwLastMux0 = m_dwLastMux1 = 0; debuggerDropCombiners = false; } #endif for( uint32 i=0; im_dwMux0 && m_vCompiledShaders[i].dwMux1 == m_pDecodedMux->m_dwMux1 && m_vCompiledShaders[i].fogIsUsed == (gRDP.bFogEnableInBlender && gRSP.bFogEnabled) ) return (int)i; } return -1; } ////////////////////////////////////////////////////////////////////////// void COGL_FragmentProgramCombiner::InitCombinerCycle12(void) { if( !m_bFragmentProgramIsSupported ) { COGLColorCombiner4::InitCombinerCycle12(); return; } #ifdef DEBUGGER if( debuggerDropCombiners ) { UpdateCombiner(m_pDecodedMux->m_dwMux0,m_pDecodedMux->m_dwMux1); m_vCompiledShaders.clear(); m_dwLastMux0 = m_dwLastMux1 = 0; debuggerDropCombiners = false; } #endif m_pOGLRender->EnableMultiTexture(); bool combinerIsChanged = false; if( m_pDecodedMux->m_dwMux0 != m_dwLastMux0 || m_pDecodedMux->m_dwMux1 != m_dwLastMux1 || m_lastIndex < 0 ) { combinerIsChanged = true; m_lastIndex = FindCompiledMux(); if( m_lastIndex < 0 ) // Can not found { m_lastIndex = ParseDecodedMux(); } m_dwLastMux0 = m_pDecodedMux->m_dwMux0; m_dwLastMux1 = m_pDecodedMux->m_dwMux1; } GenerateCombinerSettingConstants(m_lastIndex); if( m_bCycleChanged || combinerIsChanged || gRDP.texturesAreReloaded || gRDP.colorsAreReloaded ) { if( m_bCycleChanged || combinerIsChanged ) { GenerateCombinerSettingConstants(m_lastIndex); GenerateCombinerSetting(m_lastIndex); } else if( gRDP.colorsAreReloaded ) { GenerateCombinerSettingConstants(m_lastIndex); } m_pOGLRender->SetAllTexelRepeatFlag(); gRDP.colorsAreReloaded = false; gRDP.texturesAreReloaded = false; } else { m_pOGLRender->SetAllTexelRepeatFlag(); } } #ifdef DEBUGGER void COGL_FragmentProgramCombiner::DisplaySimpleMuxString(void) { COGLColorCombiner::DisplaySimpleMuxString(); DecodedMuxForPixelShader &mux = *(DecodedMuxForPixelShader*)m_pDecodedMux; mux.Reformat(false); GenerateProgramStr(); //sprintf(oglNewFP, oglFP, // MuxToOC(mux.aRGB0), MuxToOC(mux.bRGB0), MuxToOC(mux.cRGB0), MuxToOC(mux.dRGB0), // MuxToOA(mux.aA0), MuxToOA(mux.bA0), MuxToOA(mux.cA0), MuxToOA(mux.dA0), // MuxToOC(mux.aRGB1), MuxToOC(mux.bRGB1), MuxToOC(mux.cRGB1), MuxToOC(mux.dRGB1), // MuxToOA(mux.aA1), MuxToOA(mux.bA1), MuxToOA(mux.cA1), MuxToOA(mux.dA1) // ); TRACE0("OGL Fragment Program:"); TRACE0(oglNewFP); } #endif mupen64plus-video-rice-src-2.0/src/OGLFragmentShaders.h0000644000000000000000000000451012165031100021060 0ustar 00000000000000/* Copyright (C) 2005 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _OGL_FRAGMENT_SHADER_H_ #define _OGL_FRAGMENT_SHADER_H_ #include #include #include "OGLCombiner.h" #include "OGLExtCombiner.h" #include "GeneralCombiner.h" typedef struct { uint32 dwMux0; uint32 dwMux1; bool fogIsUsed; GLuint programID; } OGLShaderCombinerSaveType; class COGL_FragmentProgramCombiner : public COGLColorCombiner4 { public: bool Initialize(void); protected: friend class OGLDeviceBuilder; void DisableCombiner(void); void InitCombinerCycleCopy(void); void InitCombinerCycleFill(void); void InitCombinerCycle12(void); COGL_FragmentProgramCombiner(CRender *pRender); ~COGL_FragmentProgramCombiner(); bool m_bFragmentProgramIsSupported; std::vector m_vCompiledShaders; private: virtual int ParseDecodedMux(); virtual void GenerateProgramStr(); int FindCompiledMux(); virtual void GenerateCombinerSetting(int index); virtual void GenerateCombinerSettingConstants(int index); #ifdef DEBUGGER void DisplaySimpleMuxString(void); #endif }; class COGLFragmentShaderCombiner : public COGLColorCombiner { public: bool Initialize(void); void InitCombinerBlenderForSimpleTextureDraw(uint32 tile=0); protected: friend class OGLDeviceBuilder; void DisableCombiner(void); void InitCombinerCycleCopy(void); void InitCombinerCycleFill(void); void InitCombinerCycle12(void); COGLFragmentShaderCombiner(CRender *pRender); ~COGLFragmentShaderCombiner(); bool m_bShaderIsSupported; #ifdef DEBUGGER void DisplaySimpleMuxString(void); #endif }; #endif mupen64plus-video-rice-src-2.0/src/OGLGraphicsContext.cpp0000644000000000000000000004166312165031100021455 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "osal_opengl.h" #define M64P_PLUGIN_PROTOTYPES 1 #include "m64p_plugin.h" #include "Config.h" #include "Debugger.h" #if SDL_VIDEO_OPENGL #include "OGLExtensions.h" #endif #include "OGLDebug.h" #include "OGLGraphicsContext.h" #include "TextureManager.h" #include "Video.h" #include "version.h" COGLGraphicsContext::COGLGraphicsContext() : m_bSupportMultiTexture(false), m_bSupportTextureEnvCombine(false), m_bSupportSeparateSpecularColor(false), m_bSupportSecondColor(false), m_bSupportFogCoord(false), m_bSupportTextureObject(false), m_bSupportRescaleNormal(false), m_bSupportLODBias(false), m_bSupportTextureMirrorRepeat(false), m_bSupportTextureLOD(false), m_bSupportNVRegisterCombiner(false), m_bSupportBlendColor(false), m_bSupportBlendSubtract(false), m_bSupportNVTextureEnvCombine4(false), m_pVendorStr(NULL), m_pRenderStr(NULL), m_pExtensionStr(NULL), m_pVersionStr(NULL) { } COGLGraphicsContext::~COGLGraphicsContext() { } bool COGLGraphicsContext::Initialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed ) { DebugMessage(M64MSG_INFO, "Initializing OpenGL Device Context."); Lock(); CGraphicsContext::Get()->m_supportTextureMirror = false; CGraphicsContext::Initialize(dwWidth, dwHeight, bWindowed ); if( bWindowed ) { windowSetting.statusBarHeightToUse = windowSetting.statusBarHeight; windowSetting.toolbarHeightToUse = windowSetting.toolbarHeight; } else { windowSetting.statusBarHeightToUse = 0; windowSetting.toolbarHeightToUse = 0; } int depthBufferDepth = options.OpenglDepthBufferSetting; int colorBufferDepth = 32; int bVerticalSync = windowSetting.bVerticalSync; if( options.colorQuality == TEXTURE_FMT_A4R4G4B4 ) colorBufferDepth = 16; // init sdl & gl DebugMessage(M64MSG_VERBOSE, "Initializing video subsystem..."); if (CoreVideo_Init() != M64ERR_SUCCESS) return false; /* hard-coded attribute values */ const int iDOUBLEBUFFER = 1; /* set opengl attributes */ CoreVideo_GL_SetAttribute(M64P_GL_DOUBLEBUFFER, iDOUBLEBUFFER); CoreVideo_GL_SetAttribute(M64P_GL_SWAP_CONTROL, bVerticalSync); CoreVideo_GL_SetAttribute(M64P_GL_BUFFER_SIZE, colorBufferDepth); CoreVideo_GL_SetAttribute(M64P_GL_DEPTH_SIZE, depthBufferDepth); /* set multisampling */ if (options.multiSampling > 0) { CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLEBUFFERS, 1); if (options.multiSampling <= 2) CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 2); else if (options.multiSampling <= 4) CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 4); else if (options.multiSampling <= 8) CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 8); else CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 16); } /* Set the video mode */ m64p_video_mode ScreenMode = bWindowed ? M64VIDEO_WINDOWED : M64VIDEO_FULLSCREEN; m64p_video_flags flags = M64VIDEOFLAG_SUPPORT_RESIZING; if (CoreVideo_SetVideoMode(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, colorBufferDepth, ScreenMode, flags) != M64ERR_SUCCESS) { DebugMessage(M64MSG_ERROR, "Failed to set %i-bit video mode: %ix%i", colorBufferDepth, (int)windowSetting.uDisplayWidth, (int)windowSetting.uDisplayHeight); CoreVideo_Quit(); return false; } /* check that our opengl attributes were properly set */ int iActual; if (CoreVideo_GL_GetAttribute(M64P_GL_DOUBLEBUFFER, &iActual) == M64ERR_SUCCESS) if (iActual != iDOUBLEBUFFER) DebugMessage(M64MSG_WARNING, "Failed to set GL_DOUBLEBUFFER to %i. (it's %i)", iDOUBLEBUFFER, iActual); if (CoreVideo_GL_GetAttribute(M64P_GL_SWAP_CONTROL, &iActual) == M64ERR_SUCCESS) if (iActual != bVerticalSync) DebugMessage(M64MSG_WARNING, "Failed to set GL_SWAP_CONTROL to %i. (it's %i)", bVerticalSync, iActual); if (CoreVideo_GL_GetAttribute(M64P_GL_BUFFER_SIZE, &iActual) == M64ERR_SUCCESS) if (iActual != colorBufferDepth) DebugMessage(M64MSG_WARNING, "Failed to set GL_BUFFER_SIZE to %i. (it's %i)", colorBufferDepth, iActual); if (CoreVideo_GL_GetAttribute(M64P_GL_DEPTH_SIZE, &iActual) == M64ERR_SUCCESS) if (iActual != depthBufferDepth) DebugMessage(M64MSG_WARNING, "Failed to set GL_DEPTH_SIZE to %i. (it's %i)", depthBufferDepth, iActual); #if SDL_VIDEO_OPENGL /* Get function pointers to OpenGL extensions (blame Microsoft Windows for this) */ OGLExtensions_Init(); #endif char caption[500]; sprintf(caption, "%s v%i.%i.%i", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION)); CoreVideo_SetCaption(caption); SetWindowMode(); InitState(); InitOGLExtension(); sprintf(m_strDeviceStats, "%.60s - %.128s : %.60s", m_pVendorStr, m_pRenderStr, m_pVersionStr); TRACE0(m_strDeviceStats); DebugMessage(M64MSG_INFO, "Using OpenGL: %s", m_strDeviceStats); Unlock(); Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); // Clear buffers UpdateFrame(); Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); UpdateFrame(); m_bReady = true; status.isVertexShaderEnabled = false; return true; } bool COGLGraphicsContext::ResizeInitialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed ) { Lock(); CGraphicsContext::Initialize(dwWidth, dwHeight, bWindowed ); int depthBufferDepth = options.OpenglDepthBufferSetting; int colorBufferDepth = 32; int bVerticalSync = windowSetting.bVerticalSync; if( options.colorQuality == TEXTURE_FMT_A4R4G4B4 ) colorBufferDepth = 16; /* hard-coded attribute values */ const int iDOUBLEBUFFER = 1; /* set opengl attributes */ CoreVideo_GL_SetAttribute(M64P_GL_DOUBLEBUFFER, iDOUBLEBUFFER); CoreVideo_GL_SetAttribute(M64P_GL_SWAP_CONTROL, bVerticalSync); CoreVideo_GL_SetAttribute(M64P_GL_BUFFER_SIZE, colorBufferDepth); CoreVideo_GL_SetAttribute(M64P_GL_DEPTH_SIZE, depthBufferDepth); /* set multisampling */ if (options.multiSampling > 0) { CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLEBUFFERS, 1); if (options.multiSampling <= 2) CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 2); else if (options.multiSampling <= 4) CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 4); else if (options.multiSampling <= 8) CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 8); else CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 16); } /* Call Mupen64plus core Video Extension to resize the window, which will create a new OpenGL Context under SDL */ if (CoreVideo_ResizeWindow(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight) != M64ERR_SUCCESS) { DebugMessage(M64MSG_ERROR, "Failed to set %i-bit video mode: %ix%i", colorBufferDepth, (int)windowSetting.uDisplayWidth, (int)windowSetting.uDisplayHeight); CoreVideo_Quit(); return false; } InitState(); Unlock(); Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); // Clear buffers UpdateFrame(); Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); UpdateFrame(); return true; } void COGLGraphicsContext::InitState(void) { m_pRenderStr = glGetString(GL_RENDERER); m_pExtensionStr = glGetString(GL_EXTENSIONS); m_pVersionStr = glGetString(GL_VERSION); m_pVendorStr = glGetString(GL_VENDOR); glMatrixMode(GL_PROJECTION); OPENGL_CHECK_ERRORS; glLoadIdentity(); OPENGL_CHECK_ERRORS; glClearColor(0.0f, 0.0f, 0.0f, 0.0f); OPENGL_CHECK_ERRORS; glClearDepth(1.0f); OPENGL_CHECK_ERRORS; #if SDL_VIDEO_OPENGL glShadeModel(GL_SMOOTH); OPENGL_CHECK_ERRORS; //position viewer //glMatrixMode(GL_MODELVIEW); //glLoadIdentity(); glDisable(GL_ALPHA_TEST); OPENGL_CHECK_ERRORS; #endif glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); OPENGL_CHECK_ERRORS; glDisable(GL_BLEND); OPENGL_CHECK_ERRORS; glFrontFace(GL_CCW); OPENGL_CHECK_ERRORS; glDisable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; #if SDL_VIDEO_OPENGL glDisable(GL_NORMALIZE); OPENGL_CHECK_ERRORS; #endif glDepthFunc(GL_LEQUAL); OPENGL_CHECK_ERRORS; glEnable(GL_DEPTH_TEST); OPENGL_CHECK_ERRORS; #if SDL_VIDEO_OPENGL glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); OPENGL_CHECK_ERRORS; #endif glEnable(GL_BLEND); OPENGL_CHECK_ERRORS; #if SDL_VIDEO_OPENGL glEnable(GL_ALPHA_TEST); OPENGL_CHECK_ERRORS; glMatrixMode(GL_PROJECTION); OPENGL_CHECK_ERRORS; glLoadIdentity(); OPENGL_CHECK_ERRORS; glDepthRange(-1, 1); #elif SDL_VIDEO_OPENGL_ES2 glDepthRangef(0.0f, 1.0f); #endif OPENGL_CHECK_ERRORS; } void COGLGraphicsContext::InitOGLExtension(void) { // important extension features, it is very bad not to have these feature m_bSupportMultiTexture = IsExtensionSupported(OSAL_GL_ARB_MULTITEXTURE); m_bSupportTextureEnvCombine = IsExtensionSupported("GL_EXT_texture_env_combine"); m_bSupportSeparateSpecularColor = IsExtensionSupported("GL_EXT_separate_specular_color"); m_bSupportSecondColor = IsExtensionSupported("GL_EXT_secondary_color"); m_bSupportFogCoord = IsExtensionSupported("GL_EXT_fog_coord"); m_bSupportTextureObject = IsExtensionSupported("GL_EXT_texture_object"); // Optional extension features m_bSupportRescaleNormal = IsExtensionSupported("GL_EXT_rescale_normal"); m_bSupportLODBias = IsExtensionSupported("GL_EXT_texture_lod_bias"); m_bSupportAnisotropicFiltering = IsExtensionSupported("GL_EXT_texture_filter_anisotropic"); // Compute maxAnisotropicFiltering m_maxAnisotropicFiltering = 0; if( m_bSupportAnisotropicFiltering && (options.anisotropicFiltering == 2 || options.anisotropicFiltering == 4 || options.anisotropicFiltering == 8 || options.anisotropicFiltering == 16)) { //Get the max value of aniso that the graphic card support glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &m_maxAnisotropicFiltering); OPENGL_CHECK_ERRORS; // If user want more aniso than hardware can do if(options.anisotropicFiltering > (uint32) m_maxAnisotropicFiltering) { DebugMessage(M64MSG_INFO, "A value of '%i' is set for AnisotropicFiltering option but the hardware has a maximum value of '%i' so this will be used", options.anisotropicFiltering, m_maxAnisotropicFiltering); } //check if user want less anisotropy than hardware can do if((uint32) m_maxAnisotropicFiltering > options.anisotropicFiltering) m_maxAnisotropicFiltering = options.anisotropicFiltering; } // Nvidia only extension features (optional) m_bSupportNVRegisterCombiner = IsExtensionSupported("GL_NV_register_combiners"); m_bSupportTextureMirrorRepeat = IsExtensionSupported("GL_IBM_texture_mirrored_repeat") || IsExtensionSupported("ARB_texture_mirrored_repeat"); m_supportTextureMirror = m_bSupportTextureMirrorRepeat; m_bSupportTextureLOD = IsExtensionSupported("GL_EXT_texture_lod"); m_bSupportBlendColor = IsExtensionSupported("GL_EXT_blend_color"); m_bSupportBlendSubtract = IsExtensionSupported("GL_EXT_blend_subtract"); m_bSupportNVTextureEnvCombine4 = IsExtensionSupported("GL_NV_texture_env_combine4"); } bool COGLGraphicsContext::IsExtensionSupported(const char* pExtName) { if (strstr((const char*)m_pExtensionStr, pExtName) != NULL) { DebugMessage(M64MSG_VERBOSE, "OpenGL Extension '%s' is supported.", pExtName); return true; } else { DebugMessage(M64MSG_VERBOSE, "OpenGL Extension '%s' is NOT supported.", pExtName); return false; } } bool COGLGraphicsContext::IsWglExtensionSupported(const char* pExtName) { if( m_pWglExtensionStr == NULL ) return false; if( strstr((const char*)m_pWglExtensionStr, pExtName) != NULL ) return true; else return false; } void COGLGraphicsContext::CleanUp() { CoreVideo_Quit(); m_bReady = false; } void COGLGraphicsContext::Clear(ClearFlag dwFlags, uint32 color, float depth) { uint32 flag=0; if( dwFlags&CLEAR_COLOR_BUFFER ) flag |= GL_COLOR_BUFFER_BIT; if( dwFlags&CLEAR_DEPTH_BUFFER ) flag |= GL_DEPTH_BUFFER_BIT; float r = ((color>>16)&0xFF)/255.0f; float g = ((color>> 8)&0xFF)/255.0f; float b = ((color )&0xFF)/255.0f; float a = ((color>>24)&0xFF)/255.0f; glClearColor(r, g, b, a); OPENGL_CHECK_ERRORS; glClearDepth(depth); OPENGL_CHECK_ERRORS; glClear(flag); //Clear color buffer and depth buffer OPENGL_CHECK_ERRORS; } void COGLGraphicsContext::UpdateFrame(bool swaponly) { status.gFrameCount++; glFlush(); OPENGL_CHECK_ERRORS; //glFinish(); //wglSwapIntervalEXT(0); /* if (debuggerPauseCount == countToPause) { static int iShotNum = 0; // get width, height, allocate buffer to store image int width = windowSetting.uDisplayWidth; int height = windowSetting.uDisplayHeight; printf("Saving debug images: width=%i height=%i\n", width, height); short *buffer = (short *) malloc(((width+3)&~3)*(height+1)*4); glReadBuffer( GL_FRONT ); // set up a BMGImage struct struct BMGImageStruct img; memset(&img, 0, sizeof(BMGImageStruct)); InitBMGImage(&img); img.bits = (unsigned char *) buffer; img.bits_per_pixel = 32; img.height = height; img.width = width; img.scan_width = width * 4; // store the RGB color image char chFilename[64]; sprintf(chFilename, "dbg_rgb_%03i.png", iShotNum); glReadPixels(0,0,width,height, GL_BGRA, GL_UNSIGNED_BYTE, buffer); WritePNG(chFilename, img); // store the Z buffer sprintf(chFilename, "dbg_Z_%03i.png", iShotNum); glReadPixels(0,0,width,height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buffer); //img.bits_per_pixel = 16; //img.scan_width = width * 2; WritePNG(chFilename, img); // dump a subset of the Z data for (int y = 0; y < 480; y += 16) { for (int x = 0; x < 640; x+= 16) printf("%4hx ", buffer[y*640 + x]); printf("\n"); } printf("\n"); // free memory and get out of here free(buffer); iShotNum++; } */ // if emulator defined a render callback function, call it before buffer swap if(renderCallback) (*renderCallback)(status.bScreenIsDrawn); CoreVideo_GL_SwapBuffers(); /*if(options.bShowFPS) { static unsigned int lastTick=0; static int frames=0; unsigned int nowTick = SDL_GetTicks(); frames++; if(lastTick + 5000 <= nowTick) { char caption[200]; sprintf(caption, "%s v%i.%i.%i - %.3f VI/S", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION), frames/5.0); CoreVideo_SetCaption(caption); frames = 0; lastTick = nowTick; } }*/ glDepthMask(GL_TRUE); OPENGL_CHECK_ERRORS; glClearDepth(1.0f); OPENGL_CHECK_ERRORS; if( !g_curRomInfo.bForceScreenClear ) { glClear(GL_DEPTH_BUFFER_BIT); OPENGL_CHECK_ERRORS; } else needCleanScene = true; status.bScreenIsDrawn = false; } bool COGLGraphicsContext::SetFullscreenMode() { windowSetting.statusBarHeightToUse = 0; windowSetting.toolbarHeightToUse = 0; return true; } bool COGLGraphicsContext::SetWindowMode() { windowSetting.statusBarHeightToUse = windowSetting.statusBarHeight; windowSetting.toolbarHeightToUse = windowSetting.toolbarHeight; return true; } int COGLGraphicsContext::ToggleFullscreen() { if (CoreVideo_ToggleFullScreen() == M64ERR_SUCCESS) { m_bWindowed = !m_bWindowed; if(m_bWindowed) SetWindowMode(); else SetFullscreenMode(); } return m_bWindowed?0:1; } // This is a static function, will be called when the plugin DLL is initialized void COGLGraphicsContext::InitDeviceParameters() { status.isVertexShaderEnabled = false; // Disable it for now } // Get methods bool COGLGraphicsContext::IsSupportAnisotropicFiltering() { return m_bSupportAnisotropicFiltering; } int COGLGraphicsContext::getMaxAnisotropicFiltering() { return m_maxAnisotropicFiltering; } mupen64plus-video-rice-src-2.0/src/OGLGraphicsContext.h0000644000000000000000000000556212165031100021120 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _OGL_CONTEXT_H_ #define _OGL_CONTEXT_H_ #include "typedefs.h" #include "GraphicsContext.h" class COGLGraphicsContext : public CGraphicsContext { friend class OGLRender; friend class COGLRenderTexture; public: virtual ~COGLGraphicsContext(); bool Initialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed ); bool ResizeInitialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed ); void CleanUp(); void Clear(ClearFlag dwFlags, uint32 color=0xFF000000, float depth=1.0f); void UpdateFrame(bool swaponly=false); int ToggleFullscreen(); // return 0 as the result is windowed bool IsExtensionSupported(const char* pExtName); bool IsWglExtensionSupported(const char* pExtName); static void InitDeviceParameters(); //Get methods (TODO, remove all friend class and use get methods instead) bool IsSupportAnisotropicFiltering(); int getMaxAnisotropicFiltering(); protected: friend class OGLDeviceBuilder; COGLGraphicsContext(); void InitState(void); void InitOGLExtension(void); bool SetFullscreenMode(); bool SetWindowMode(); // Important OGL extension features bool m_bSupportMultiTexture; bool m_bSupportTextureEnvCombine; bool m_bSupportSeparateSpecularColor; bool m_bSupportSecondColor; bool m_bSupportFogCoord; bool m_bSupportTextureObject; // Optional OGL extension features; bool m_bSupportRescaleNormal; bool m_bSupportLODBias; bool m_bSupportAnisotropicFiltering; int m_maxAnisotropicFiltering; // Nvidia OGL only features bool m_bSupportTextureMirrorRepeat; bool m_bSupportTextureLOD; bool m_bSupportNVRegisterCombiner; bool m_bSupportBlendColor; bool m_bSupportBlendSubtract; bool m_bSupportNVTextureEnvCombine4; // Minimal requirements, I will even not check them at runtime //bool m_bSupportTextureEnvAdd; //bool m_bSupportVertexArray; const unsigned char* m_pVendorStr; const unsigned char* m_pRenderStr; const unsigned char* m_pExtensionStr; const char* m_pWglExtensionStr; const unsigned char* m_pVersionStr; }; #endif mupen64plus-video-rice-src-2.0/src/OGLRender.cpp0000644000000000000000000011460712165031100017566 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "osal_opengl.h" #if SDL_VIDEO_OPENGL #include "OGLExtensions.h" #elif SDL_VIDEO_OPENGL_ES2 #include "OGLES2FragmentShaders.h" #endif #include "OGLDebug.h" #include "OGLRender.h" #include "OGLGraphicsContext.h" #include "OGLTexture.h" #include "TextureManager.h" // FIXME: Use OGL internal L/T and matrix stack // FIXME: Use OGL lookupAt function // FIXME: Use OGL DisplayList UVFlagMap OGLXUVFlagMaps[] = { {TEXTURE_UV_FLAG_WRAP, GL_REPEAT}, {TEXTURE_UV_FLAG_MIRROR, GL_MIRRORED_REPEAT_ARB}, {TEXTURE_UV_FLAG_CLAMP, GL_CLAMP}, }; #if SDL_VIDEO_OPENGL_ES2 static GLuint disabledTextureID; #endif //=================================================================== OGLRender::OGLRender() { COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); m_bSupportFogCoordExt = pcontext->m_bSupportFogCoord; m_bMultiTexture = pcontext->m_bSupportMultiTexture; m_bSupportClampToEdge = false; for( int i=0; i<8; i++ ) { m_curBoundTex[i]=0; m_texUnitEnabled[i]=FALSE; } #if SDL_VIDEO_OPENGL m_bEnableMultiTexture = false; #elif SDL_VIDEO_OPENGL_ES2 m_bEnableMultiTexture = true; //Create a texture as replacement for glEnable/Disable(GL_TEXTURE_2D) TLITVERTEX white; white.r = white.g = white.b = 0; white.a = 0; glGenTextures(1,&disabledTextureID); OPENGL_CHECK_ERRORS; glBindTexture(GL_TEXTURE_2D, disabledTextureID); OPENGL_CHECK_ERRORS; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); OPENGL_CHECK_ERRORS; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &white.dcDiffuse); OPENGL_CHECK_ERRORS; #endif } OGLRender::~OGLRender() { ClearDeviceObjects(); } bool OGLRender::InitDeviceObjects() { // enable Z-buffer by default ZBufferEnable(true); return true; } bool OGLRender::ClearDeviceObjects() { return true; } void OGLRender::Initialize(void) { glMatrixMode(GL_MODELVIEW); OPENGL_CHECK_ERRORS; glLoadIdentity(); OPENGL_CHECK_ERRORS; glViewportWrapper(0, windowSetting.statusBarHeightToUse, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); OPENGL_CHECK_ERRORS; #if SDL_VIDEO_OPENGL COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); if( pcontext->IsExtensionSupported("GL_IBM_texture_mirrored_repeat") ) { OGLXUVFlagMaps[TEXTURE_UV_FLAG_MIRROR].realFlag = GL_MIRRORED_REPEAT_IBM; } else if( pcontext->IsExtensionSupported("ARB_texture_mirrored_repeat") ) { OGLXUVFlagMaps[TEXTURE_UV_FLAG_MIRROR].realFlag = GL_MIRRORED_REPEAT_ARB; } else { OGLXUVFlagMaps[TEXTURE_UV_FLAG_MIRROR].realFlag = GL_REPEAT; } if( pcontext->IsExtensionSupported("GL_ARB_texture_border_clamp") || pcontext->IsExtensionSupported("GL_EXT_texture_edge_clamp") ) { m_bSupportClampToEdge = true; OGLXUVFlagMaps[TEXTURE_UV_FLAG_CLAMP].realFlag = GL_CLAMP_TO_EDGE; } else { m_bSupportClampToEdge = false; OGLXUVFlagMaps[TEXTURE_UV_FLAG_CLAMP].realFlag = GL_CLAMP; } glVertexPointer( 4, GL_FLOAT, sizeof(float)*5, &(g_vtxProjected5[0][0]) ); OPENGL_CHECK_ERRORS; glEnableClientState( GL_VERTEX_ARRAY ); OPENGL_CHECK_ERRORS; if( m_bMultiTexture ) { pglClientActiveTextureARB( GL_TEXTURE0_ARB ); OPENGL_CHECK_ERRORS; glTexCoordPointer( 2, GL_FLOAT, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u) ); OPENGL_CHECK_ERRORS; glEnableClientState( GL_TEXTURE_COORD_ARRAY ); OPENGL_CHECK_ERRORS; pglClientActiveTextureARB( GL_TEXTURE1_ARB ); OPENGL_CHECK_ERRORS; glTexCoordPointer( 2, GL_FLOAT, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[1].u) ); OPENGL_CHECK_ERRORS; glEnableClientState( GL_TEXTURE_COORD_ARRAY ); OPENGL_CHECK_ERRORS; } else { glTexCoordPointer( 2, GL_FLOAT, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u) ); OPENGL_CHECK_ERRORS; glEnableClientState( GL_TEXTURE_COORD_ARRAY ); OPENGL_CHECK_ERRORS; } if (m_bSupportFogCoordExt) { pglFogCoordPointerEXT( GL_FLOAT, sizeof(float)*5, &(g_vtxProjected5[0][4]) ); OPENGL_CHECK_ERRORS; glEnableClientState( GL_FOG_COORDINATE_ARRAY_EXT ); OPENGL_CHECK_ERRORS; glFogi( GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT ); OPENGL_CHECK_ERRORS; glFogi(GL_FOG_MODE, GL_LINEAR); // Fog Mode OPENGL_CHECK_ERRORS; glFogf(GL_FOG_DENSITY, 1.0f); // How Dense Will The Fog Be OPENGL_CHECK_ERRORS; glHint(GL_FOG_HINT, GL_FASTEST); // Fog Hint Value OPENGL_CHECK_ERRORS; glFogi( GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT ); OPENGL_CHECK_ERRORS; glFogf( GL_FOG_START, 0.0f ); OPENGL_CHECK_ERRORS; glFogf( GL_FOG_END, 1.0f ); OPENGL_CHECK_ERRORS; } //glColorPointer( 1, GL_UNSIGNED_BYTE, sizeof(TLITVERTEX), &g_vtxBuffer[0].r); glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); OPENGL_CHECK_ERRORS; glEnableClientState( GL_COLOR_ARRAY ); OPENGL_CHECK_ERRORS; if( pcontext->IsExtensionSupported("GL_NV_depth_clamp") ) { glEnable(GL_DEPTH_CLAMP_NV); OPENGL_CHECK_ERRORS; } #elif SDL_VIDEO_OPENGL_ES2 OGLXUVFlagMaps[TEXTURE_UV_FLAG_MIRROR].realFlag = GL_MIRRORED_REPEAT; m_bSupportClampToEdge = true; OGLXUVFlagMaps[TEXTURE_UV_FLAG_CLAMP].realFlag = GL_CLAMP_TO_EDGE; #endif } //=================================================================== TextureFilterMap OglTexFilterMap[2]= { {FILTER_POINT, GL_NEAREST}, {FILTER_LINEAR, GL_LINEAR}, }; void OGLRender::ApplyTextureFilter() { static uint32 minflag=0xFFFF, magflag=0xFFFF; static uint32 mtex; if( m_texUnitEnabled[0] ) { if( mtex != m_curBoundTex[0] ) { mtex = m_curBoundTex[0]; minflag = m_dwMinFilter; magflag = m_dwMagFilter; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, OglTexFilterMap[m_dwMinFilter].realFilter); OPENGL_CHECK_ERRORS; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, OglTexFilterMap[m_dwMagFilter].realFilter); OPENGL_CHECK_ERRORS; } else { if( minflag != (unsigned int)m_dwMinFilter ) { minflag = m_dwMinFilter; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, OglTexFilterMap[m_dwMinFilter].realFilter); OPENGL_CHECK_ERRORS; } if( magflag != (unsigned int)m_dwMagFilter ) { magflag = m_dwMagFilter; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, OglTexFilterMap[m_dwMagFilter].realFilter); OPENGL_CHECK_ERRORS; } } } } void OGLRender::SetShadeMode(RenderShadeMode mode) { #if SDL_VIDEO_OPENGL if( mode == SHADE_SMOOTH ) glShadeModel(GL_SMOOTH); else glShadeModel(GL_FLAT); OPENGL_CHECK_ERRORS; #endif } void OGLRender::ZBufferEnable(BOOL bZBuffer) { gRSP.bZBufferEnabled = bZBuffer; if( g_curRomInfo.bForceDepthBuffer ) bZBuffer = TRUE; if( bZBuffer ) { glDepthMask(GL_TRUE); OPENGL_CHECK_ERRORS; //glEnable(GL_DEPTH_TEST); glDepthFunc( GL_LEQUAL ); OPENGL_CHECK_ERRORS; } else { glDepthMask(GL_FALSE); OPENGL_CHECK_ERRORS; //glDisable(GL_DEPTH_TEST); glDepthFunc( GL_ALWAYS ); OPENGL_CHECK_ERRORS; } } void OGLRender::ClearBuffer(bool cbuffer, bool zbuffer) { uint32 flag=0; if( cbuffer ) flag |= GL_COLOR_BUFFER_BIT; if( zbuffer ) flag |= GL_DEPTH_BUFFER_BIT; float depth = ((gRDP.originalFillColor&0xFFFF)>>2)/(float)0x3FFF; glClearDepth(depth); OPENGL_CHECK_ERRORS; glClear(flag); OPENGL_CHECK_ERRORS; } void OGLRender::ClearZBuffer(float depth) { uint32 flag=GL_DEPTH_BUFFER_BIT; glClearDepth(depth); OPENGL_CHECK_ERRORS; glClear(flag); OPENGL_CHECK_ERRORS; } void OGLRender::SetZCompare(BOOL bZCompare) { if( g_curRomInfo.bForceDepthBuffer ) bZCompare = TRUE; gRSP.bZBufferEnabled = bZCompare; if( bZCompare == TRUE ) { //glEnable(GL_DEPTH_TEST); glDepthFunc( GL_LEQUAL ); OPENGL_CHECK_ERRORS; } else { //glDisable(GL_DEPTH_TEST); glDepthFunc( GL_ALWAYS ); OPENGL_CHECK_ERRORS; } } void OGLRender::SetZUpdate(BOOL bZUpdate) { if( g_curRomInfo.bForceDepthBuffer ) bZUpdate = TRUE; if( bZUpdate ) { //glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); OPENGL_CHECK_ERRORS; } else { glDepthMask(GL_FALSE); OPENGL_CHECK_ERRORS; } } void OGLRender::ApplyZBias(int bias) { float f1 = bias > 0 ? -3.0f : 0.0f; // z offset = -3.0 * max(abs(dz/dx),abs(dz/dy)) per pixel delta z slope float f2 = bias > 0 ? -3.0f : 0.0f; // z offset += -3.0 * 1 bit if (bias > 0) { glEnable(GL_POLYGON_OFFSET_FILL); // enable z offsets OPENGL_CHECK_ERRORS; } else { glDisable(GL_POLYGON_OFFSET_FILL); // disable z offsets OPENGL_CHECK_ERRORS; } glPolygonOffset(f1, f2); // set bias functions OPENGL_CHECK_ERRORS; } void OGLRender::SetZBias(int bias) { #if defined(DEBUGGER) if( pauseAtNext == true ) DebuggerAppendMsg("Set zbias = %d", bias); #endif // set member variable and apply the setting in opengl m_dwZBias = bias; ApplyZBias(bias); } void OGLRender::SetAlphaRef(uint32 dwAlpha) { if (m_dwAlpha != dwAlpha) { m_dwAlpha = dwAlpha; #if SDL_VIDEO_OPENGL glAlphaFunc(GL_GEQUAL, (float)dwAlpha); OPENGL_CHECK_ERRORS; #endif } } void OGLRender::ForceAlphaRef(uint32 dwAlpha) { #if SDL_VIDEO_OPENGL float ref = dwAlpha/255.0f; glAlphaFunc(GL_GEQUAL, ref); OPENGL_CHECK_ERRORS; #elif SDL_VIDEO_OPENGL_ES2 m_dwAlpha = dwAlpha; #endif } void OGLRender::SetFillMode(FillMode mode) { #if SDL_VIDEO_OPENGL if( mode == RICE_FILLMODE_WINFRAME ) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); OPENGL_CHECK_ERRORS; } else { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); OPENGL_CHECK_ERRORS; } #endif } void OGLRender::SetCullMode(bool bCullFront, bool bCullBack) { CRender::SetCullMode(bCullFront, bCullBack); if( bCullFront && bCullBack ) { glCullFace(GL_FRONT_AND_BACK); OPENGL_CHECK_ERRORS; glEnable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; } else if( bCullFront ) { glCullFace(GL_FRONT); OPENGL_CHECK_ERRORS; glEnable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; } else if( bCullBack ) { glCullFace(GL_BACK); OPENGL_CHECK_ERRORS; glEnable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; } else { glDisable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; } } bool OGLRender::SetCurrentTexture(int tile, CTexture *handler,uint32 dwTileWidth, uint32 dwTileHeight, TxtrCacheEntry *pTextureEntry) { RenderTexture &texture = g_textures[tile]; texture.pTextureEntry = pTextureEntry; if( handler!= NULL && texture.m_lpsTexturePtr != handler->GetTexture() ) { texture.m_pCTexture = handler; texture.m_lpsTexturePtr = handler->GetTexture(); texture.m_dwTileWidth = dwTileWidth; texture.m_dwTileHeight = dwTileHeight; if( handler->m_bIsEnhancedTexture ) { texture.m_fTexWidth = (float)pTextureEntry->pTexture->m_dwCreatedTextureWidth; texture.m_fTexHeight = (float)pTextureEntry->pTexture->m_dwCreatedTextureHeight; } else { texture.m_fTexWidth = (float)handler->m_dwCreatedTextureWidth; texture.m_fTexHeight = (float)handler->m_dwCreatedTextureHeight; } } return true; } bool OGLRender::SetCurrentTexture(int tile, TxtrCacheEntry *pEntry) { if (pEntry != NULL && pEntry->pTexture != NULL) { SetCurrentTexture( tile, pEntry->pTexture, pEntry->ti.WidthToCreate, pEntry->ti.HeightToCreate, pEntry); return true; } else { SetCurrentTexture( tile, NULL, 64, 64, NULL ); return false; } return true; } void OGLRender::SetAddressUAllStages(uint32 dwTile, TextureUVFlag dwFlag) { SetTextureUFlag(dwFlag, dwTile); } void OGLRender::SetAddressVAllStages(uint32 dwTile, TextureUVFlag dwFlag) { SetTextureVFlag(dwFlag, dwTile); } void OGLRender::SetTexWrapS(int unitno,GLuint flag) { static GLuint mflag; static GLuint mtex; #ifdef DEBUGGER if( unitno != 0 ) { DebuggerAppendMsg("Check me, unitno != 0 in base ogl"); } #endif if( m_curBoundTex[0] != mtex || mflag != flag ) { mtex = m_curBoundTex[0]; mflag = flag; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, flag); OPENGL_CHECK_ERRORS; } } void OGLRender::SetTexWrapT(int unitno,GLuint flag) { static GLuint mflag; static GLuint mtex; if( m_curBoundTex[0] != mtex || mflag != flag ) { mtex = m_curBoundTex[0]; mflag = flag; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, flag); OPENGL_CHECK_ERRORS; } } void OGLRender::SetTextureUFlag(TextureUVFlag dwFlag, uint32 dwTile) { TileUFlags[dwTile] = dwFlag; if( dwTile == gRSP.curTile ) // For basic OGL, only support the 1st texel { COGLTexture* pTexture = g_textures[gRSP.curTile].m_pCOGLTexture; if( pTexture ) { EnableTexUnit(0,TRUE); BindTexture(pTexture->m_dwTextureName, 0); } SetTexWrapS(0, OGLXUVFlagMaps[dwFlag].realFlag); } } void OGLRender::SetTextureVFlag(TextureUVFlag dwFlag, uint32 dwTile) { TileVFlags[dwTile] = dwFlag; if( dwTile == gRSP.curTile ) // For basic OGL, only support the 1st texel { COGLTexture* pTexture = g_textures[gRSP.curTile].m_pCOGLTexture; if( pTexture ) { EnableTexUnit(0,TRUE); BindTexture(pTexture->m_dwTextureName, 0); } SetTexWrapT(0, OGLXUVFlagMaps[dwFlag].realFlag); } } // Basic render drawing functions bool OGLRender::RenderTexRect() { glViewportWrapper(0, windowSetting.statusBarHeightToUse, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); OPENGL_CHECK_ERRORS; GLboolean cullface = glIsEnabled(GL_CULL_FACE); glDisable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; float depth = -(g_texRectTVtx[3].z*2-1); #if SDL_VIDEO_OPENGL glBegin(GL_TRIANGLE_FAN); glColor4f(g_texRectTVtx[3].r, g_texRectTVtx[3].g, g_texRectTVtx[3].b, g_texRectTVtx[3].a); TexCoord(g_texRectTVtx[3]); glVertex3f(g_texRectTVtx[3].x, g_texRectTVtx[3].y, depth); glColor4f(g_texRectTVtx[2].r, g_texRectTVtx[2].g, g_texRectTVtx[2].b, g_texRectTVtx[2].a); TexCoord(g_texRectTVtx[2]); glVertex3f(g_texRectTVtx[2].x, g_texRectTVtx[2].y, depth); glColor4f(g_texRectTVtx[1].r, g_texRectTVtx[1].g, g_texRectTVtx[1].b, g_texRectTVtx[1].a); TexCoord(g_texRectTVtx[1]); glVertex3f(g_texRectTVtx[1].x, g_texRectTVtx[1].y, depth); glColor4f(g_texRectTVtx[0].r, g_texRectTVtx[0].g, g_texRectTVtx[0].b, g_texRectTVtx[0].a); TexCoord(g_texRectTVtx[0]); glVertex3f(g_texRectTVtx[0].x, g_texRectTVtx[0].y, depth); glEnd(); OPENGL_CHECK_ERRORS; #elif SDL_VIDEO_OPENGL_ES2 GLfloat colour[] = { g_texRectTVtx[3].r, g_texRectTVtx[3].g, g_texRectTVtx[3].b, g_texRectTVtx[3].a, g_texRectTVtx[2].r, g_texRectTVtx[2].g, g_texRectTVtx[2].b, g_texRectTVtx[2].a, g_texRectTVtx[1].r, g_texRectTVtx[1].g, g_texRectTVtx[1].b, g_texRectTVtx[1].a, g_texRectTVtx[0].r, g_texRectTVtx[0].g, g_texRectTVtx[0].b, g_texRectTVtx[0].a }; GLfloat tex[] = { g_texRectTVtx[3].tcord[0].u,g_texRectTVtx[3].tcord[0].v, g_texRectTVtx[2].tcord[0].u,g_texRectTVtx[2].tcord[0].v, g_texRectTVtx[1].tcord[0].u,g_texRectTVtx[1].tcord[0].v, g_texRectTVtx[0].tcord[0].u,g_texRectTVtx[0].tcord[0].v }; float w = windowSetting.uDisplayWidth / 2.0f, h = windowSetting.uDisplayHeight / 2.0f, inv = 1.0f; GLfloat vertices[] = { -inv + g_texRectTVtx[3].x / w, inv - g_texRectTVtx[3].y / h, depth, 1, -inv + g_texRectTVtx[2].x / w, inv - g_texRectTVtx[2].y / h, depth, 1, -inv + g_texRectTVtx[1].x / w, inv - g_texRectTVtx[1].y / h, depth, 1, -inv + g_texRectTVtx[0].x / w, inv - g_texRectTVtx[0].y / h, depth, 1 }; glVertexAttribPointer(VS_COLOR, 4, GL_FLOAT,GL_TRUE, 0, &colour ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,0,&vertices); glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, 0, &tex); OPENGL_CHECK_ERRORS; glDrawArrays(GL_TRIANGLE_FAN,0,4); OPENGL_CHECK_ERRORS; //Restore old pointers glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u)); #endif if( cullface ) glEnable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; return true; } bool OGLRender::RenderFillRect(uint32 dwColor, float depth) { float a = (dwColor>>24)/255.0f; float r = ((dwColor>>16)&0xFF)/255.0f; float g = ((dwColor>>8)&0xFF)/255.0f; float b = (dwColor&0xFF)/255.0f; glViewportWrapper(0, windowSetting.statusBarHeightToUse, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); OPENGL_CHECK_ERRORS; GLboolean cullface = glIsEnabled(GL_CULL_FACE); glDisable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; #if SDL_VIDEO_OPENGL glBegin(GL_TRIANGLE_FAN); glColor4f(r,g,b,a); glVertex4f(m_fillRectVtx[0].x, m_fillRectVtx[1].y, depth, 1); glVertex4f(m_fillRectVtx[1].x, m_fillRectVtx[1].y, depth, 1); glVertex4f(m_fillRectVtx[1].x, m_fillRectVtx[0].y, depth, 1); glVertex4f(m_fillRectVtx[0].x, m_fillRectVtx[0].y, depth, 1); glEnd(); OPENGL_CHECK_ERRORS; #elif SDL_VIDEO_OPENGL_ES2 GLfloat colour[] = { r,g,b,a, r,g,b,a, r,g,b,a, r,g,b,a}; float w = windowSetting.uDisplayWidth / 2.0f, h = windowSetting.uDisplayHeight / 2.0f, inv = 1.0f; GLfloat vertices[] = { -inv + m_fillRectVtx[0].x / w, inv - m_fillRectVtx[1].y / h, depth, 1, -inv + m_fillRectVtx[1].x / w, inv - m_fillRectVtx[1].y / h, depth, 1, -inv + m_fillRectVtx[1].x / w, inv - m_fillRectVtx[0].y / h, depth, 1, -inv + m_fillRectVtx[0].x / w, inv - m_fillRectVtx[0].y / h, depth, 1 }; glVertexAttribPointer(VS_COLOR, 4, GL_FLOAT,GL_FALSE, 0, &colour ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,0,&vertices); glDisableVertexAttribArray(VS_TEXCOORD0); OPENGL_CHECK_ERRORS; glDrawArrays(GL_TRIANGLE_FAN,0,4); OPENGL_CHECK_ERRORS; //Restore old pointers glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); glEnableVertexAttribArray(VS_TEXCOORD0); #endif if( cullface ) glEnable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; return true; } bool OGLRender::RenderLine3D() { #if SDL_VIDEO_OPENGL ApplyZBias(0); // disable z offsets glBegin(GL_TRIANGLE_FAN); glColor4f(m_line3DVtx[1].r, m_line3DVtx[1].g, m_line3DVtx[1].b, m_line3DVtx[1].a); glVertex3f(m_line3DVector[3].x, m_line3DVector[3].y, -m_line3DVtx[1].z); glVertex3f(m_line3DVector[2].x, m_line3DVector[2].y, -m_line3DVtx[0].z); glColor4ub(m_line3DVtx[0].r, m_line3DVtx[0].g, m_line3DVtx[0].b, m_line3DVtx[0].a); glVertex3f(m_line3DVector[1].x, m_line3DVector[1].y, -m_line3DVtx[1].z); glVertex3f(m_line3DVector[0].x, m_line3DVector[0].y, -m_line3DVtx[0].z); glEnd(); OPENGL_CHECK_ERRORS; ApplyZBias(m_dwZBias); // set Z offset back to previous value #endif return true; } extern FiddledVtx * g_pVtxBase; // This is so weired that I can not do vertex transform by myself. I have to use // OpenGL internal transform bool OGLRender::RenderFlushTris() { if( !m_bSupportFogCoordExt ) SetFogFlagForNegativeW(); else { if( !gRDP.bFogEnableInBlender && gRSP.bFogEnabled ) { TurnFogOnOff(false); } } ApplyZBias(m_dwZBias); // set the bias factors glViewportWrapper(windowSetting.vpLeftW, windowSetting.uDisplayHeight-windowSetting.vpTopW-windowSetting.vpHeightW+windowSetting.statusBarHeightToUse, windowSetting.vpWidthW, windowSetting.vpHeightW, false); OPENGL_CHECK_ERRORS; //if options.bOGLVertexClipper == FALSE ) { glDrawElements( GL_TRIANGLES, gRSP.numVertices, GL_UNSIGNED_SHORT, g_vtxIndex ); OPENGL_CHECK_ERRORS; } /* else { //ClipVertexesOpenGL(); // Redo the index // Set the array glVertexPointer( 4, GL_FLOAT, sizeof(float)*5, &(g_vtxProjected5Clipped[0][0]) ); glEnableClientState( GL_VERTEX_ARRAY ); pglClientActiveTextureARB( GL_TEXTURE0_ARB ); glTexCoordPointer( 2, GL_FLOAT, sizeof( TLITVERTEX ), &(g_clippedVtxBuffer[0].tcord[0].u) ); glEnableClientState( GL_TEXTURE_COORD_ARRAY ); pglClientActiveTextureARB( GL_TEXTURE1_ARB ); glTexCoordPointer( 2, GL_FLOAT, sizeof( TLITVERTEX ), &(g_clippedVtxBuffer[0].tcord[1].u) ); glEnableClientState( GL_TEXTURE_COORD_ARRAY ); glDrawElements( GL_TRIANGLES, gRSP.numVertices, GL_UNSIGNED_INT, g_vtxIndex ); // Reset the array pglClientActiveTextureARB( GL_TEXTURE0_ARB ); glTexCoordPointer( 2, GL_FLOAT, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u) ); glEnableClientState( GL_TEXTURE_COORD_ARRAY ); pglClientActiveTextureARB( GL_TEXTURE1_ARB ); glTexCoordPointer( 2, GL_FLOAT, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[1].u) ); glEnableClientState( GL_TEXTURE_COORD_ARRAY ); glVertexPointer( 4, GL_FLOAT, sizeof(float)*5, &(g_vtxProjected5[0][0]) ); glEnableClientState( GL_VERTEX_ARRAY ); } */ if( !m_bSupportFogCoordExt ) RestoreFogFlag(); else { if( !gRDP.bFogEnableInBlender && gRSP.bFogEnabled ) { TurnFogOnOff(true); } } return true; } void OGLRender::DrawSimple2DTexture(float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, COLOR dif, COLOR spe, float z, float rhw) { if( status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_1ST_PRIMITIVE ) { status.bVIOriginIsUpdated=false; CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG,{DebuggerAppendMsg("Screen Update at 1st Simple2DTexture");}); } StartDrawSimple2DTexture(x0, y0, x1, y1, u0, v0, u1, v1, dif, spe, z, rhw); GLboolean cullface = glIsEnabled(GL_CULL_FACE); glDisable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; glViewportWrapper(0, windowSetting.statusBarHeightToUse, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); OPENGL_CHECK_ERRORS; float a = (g_texRectTVtx[0].dcDiffuse >>24)/255.0f; float r = ((g_texRectTVtx[0].dcDiffuse>>16)&0xFF)/255.0f; float g = ((g_texRectTVtx[0].dcDiffuse>>8)&0xFF)/255.0f; float b = (g_texRectTVtx[0].dcDiffuse&0xFF)/255.0f; #if SDL_VIDEO_OPENGL glBegin(GL_TRIANGLES); glColor4f(r,g,b,a); OGLRender::TexCoord(g_texRectTVtx[0]); glVertex3f(g_texRectTVtx[0].x, g_texRectTVtx[0].y, -g_texRectTVtx[0].z); OGLRender::TexCoord(g_texRectTVtx[1]); glVertex3f(g_texRectTVtx[1].x, g_texRectTVtx[1].y, -g_texRectTVtx[1].z); OGLRender::TexCoord(g_texRectTVtx[2]); glVertex3f(g_texRectTVtx[2].x, g_texRectTVtx[2].y, -g_texRectTVtx[2].z); OGLRender::TexCoord(g_texRectTVtx[0]); glVertex3f(g_texRectTVtx[0].x, g_texRectTVtx[0].y, -g_texRectTVtx[0].z); OGLRender::TexCoord(g_texRectTVtx[2]); glVertex3f(g_texRectTVtx[2].x, g_texRectTVtx[2].y, -g_texRectTVtx[2].z); OGLRender::TexCoord(g_texRectTVtx[3]); glVertex3f(g_texRectTVtx[3].x, g_texRectTVtx[3].y, -g_texRectTVtx[3].z); glEnd(); OPENGL_CHECK_ERRORS; #elif SDL_VIDEO_OPENGL_ES2 GLfloat colour[] = { r,g,b,a, r,g,b,a, r,g,b,a, r,g,b,a, r,g,b,a, r,g,b,a }; GLfloat tex[] = { g_texRectTVtx[0].tcord[0].u,g_texRectTVtx[0].tcord[0].v, g_texRectTVtx[1].tcord[0].u,g_texRectTVtx[1].tcord[0].v, g_texRectTVtx[2].tcord[0].u,g_texRectTVtx[2].tcord[0].v, g_texRectTVtx[0].tcord[0].u,g_texRectTVtx[0].tcord[0].v, g_texRectTVtx[2].tcord[0].u,g_texRectTVtx[2].tcord[0].v, g_texRectTVtx[3].tcord[0].u,g_texRectTVtx[3].tcord[0].v, }; float w = windowSetting.uDisplayWidth / 2.0f, h = windowSetting.uDisplayHeight / 2.0f, inv = 1.0f; GLfloat vertices[] = { -inv + g_texRectTVtx[0].x/ w, inv - g_texRectTVtx[0].y/ h, -g_texRectTVtx[0].z,1, -inv + g_texRectTVtx[1].x/ w, inv - g_texRectTVtx[1].y/ h, -g_texRectTVtx[1].z,1, -inv + g_texRectTVtx[2].x/ w, inv - g_texRectTVtx[2].y/ h, -g_texRectTVtx[2].z,1, -inv + g_texRectTVtx[0].x/ w, inv - g_texRectTVtx[0].y/ h, -g_texRectTVtx[0].z,1, -inv + g_texRectTVtx[2].x/ w, inv - g_texRectTVtx[2].y/ h, -g_texRectTVtx[2].z,1, -inv + g_texRectTVtx[3].x/ w, inv - g_texRectTVtx[3].y/ h, -g_texRectTVtx[3].z,1 }; glVertexAttribPointer(VS_COLOR, 4, GL_FLOAT,GL_FALSE, 0, &colour ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,0,&vertices); glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, 0, &tex); OPENGL_CHECK_ERRORS; glDrawArrays(GL_TRIANGLES,0,6); OPENGL_CHECK_ERRORS; //Restore old pointers glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u)); #endif if( cullface ) glEnable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; } void OGLRender::DrawSimpleRect(int nX0, int nY0, int nX1, int nY1, uint32 dwColor, float depth, float rhw) { StartDrawSimpleRect(nX0, nY0, nX1, nY1, dwColor, depth, rhw); GLboolean cullface = glIsEnabled(GL_CULL_FACE); glDisable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; float a = (dwColor>>24)/255.0f; float r = ((dwColor>>16)&0xFF)/255.0f; float g = ((dwColor>>8)&0xFF)/255.0f; float b = (dwColor&0xFF)/255.0f; #if SDL_VIDEO_OPENGL glBegin(GL_TRIANGLE_FAN); glColor4f(r,g,b,a); glVertex3f(m_simpleRectVtx[1].x, m_simpleRectVtx[0].y, -depth); glVertex3f(m_simpleRectVtx[1].x, m_simpleRectVtx[1].y, -depth); glVertex3f(m_simpleRectVtx[0].x, m_simpleRectVtx[1].y, -depth); glVertex3f(m_simpleRectVtx[0].x, m_simpleRectVtx[0].y, -depth); glEnd(); OPENGL_CHECK_ERRORS; #elif SDL_VIDEO_OPENGL_ES2 GLfloat colour[] = { r,g,b,a, r,g,b,a, r,g,b,a, r,g,b,a}; float w = windowSetting.uDisplayWidth / 2.0f, h = windowSetting.uDisplayHeight / 2.0f, inv = 1.0f; GLfloat vertices[] = { -inv + m_simpleRectVtx[1].x / w, inv - m_simpleRectVtx[0].y / h, -depth, 1, -inv + m_simpleRectVtx[1].x / w, inv - m_simpleRectVtx[1].y / h, -depth, 1, -inv + m_simpleRectVtx[0].x / w, inv - m_simpleRectVtx[1].y / h, -depth, 1, -inv + m_simpleRectVtx[0].x / w, inv - m_simpleRectVtx[0].y / h, -depth, 1 }; glVertexAttribPointer(VS_COLOR, 4, GL_FLOAT,GL_FALSE, 0, &colour ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,0,&vertices); glDisableVertexAttribArray(VS_TEXCOORD0); OPENGL_CHECK_ERRORS; glDrawArrays(GL_TRIANGLE_FAN,0,4); OPENGL_CHECK_ERRORS; //Restore old pointers glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); glEnableVertexAttribArray(VS_TEXCOORD0); #endif if( cullface ) glEnable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; } void OGLRender::InitCombinerBlenderForSimpleRectDraw(uint32 tile) { //glEnable(GL_CULL_FACE); EnableTexUnit(0,FALSE); OPENGL_CHECK_ERRORS; glEnable(GL_BLEND); OPENGL_CHECK_ERRORS; glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); OPENGL_CHECK_ERRORS; //glEnable(GL_ALPHA_TEST); } COLOR OGLRender::PostProcessDiffuseColor(COLOR curDiffuseColor) { uint32 color = curDiffuseColor; uint32 colorflag = m_pColorCombiner->m_pDecodedMux->m_dwShadeColorChannelFlag; uint32 alphaflag = m_pColorCombiner->m_pDecodedMux->m_dwShadeAlphaChannelFlag; if( colorflag+alphaflag != MUX_0 ) { if( (colorflag & 0xFFFFFF00) == 0 && (alphaflag & 0xFFFFFF00) == 0 ) { color = (m_pColorCombiner->GetConstFactor(colorflag, alphaflag, curDiffuseColor)); } else color = (CalculateConstFactor(colorflag, alphaflag, curDiffuseColor)); } //return (color<<8)|(color>>24); return color; } COLOR OGLRender::PostProcessSpecularColor() { return 0; } void OGLRender::SetViewportRender() { glViewportWrapper(windowSetting.vpLeftW, windowSetting.uDisplayHeight-windowSetting.vpTopW-windowSetting.vpHeightW+windowSetting.statusBarHeightToUse, windowSetting.vpWidthW, windowSetting.vpHeightW); OPENGL_CHECK_ERRORS; } void OGLRender::RenderReset() { CRender::RenderReset(); glMatrixMode(GL_PROJECTION); OPENGL_CHECK_ERRORS; glLoadIdentity(); OPENGL_CHECK_ERRORS; glOrtho(0, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, 0, -1, 1); OPENGL_CHECK_ERRORS; // position viewer glMatrixMode(GL_MODELVIEW); OPENGL_CHECK_ERRORS; glLoadIdentity(); OPENGL_CHECK_ERRORS; } void OGLRender::SetAlphaTestEnable(BOOL bAlphaTestEnable) { #ifdef DEBUGGER if( bAlphaTestEnable && debuggerEnableAlphaTest ) #else if( bAlphaTestEnable ) #endif #if SDL_VIDEO_OPENGL glEnable(GL_ALPHA_TEST); else glDisable(GL_ALPHA_TEST); #elif SDL_VIDEO_OPENGL_ES2 { COGL_FragmentProgramCombiner* frag = (COGL_FragmentProgramCombiner*)m_pColorCombiner; frag->m_AlphaRef = m_dwAlpha / 255.0f; } else { COGL_FragmentProgramCombiner* frag = (COGL_FragmentProgramCombiner*)m_pColorCombiner; frag->m_AlphaRef = 0.0f; } #endif OPENGL_CHECK_ERRORS; } void OGLRender::BindTexture(GLuint texture, int unitno) { #ifdef DEBUGGER if( unitno != 0 ) { DebuggerAppendMsg("Check me, base ogl bind texture, unit no != 0"); } #endif if( m_curBoundTex[0] != texture ) { glBindTexture(GL_TEXTURE_2D,texture); OPENGL_CHECK_ERRORS; m_curBoundTex[0] = texture; } } void OGLRender::DisBindTexture(GLuint texture, int unitno) { //EnableTexUnit(0,FALSE); //glBindTexture(GL_TEXTURE_2D, 0); //Not to bind any texture } void OGLRender::EnableTexUnit(int unitno, BOOL flag) { #ifdef DEBUGGER if( unitno != 0 ) { DebuggerAppendMsg("Check me, in the base ogl render, unitno!=0"); } #endif if( m_texUnitEnabled[0] != flag ) { m_texUnitEnabled[0] = flag; #if SDL_VIDEO_OPENGL if( flag == TRUE ) glEnable(GL_TEXTURE_2D); else glDisable(GL_TEXTURE_2D); #elif SDL_VIDEO_OPENGL_ES2 if(flag) { pglActiveTexture(GL_TEXTURE0_ARB + unitno); OPENGL_CHECK_ERRORS; glBindTexture(GL_TEXTURE_2D,m_curBoundTex[unitno]); } else { pglActiveTexture(GL_TEXTURE0_ARB + unitno); OPENGL_CHECK_ERRORS; glEnable(GL_BLEND); //Need blend for transparent disabled texture glBindTexture(GL_TEXTURE_2D,disabledTextureID); } #endif OPENGL_CHECK_ERRORS; } } void OGLRender::TexCoord2f(float u, float v) { glTexCoord2f(u, v); } void OGLRender::TexCoord(TLITVERTEX &vtxInfo) { glTexCoord2f(vtxInfo.tcord[0].u, vtxInfo.tcord[0].v); } void OGLRender::UpdateScissor() { if( options.bEnableHacks && g_CI.dwWidth == 0x200 && gRDP.scissor.right == 0x200 && g_CI.dwWidth>(*g_GraphicsInfo.VI_WIDTH_REG & 0xFFF) ) { // Hack for RE2 uint32 width = *g_GraphicsInfo.VI_WIDTH_REG & 0xFFF; uint32 height = (gRDP.scissor.right*gRDP.scissor.bottom)/width; glEnable(GL_SCISSOR_TEST); OPENGL_CHECK_ERRORS; glScissor(0, int(height*windowSetting.fMultY+windowSetting.statusBarHeightToUse), int(width*windowSetting.fMultX), int(height*windowSetting.fMultY) ); OPENGL_CHECK_ERRORS; } else { UpdateScissorWithClipRatio(); } } void OGLRender::ApplyRDPScissor(bool force) { if( !force && status.curScissor == RDP_SCISSOR ) return; if( options.bEnableHacks && g_CI.dwWidth == 0x200 && gRDP.scissor.right == 0x200 && g_CI.dwWidth>(*g_GraphicsInfo.VI_WIDTH_REG & 0xFFF) ) { // Hack for RE2 uint32 width = *g_GraphicsInfo.VI_WIDTH_REG & 0xFFF; uint32 height = (gRDP.scissor.right*gRDP.scissor.bottom)/width; glEnable(GL_SCISSOR_TEST); OPENGL_CHECK_ERRORS; glScissor(0, int(height*windowSetting.fMultY+windowSetting.statusBarHeightToUse), int(width*windowSetting.fMultX), int(height*windowSetting.fMultY) ); OPENGL_CHECK_ERRORS; } else { glScissor(int(gRDP.scissor.left*windowSetting.fMultX), int((windowSetting.uViHeight-gRDP.scissor.bottom)*windowSetting.fMultY+windowSetting.statusBarHeightToUse), int((gRDP.scissor.right-gRDP.scissor.left)*windowSetting.fMultX), int((gRDP.scissor.bottom-gRDP.scissor.top)*windowSetting.fMultY )); OPENGL_CHECK_ERRORS; } status.curScissor = RDP_SCISSOR; } void OGLRender::ApplyScissorWithClipRatio(bool force) { if( !force && status.curScissor == RSP_SCISSOR ) return; glEnable(GL_SCISSOR_TEST); OPENGL_CHECK_ERRORS; glScissor(windowSetting.clipping.left, int((windowSetting.uViHeight-gRSP.real_clip_scissor_bottom)*windowSetting.fMultY)+windowSetting.statusBarHeightToUse, windowSetting.clipping.width, windowSetting.clipping.height); OPENGL_CHECK_ERRORS; status.curScissor = RSP_SCISSOR; } void OGLRender::SetFogMinMax(float fMin, float fMax) { #if SDL_VIDEO_OPENGL glFogf(GL_FOG_START, gRSPfFogMin); // Fog Start Depth OPENGL_CHECK_ERRORS; glFogf(GL_FOG_END, gRSPfFogMax); // Fog End Depth OPENGL_CHECK_ERRORS; #elif SDL_VIDEO_OPENGL_ES2 ((COGL_FragmentProgramCombiner*)m_pColorCombiner)->UpdateFog(gRSP.bFogEnabled); OPENGL_CHECK_ERRORS; #endif } void OGLRender::TurnFogOnOff(bool flag) { #if SDL_VIDEO_OPENGL if( flag ) glEnable(GL_FOG); else glDisable(GL_FOG); OPENGL_CHECK_ERRORS; #elif SDL_VIDEO_OPENGL_ES2 ((COGL_FragmentProgramCombiner*)m_pColorCombiner)->UpdateFog(flag); OPENGL_CHECK_ERRORS; #endif } void OGLRender::SetFogEnable(bool bEnable) { DEBUGGER_IF_DUMP( (gRSP.bFogEnabled != (bEnable==TRUE) && logFog ), TRACE1("Set Fog %s", bEnable? "enable":"disable")); gRSP.bFogEnabled = bEnable&&(options.fogMethod == 1); // If force fog if(options.fogMethod == 2) { gRSP.bFogEnabled = true; } #if SDL_VIDEO_OPENGL if( gRSP.bFogEnabled ) { //TRACE2("Enable fog, min=%f, max=%f",gRSPfFogMin,gRSPfFogMax ); glFogfv(GL_FOG_COLOR, gRDP.fvFogColor); // Set Fog Color OPENGL_CHECK_ERRORS; glFogf(GL_FOG_START, gRSPfFogMin); // Fog Start Depth OPENGL_CHECK_ERRORS; glFogf(GL_FOG_END, gRSPfFogMax); // Fog End Depth OPENGL_CHECK_ERRORS; glEnable(GL_FOG); OPENGL_CHECK_ERRORS; } else { glDisable(GL_FOG); OPENGL_CHECK_ERRORS; } #elif SDL_VIDEO_OPENGL_ES2 ((COGL_FragmentProgramCombiner*)m_pColorCombiner)->UpdateFog(gRSP.bFogEnabled); OPENGL_CHECK_ERRORS; #endif } void OGLRender::SetFogColor(uint32 r, uint32 g, uint32 b, uint32 a) { gRDP.fogColor = COLOR_RGBA(r, g, b, a); gRDP.fvFogColor[0] = r/255.0f; //r gRDP.fvFogColor[1] = g/255.0f; //g gRDP.fvFogColor[2] = b/255.0f; //b gRDP.fvFogColor[3] = a/255.0f; //a #if SDL_VIDEO_OPENGL glFogfv(GL_FOG_COLOR, gRDP.fvFogColor); // Set Fog Color #endif OPENGL_CHECK_ERRORS; } void OGLRender::DisableMultiTexture() { pglActiveTexture(GL_TEXTURE1_ARB); OPENGL_CHECK_ERRORS; EnableTexUnit(1,FALSE); pglActiveTexture(GL_TEXTURE0_ARB); OPENGL_CHECK_ERRORS; EnableTexUnit(0,FALSE); pglActiveTexture(GL_TEXTURE0_ARB); OPENGL_CHECK_ERRORS; EnableTexUnit(0,TRUE); } void OGLRender::EndRendering(void) { #if SDL_VIDEO_OPENGL glFlush(); OPENGL_CHECK_ERRORS; #endif if( CRender::gRenderReferenceCount > 0 ) CRender::gRenderReferenceCount--; } void OGLRender::glViewportWrapper(GLint x, GLint y, GLsizei width, GLsizei height, bool flag) { static GLint mx=0,my=0; static GLsizei m_width=0, m_height=0; static bool mflag=true; if( x!=mx || y!=my || width!=m_width || height!=m_height || mflag!=flag) { mx=x; my=y; m_width=width; m_height=height; mflag=flag; glMatrixMode(GL_PROJECTION); OPENGL_CHECK_ERRORS; glLoadIdentity(); OPENGL_CHECK_ERRORS; if( flag ) glOrtho(0, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, 0, -1, 1); OPENGL_CHECK_ERRORS; glViewport(x,y,width,height); OPENGL_CHECK_ERRORS; } } mupen64plus-video-rice-src-2.0/src/OGLRender.h0000644000000000000000000000760212165031100017227 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _OGL_RENDER_H_ #define _OGL_RENDER_H_ #include "Combiner.h" #include "Render.h" class OGLRender : public CRender { friend class COGLColorCombiner; friend class COGLBlender; friend class OGLDeviceBuilder; protected: OGLRender(); public: ~OGLRender(); void Initialize(void); bool InitDeviceObjects(); bool ClearDeviceObjects(); void ApplyTextureFilter(); void SetShadeMode(RenderShadeMode mode); void ZBufferEnable(BOOL bZBuffer); void ClearBuffer(bool cbuffer, bool zbuffer); void ClearZBuffer(float depth); void SetZCompare(BOOL bZCompare); void SetZUpdate(BOOL bZUpdate); void SetZBias(int bias); void ApplyZBias(int bias); void SetAlphaRef(uint32 dwAlpha); void ForceAlphaRef(uint32 dwAlpha); void SetFillMode(FillMode mode); void SetViewportRender(); void RenderReset(); void SetCullMode(bool bCullFront, bool bCullBack); void SetAlphaTestEnable(BOOL bAlphaTestEnable); void UpdateScissor(); void ApplyRDPScissor(bool force=false); void ApplyScissorWithClipRatio(bool force=false); bool SetCurrentTexture(int tile, CTexture *handler,uint32 dwTileWidth, uint32 dwTileHeight, TxtrCacheEntry *pTextureEntry); bool SetCurrentTexture(int tile, TxtrCacheEntry *pTextureEntry); void SetAddressUAllStages(uint32 dwTile, TextureUVFlag dwFlag); void SetAddressVAllStages(uint32 dwTile, TextureUVFlag dwFlag); void SetTextureUFlag(TextureUVFlag dwFlag, uint32 tile); void SetTextureVFlag(TextureUVFlag dwFlag, uint32 tile); virtual void BindTexture(GLuint texture, int unitno); virtual void DisBindTexture(GLuint texture, int unitno); virtual void TexCoord2f(float u, float v); virtual void TexCoord(TLITVERTEX &vtxInfo); void DrawSimple2DTexture(float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, COLOR dif, COLOR spe, float z, float rhw); void DrawSimpleRect(int nX0, int nY0, int nX1, int nY1, uint32 dwColor, float depth, float rhw); void InitCombinerBlenderForSimpleRectDraw(uint32 tile=0); void DrawSpriteR_Render(); void DrawObjBGCopy(uObjBg &info); void DrawText(const char* str, RECT *rect); void SetFogMinMax(float fMin, float fMax); void SetFogEnable(bool bEnable); void TurnFogOnOff(bool flag); void SetFogColor(uint32 r, uint32 g, uint32 b, uint32 a); void DisableMultiTexture(); void EnableMultiTexture() {m_bEnableMultiTexture=true;} void EndRendering(void); void glViewportWrapper(GLint x, GLint y, GLsizei width, GLsizei height, bool flag=true); virtual void EnableTexUnit(int unitno, BOOL flag); virtual void SetTexWrapS(int unitno,GLuint flag); virtual void SetTexWrapT(int unitno,GLuint flag); protected: COLOR PostProcessDiffuseColor(COLOR curDiffuseColor); COLOR PostProcessSpecularColor(); // Basic render drawing functions bool RenderFlushTris(); bool RenderTexRect(); bool RenderFillRect(uint32 dwColor, float depth); bool RenderLine3D(); bool m_bSupportFogCoordExt; bool m_bMultiTexture; bool m_bSupportClampToEdge; GLuint m_curBoundTex[8]; BOOL m_texUnitEnabled[8]; bool m_bEnableMultiTexture; }; #endif mupen64plus-video-rice-src-2.0/src/OGLRenderExt.cpp0000644000000000000000000001162412165031100020242 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "osal_opengl.h" #include "OGLRender.h" extern Matrix g_MtxReal; extern uObjMtxReal gObjMtxReal; //======================================================================== void OGLRender::DrawText(const char* str, RECT *rect) { return; } void OGLRender::DrawSpriteR_Render() // With Rotation { glViewportWrapper(0, windowSetting.statusBarHeightToUse, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); GLboolean cullface = glIsEnabled(GL_CULL_FACE); glDisable(GL_CULL_FACE); #if SDL_VIDEO_OPENGL glBegin(GL_TRIANGLES); glColor4fv(gRDP.fvPrimitiveColor); OGLRender::TexCoord(g_texRectTVtx[0]); glVertex3f(g_texRectTVtx[0].x, g_texRectTVtx[0].y, -g_texRectTVtx[0].z); OGLRender::TexCoord(g_texRectTVtx[1]); glVertex3f(g_texRectTVtx[1].x, g_texRectTVtx[1].y, -g_texRectTVtx[1].z); OGLRender::TexCoord(g_texRectTVtx[2]); glVertex3f(g_texRectTVtx[2].x, g_texRectTVtx[2].y, -g_texRectTVtx[2].z); OGLRender::TexCoord(g_texRectTVtx[0]); glVertex3f(g_texRectTVtx[0].x, g_texRectTVtx[0].y, -g_texRectTVtx[0].z); OGLRender::TexCoord(g_texRectTVtx[2]); glVertex3f(g_texRectTVtx[2].x, g_texRectTVtx[2].y, -g_texRectTVtx[2].z); OGLRender::TexCoord(g_texRectTVtx[3]); glVertex3f(g_texRectTVtx[3].x, g_texRectTVtx[3].y, -g_texRectTVtx[3].z); glEnd(); #elif SDL_VIDEO_OPENGL_ES2 GLfloat colour[] = { gRDP.fvPrimitiveColor[0], gRDP.fvPrimitiveColor[1], gRDP.fvPrimitiveColor[2], gRDP.fvPrimitiveColor[3], gRDP.fvPrimitiveColor[0], gRDP.fvPrimitiveColor[1], gRDP.fvPrimitiveColor[2], gRDP.fvPrimitiveColor[3], gRDP.fvPrimitiveColor[0], gRDP.fvPrimitiveColor[1], gRDP.fvPrimitiveColor[2], gRDP.fvPrimitiveColor[3], gRDP.fvPrimitiveColor[0], gRDP.fvPrimitiveColor[1], gRDP.fvPrimitiveColor[2], gRDP.fvPrimitiveColor[3], gRDP.fvPrimitiveColor[0], gRDP.fvPrimitiveColor[1], gRDP.fvPrimitiveColor[2], gRDP.fvPrimitiveColor[3], gRDP.fvPrimitiveColor[0], gRDP.fvPrimitiveColor[1], gRDP.fvPrimitiveColor[2], gRDP.fvPrimitiveColor[3], }; GLfloat tex[] = { g_texRectTVtx[0].tcord[0].u,g_texRectTVtx[0].tcord[0].v, g_texRectTVtx[1].tcord[0].u,g_texRectTVtx[1].tcord[0].v, g_texRectTVtx[2].tcord[0].u,g_texRectTVtx[2].tcord[0].v, g_texRectTVtx[0].tcord[0].u,g_texRectTVtx[0].tcord[0].v, g_texRectTVtx[2].tcord[0].u,g_texRectTVtx[2].tcord[0].v, g_texRectTVtx[3].tcord[0].u,g_texRectTVtx[3].tcord[0].v, }; float w = windowSetting.uDisplayWidth / 2.0f, h = windowSetting.uDisplayHeight / 2.0f, inv = 1.0f; GLfloat vertices[] = { -inv + g_texRectTVtx[0].x/ w, inv - g_texRectTVtx[0].y/ h, -g_texRectTVtx[0].z,1, -inv + g_texRectTVtx[1].x/ w, inv - g_texRectTVtx[1].y/ h, -g_texRectTVtx[1].z,1, -inv + g_texRectTVtx[2].x/ w, inv - g_texRectTVtx[2].y/ h, -g_texRectTVtx[2].z,1, -inv + g_texRectTVtx[0].x/ w, inv - g_texRectTVtx[0].y/ h, -g_texRectTVtx[0].z,1, -inv + g_texRectTVtx[2].x/ w, inv - g_texRectTVtx[2].y/ h, -g_texRectTVtx[2].z,1, -inv + g_texRectTVtx[3].x/ w, inv - g_texRectTVtx[3].y/ h, -g_texRectTVtx[3].z,1 }; glVertexAttribPointer(VS_COLOR, 4, GL_FLOAT,GL_FALSE, 0, &colour ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,0,&vertices); glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, 0, &tex); //OPENGL_CHECK_ERRORS; glDrawArrays(GL_TRIANGLES,0,6); //OPENGL_CHECK_ERRORS; //Restore old pointers glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u)); #endif if( cullface ) glEnable(GL_CULL_FACE); } void OGLRender::DrawObjBGCopy(uObjBg &info) { if( IsUsedAsDI(g_CI.dwAddr) ) { DebugMessage(M64MSG_WARNING, "Unimplemented: write into Z buffer. Was mostly commented out in Rice Video 6.1.0"); return; } else { CRender::LoadObjBGCopy(info); CRender::DrawObjBGCopy(info); } } mupen64plus-video-rice-src-2.0/src/OGLTexture.cpp0000644000000000000000000001175112165031100020003 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "Config.h" #include "Debugger.h" #include "OGLDebug.h" #include "OGLGraphicsContext.h" #include "OGLTexture.h" #include "TextureManager.h" COGLTexture::COGLTexture(uint32 dwWidth, uint32 dwHeight, TextureUsage usage) : CTexture(dwWidth,dwHeight,usage), m_glFmt(GL_RGBA) { // FIXME: If usage is AS_RENDER_TARGET, we need to create pbuffer instead of regular texture m_dwTextureFmt = TEXTURE_FMT_A8R8G8B8; // Always use 32bit to load texture glGenTextures( 1, &m_dwTextureName ); OPENGL_CHECK_ERRORS; // Make the width and height be the power of 2 uint32 w; for (w = 1; w < dwWidth; w <<= 1); m_dwCreatedTextureWidth = w; for (w = 1; w < dwHeight; w <<= 1); m_dwCreatedTextureHeight = w; if (dwWidth*dwHeight > 256*256) TRACE4("Large texture: (%d x %d), created as (%d x %d)", dwWidth, dwHeight,m_dwCreatedTextureWidth,m_dwCreatedTextureHeight); m_fYScale = (float)m_dwCreatedTextureHeight/(float)m_dwHeight; m_fXScale = (float)m_dwCreatedTextureWidth/(float)m_dwWidth; m_pTexture = malloc(m_dwCreatedTextureWidth * m_dwCreatedTextureHeight * GetPixelSize()); switch( options.textureQuality ) { case TXT_QUALITY_DEFAULT: if( options.colorQuality == TEXTURE_FMT_A4R4G4B4 ) m_glFmt = GL_RGBA4; break; case TXT_QUALITY_32BIT: break; case TXT_QUALITY_16BIT: m_glFmt = GL_RGBA4; break; }; LOG_TEXTURE(TRACE2("New texture: (%d, %d)", dwWidth, dwHeight)); } COGLTexture::~COGLTexture() { // FIXME: If usage is AS_RENDER_TARGET, we need to destroy the pbuffer glDeleteTextures(1, &m_dwTextureName ); OPENGL_CHECK_ERRORS; free(m_pTexture); m_pTexture = NULL; m_dwWidth = 0; m_dwHeight = 0; } bool COGLTexture::StartUpdate(DrawInfo *di) { if (m_pTexture == NULL) return false; di->dwHeight = (uint16)m_dwHeight; di->dwWidth = (uint16)m_dwWidth; di->dwCreatedHeight = m_dwCreatedTextureHeight; di->dwCreatedWidth = m_dwCreatedTextureWidth; di->lpSurface = m_pTexture; di->lPitch = GetPixelSize()*m_dwCreatedTextureWidth; return true; } void COGLTexture::EndUpdate(DrawInfo *di) { COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); // we need this to check if the GL extension is avaible glBindTexture(GL_TEXTURE_2D, m_dwTextureName); OPENGL_CHECK_ERRORS; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); OPENGL_CHECK_ERRORS; // mipmap support if(options.mipmapping) { int m_maximumAnistropy = pcontext->getMaxAnisotropicFiltering(); //if getMaxAnisotropicFiltering() return more than 0, so aniso is supported and maxAnisotropicFiltering is set // Set Anisotropic filtering (mipmapping have to be activated, aniso filtering is not effective without) if( m_maximumAnistropy ) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_maximumAnistropy); OPENGL_CHECK_ERRORS; } // Set Mipmap glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); OPENGL_CHECK_ERRORS; #if SDL_VIDEO_OPENGL // Tell to hardware to generate mipmap (himself) when glTexImage2D is called glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); #elif SDL_VIDEO_OPENGL_ES2 glGenerateMipmap(GL_TEXTURE_2D); #endif OPENGL_CHECK_ERRORS; } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); OPENGL_CHECK_ERRORS; } // Copy the image data from main memory to video card texture memory #if SDL_VIDEO_OPENGL glTexImage2D(GL_TEXTURE_2D, 0, m_glFmt, m_dwCreatedTextureWidth, m_dwCreatedTextureHeight, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, m_pTexture); #elif SDL_VIDEO_OPENGL_ES2 //GL_BGRA_IMG works on adreno but not inside profiler. glTexImage2D(GL_TEXTURE_2D, 0, m_glFmt, m_dwCreatedTextureWidth, m_dwCreatedTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_pTexture); #endif OPENGL_CHECK_ERRORS; } // Keep in mind that the real texture is not scaled to fix the created opengl texture yet. // when the image is need to be scaled, ScaleImageToSurface in CTexure will be called to // scale the image automatically mupen64plus-video-rice-src-2.0/src/OGLTexture.h0000644000000000000000000000223712165031100017447 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _OGL_TEXTURE_H_ #define _OGL_TEXTURE_H_ #include "osal_opengl.h" #include "TextureManager.h" class COGLTexture : public CTexture { friend class COGLRenderTexture; public: ~COGLTexture(); bool StartUpdate(DrawInfo *di); void EndUpdate(DrawInfo *di); GLuint m_dwTextureName; GLuint m_glFmt; protected: friend class OGLDeviceBuilder; COGLTexture(uint32 dwWidth, uint32 dwHeight, TextureUsage usage = AS_NORMAL); }; #endif mupen64plus-video-rice-src-2.0/src/RDP_Texture.h0000644000000000000000000021572112165031100017616 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // Texture related ucode #include #include #include "Render.h" uint32 g_TmemFlag[16]; void SetTmemFlag(uint32 tmemAddr, uint32 size); bool IsTmemFlagValid(uint32 tmemAddr); uint32 GetValidTmemInfoIndex(uint32 tmemAddr); void EnhanceTexture(TxtrCacheEntry *pEntry); void MirrorTexture(uint32 tileno, TxtrCacheEntry *pEntry); void LoadHiresTexture( TxtrCacheEntry &entry ); extern TMEMLoadMapInfo g_tmemInfo0; // Info for Tmem=0 extern TMEMLoadMapInfo g_tmemInfo1; // Info for Tmem=0x100 TmemType g_Tmem; /************************************************************************/ /* */ /************************************************************************/ uint32 sizeShift[4] = {2,1,0,0}; uint32 sizeIncr[4] = {3,1,0,0}; uint32 sizeBytes[4] = {0,1,2,4}; inline uint32 Txl2Words(uint32 width, uint32 size) { if( size == TXT_SIZE_4b ) return max(1, width/16); else return max(1, width*sizeBytes[size]/8); } inline uint32 CalculateImgSize(uint32 width, uint32 height, uint32 size) { //(((width)*(height) + siz##_INCR) >> siz##_SHIFT) -1 return (((width)*(height) + sizeIncr[size]) >> sizeShift[size]) -1; } inline uint32 CalculateDXT(uint32 txl2words) { //#define CALC_DXT(width, b_txl) ((2048 + TXL2WORDS(width, b_txl) - 1) / TXL2WORDS(width, b_txl)) if( txl2words == 0 ) return 1; else return (2048+txl2words-1)/txl2words; } inline uint32 ReverseDXT(uint32 val, uint32 lrs, uint32 width, uint32 size) { //#define TXL2WORDS(txls, b_txl) MAX(1, ((txls)*(b_txl)/8)) if( val == 0x800 ) return 1; unsigned int low = 2047/val; if( CalculateDXT(low) > val ) low++; unsigned int high = 2047/(val-1); if( low == high ) return low; for( unsigned int i=low; i<=high; i++ ) { if( Txl2Words(width, size) == i ) return i; } return (low+high)/2; //dxt = 2047 / (dxt-1); } // The following inline assemble routines are borrowed from glN64, I am too tired to // rewrite these routine by myself. // Rice, 02/24/2004 inline void UnswapCopy( void *src, void *dest, uint32 numBytes ) { #if !defined(__GNUC__) && !defined(NO_ASM) __asm { mov ecx, 0 mov esi, dword ptr [src] mov edi, dword ptr [dest] mov ebx, esi and ebx, 3 // ebx = number of leading bytes cmp ebx, 0 jz StartDWordLoop neg ebx add ebx, 4 cmp ebx, [numBytes] jle NotGreater mov ebx, [numBytes] NotGreater: mov ecx, ebx xor esi, 3 LeadingLoop: // Copies leading bytes, in reverse order (un-swaps) mov al, byte ptr [esi] mov byte ptr [edi], al sub esi, 1 add edi, 1 loop LeadingLoop add esi, 5 StartDWordLoop: mov ecx, dword ptr [numBytes] sub ecx, ebx // Don't copy what's already been copied mov ebx, ecx and ebx, 3 // add ecx, 3 // Round up to nearest dword shr ecx, 2 cmp ecx, 0 // If there's nothing to do, don't do it jle StartTrailingLoop // Copies from source to destination, bswap-ing first DWordLoop: mov eax, dword ptr [esi] bswap eax mov dword ptr [edi], eax add esi, 4 add edi, 4 loop DWordLoop StartTrailingLoop: cmp ebx, 0 jz Done mov ecx, ebx xor esi, 3 TrailingLoop: mov al, byte ptr [esi] mov byte ptr [edi], al sub esi, 1 add edi, 1 loop TrailingLoop Done: } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) asm volatile(" movl %k1, %%ebx \n" " andl $3, %%ebx \n" " cmpl $0, %%ebx \n" " jz 2f \n" " negl %%ebx \n" " addl $4, %%ebx \n" " cmpl %k2, %%ebx \n" " jle 0f \n" " movl %k2, %%ebx \n" "0: \n" " movl %%ebx, %%ecx \n" " xor $3, %1 \n" "1: \n" " movb (%1), %%al \n" " movb %%al, (%0) \n" " sub $1, %1 \n" " add $1, %0 \n" " decl %%ecx \n" " jne 1b \n" " add $5, %1 \n" "2: \n" " movl %k2, %%ecx \n" " subl %%ebx, %%ecx \n" " movl %%ecx, %%ebx \n" " andl $3, %%ebx \n" " shrl $2, %%ecx \n" " cmpl $0, %%ecx \n" " jle 4f \n" "3: \n" " movl (%1), %%eax \n" " bswapl %%eax \n" " movl %%eax, (%0) \n" " add $4, %1 \n" " add $4, %0 \n" " decl %%ecx \n" " jne 3b \n" "4: \n" " cmpl $0, %%ebx \n" " jz 6f \n" " xor $3, %1 \n" "5: \n" " movb (%1), %%al \n" " movb %%al, (%0) \n" " sub $1, %1 \n" " add $1, %0 \n" " decl %%ebx \n" " jne 5b \n" "6: \n" :"+r"(dest), "+r"(src) :"r"(numBytes) : "memory", "cc", "%rax", "%rbx", "%rcx" ); #elif !defined(NO_ASM) unsigned int saveEBX; asm volatile ("mov %%ebx, %2 \n" "mov $0, %%ecx \n" "mov %0, %%esi \n" "mov %1, %%edi \n" "mov %%esi, %%ebx \n" "and $3, %%ebx \n" // ebx = number of leading bytes "cmp $0, %%ebx \n" "jz 2f \n" //jz StartDWordLoop "neg %%ebx \n" "add $4, %%ebx \n" "cmp %3, %%ebx \n" "jle 0f \n" //jle NotGreater "mov %3, %%ebx \n" "0: \n" //NotGreater: "mov %%ebx, %%ecx \n" "xor $3, %%esi \n" "1: \n" //LeadingLoop: // Copies leading bytes, in reverse order (un-swaps) "mov (%%esi), %%al \n" "mov %%al, (%%edi) \n" "sub $1, %%esi \n" "add $1, %%edi \n" "loop 1b \n" //loop LeadingLoop "add $5, %%esi \n" "2: \n" //StartDWordLoop: "mov %3, %%ecx \n" "sub %%ebx, %%ecx \n" // Don't copy what's already been copied "mov %%ecx, %%ebx \n" "and $3, %%ebx \n" // add ecx, 3 // Round up to nearest dword "shr $2, %%ecx \n" "cmp $0, %%ecx \n" // If there's nothing to do, don't do it "jle 4f \n" //jle StartTrailingLoop // Copies from source to destination, bswap-ing first "3: \n" //DWordLoop: "mov (%%esi), %%eax \n" "bswap %%eax \n" "mov %%eax, (%%edi) \n" "add $4, %%esi \n" "add $4, %%edi \n" "loop 3b \n" //loop DWordLoop "4: \n" //StartTrailingLoop: "cmp $0, %%ebx \n" "jz 6f \n" //jz Done "mov %%ebx, %%ecx \n" "xor $3, %%esi \n" "5: \n" //TrailingLoop: "mov (%%esi), %%al \n" "mov %%al, (%%edi) \n" "sub $1, %%esi \n" "add $1, %%edi \n" "loop 5b \n" //loop TrailingLoop "6: \n" //Done: "mov %2, %%ebx \n" : : "m"(src), "m"(dest), "m"(saveEBX), "m"(numBytes) : "memory", "cc", "%ecx", "%esi", "%edi", "%eax" ); #endif } inline void DWordInterleave( void *mem, uint32 numDWords ) { #if !defined(__GNUC__) && !defined(NO_ASM) __asm { mov esi, dword ptr [mem] mov edi, dword ptr [mem] add edi, 4 mov ecx, dword ptr [numDWords] DWordInterleaveLoop: mov eax, dword ptr [esi] mov ebx, dword ptr [edi] mov dword ptr [esi], ebx mov dword ptr [edi], eax add esi, 8 add edi, 8 loop DWordInterleaveLoop } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) asm volatile("0: \n" " movl (%0), %%eax \n" " movl 8(%0), %%ebx \n" " movl %%eax, 8(%0) \n" " movl %%ebx, (%0) \n" " add $8, %0 \n" " decl %k1 \n" " jne 0b \n" : "+r"(mem), "+r"(numDWords) : : "memory", "cc", "%rax", "%rbx" ); #elif !defined(NO_ASM) unsigned int saveEBX; asm volatile ("mov %%ebx, %2 \n" "mov %0, %%esi \n" "mov %0, %%edi \n" "add $4, %%edi \n" "mov %1, %%ecx \n" "0: \n" //DWordInterleaveLoop: "mov (%%esi), %%eax \n" "mov (%%edi), %%ebx \n" "mov %%ebx, (%%esi) \n" "mov %%eax, (%%edi) \n" "add $8, %%esi \n" "add $8, %%edi \n" "loop 0b \n" //loop DWordInterleaveLoop "mov %2, %%ebx \n" : : "m"(mem), "m"(numDWords), "m"(saveEBX) : "memory", "cc", "%esi", "%edi", "%ecx", "%eax" ); #endif } inline void QWordInterleave( void *mem, uint32 numDWords ) { #if !defined(__GNUC__) && !defined(NO_ASM) __asm { // Interleave the line on the qword mov esi, dword ptr [mem] mov edi, dword ptr [mem] add edi, 8 mov ecx, dword ptr [numDWords] shr ecx, 1 QWordInterleaveLoop: mov eax, dword ptr [esi] mov ebx, dword ptr [edi] mov dword ptr [esi], ebx mov dword ptr [edi], eax add esi, 4 add edi, 4 mov eax, dword ptr [esi] mov ebx, dword ptr [edi] mov dword ptr [esi], ebx mov dword ptr [edi], eax add esi, 12 add edi, 12 loop QWordInterleaveLoop } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) asm volatile(" shr $1, %k1 \n" "0: \n" " mov (%0), %%rax \n" " mov 8(%0), %%rbx \n" " mov %%rax, 8(%0) \n" " mov %%rbx, (%0) \n" " add $16, %0 \n" " decl %k1 \n" " jne 0b \n" : "+r"(mem), "+r"(numDWords) : : "memory", "cc", "%rax", "%rbx" ); #elif !defined(NO_ASM) // GCC assumed unsigned int saveEBX; asm volatile("mov %%ebx, %2 \n" // Interleave the line on the qword "mov %0, %%esi \n" "mov %0, %%edi \n" "add $8, %%edi \n" "mov %1, %%ecx \n" "shr $1, %%ecx \n" "0: \n" //QWordInterleaveLoop: "mov (%%esi), %%eax \n" "mov (%%edi), %%ebx \n" "mov %%ebx, (%%esi) \n" "mov %%eax, (%%edi) \n" "add $4, %%esi \n" "add $4, %%edi \n" "mov (%%esi), %%eax \n" "mov (%%edi), %%ebx \n" "mov %%ebx, (%%esi) \n" "mov %%eax, (%%edi) \n" "add $12, %%esi \n" "add $12, %%edi \n" "loop 0b \n" //loop QWordInterleaveLoop "mov %2, %%ebx \n" : : "m"(mem), "m"(numDWords), "m"(saveEBX) : "memory", "cc", "%esi", "%edi", "%ecx", "%eax" ); #endif } inline uint32 swapdword( uint32 value ) { #if defined(__INTEL_COMPILER) && !defined(NO_ASM) __asm { mov eax, dword ptr [value] bswap eax } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) asm volatile(" bswapl %k0 \n" : "+r"(value) : : ); return value; #elif defined(__GNUC__) && defined(__i386__) && !defined(NO_ASM) asm volatile("bswapl %0 \n" : "+r"(value) : : ); return value; #else return ((value & 0xff000000) >> 24) | ((value & 0x00ff0000) >> 8) | ((value & 0x0000ff00) << 8) | ((value & 0x000000ff) << 24); #endif } inline uint16 swapword( uint16 value ) { #if defined(__INTEL_COMPILER) && !defined(NO_ASM) __asm { mov ax, word ptr [value] xchg ah, al } #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) && !defined(NO_ASM) asm volatile("xchg %%al, %%ah \n" : "+a"(value) : : ); return value; #else return ((value & 0xff00) >> 8) | ((value & 0x00ff) << 8); #endif } void ComputeTileDimension(int mask, int clamp, int mirror, int width, uint32 &widthToCreate, uint32 &widthToLoad) { int maskwidth = mask > 0 ? (1< 0 ) { if( width > maskwidth ) { if( clamp == 0 ) { // clamp is not used, so just use the dwTileMaskWidth as the real width widthToCreate = widthToLoad = maskwidth; } else { widthToLoad = maskwidth; //gti.WidthToCreate = dwTileWidth; // keep the current WidthToCreate, we will do mirror/wrap // during texture loading, not during rendering } } else if( width < maskwidth ) { // dwTileWidth < dwTileMaskWidth if( clamp == 0 ) { if( maskwidth%width == 0 ) { if( (maskwidth/width)%2 == 0 || mirror == 0 ) { // Do nothing // gti.WidthToLoad = gti.WidthToCreate = gRDP.tiles[tileno].dwWidth = dwTileWidth } else { widthToCreate = maskwidth; } } else { widthToCreate = maskwidth; //widthToLoad = maskwidth; } } else { widthToCreate = maskwidth; //widthToLoad = maskwidth; } } else // dwTileWidth == dwTileMaskWidth { } // Some hacks, to limit the image size if( mask >= 8 ) { if( maskwidth / width >= 2 ) { widthToCreate = width; } } } } bool conkerSwapHack=false; bool CalculateTileSizes_method_2(int tileno, TMEMLoadMapInfo *info, TxtrInfo >i) { Tile &tile = gRDP.tiles[tileno]; Tile &loadtile = gRDP.tiles[RDP_TXT_LOADTILE]; uint32 dwPitch; // Now Initialize the texture dimension int dwTileWidth; int dwTileHeight; if( info->bSetBy == CMD_LOADTILE ) { if( tile.sl >= tile.sh ) { dwTileWidth = info->dwWidth; // From SetTImage dwTileWidth = dwTileWidth << info->dwSize >> tile.dwSize; } else { dwTileWidth= tile.sh - tile.sl + 1; } if( tile.tl >= tile.th ) { dwTileHeight= info->th - info->tl + 1; } else { dwTileHeight= tile.th - tile.tl + 1; } } else { if( tile.dwMaskS == 0 || tile.bClampS ) { dwTileWidth = tile.hilite_sh - tile.hilite_sl +1; if( dwTileWidth < tile.sh - tile.sl +1 ) dwTileWidth = tile.sh - tile.sl +1; if( dwTileWidth <= 0 ) { DebuggerAppendMsg("Error"); } } else { if( tile.dwMaskS < 8 ) dwTileWidth = (1 << tile.dwMaskS ); else if( tile.dwLine ) { dwTileWidth = (tile.dwLine<<5)>>tile.dwSize; } else { if( tile.sl <= tile.sh ) { dwTileWidth = tile.sh - tile.sl +1; } else if( loadtile.sl <= loadtile.sh ) { dwTileWidth = loadtile.sh - loadtile.sl +1; } else { dwTileWidth = tile.sh - tile.sl +1; } } } if( tile.dwMaskT == 0 || tile.bClampT ) { dwTileHeight= tile.hilite_th - tile.hilite_tl +1; if( dwTileHeight < tile.th - tile.tl +1 ) dwTileHeight = tile.th - tile.tl +1; if( dwTileHeight <= 0 ) { DebuggerAppendMsg("Error"); } } else { if( tile.dwMaskT < 8 ) dwTileHeight = (1 << tile.dwMaskT ); else if( tile.tl <= tile.th ) { dwTileHeight = tile.th - tile.tl +1; } else if( loadtile.tl <= loadtile.th ) { dwTileHeight = loadtile.th - loadtile.tl +1; } else { dwTileHeight = tile.th - tile.tl +1; } } } int dwTileMaskWidth = tile.dwMaskS > 0 ? (1 << tile.dwMaskS ) : 0; int dwTileMaskHeight = tile.dwMaskT > 0 ? (1 << tile.dwMaskT ) : 0; if( dwTileWidth < 0 || dwTileHeight < 0) { if( dwTileMaskWidth > 0 ) dwTileWidth = dwTileMaskWidth; else if( dwTileWidth < 0 ) dwTileWidth = -dwTileWidth; if( dwTileMaskHeight > 0 ) dwTileHeight = dwTileMaskHeight; else if( dwTileHeight < 0 ) dwTileHeight = -dwTileHeight; } if( dwTileWidth-dwTileMaskWidth == 1 && dwTileMaskWidth && dwTileHeight-dwTileMaskHeight == 1 && dwTileMaskHeight ) { // Hack for Mario Kart dwTileWidth--; dwTileHeight--; } ComputeTileDimension(tile.dwMaskS, tile.bClampS, tile.bMirrorS, dwTileWidth, gti.WidthToCreate, gti.WidthToLoad); tile.dwWidth = gti.WidthToCreate; ComputeTileDimension(tile.dwMaskT, tile.bClampT, tile.bMirrorT, dwTileHeight, gti.HeightToCreate, gti.HeightToLoad); tile.dwHeight = gti.HeightToCreate; #ifdef DEBUGGER if( gti.WidthToCreate < gti.WidthToLoad ) TRACE2("Check me, width to create = %d, width to load = %d", gti.WidthToCreate, gti.WidthToLoad); if( gti.HeightToCreate < gti.HeightToLoad ) TRACE2("Check me, height to create = %d, height to load = %d", gti.HeightToCreate, gti.HeightToLoad); #endif gti.bSwapped = info->bSwapped; if( info->bSetBy == CMD_LOADTILE ) { // It was a tile - the pitch is set by LoadTile dwPitch = info->dwWidth<<(info->dwSize-1); if( dwPitch == 0 ) { dwPitch = 1024; // Hack for Bust-A-Move } } else //Set by LoadBlock { // It was a block load - the pitch is determined by the tile size if (info->dxt == 0 || info->dwTmem != tile.dwTMem ) { dwPitch = tile.dwLine << 3; gti.bSwapped = TRUE; if( info->dwTmem != tile.dwTMem && info->dxt != 0 && info->dwSize == TXT_SIZE_16b && tile.dwSize == TXT_SIZE_4b ) conkerSwapHack = true; } else { uint32 DXT = info->dxt; if( info->dxt > 1 ) { DXT = ReverseDXT(info->dxt, info->sh, dwTileWidth, tile.dwSize); } dwPitch = DXT << 3; } if (tile.dwSize == TXT_SIZE_32b) dwPitch = tile.dwLine << 4; } gti.Pitch = tile.dwPitch = dwPitch; if( (gti.WidthToLoad < gti.WidthToCreate || tile.bSizeIsValid == false) && tile.dwMaskS > 0 && gti.WidthToLoad != (unsigned int)dwTileMaskWidth && info->bSetBy == CMD_LOADBLOCK ) //if( (gti.WidthToLoad < gti.WidthToCreate ) && tile.dwMaskS > 0 && gti.WidthToLoad != dwTileMaskWidth && // info->bSetBy == CMD_LOADBLOCK ) { // We have got the pitch now, recheck the width_to_load uint32 pitchwidth = dwPitch<<1>>tile.dwSize; if( pitchwidth == (unsigned int)dwTileMaskWidth ) { gti.WidthToLoad = pitchwidth; } } if( (gti.HeightToLoad < gti.HeightToCreate || tile.bSizeIsValid == false) && tile.dwMaskT > 0 && gti.HeightToLoad != (unsigned int)dwTileMaskHeight && info->bSetBy == CMD_LOADBLOCK ) //if( (gti.HeightToLoad < gti.HeightToCreate ) && tile.dwMaskT > 0 && gti.HeightToLoad != dwTileMaskHeight && // info->bSetBy == CMD_LOADBLOCK ) { //uint32 pitchwidth = dwPitch<<1>>tile.dwSize; uint32 pitchHeight = (info->dwTotalWords<<1)/dwPitch; if( pitchHeight == (unsigned int)dwTileMaskHeight || gti.HeightToLoad == 1 ) { gti.HeightToLoad = pitchHeight; } } if( gti.WidthToCreate < gti.WidthToLoad ) gti.WidthToCreate = gti.WidthToLoad; if( gti.HeightToCreate < gti.HeightToLoad ) gti.HeightToCreate = gti.HeightToLoad; if( info->bSetBy == CMD_LOADTILE ) { gti.LeftToLoad = (info->sl<dwSize)>>tile.dwSize; gti.TopToLoad = info->tl; } else { gti.LeftToLoad = (info->sl<dwSize)>>tile.dwSize; gti.TopToLoad = (info->tl<dwSize)>>tile.dwSize; } uint32 total64BitWordsToLoad = (gti.HeightToLoad*gti.WidthToLoad)>>(4-tile.dwSize); if( total64BitWordsToLoad + tile.dwTMem > 0x200 ) { //TRACE0("Warning: texture loading tmem is over range"); if( gti.WidthToLoad > gti.HeightToLoad ) { uint32 newheight = (dwPitch << 1 )>> tile.dwSize; tile.dwWidth = gti.WidthToLoad = gti.WidthToCreate = min(newheight, (gti.WidthToLoad&0xFFFFFFFE)); tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = ((0x200 - tile.dwTMem) << (4-tile.dwSize)) / gti.WidthToLoad; } else { tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = info->dwTotalWords / ((gti.WidthToLoad << tile.dwSize) >> 1); } } // Check the info if( (info->dwTotalWords>>2) < total64BitWordsToLoad+tile.dwTMem-info->dwTmem - 4 ) { // Hack here if( (options.enableHackForGames == HACK_FOR_ZELDA||options.enableHackForGames == HACK_FOR_ZELDA_MM) && (unsigned int)tileno != gRSP.curTile ) { return false; } if( total64BitWordsToLoad+tile.dwTMem-info->dwTmem <= 0x200 ) { LOG_TEXTURE(TRACE4("Fix me, info is not covering this Tmem address,Info start: 0x%x, total=0x%x, Tmem start: 0x%x, total=0x%x", info->dwTmem,info->dwTotalWords>>2, tile.dwTMem, total64BitWordsToLoad)); } } //Check memory boundary if( gti.Address + gti.HeightToLoad*gti.Pitch >= g_dwRamSize ) { WARNING(TRACE0("Warning: texture loading tmem is over range 3")); gti.HeightToCreate = gti.HeightToLoad = tile.dwHeight = (g_dwRamSize-gti.Address)/gti.Pitch; } return true; } bool CalculateTileSizes_method_1(int tileno, TMEMLoadMapInfo *info, TxtrInfo >i) { Tile &tile = gRDP.tiles[tileno]; //Tile &loadtile = gRDP.tiles[RDP_TXT_LOADTILE]; // Now Initialize the texture dimension int loadwidth, loadheight; int maskwidth = tile.dwMaskS ? (1 << tile.dwMaskS ) : 0; int maskheight = tile.dwMaskT ? (1 << tile.dwMaskT ) : 0; int clampwidth = abs(tile.hilite_sh - tile.hilite_sl) +1; int clampheight = abs(tile.hilite_th - tile.hilite_tl) +1; int linewidth = tile.dwLine << (5 - tile.dwSize); gti.bSwapped = info->bSwapped; if( info->bSetBy == CMD_LOADTILE ) { loadwidth = (abs(info->sh - info->sl) + 1) << info->dwSize >> tile.dwSize; loadheight = (abs(info->th - info->tl) + 1) << info->dwSize >> tile.dwSize; tile.dwPitch = info->dwWidth << info->dwSize >> 1; if( tile.dwPitch == 0 ) tile.dwPitch = 1024; // Hack for Bust-A-Move gti.LeftToLoad = (info->sl<dwSize)>>tile.dwSize; gti.TopToLoad = info->tl; } else { loadwidth = abs(tile.sh - tile.sl) +1; if( tile.dwMaskS ) { loadwidth = maskwidth; } loadheight = abs(tile.th - tile.tl) +1; if( tile.dwMaskT ) { loadheight = maskheight; } // It was a block load - the pitch is determined by the tile size if (tile.dwSize == TXT_SIZE_32b) tile.dwPitch = tile.dwLine << 4; else if (info->dxt == 0 ) { tile.dwPitch = tile.dwLine << 3; gti.bSwapped = TRUE; if( info->dwTmem != tile.dwTMem && info->dxt != 0 && info->dwSize == TXT_SIZE_16b && tile.dwSize == TXT_SIZE_4b ) conkerSwapHack = true; } else { uint32 DXT = info->dxt; if( info->dxt > 1 ) { DXT = ReverseDXT(info->dxt, info->sh, loadwidth, tile.dwSize); } tile.dwPitch = DXT << 3; } gti.LeftToLoad = (info->sl<dwSize)>>tile.dwSize; gti.TopToLoad = (info->tl<dwSize)>>tile.dwSize; } if( options.enableHackForGames == HACK_FOR_MARIO_KART ) { if( loadwidth-maskwidth == 1 && tile.dwMaskS ) { loadwidth--; if( loadheight%2 ) loadheight--; } if( loadheight-maskheight == 1 && tile.dwMaskT ) { loadheight--; if(loadwidth%2) loadwidth--; } if( loadwidth - ((g_TI.dwWidth<>tile.dwSize) == 1 ) { loadwidth--; if( loadheight%2 ) loadheight--; } } // Limit the texture size if( g_curRomInfo.bUseSmallerTexture ) { if( tile.dwMaskS && tile.bClampS ) { if( !tile.bMirrorS ) { if( clampwidth/maskwidth >= 2 ) { clampwidth = maskwidth; tile.bForceWrapS = true; } else if( clampwidth && maskwidth/clampwidth >= 2 ) { maskwidth = clampwidth; tile.bForceClampS = true; } } else { if( clampwidth/maskwidth == 2 ) { clampwidth = maskwidth*2; tile.bForceWrapS = false; } else if( clampwidth/maskwidth > 2 ) { clampwidth = maskwidth*2; tile.bForceWrapS = true; } } } if( tile.dwMaskT && tile.bClampT ) { if( !tile.bMirrorT ) { if( clampheight/maskheight >= 2 ) { clampheight = maskheight; tile.bForceWrapT = true; } else if( clampheight && maskheight/clampheight >= 2 ) { maskwidth = clampwidth; tile.bForceClampT = true; } } else { if( clampheight/maskheight == 2 ) { clampheight = maskheight*2; tile.bForceWrapT = false; } else if( clampheight/maskheight >= 2 ) { clampheight = maskheight*2; tile.bForceWrapT = true; } } } } else { //if( clampwidth > linewidth ) clampwidth = linewidth; if( clampwidth > 512 && clampheight > 512 ) { if( clampwidth > maskwidth && maskwidth && clampheight > 256 ) clampwidth = maskwidth; if( clampheight > maskheight && maskheight && clampheight > 256 ) clampheight = maskheight; } if( tile.dwMaskS > 8 && tile.dwMaskT > 8 ) { maskwidth = loadwidth; maskheight = loadheight; } else { if( tile.dwMaskS > 10 ) maskwidth = loadwidth; if( tile.dwMaskT > 10 ) maskheight = loadheight; } } gti.Pitch = tile.dwPitch; if( tile.dwMaskS == 0 || tile.bClampS ) { gti.WidthToLoad = linewidth ? min( linewidth, maskwidth ? min(clampwidth,maskwidth) : clampwidth ) : clampwidth; if( tile.dwMaskS && clampwidth < maskwidth ) tile.dwWidth = gti.WidthToCreate = clampwidth; else tile.dwWidth = gti.WidthToCreate = max(clampwidth,maskwidth); } else { gti.WidthToLoad = loadwidth > 2 ? min(loadwidth,maskwidth) : maskwidth; if( linewidth ) gti.WidthToLoad = min( linewidth, (int)gti.WidthToLoad ); tile.dwWidth = gti.WidthToCreate = maskwidth; } if( tile.dwMaskT == 0 || tile.bClampT ) { gti.HeightToLoad = maskheight ? min(clampheight,maskheight) : clampheight; if( tile.dwMaskT && clampheight < maskheight ) tile.dwHeight = gti.HeightToCreate = clampheight; else tile.dwHeight = gti.HeightToCreate = max(clampheight,maskheight); } else { gti.HeightToLoad = loadheight > 2 ? min(loadheight,maskheight) : maskheight; tile.dwHeight = gti.HeightToCreate = maskheight; } if( options.enableHackForGames == HACK_FOR_MARIO_KART ) { if( gti.WidthToLoad - ((g_TI.dwWidth<>tile.dwSize) == 1 ) { gti.WidthToLoad--; if( gti.HeightToLoad%2 ) gti.HeightToLoad--; } } // Double check uint32 total64BitWordsToLoad = (gti.HeightToLoad*gti.WidthToLoad)>>(4-tile.dwSize); if( total64BitWordsToLoad + tile.dwTMem > 0x200 ) { //TRACE0("Warning: texture loading tmem is over range"); if( gti.WidthToLoad > gti.HeightToLoad ) { uint32 newheight = (tile.dwPitch << 1 )>> tile.dwSize; tile.dwWidth = gti.WidthToLoad = gti.WidthToCreate = min(newheight, (gti.WidthToLoad&0xFFFFFFFE)); tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = ((0x200 - tile.dwTMem) << (4-tile.dwSize)) / gti.WidthToLoad; } else { tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = info->dwTotalWords / ((gti.WidthToLoad << tile.dwSize) >> 1); } } // Check the info if( (info->dwTotalWords>>2) < total64BitWordsToLoad+tile.dwTMem-info->dwTmem - 4 ) { // Hack here if( (options.enableHackForGames == HACK_FOR_ZELDA||options.enableHackForGames == HACK_FOR_ZELDA_MM) && (unsigned int)tileno != gRSP.curTile ) { return false; } if( total64BitWordsToLoad+tile.dwTMem-info->dwTmem <= 0x200 ) { LOG_TEXTURE(TRACE4("Fix me, info is not covering this Tmem address,Info start: 0x%x, total=0x%x, Tmem start: 0x%x, total=0x%x", info->dwTmem,info->dwTotalWords>>2, tile.dwTMem, total64BitWordsToLoad)); } } //Check memory boundary if( gti.Address + gti.HeightToLoad*gti.Pitch >= g_dwRamSize ) { WARNING(TRACE0("Warning: texture loading tmem is over range 3")); gti.HeightToCreate = gti.HeightToLoad = tile.dwHeight = (g_dwRamSize-gti.Address)/gti.Pitch; } return true; } TxtrCacheEntry* LoadTexture(uint32 tileno) { //TxtrCacheEntry *pEntry = NULL; TxtrInfo gti; Tile &tile = gRDP.tiles[tileno]; // Retrieve the tile loading info uint32 infoTmemAddr = tile.dwTMem; TMEMLoadMapInfo *info = &g_tmemLoadAddrMap[infoTmemAddr]; if( !IsTmemFlagValid(infoTmemAddr) ) { infoTmemAddr = GetValidTmemInfoIndex(infoTmemAddr); info = &g_tmemLoadAddrMap[infoTmemAddr]; } if( info->dwFormat != tile.dwFormat ) { // Check the tile format, hack for Zelda's road if( tileno != gRSP.curTile && tile.dwTMem == gRDP.tiles[gRSP.curTile].dwTMem && tile.dwFormat != gRDP.tiles[gRSP.curTile].dwFormat ) { //TRACE1("Tile %d format is not matching the loaded texture format", tileno); return NULL; } } gti = tile; // Copy tile info to textureInfo entry gti.TLutFmt = gRDP.otherMode.text_tlut <dwLoadAddress+(tile.dwTMem-infoTmemAddr)*8) & (g_dwRamSize-1) ; gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address; gti.tileNo = tileno; if( g_curRomInfo.bTxtSizeMethod2 ) { if( !CalculateTileSizes_method_2(tileno, info, gti) ) return NULL; } else { if( !CalculateTileSizes_method_1(tileno, info, gti) ) return NULL; } LOG_TEXTURE( { TRACE0("Loading texture:\n"); DebuggerAppendMsg("Left: %d, Top: %d, Width: %d, Height: %d, Size to Load (%d, %d)", gti.LeftToLoad, gti.TopToLoad, gti.WidthToCreate, gti.HeightToCreate, gti.WidthToLoad, gti.HeightToLoad); DebuggerAppendMsg("Pitch: %d, Addr: 0x%08x", gti.Pitch, gti.Address); }); // Option for faster loading tiles if( g_curRomInfo.bFastLoadTile && info->bSetBy == CMD_LOADTILE && ((gti.Pitch<<1)>>gti.Size) <= 0x400 //&& ((gti.Pitch<<1)>>gti.Size) > 128 && status.primitiveType == PRIM_TEXTRECT ) { uint32 idx = tileno-gRSP.curTile; status.LargerTileRealLeft[idx] = gti.LeftToLoad; gti.LeftToLoad=0; gti.WidthToLoad = gti.WidthToCreate = ((gti.Pitch<<1)>>gti.Size); status.UseLargerTile[idx]=true; } // Loading the textures by using texture cache manager return gTextureManager.GetTexture(>i, true, true, true); // Load the texture by using texture cache } void PrepareTextures() { if( gRDP.textureIsChanged || !currentRomOptions.bFastTexCRC || CRender::g_pRender->m_pColorCombiner->m_pDecodedMux->m_ColorTextureFlag[0] || CRender::g_pRender->m_pColorCombiner->m_pDecodedMux->m_ColorTextureFlag[1] ) { status.UseLargerTile[0]=false; status.UseLargerTile[1]=false; int tilenos[2]; if( CRender::g_pRender->IsTexel0Enable() || gRDP.otherMode.cycle_type == CYCLE_TYPE_COPY ) tilenos[0] = gRSP.curTile; else tilenos[0] = -1; if( gRSP.curTile<7 && CRender::g_pRender->IsTexel1Enable() ) tilenos[1] = gRSP.curTile+1; else tilenos[1] = -1; for( int i=0; i<2; i++ ) { if( tilenos[i] < 0 ) continue; if( CRender::g_pRender->m_pColorCombiner->m_pDecodedMux->m_ColorTextureFlag[i] ) { TxtrCacheEntry *pEntry = gTextureManager.GetConstantColorTexture(CRender::g_pRender->m_pColorCombiner->m_pDecodedMux->m_ColorTextureFlag[i]); CRender::g_pRender->SetCurrentTexture( tilenos[i], pEntry->pTexture, 4, 4, pEntry); } else { TxtrCacheEntry *pEntry = LoadTexture(tilenos[i]); if (pEntry && pEntry->pTexture ) { if( pEntry->txtrBufIdx <= 0 ) { if( pEntry->pEnhancedTexture && pEntry->dwEnhancementFlag == TEXTURE_EXTERNAL && !options.bLoadHiResTextures ) { SAFE_DELETE(pEntry->pEnhancedTexture); } if( pEntry->pEnhancedTexture == NULL ) { MirrorTexture(tilenos[i], pEntry);; } if( options.bLoadHiResTextures && (pEntry->pEnhancedTexture == NULL || pEntry->dwEnhancementFlag < TEXTURE_EXTERNAL ) ) { LoadHiresTexture(*pEntry); } if( pEntry->pEnhancedTexture == NULL || (pEntry->dwEnhancementFlag != options.textureEnhancement && pEntry->dwEnhancementFlag < TEXTURE_EXTERNAL ) ) { EnhanceTexture(pEntry); } } CRender::g_pRender->SetCurrentTexture( tilenos[i], (pEntry->pEnhancedTexture)?pEntry->pEnhancedTexture:pEntry->pTexture, pEntry->ti.WidthToLoad, pEntry->ti.HeightToLoad, pEntry); } else { pEntry = gTextureManager.GetBlackTexture(); CRender::g_pRender->SetCurrentTexture( tilenos[i], pEntry->pTexture, 4, 4, pEntry); _VIDEO_DisplayTemporaryMessage("Fail to load texture, use black to replace"); } } } gRDP.textureIsChanged = false; } } extern uint32 g_TxtLoadBy;; void DLParser_LoadTLut(Gfx *gfx) { gRDP.textureIsChanged = true; uint32 tileno = gfx->loadtile.tile; uint32 uls = gfx->loadtile.sl/4; uint32 ult = gfx->loadtile.tl/4; uint32 lrs = gfx->loadtile.sh/4; uint32 lrt = gfx->loadtile.th/4; #ifdef DEBUGGER uint32 dwTLutFmt = (gRDP.otherModeH >> RSP_SETOTHERMODE_SHIFT_TEXTLUT)&0x3; #endif uint32 dwCount; // starting location in the palettes uint32 dwTMEMOffset = gRDP.tiles[tileno].dwTMem - 256; // number to copy dwCount = ((uint16)((gfx->words.w1) >> 14) & 0x03FF) + 1; uint32 dwRDRAMOffset = 0; Tile &tile = gRDP.tiles[tileno]; tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false; tile.hilite_sl = tile.sl = uls; tile.hilite_tl = tile.tl = ult; tile.sh = lrs; tile.th = lrt; tile.bSizeIsValid = true; tile.lastTileCmd = CMD_LOADTLUT; #ifdef DEBUGGER /* if((((gfx->words.w0)>>12)&0x3) != 0 || (((gfx->words.w0))&0x3) != 0 || (((gfx->words.w1)>>12)&0x3) != 0 || (((gfx->words.w1))&0x3) != 0) TRACE0("Load tlut, sl,tl,sh,th are not integers"); */ #endif dwCount = (lrs - uls)+1; dwRDRAMOffset = (uls + ult*g_TI.dwWidth )*2; uint32 dwPalAddress = g_TI.dwAddr + dwRDRAMOffset; //Copy PAL to the PAL memory uint16 *srcPal = (uint16*)(g_pRDRAMu8 + (dwPalAddress& (g_dwRamSize-1)) ); for (uint32 i=0; iloadtile.tile; uint32 uls = gfx->loadtile.sl; uint32 ult = gfx->loadtile.tl; uint32 lrs = gfx->loadtile.sh; uint32 dxt = gfx->loadtile.th; // 1.11 fixed point Tile &tile = gRDP.tiles[tileno]; tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false; uint32 size = lrs+1; if( tile.dwSize == TXT_SIZE_32b ) size<<=1; SetTmemFlag(tile.dwTMem, size>>2); TMEMLoadMapInfo &info = g_tmemLoadAddrMap[tile.dwTMem]; info.bSwapped = (dxt == 0? TRUE : FALSE); info.sl = tile.hilite_sl = tile.sl = uls; info.sh = tile.hilite_sh = tile.sh = lrs; info.tl = tile.tl = ult; info.th = tile.th = dxt; tile.bSizeIsValid = false; for( int i=0; i<8; i++ ) { if( tile.dwTMem == tile.dwTMem ) tile.lastTileCmd = CMD_LOADBLOCK; } info.dwLoadAddress = g_TI.dwAddr; info.bSetBy = CMD_LOADBLOCK; info.dxt = dxt; info.dwLine = tile.dwLine; info.dwFormat = g_TI.dwFormat; info.dwSize = g_TI.dwSize; info.dwWidth = g_TI.dwWidth; info.dwTotalWords = size; info.dwTmem = tile.dwTMem; if( gRDP.tiles[tileno].dwTMem == 0 ) { if( size >= 1024 ) { memcpy(&g_tmemInfo0, &info, sizeof(TMEMLoadMapInfo) ); g_tmemInfo0.dwTotalWords = size>>2; } if( size == 2048 ) { memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) ); g_tmemInfo1.dwTotalWords = size>>2; } } else if( tile.dwTMem == 0x100 ) { if( size == 1024 ) { memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) ); g_tmemInfo1.dwTotalWords = size>>2; } } g_TxtLoadBy = CMD_LOADBLOCK; if( options.bUseFullTMEM ) { uint32 bytes = (lrs + 1) << tile.dwSize >> 1; uint32 address = g_TI.dwAddr + ult * g_TI.bpl + (uls << g_TI.dwSize >> 1); if ((bytes == 0) || ((address + bytes) > g_dwRamSize) || (((tile.dwTMem << 3) + bytes) > 4096)) { return; } uint64* src = (uint64*)(g_pRDRAMu8+address); uint64* dest = &g_Tmem.g_Tmem64bit[tile.dwTMem]; if( dxt > 0) { void (*Interleave)( void *mem, uint32 numDWords ); uint32 line = (2047 + dxt) / dxt; uint32 bpl = line << 3; uint32 height = bytes / bpl; if (tile.dwSize == TXT_SIZE_32b) Interleave = QWordInterleave; else Interleave = DWordInterleave; for (uint32 y = 0; y < height; y++) { UnswapCopy( src, dest, bpl ); if (y & 1) Interleave( dest, line ); src += line; dest += line; } } else UnswapCopy( src, dest, bytes ); } LOG_UCODE(" Tile:%d (%d,%d - %d) DXT:0x%04x\n", tileno, uls, ult, lrs, dxt); LOG_TEXTURE( { DebuggerAppendMsg("LoadBlock:%d (%d,%d,%d) DXT:0x%04x(%X)\n", tileno, uls, ult, (((gfx->words.w1)>>12)&0x0FFF), dxt, ((gfx->words.w1)&0x0FFF)); }); DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD); } void swap(uint32 &a, uint32 &b) { uint32 temp = a; a = b; b = temp; } void DLParser_LoadTile(Gfx *gfx) { gRDP.textureIsChanged = true; uint32 tileno = gfx->loadtile.tile; uint32 uls = gfx->loadtile.sl/4; uint32 ult = gfx->loadtile.tl/4; uint32 lrs = gfx->loadtile.sh/4; uint32 lrt = gfx->loadtile.th/4; Tile &tile = gRDP.tiles[tileno]; tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false; if (lrt < ult) swap(lrt, ult); if (lrs < uls) swap(lrs, uls); tile.hilite_sl = tile.sl = uls; tile.hilite_tl = tile.tl = ult; tile.hilite_sh = tile.sh = lrs; tile.hilite_th = tile.th = lrt; tile.bSizeIsValid = true; // compute block height, and bpl of source and destination uint32 bpl = (lrs - uls + 1) << tile.dwSize >> 1; uint32 height = lrt - ult + 1; uint32 line = tile.dwLine; if (tile.dwSize == TXT_SIZE_32b) line <<= 1; if (((tile.dwTMem << 3) + line * height) > 4096) // check destination ending point (TMEM is 4k bytes) return; if( options.bUseFullTMEM ) { void (*Interleave)( void *mem, uint32 numDWords ); uint32 address, y; uint64 *dest; uint8 *src; if( g_TI.bpl == 0 ) { if( options.enableHackForGames == HACK_FOR_BUST_A_MOVE ) { g_TI.bpl = 1024; // Hack for Bust-A-Move } else { TRACE0("Warning: g_TI.bpl = 0" ); } } address = g_TI.dwAddr + tile.tl * g_TI.bpl + (tile.sl << g_TI.dwSize >> 1); src = &g_pRDRAMu8[address]; dest = &g_Tmem.g_Tmem64bit[tile.dwTMem]; if ((address + height * bpl) > g_dwRamSize) // check source ending point { return; } // Line given for 32-bit is half what it seems it should since they split the // high and low words. I'm cheating by putting them together. if (tile.dwSize == TXT_SIZE_32b) { Interleave = QWordInterleave; } else { Interleave = DWordInterleave; } if( tile.dwLine == 0 ) { //tile.dwLine = 1; return; } for (y = 0; y < height; y++) { UnswapCopy( src, dest, bpl ); if (y & 1) Interleave( dest, line ); src += g_TI.bpl; dest += line; } } for( int i=0; i<8; i++ ) { if( gRDP.tiles[i].dwTMem == tile.dwTMem ) gRDP.tiles[i].lastTileCmd = CMD_LOADTILE; } uint32 size = line * height; SetTmemFlag(tile.dwTMem,size ); LOG_TEXTURE( { DebuggerAppendMsg("LoadTile:%d (%d,%d) -> (%d,%d) [%d x %d]\n", tileno, uls, ult, lrs, lrt, (lrs - uls)+1, (lrt - ult)+1); }); DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD); LOG_UCODE(" Tile:%d (%d,%d) -> (%d,%d) [%d x %d]", tileno, uls, ult, lrs, lrt, (lrs - uls)+1, (lrt - ult)+1); TMEMLoadMapInfo &info = g_tmemLoadAddrMap[tile.dwTMem]; info.dwLoadAddress = g_TI.dwAddr; info.dwFormat = g_TI.dwFormat; info.dwSize = g_TI.dwSize; info.dwWidth = g_TI.dwWidth; info.sl = uls; info.sh = lrs; info.tl = ult; info.th = lrt; info.dxt = 0; info.dwLine = tile.dwLine; info.dwTmem = tile.dwTMem; info.dwTotalWords = size<<2; info.bSetBy = CMD_LOADTILE; info.bSwapped =FALSE; g_TxtLoadBy = CMD_LOADTILE; if( tile.dwTMem == 0 ) { if( size >= 256 ) { memcpy(&g_tmemInfo0, &info, sizeof(TMEMLoadMapInfo) ); g_tmemInfo0.dwTotalWords = size; } if( size == 512 ) { memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) ); g_tmemInfo1.dwTotalWords = size; } } else if( tile.dwTMem == 0x100 ) { if( size == 256 ) { memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) ); g_tmemInfo1.dwTotalWords = size; } } } const char *pszOnOff[2] = {"Off", "On"}; uint32 lastSetTile; void DLParser_SetTile(Gfx *gfx) { gRDP.textureIsChanged = true; uint32 tileno = gfx->settile.tile; Tile &tile = gRDP.tiles[tileno]; tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false; lastSetTile = tileno; tile.dwFormat = gfx->settile.fmt; tile.dwSize = gfx->settile.siz; tile.dwLine = gfx->settile.line; tile.dwTMem = gfx->settile.tmem; tile.dwPalette = gfx->settile.palette; tile.bClampT = gfx->settile.ct; tile.bMirrorT = gfx->settile.mt; tile.dwMaskT = gfx->settile.maskt; tile.dwShiftT = gfx->settile.shiftt; tile.bClampS = gfx->settile.cs; tile.bMirrorS = gfx->settile.ms; tile.dwMaskS = gfx->settile.masks; tile.dwShiftS = gfx->settile.shifts; tile.fShiftScaleS = 1.0f; if( tile.dwShiftS ) { if( tile.dwShiftS > 10 ) { tile.fShiftScaleS = (float)(1 << (16 - tile.dwShiftS)); } else { tile.fShiftScaleS = (float)1.0f/(1 << tile.dwShiftS); } } tile.fShiftScaleT = 1.0f; if( tile.dwShiftT ) { if( tile.dwShiftT > 10 ) { tile.fShiftScaleT = (float)(1 << (16 - tile.dwShiftT)); } else { tile.fShiftScaleT = (float)1.0f/(1 << tile.dwShiftT); } } // Hack for DK64 /* if( tile.dwMaskS > 0 && tile.dwMaskT > 0 && tile.dwMaskS < 8 && tile.dwMaskT < 8 ) { tile.sh = tile.sl + (1<loadtile.tile; int sl = gfx->loadtile.sl; int tl = gfx->loadtile.tl; int sh = gfx->loadtile.sh; int th = gfx->loadtile.th; Tile &tile = gRDP.tiles[tileno]; tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false; if( options.bUseFullTMEM ) { tile.bSizeIsValid = true; tile.hilite_sl = tile.sl = sl / 4; tile.hilite_tl = tile.tl = tl / 4; tile.hilite_sh = tile.sh = sh / 4; tile.hilite_th = tile.th = th / 4; tile.fhilite_sl = tile.fsl = sl / 4.0f; tile.fhilite_tl = tile.ftl = tl / 4.0f; tile.fhilite_sh = tile.fsh = sh / 4.0f; tile.fhilite_th = tile.fth = th / 4.0f; tile.lastTileCmd = CMD_SETTILE_SIZE; } else { if( tile.lastTileCmd != CMD_SETTILE_SIZE ) { tile.bSizeIsValid = true; if( sl/4 > sh/4 || tl/4 > th/4 || (sh == 0 && tile.dwShiftS==0 && th == 0 && tile.dwShiftT ==0 ) ) { #ifdef DEBUGGER if( sl != 0 || tl != 0 || sh != 0 || th != 0 ) { if( tile.dwMaskS==0 || tile.dwMaskT==0 ) TRACE0("Check me, setTileSize is not correct"); } #endif tile.bSizeIsValid = false; } tile.hilite_sl = tile.sl = sl / 4; tile.hilite_tl = tile.tl = tl / 4; tile.hilite_sh = tile.sh = sh / 4; tile.hilite_th = tile.th = th / 4; tile.fhilite_sl = tile.fsl = sl / 4.0f; tile.fhilite_tl = tile.ftl = tl / 4.0f; tile.fhilite_sh = tile.fsh = sh / 4.0f; tile.fhilite_th = tile.fth = th / 4.0f; tile.lastTileCmd = CMD_SETTILE_SIZE; } else { tile.fhilite_sh = tile.fsh; tile.fhilite_th = tile.fth; tile.fhilite_sl = tile.fsl = (sl>0x7ff ? (sl-0xfff) : sl)/4.0f; tile.fhilite_tl = tile.ftl = (tl>0x7ff ? (tl-0xfff) : tl)/4.0f; tile.hilite_sl = sl>0x7ff ? (sl-0xfff) : sl; tile.hilite_tl = tl>0x7ff ? (tl-0xfff) : tl; tile.hilite_sl /= 4; tile.hilite_tl /= 4; tile.hilite_sh = sh/4; tile.hilite_th = th/4; tile.lastTileCmd = CMD_SETTILE_SIZE; } } LOG_TEXTURE( { DebuggerAppendMsg("SetTileSize:%d (%d/4,%d/4) -> (%d/4,%d/4) [%d x %d]\n", tileno, sl, tl, sh, th, ((sh/4) - (sl/4)) + 1, ((th/4) - (tl/4)) + 1); }); DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD); LOG_UCODE(" Tile:%d (%d,%d) -> (%d,%d) [%d x %d]", tileno, sl/4, tl/4, sh/4, th/4, ((sh/4) - (sl/4)) + 1, ((th/4) - (tl/4)) + 1); } extern const char *pszImgFormat[8];// = {"RGBA", "YUV", "CI", "IA", "I", "?1", "?2", "?3"}; extern const char *pszImgSize[4];// = {"4", "8", "16", "32"}; void DLParser_SetTImg(Gfx *gfx) { gRDP.textureIsChanged = true; g_TI.dwFormat = gfx->setimg.fmt; g_TI.dwSize = gfx->setimg.siz; g_TI.dwWidth = gfx->setimg.width + 1; g_TI.dwAddr = RSPSegmentAddr((gfx->setimg.addr)); g_TI.bpl = g_TI.dwWidth << g_TI.dwSize >> 1; #ifdef DEBUGGER if( g_TI.dwAddr == 0x00ffffff) { TRACE0("Check me here in setTimg"); } LOG_TEXTURE(TRACE4("SetTImage: 0x%08x Fmt: %s/%s Width in Pixel: %d\n", g_TI.dwAddr, pszImgFormat[g_TI.dwFormat], pszImgSize[g_TI.dwSize], g_TI.dwWidth)); DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD); LOG_UCODE("Image: 0x%08x Fmt: %s/%s Width in Pixel: %d", g_TI.dwAddr, pszImgFormat[g_TI.dwFormat], pszImgSize[g_TI.dwSize], g_TI.dwWidth); #endif } void DLParser_TexRect(Gfx *gfx) { //Gtexrect *gtextrect = (Gtexrect *)gfx; if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); status.primitiveType = PRIM_TEXTRECT; // This command used 128bits, and not 64 bits. This means that we have to look one // Command ahead in the buffer, and update the PC. uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4+8); uint32 dwHalf1 = *(uint32 *)(g_pRDRAMu8 + dwPC); uint32 dwHalf2 = *(uint32 *)(g_pRDRAMu8 + dwPC+8); if( options.enableHackForGames == HACK_FOR_ALL_STAR_BASEBALL || options.enableHackForGames == HACK_FOR_MLB ) { if( ((dwHalf1>>24) == 0xb4 || (dwHalf1>>24) == 0xb3 || (dwHalf1>>24) == 0xb2 || (dwHalf1>>24) == 0xe1) && ((dwHalf2>>24) == 0xb4 || (dwHalf2>>24) == 0xb3 || (dwHalf2>>24) == 0xb2 || (dwHalf2>>24) == 0xf1) ) { // Increment PC so that it points to the right place gDlistStack[gDlistStackPointer].pc += 16; } else { // Hack for some games, All_Star_Baseball_2000 gDlistStack[gDlistStackPointer].pc += 8; dwCmd3 = dwCmd2; //dwCmd2 = dwHalf1; //dwCmd2 = 0; // fix me here dwCmd2 = (((dwHalf1>>12)&0x03FF)<<17) | (((dwHalf1)&0x03FF)<<1); } } else { gDlistStack[gDlistStackPointer].pc += 16; } // Hack for Mario Tennis if( !status.bHandleN64RenderTexture && g_CI.dwAddr == g_ZI.dwAddr ) { return; } LOG_UCODE("0x%08x: %08x %08x", dwPC, *(uint32 *)(g_pRDRAMu8 + dwPC+0), *(uint32 *)(g_pRDRAMu8 + dwPC+4)); LOG_UCODE("0x%08x: %08x %08x", dwPC+8, *(uint32 *)(g_pRDRAMu8 + dwPC+8), *(uint32 *)(g_pRDRAMu8 + dwPC+8+4)); uint32 dwXH = (((gfx->words.w0)>>12)&0x0FFF)/4; uint32 dwYH = (((gfx->words.w0) )&0x0FFF)/4; uint32 tileno = ((gfx->words.w1)>>24)&0x07; uint32 dwXL = (((gfx->words.w1)>>12)&0x0FFF)/4; uint32 dwYL = (((gfx->words.w1) )&0x0FFF)/4; uint16 uS = (uint16)( dwCmd2>>16)&0xFFFF; uint16 uT = (uint16)( dwCmd2 )&0xFFFF; uint16 uDSDX = (uint16)(( dwCmd3>>16)&0xFFFF); uint16 uDTDY = (uint16)(( dwCmd3 )&0xFFFF); if( (int)dwXL >= gRDP.scissor.right || (int)dwYL >= gRDP.scissor.bottom || (int)dwXH < gRDP.scissor.left || (int)dwYH < gRDP.scissor.top ) { // Clipping return; } short s16S = *(short*)(&uS); short s16T = *(short*)(&uT); short s16DSDX = *(short*)(&uDSDX); short s16DTDY = *(short*)(&uDTDY); uint32 curTile = gRSP.curTile; ForceMainTextureIndex(tileno); float fS0 = s16S / 32.0f; float fT0 = s16T / 32.0f; float fDSDX = s16DSDX / 1024.0f; float fDTDY = s16DTDY / 1024.0f; uint32 cycletype = gRDP.otherMode.cycle_type; if (cycletype == CYCLE_TYPE_COPY) { fDSDX /= 4.0f; // In copy mode 4 pixels are copied at once. dwXH++; dwYH++; } else if (cycletype == CYCLE_TYPE_FILL) { dwXH++; dwYH++; } if( fDSDX == 0 ) fDSDX = 1; if( fDTDY == 0 ) fDTDY = 1; float fS1 = fS0 + (fDSDX * (dwXH - dwXL)); float fT1 = fT0 + (fDTDY * (dwYH - dwYL)); LOG_UCODE(" Tile:%d Screen(%d,%d) -> (%d,%d)", tileno, dwXL, dwYL, dwXH, dwYH); LOG_UCODE(" Tex:(%#5f,%#5f) -> (%#5f,%#5f) (DSDX:%#5f DTDY:%#5f)", fS0, fT0, fS1, fT1, fDSDX, fDTDY); LOG_UCODE(""); float t0u0 = (fS0-gRDP.tiles[tileno].hilite_sl) * gRDP.tiles[tileno].fShiftScaleS; float t0v0 = (fT0-gRDP.tiles[tileno].hilite_tl) * gRDP.tiles[tileno].fShiftScaleT; float t0u1 = t0u0 + (fDSDX * (dwXH - dwXL))*gRDP.tiles[tileno].fShiftScaleS; float t0v1 = t0v0 + (fDTDY * (dwYH - dwYL))*gRDP.tiles[tileno].fShiftScaleT; if( dwXL==0 && dwYL==0 && dwXH==windowSetting.fViWidth-1 && dwYH==windowSetting.fViHeight-1 && t0u0 == 0 && t0v0==0 && t0u1==0 && t0v1==0 ) { //Using TextRect to clear the screen } else { if( status.bHandleN64RenderTexture && //status.bDirectWriteIntoRDRAM && g_pRenderTextureInfo->CI_Info.dwFormat == gRDP.tiles[tileno].dwFormat && g_pRenderTextureInfo->CI_Info.dwSize == gRDP.tiles[tileno].dwSize && gRDP.tiles[tileno].dwFormat == TXT_FMT_CI && gRDP.tiles[tileno].dwSize == TXT_SIZE_8b ) { if( options.enableHackForGames == HACK_FOR_YOSHI ) { // Hack for Yoshi background image PrepareTextures(); TexRectToFrameBuffer_8b(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_FLUSH_TRI || eventToPause == NEXT_TEXTRECT), { DebuggerAppendMsg("TexRect: tile=%d, X0=%d, Y0=%d, X1=%d, Y1=%d,\nfS0=%f, fT0=%f, ScaleS=%f, ScaleT=%f\n", gRSP.curTile, dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY); DebuggerAppendMsg("Pause after TexRect for Yoshi\n"); }); } else { if( frameBufferOptions.bUpdateCIInfo ) { PrepareTextures(); TexRectToFrameBuffer_8b(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno); } if( !status.bDirectWriteIntoRDRAM ) { CRender::g_pRender->TexRect(dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY); status.dwNumTrisRendered += 2; } } } else { CRender::g_pRender->TexRect(dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY); status.bFrameBufferDrawnByTriangles = true; status.dwNumTrisRendered += 2; } } if( status.bHandleN64RenderTexture ) g_pRenderTextureInfo->maxUsedHeight = max(g_pRenderTextureInfo->maxUsedHeight,(int)dwYH); ForceMainTextureIndex(curTile); } void DLParser_TexRectFlip(Gfx *gfx) { status.bCIBufferIsRendered = true; status.primitiveType = PRIM_TEXTRECTFLIP; // This command used 128bits, and not 64 bits. This means that we have to look one // Command ahead in the buffer, and update the PC. uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4+8); // Increment PC so that it points to the right place gDlistStack[gDlistStackPointer].pc += 16; uint32 dwXH = (((gfx->words.w0)>>12)&0x0FFF)/4; uint32 dwYH = (((gfx->words.w0) )&0x0FFF)/4; uint32 tileno = ((gfx->words.w1)>>24)&0x07; uint32 dwXL = (((gfx->words.w1)>>12)&0x0FFF)/4; uint32 dwYL = (((gfx->words.w1) )&0x0FFF)/4; uint32 dwS = ( dwCmd2>>16)&0xFFFF; uint32 dwT = ( dwCmd2 )&0xFFFF; int nDSDX = (int)(short)(( dwCmd3>>16)&0xFFFF); int nDTDY = (int)(short)(( dwCmd3 )&0xFFFF); uint32 curTile = gRSP.curTile; ForceMainTextureIndex(tileno); float fS0 = (float)dwS / 32.0f; float fT0 = (float)dwT / 32.0f; float fDSDX = (float)nDSDX / 1024.0f; float fDTDY = (float)nDTDY / 1024.0f; uint32 cycletype = gRDP.otherMode.cycle_type; if (cycletype == CYCLE_TYPE_COPY) { fDSDX /= 4.0f; // In copy mode 4 pixels are copied at once. dwXH++; dwYH++; } else if (cycletype == CYCLE_TYPE_FILL) { dwXH++; dwYH++; } float fS1 = fS0 + (fDSDX * (dwYH - dwYL)); float fT1 = fT0 + (fDTDY * (dwXH - dwXL)); LOG_UCODE(" Tile:%d (%d,%d) -> (%d,%d)", tileno, dwXL, dwYL, dwXH, dwYH); LOG_UCODE(" Tex:(%#5f,%#5f) -> (%#5f,%#5f) (DSDX:%#5f DTDY:%#5f)", fS0, fT0, fS1, fT1, fDSDX, fDTDY); LOG_UCODE(""); float t0u0 = (fS0) * gRDP.tiles[tileno].fShiftScaleS-gRDP.tiles[tileno].sl; float t0v0 = (fT0) * gRDP.tiles[tileno].fShiftScaleT-gRDP.tiles[tileno].tl; float t0u1 = t0u0 + (fDSDX * (dwYH - dwYL))*gRDP.tiles[tileno].fShiftScaleS; float t0v1 = t0v0 + (fDTDY * (dwXH - dwXL))*gRDP.tiles[tileno].fShiftScaleT; CRender::g_pRender->TexRectFlip(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1); status.dwNumTrisRendered += 2; if( status.bHandleN64RenderTexture ) g_pRenderTextureInfo->maxUsedHeight = max(g_pRenderTextureInfo->maxUsedHeight,int(dwYL+(dwXH-dwXL))); ForceMainTextureIndex(curTile); } /************************************************************************/ /* */ /************************************************************************/ /* * TMEM emulation * There are 0x200's 64bits entry in TMEM * Usually, textures are loaded into TMEM at 0x0, and TLUT is loaded at 0x100 * of course, the whole TMEM can be used by textures if TLUT is not used, and TLUT * can be at other address of TMEM. * * We don't want to emulate TMEM by creating a block of memory for TMEM and load * everything into the block of memory, this will be slow. */ typedef struct TmemInfoEntry{ uint32 start; uint32 length; uint32 rdramAddr; TmemInfoEntry* next; } TmemInfoEntry; const int tmenMaxEntry=20; TmemInfoEntry tmenEntryBuffer[20]={{0}}; TmemInfoEntry *g_pTMEMInfo=NULL; TmemInfoEntry *g_pTMEMFreeList=tmenEntryBuffer; void TMEM_Init() { g_pTMEMInfo=NULL; g_pTMEMFreeList=tmenEntryBuffer; int i; for( i=0; inext; p->start = tmemstart; p->length = length; p->rdramAddr = rdramaddr; p->next = NULL; } else { while ( tmemstart > (p->start+p->length) ) { if( p->next != NULL ) { p = p->next; continue; } else { break; } } if ( p->start == tmemstart ) { // need to replace the block of 'p' // or append a new block depend the block lengths if( length == p->length ) { p->rdramAddr = rdramaddr; return; } else if( length < p->length ) { TmemInfoEntry *newentry = g_pTMEMFreeList; g_pTMEMFreeList = g_pTMEMFreeList->next; newentry->length = p->length - length; newentry->next = p->next; newentry->rdramAddr = p->rdramAddr + p->length; newentry->start = p->start + p->length; p->length = length; p->next = newentry; p->rdramAddr = rdramaddr; } } else if( p->start > tmemstart ) { // p->start > tmemstart, need to insert the new block before 'p' TmemInfoEntry *newentry = g_pTMEMFreeList; g_pTMEMFreeList = g_pTMEMFreeList->next; if( length+tmemstart < p->start+p->length ) { newentry->length = p->length - length; newentry->next = p->next; newentry->rdramAddr = p->rdramAddr + p->length; newentry->start = p->start + p->length; p->length = length; p->next = newentry; p->rdramAddr = rdramaddr; p->start = tmemstart; } else if( length+tmemstart == p->start+p->length ) { } } else { } } } uint32 TMEM_GetRdramAddr(uint32 tmemstart, uint32 length) { return 0; } /* * New implementation of texture loading */ bool IsTmemFlagValid(uint32 tmemAddr) { uint32 index = tmemAddr>>5; uint32 bitIndex = (tmemAddr&0x1F); return ((g_TmemFlag[index] & (1<>5; uint32 bitIndex = (tmemAddr&0x1F); if ((g_TmemFlag[index] & (1<>5; uint32 bitIndex = (tmemAddr&0x1F); #ifdef DEBUGGER if( size > 0x200 ) { DebuggerAppendMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size); size = 0x200-tmemAddr; } #endif if( bitIndex == 0 ) { uint32 i; for( i=0; i< (size>>5); i++ ) { g_TmemFlag[index+i] = 0; } if( (size&0x1F) != 0 ) { //ErrorMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size); g_TmemFlag[index+i] &= ~((1<<(size&0x1F))-1); } g_TmemFlag[index] |= 1; } else { if( bitIndex + size <= 0x1F ) { uint32 val = g_TmemFlag[index]; uint32 mask = (1<<(bitIndex))-1; mask |= ~((1<<(bitIndex + size))-1); val &= mask; val |= (1<>5); i++ ) { g_TmemFlag[index+i] = 0; } if( (size&0x1F) != 0 ) { //ErrorMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size); g_TmemFlag[index+i] &= ~((1<<(size&0x1F))-1); } } } } mupen64plus-video-rice-src-2.0/src/RSP_GBI0.h0000644000000000000000000006422312165031100016655 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "Render.h" #include "Timing.h" void RSP_GBI1_SpNoop(Gfx *gfx) { SP_Timing(RSP_GBI1_SpNoop); if( (gfx+1)->words.cmd == 0x00 && gRSP.ucode >= 17 ) { RSP_RDP_NOIMPL("Double SPNOOP, Skip remain ucodes, PC=%08X, Cmd1=%08X", gDlistStack[gDlistStackPointer].pc, gfx->words.w1); RDP_GFX_PopDL(); //if( gRSP.ucode < 17 ) TriggerDPInterrupt(); } } void RSP_GBI0_Mtx(Gfx *gfx) { SP_Timing(RSP_GBI0_Mtx); uint32 addr = RSPSegmentAddr((gfx->gbi0matrix.addr)); LOG_UCODE(" Command: %s %s %s Length %d Address 0x%08x", gfx->gbi0matrix.projection == 1 ? "Projection" : "ModelView", gfx->gbi0matrix.load == 1 ? "Load" : "Mul", gfx->gbi0matrix.push == 1 ? "Push" : "NoPush", gfx->gbi0matrix.len, addr); if (addr + 64 > g_dwRamSize) { TRACE1("Mtx: Address invalid (0x%08x)", addr); return; } LoadMatrix(addr); if (gfx->gbi0matrix.projection) { CRender::g_pRender->SetProjection(matToLoad, gfx->gbi0matrix.push, gfx->gbi0matrix.load); } else { CRender::g_pRender->SetWorldView(matToLoad, gfx->gbi0matrix.push, gfx->gbi0matrix.load); } #ifdef DEBUGGER const char *loadstr = gfx->gbi0matrix.load == 1 ? "Load" : "Mul"; const char *pushstr = gfx->gbi0matrix.push == 1 ? "Push" : "Nopush"; int projlevel = CRender::g_pRender->GetProjectMatrixLevel(); int worldlevel = CRender::g_pRender->GetWorldViewMatrixLevel(); if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) { pauseAtNext = false; debuggerPause = true; if (gfx->gbi0matrix.projection) { TRACE3("Pause after %s and %s Matrix: Projection, level=%d\n", loadstr, pushstr, projlevel ); } else { TRACE3("Pause after %s and %s Matrix: WorldView level=%d\n", loadstr, pushstr, worldlevel); } } else { if( pauseAtNext && logMatrix ) { if (gfx->gbi0matrix.projection) { TRACE3("Matrix: %s and %s Projection level=%d\n", loadstr, pushstr, projlevel); } else { TRACE3("Matrix: %s and %s WorldView\n level=%d", loadstr, pushstr, worldlevel); } } } #endif } void RSP_GBI1_Reserved(Gfx *gfx) { SP_Timing(RSP_GBI1_Reserved); RSP_RDP_NOIMPL("RDP: Reserved (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); } void RSP_GBI1_MoveMem(Gfx *gfx) { SP_Timing(RSP_GBI1_MoveMem); uint32 type = ((gfx->words.w0)>>16)&0xFF; uint32 dwLength = ((gfx->words.w0))&0xFFFF; uint32 addr = RSPSegmentAddr((gfx->words.w1)); switch (type) { case RSP_GBI1_MV_MEM_VIEWPORT: { LOG_UCODE(" RSP_GBI1_MV_MEM_VIEWPORT. Address: 0x%08x, Length: 0x%04x", addr, dwLength); RSP_MoveMemViewport(addr); } break; case RSP_GBI1_MV_MEM_LOOKATY: LOG_UCODE(" RSP_GBI1_MV_MEM_LOOKATY"); break; case RSP_GBI1_MV_MEM_LOOKATX: LOG_UCODE(" RSP_GBI1_MV_MEM_LOOKATX"); break; case RSP_GBI1_MV_MEM_L0: case RSP_GBI1_MV_MEM_L1: case RSP_GBI1_MV_MEM_L2: case RSP_GBI1_MV_MEM_L3: case RSP_GBI1_MV_MEM_L4: case RSP_GBI1_MV_MEM_L5: case RSP_GBI1_MV_MEM_L6: case RSP_GBI1_MV_MEM_L7: { uint32 dwLight = (type-RSP_GBI1_MV_MEM_L0)/2; LOG_UCODE(" RSP_GBI1_MV_MEM_L%d", dwLight); LOG_UCODE(" Light%d: Length:0x%04x, Address: 0x%08x", dwLight, dwLength, addr); RSP_MoveMemLight(dwLight, addr); } break; case RSP_GBI1_MV_MEM_TXTATT: LOG_UCODE(" RSP_GBI1_MV_MEM_TXTATT"); break; case RSP_GBI1_MV_MEM_MATRIX_1: RSP_GFX_Force_Matrix(addr); break; case RSP_GBI1_MV_MEM_MATRIX_2: break; case RSP_GBI1_MV_MEM_MATRIX_3: break; case RSP_GBI1_MV_MEM_MATRIX_4: break; default: RSP_RDP_NOIMPL("MoveMem: Unknown Move Type, cmd=%08X, %08X", gfx->words.w0, gfx->words.w1); break; } } void RSP_GBI0_Vtx(Gfx *gfx) { SP_Timing(RSP_GBI0_Vtx); int n = gfx->gbi0vtx.n + 1; int v0 = gfx->gbi0vtx.v0; uint32 addr = RSPSegmentAddr((gfx->gbi0vtx.addr)); LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d, Length: 0x%04x", addr, v0, n, gfx->gbi0vtx.len); if ((v0 + n) > 80) { TRACE3("Warning, invalid vertex positions, N=%d, v0=%d, Addr=0x%08X", n, v0, addr); n = 32 - v0; } // Check that address is valid... if ((addr + n*16) > g_dwRamSize) { TRACE1("Vertex Data: Address out of range (0x%08x)", addr); } else { ProcessVertexData(addr, v0, n); status.dwNumVertices += n; DisplayVertexInfo(addr, v0, n); } } void RSP_GBI0_DL(Gfx *gfx) { SP_Timing(RSP_GBI0_DL); uint32 addr = RSPSegmentAddr((gfx->gbi0dlist.addr)) & (g_dwRamSize-1); LOG_UCODE(" Address=0x%08x Push: 0x%02x", addr, gfx->gbi0dlist.param); if( addr > g_dwRamSize ) { RSP_RDP_NOIMPL("Error: DL addr = %08X out of range, PC=%08X", addr, gDlistStack[gDlistStackPointer].pc ); addr &= (g_dwRamSize-1); DebuggerPauseCountN( NEXT_DLIST ); } if( gfx->gbi0dlist.param == RSP_DLIST_PUSH ) gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = addr; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; LOG_UCODE("Level=%d", gDlistStackPointer+1); LOG_UCODE("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); } void RSP_GBI1_RDPHalf_Cont(Gfx *gfx) { SP_Timing(RSP_GBI1_RDPHalf_Cont); LOG_UCODE("RDPHalf_Cont: (Ignored)"); } void RSP_GBI1_RDPHalf_2(Gfx *gfx) { SP_Timing(RSP_GBI1_RDPHalf_2); LOG_UCODE("RDPHalf_2: (Ignored)"); } void RSP_GBI1_RDPHalf_1(Gfx *gfx) { SP_Timing(RSP_GBI1_RDPHalf_1); LOG_UCODE("RDPHalf_1: (Ignored)"); } void RSP_GBI1_Line3D(Gfx *gfx) { status.primitiveType = PRIM_LINE3D; uint32 dwPC = gDlistStack[gDlistStackPointer].pc; BOOL bTrisAdded = FALSE; if( gfx->ln3dtri2.v3 == 0 ) { // Flying Dragon uint32 dwV0 = gfx->ln3dtri2.v0/gRSP.vertexMult; uint32 dwV1 = gfx->ln3dtri2.v1/gRSP.vertexMult; uint32 dwWidth = gfx->ln3dtri2.v2; //uint32 dwFlag = gfx->ln3dtri2.v3/gRSP.vertexMult; CRender::g_pRender->SetCombinerAndBlender(); status.dwNumTrisRendered++; CRender::g_pRender->Line3D(dwV0, dwV1, dwWidth); SP_Timing(RSP_GBI1_Line3D); DP_Timing(RSP_GBI1_Line3D); } else { do { uint32 dwV3 = gfx->ln3dtri2.v3/gRSP.vertexMult; uint32 dwV0 = gfx->ln3dtri2.v0/gRSP.vertexMult; uint32 dwV1 = gfx->ln3dtri2.v1/gRSP.vertexMult; uint32 dwV2 = gfx->ln3dtri2.v2/gRSP.vertexMult; LOG_UCODE(" Line3D: V0: %d, V1: %d, V2: %d, V3: %d", dwV0, dwV1, dwV2, dwV3); // Do first tri if (IsTriangleVisible(dwV0, dwV1, dwV2)) { DEBUG_DUMP_VERTEXES("Line3D 1/2", dwV0, dwV1, dwV2); if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } if( !bTrisAdded ) { CRender::g_pRender->SetCombinerAndBlender(); } bTrisAdded = true; PrepareTriangle(dwV0, dwV1, dwV2); } // Do second tri if (IsTriangleVisible(dwV2, dwV3, dwV0)) { DEBUG_DUMP_VERTEXES("Line3D 2/2", dwV0, dwV1, dwV2); if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } if( !bTrisAdded ) { CRender::g_pRender->SetCombinerAndBlender(); } bTrisAdded = true; PrepareTriangle(dwV2, dwV3, dwV0); } gfx++; dwPC += 8; #ifdef DEBUGGER } while (gfx->words.cmd == (uint8)RSP_LINE3D && !(pauseAtNext && eventToPause==NEXT_FLUSH_TRI)); #else } while (gfx->words.cmd == (uint8)RSP_LINE3D); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->DrawTriangles(); } } } void RSP_GBI1_ClearGeometryMode(Gfx *gfx) { SP_Timing(RSP_GBI1_ClearGeometryMode); uint32 dwMask = ((gfx->words.w1)); #ifdef DEBUGGER LOG_UCODE(" Mask=0x%08x", dwMask); if (dwMask & G_ZBUFFER) LOG_UCODE(" Disabling ZBuffer"); if (dwMask & G_TEXTURE_ENABLE) LOG_UCODE(" Disabling Texture"); if (dwMask & G_SHADE) LOG_UCODE(" Disabling Shade"); if (dwMask & G_SHADING_SMOOTH) LOG_UCODE(" Disabling Smooth Shading"); if (dwMask & G_CULL_FRONT) LOG_UCODE(" Disabling Front Culling"); if (dwMask & G_CULL_BACK) LOG_UCODE(" Disabling Back Culling"); if (dwMask & G_FOG) LOG_UCODE(" Disabling Fog"); if (dwMask & G_LIGHTING) LOG_UCODE(" Disabling Lighting"); if (dwMask & G_TEXTURE_GEN) LOG_UCODE(" Disabling Texture Gen"); if (dwMask & G_TEXTURE_GEN_LINEAR) LOG_UCODE(" Disabling Texture Gen Linear"); if (dwMask & G_LOD) LOG_UCODE(" Disabling LOD (no impl)"); #endif gRDP.geometryMode &= ~dwMask; RSP_GFX_InitGeometryMode(); } void RSP_GBI1_SetGeometryMode(Gfx *gfx) { SP_Timing(RSP_GBI1_SetGeometryMode); uint32 dwMask = ((gfx->words.w1)); #ifdef DEBUGGER LOG_UCODE(" Mask=0x%08x", dwMask); if (dwMask & G_ZBUFFER) LOG_UCODE(" Enabling ZBuffer"); if (dwMask & G_TEXTURE_ENABLE) LOG_UCODE(" Enabling Texture"); if (dwMask & G_SHADE) LOG_UCODE(" Enabling Shade"); if (dwMask & G_SHADING_SMOOTH) LOG_UCODE(" Enabling Smooth Shading"); if (dwMask & G_CULL_FRONT) LOG_UCODE(" Enabling Front Culling"); if (dwMask & G_CULL_BACK) LOG_UCODE(" Enabling Back Culling"); if (dwMask & G_FOG) LOG_UCODE(" Enabling Fog"); if (dwMask & G_LIGHTING) LOG_UCODE(" Enabling Lighting"); if (dwMask & G_TEXTURE_GEN) LOG_UCODE(" Enabling Texture Gen"); if (dwMask & G_TEXTURE_GEN_LINEAR) LOG_UCODE(" Enabling Texture Gen Linear"); if (dwMask & G_LOD) LOG_UCODE(" Enabling LOD (no impl)"); #endif // DEBUGGER gRDP.geometryMode |= dwMask; RSP_GFX_InitGeometryMode(); } void RSP_GBI1_EndDL(Gfx *gfx) { SP_Timing(RSP_GBI1_EndDL); RDP_GFX_PopDL(); } //static const char * sc_szBlClr[4] = { "In", "Mem", "Bl", "Fog" }; //static const char * sc_szBlA1[4] = { "AIn", "AFog", "AShade", "0" }; //static const char * sc_szBlA2[4] = { "1-A", "AMem", "1", "?" }; void RSP_GBI1_SetOtherModeL(Gfx *gfx) { SP_Timing(RSP_GBI1_SetOtherModeL); uint32 dwShift = ((gfx->words.w0)>>8)&0xFF; uint32 dwLength= ((gfx->words.w0) )&0xFF; uint32 dwData = (gfx->words.w1); uint32 dwMask = ((1<words.w0)>>8)&0xFF; uint32 dwLength= ((gfx->words.w0) )&0xFF; uint32 dwData = (gfx->words.w1); uint32 dwMask = ((1<texture.scaleS) / (65536.0f * 32.0f); float fTextureScaleT = (float)(gfx->texture.scaleT) / (65536.0f * 32.0f); if( (((gfx->words.w1)>>16)&0xFFFF) == 0xFFFF ) { fTextureScaleS = 1/32.0f; } else if( (((gfx->words.w1)>>16)&0xFFFF) == 0x8000 ) { fTextureScaleS = 1/64.0f; } #ifdef DEBUGGER else if( ((gfx->words.w1>>16)&0xFFFF) != 0 ) { //DebuggerAppendMsg("Warning, texture scale = %08X is not integer", (word1>>16)&0xFFFF); } #endif if( (((gfx->words.w1) )&0xFFFF) == 0xFFFF ) { fTextureScaleT = 1/32.0f; } else if( (((gfx->words.w1) )&0xFFFF) == 0x8000 ) { fTextureScaleT = 1/64.0f; } #ifdef DEBUGGER else if( (gfx->words.w1&0xFFFF) != 0 ) { //DebuggerAppendMsg("Warning, texture scale = %08X is not integer", (word1)&0xFFFF); } #endif if( gRSP.ucode == 6 ) { if( fTextureScaleS == 0 ) fTextureScaleS = 1.0f/32.0f; if( fTextureScaleT == 0 ) fTextureScaleT = 1.0f/32.0f; } CRender::g_pRender->SetTextureEnableAndScale(gfx->texture.tile, gfx->texture.enable_gbi0, fTextureScaleS, fTextureScaleT); // What happens if these are 0? Interpret as 1.0f? LOG_TEXTURE( { DebuggerAppendMsg("SetTexture: Level: %d Tile: %d %s\n", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi0 ? "enabled":"disabled"); DebuggerAppendMsg(" ScaleS: %f, ScaleT: %f\n", fTextureScaleS*32.0f, fTextureScaleT*32.0f); }); DEBUGGER_PAUSE_COUNT_N(NEXT_SET_TEXTURE); LOG_UCODE(" Level: %d Tile: %d %s", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi0 ? "enabled":"disabled"); LOG_UCODE(" ScaleS: %f, ScaleT: %f", fTextureScaleS*32.0f, fTextureScaleT*32.0f); } extern void RSP_RDP_InsertMatrix(uint32 word0, uint32 word1); void RSP_GBI1_MoveWord(Gfx *gfx) { SP_Timing(RSP_GBI1_MoveWord); switch (gfx->gbi0moveword.type) { case RSP_MOVE_WORD_MATRIX: RSP_RDP_InsertMatrix(gfx); break; case RSP_MOVE_WORD_NUMLIGHT: { uint32 dwNumLights = (((gfx->gbi0moveword.value)-0x80000000)/32)-1; LOG_UCODE(" RSP_MOVE_WORD_NUMLIGHT: Val:%d", dwNumLights); gRSP.ambientLightIndex = dwNumLights; SetNumLights(dwNumLights); } break; case RSP_MOVE_WORD_CLIP: { switch (gfx->gbi0moveword.offset) { case RSP_MV_WORD_OFFSET_CLIP_RNX: case RSP_MV_WORD_OFFSET_CLIP_RNY: case RSP_MV_WORD_OFFSET_CLIP_RPX: case RSP_MV_WORD_OFFSET_CLIP_RPY: CRender::g_pRender->SetClipRatio(gfx->gbi0moveword.offset, gfx->gbi0moveword.value); break; default: LOG_UCODE(" RSP_MOVE_WORD_CLIP ? : 0x%08x", gfx->words.w1); break; } } break; case RSP_MOVE_WORD_SEGMENT: { uint32 dwSegment = (gfx->gbi0moveword.offset >> 2) & 0xF; uint32 dwBase = (gfx->gbi0moveword.value)&0x00FFFFFF; LOG_UCODE(" RSP_MOVE_WORD_SEGMENT Seg[%d] = 0x%08x", dwSegment, dwBase); if( dwBase > g_dwRamSize ) { gRSP.segments[dwSegment] = dwBase; #ifdef DEBUGGER if( pauseAtNext ) DebuggerAppendMsg("warning: Segment %d addr is %8X", dwSegment, dwBase); #endif } else { gRSP.segments[dwSegment] = dwBase; } } break; case RSP_MOVE_WORD_FOG: { uint16 wMult = (uint16)(((gfx->gbi0moveword.value) >> 16) & 0xFFFF); uint16 wOff = (uint16)(((gfx->gbi0moveword.value) ) & 0xFFFF); float fMult = (float)(short)wMult; float fOff = (float)(short)wOff; float rng = 128000.0f / fMult; float fMin = 500.0f - (fOff*rng/256.0f); float fMax = rng + fMin; FOG_DUMP(TRACE4("Set Fog: Min=%f, Max=%f, Mul=%f, Off=%f", fMin, fMax, fMult, fOff)); //if( fMult <= 0 || fMin > fMax || fMax < 0 || fMin > 1000 ) if( fMult <= 0 || fMax < 0 ) { // Hack fMin = 996; fMax = 1000; fMult = 0; fOff = 1; } LOG_UCODE(" RSP_MOVE_WORD_FOG/Mul=%d: Off=%d", wMult, wOff); FOG_DUMP(TRACE3("Set Fog: Min=%f, Max=%f, Data=%08X", fMin, fMax, gfx->gbi0moveword.value)); SetFogMinMax(fMin, fMax, fMult, fOff); } break; case RSP_MOVE_WORD_LIGHTCOL: { uint32 dwLight = gfx->gbi0moveword.offset / 0x20; uint32 dwField = (gfx->gbi0moveword.offset & 0x7); LOG_UCODE(" RSP_MOVE_WORD_LIGHTCOL/0x%08x: 0x%08x", gfx->gbi0moveword.offset, gfx->words.w1); switch (dwField) { case 0: if (dwLight == gRSP.ambientLightIndex) { SetAmbientLight( ((gfx->gbi0moveword.value)>>8) ); } else { SetLightCol(dwLight, gfx->gbi0moveword.value); } break; case 4: break; default: TRACE1("RSP_MOVE_WORD_LIGHTCOL with unknown offset 0x%08x", dwField); break; } } break; case RSP_MOVE_WORD_POINTS: { uint32 vtx = gfx->gbi0moveword.offset/40; uint32 where = gfx->gbi0moveword.offset - vtx*40; ModifyVertexInfo(where, vtx, gfx->gbi0moveword.value); } break; case RSP_MOVE_WORD_PERSPNORM: LOG_UCODE(" RSP_MOVE_WORD_PERSPNORM"); //if( word1 != 0x1A ) DebuggerAppendMsg("PerspNorm: 0x%04x", (short)word1); break; default: RSP_RDP_NOIMPL("Unknown MoveWord, %08X, %08X", gfx->words.w0, gfx->words.w1); break; } } void RSP_GBI1_PopMtx(Gfx *gfx) { SP_Timing(RSP_GBI1_PopMtx); LOG_UCODE(" Command: (%s)", gfx->gbi0popmatrix.projection ? "Projection" : "ModelView"); // Do any of the other bits do anything? // So far only Extreme-G seems to Push/Pop projection matrices if (gfx->gbi0popmatrix.projection) { CRender::g_pRender->PopProjection(); } else { CRender::g_pRender->PopWorldView(); } #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) { pauseAtNext = false; debuggerPause = true; DebuggerAppendMsg("Pause after Pop Matrix: %s\n", gfx->gbi0popmatrix.projection ? "Proj":"World"); } else { if( pauseAtNext && logMatrix ) { DebuggerAppendMsg("Pause after Pop Matrix: %s\n", gfx->gbi0popmatrix.projection ? "Proj":"World"); } } #endif } void RSP_GBI1_CullDL(Gfx *gfx) { SP_Timing(RSP_GBI1_CullDL); #ifdef DEBUGGER if( !debuggerEnableCullFace ) { return; //Disable Culling } #endif if( g_curRomInfo.bDisableCulling ) { return; //Disable Culling } uint32 dwVFirst = ((gfx->words.w0) & 0xFFF) / gRSP.vertexMult; uint32 dwVLast = (((gfx->words.w1)) & 0xFFF) / gRSP.vertexMult; LOG_UCODE(" Culling using verts %d to %d", dwVFirst, dwVLast); // Mask into range dwVFirst &= 0x1f; dwVLast &= 0x1f; if( dwVLast < dwVFirst ) return; if( !gRSP.bRejectVtx ) return; for (uint32 i = dwVFirst; i <= dwVLast; i++) { if (g_clipFlag[i] == 0) { LOG_UCODE(" Vertex %d is visible, continuing with display list processing", i); return; } } status.dwNumDListsCulled++; LOG_UCODE(" No vertices were visible, culling rest of display list"); RDP_GFX_PopDL(); } void RSP_GBI1_Tri1(Gfx *gfx) { status.primitiveType = PRIM_TRI1; bool bTrisAdded = false; bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled(); // While the next command pair is Tri1, add vertices uint32 dwPC = gDlistStack[gDlistStackPointer].pc; //uint32 * pCmdBase = (uint32 *)(g_pRDRAMu8 + dwPC); do { uint32 dwV0 = gfx->tri1.v0/gRSP.vertexMult; uint32 dwV1 = gfx->tri1.v1/gRSP.vertexMult; uint32 dwV2 = gfx->tri1.v2/gRSP.vertexMult; if (IsTriangleVisible(dwV0, dwV1, dwV2)) { DEBUG_DUMP_VERTEXES("Tri1", dwV0, dwV1, dwV2); LOG_UCODE(" Tri1: 0x%08x 0x%08x %d,%d,%d", gfx->words.w0, gfx->words.w1, dwV0, dwV1, dwV2); if (!bTrisAdded) { if( bTexturesAreEnabled ) { PrepareTextures(); InitVertexTextureConstants(); } CRender::g_pRender->SetCombinerAndBlender(); bTrisAdded = true; } PrepareTriangle(dwV0, dwV1, dwV2); } gfx++; dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_TRI1); #else } while (gfx->words.cmd == (uint8)RSP_TRI1); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at GBI0 TRI1")); } void RSP_GBI0_Tri4(Gfx *gfx) { uint32 w0 = gfx->words.w0; uint32 w1 = gfx->words.w1; status.primitiveType = PRIM_TRI2; // While the next command pair is Tri2, add vertices uint32 dwPC = gDlistStack[gDlistStackPointer].pc; BOOL bTrisAdded = FALSE; do { uint32 dwFlag = (w0>>16)&0xFF; LOG_UCODE(" PD Tri4: 0x%08x 0x%08x Flag: 0x%02x", gfx->words.w0, gfx->words.w1, dwFlag); BOOL bVisible; for( int i=0; i<4; i++) { uint32 v0 = (w1>>(4+(i<<3))) & 0xF; uint32 v1 = (w1>>( (i<<3))) & 0xF; uint32 v2 = (w0>>( (i<<2))) & 0xF; bVisible = IsTriangleVisible(v0, v2, v1); LOG_UCODE(" (%d, %d, %d) %s", v0, v1, v2, bVisible ? "": "(clipped)"); if (bVisible) { DEBUG_DUMP_VERTEXES("Tri4_PerfectDark 1/2", v0, v1, v2); if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } if( !bTrisAdded ) { CRender::g_pRender->SetCombinerAndBlender(); } bTrisAdded = true; PrepareTriangle(v0, v2, v1); } } w0 = *(uint32 *)(g_pRDRAMu8 + dwPC+0); w1 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && (w0>>24) == (uint8)RSP_TRI2); #else } while (((w0)>>24) == (uint8)RSP_TRI2); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at GBI0 TRI4")); gRSP.DKRVtxCount=0; } //Nintro64 uses Sprite2d void RSP_RDP_Nothing(Gfx *gfx) { SP_Timing(RSP_RDP_Nothing); #ifdef DEBUGGER if( logWarning ) { TRACE0("Stack Trace"); for( int i=0; iwords.w0, gfx->words.w1); } DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_UNKNOWN_OP, {TRACE0("Paused at unknown ucode\n");}) if( debuggerContinueWithUnknown ) { return; } #endif if( options.bEnableHacks ) return; gDlistStackPointer=-1; } void RSP_RDP_InsertMatrix(Gfx *gfx) { float fraction; UpdateCombinedMatrix(); if ((gfx->words.w0) & 0x20) { int x = ((gfx->words.w0) & 0x1F) >> 1; int y = x >> 2; x &= 3; fraction = ((gfx->words.w1)>>16)/65536.0f; gRSPworldProject.m[y][x] = (float)(int)gRSPworldProject.m[y][x]; gRSPworldProject.m[y][x] += fraction; fraction = ((gfx->words.w1)&0xFFFF)/65536.0f; gRSPworldProject.m[y][x+1] = (float)(int)gRSPworldProject.m[y][x+1]; gRSPworldProject.m[y][x+1] += fraction; } else { int x = ((gfx->words.w0) & 0x1F) >> 1; int y = x >> 2; x &= 3; fraction = (float)fabs(gRSPworldProject.m[y][x] - (int)gRSPworldProject.m[y][x]); gRSPworldProject.m[y][x] = (short)((gfx->words.w1)>>16) + fraction; fraction = (float)fabs(gRSPworldProject.m[y][x+1] - (int)gRSPworldProject.m[y][x+1]); gRSPworldProject.m[y][x+1] = (short)((gfx->words.w1)&0xFFFF) + fraction; } gRSP.bMatrixIsUpdated = false; gRSP.bCombinedMatrixIsUpdated = true; #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) { pauseAtNext = false; debuggerPause = true; DebuggerAppendMsg("Pause after insert matrix: %08X, %08X", gfx->words.w0, gfx->words.w1); } else { if( pauseAtNext && logMatrix ) { DebuggerAppendMsg("insert matrix: %08X, %08X", gfx->words.w0, gfx->words.w1); } } #endif } mupen64plus-video-rice-src-2.0/src/RSP_GBI1.h0000644000000000000000000003005612165031100016653 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Render.h" #include "Timing.h" void RSP_GBI1_Vtx(Gfx *gfx) { uint32 addr = RSPSegmentAddr((gfx->gbi1vtx.addr)); uint32 v0 = gfx->gbi1vtx.v0; uint32 n = gfx->gbi1vtx.n; LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d, Length: 0x%04x", addr, v0, n, gfx->gbi1vtx.len); if (addr > g_dwRamSize) { TRACE0(" Address out of range - ignoring load"); return; } if ((v0 + n) > 80) { TRACE5("Warning, invalid vertex positions, N=%d, v0=%d, Addr=0x%08X, Cmd=%08X-%08X", n, v0, addr, gfx->words.w0, gfx->words.w1); return; } ProcessVertexData(addr, v0, n); status.dwNumVertices += n; DisplayVertexInfo(addr, v0, n); } void RSP_GBI1_ModifyVtx(Gfx *gfx) { SP_Timing(RSP_GBI1_ModifyVtx); if( gRSP.ucode == 5 && ((gfx->words.w0)&0x00FFFFFF) == 0 && ((gfx->words.w1)&0xFF000000) == 0x80000000 ) { DLParser_Bomberman2TextRect(gfx); } else { uint32 dwWhere = ((gfx->words.w0) >> 16) & 0xFF; uint32 dwVert = (((gfx->words.w0) ) & 0xFFFF) / 2; uint32 dwValue = (gfx->words.w1); if( dwVert > 80 ) { RSP_RDP_NOIMPL("RSP_GBI1_ModifyVtx: Invalid vertex number: %d", dwVert, 0); return; } // Data for other commands? switch (dwWhere) { case RSP_MV_WORD_OFFSET_POINT_RGBA: // Modify RGBA case RSP_MV_WORD_OFFSET_POINT_XYSCREEN: // Modify X,Y case RSP_MV_WORD_OFFSET_POINT_ZSCREEN: // Modify C case RSP_MV_WORD_OFFSET_POINT_ST: // Texture ModifyVertexInfo(dwWhere, dwVert, dwValue); break; default: RSP_RDP_NOIMPL("RSP_GBI1_ModifyVtx: Setting unk value: 0x%02x, 0x%08x", dwWhere, dwValue); break; } } } void RSP_GBI1_Tri2(Gfx *gfx) { status.primitiveType = PRIM_TRI2; bool bTrisAdded = false; bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled(); // While the next command pair is Tri2, add vertices uint32 dwPC = gDlistStack[gDlistStackPointer].pc; do { // Vertex indices are multiplied by 10 for Mario64, by 2 for MarioKart uint32 dwV0 = gfx->gbi1tri2.v0/gRSP.vertexMult; uint32 dwV1 = gfx->gbi1tri2.v1/gRSP.vertexMult; uint32 dwV2 = gfx->gbi1tri2.v2/gRSP.vertexMult; uint32 dwV3 = gfx->gbi1tri2.v3/gRSP.vertexMult; uint32 dwV4 = gfx->gbi1tri2.v4/gRSP.vertexMult; uint32 dwV5 = gfx->gbi1tri2.v5/gRSP.vertexMult; // Do first tri if (IsTriangleVisible(dwV0, dwV1, dwV2)) { DEBUG_DUMP_VERTEXES("Tri2 1/2", dwV0, dwV1, dwV2); if (!bTrisAdded) { if( bTexturesAreEnabled ) { PrepareTextures(); InitVertexTextureConstants(); } CRender::g_pRender->SetCombinerAndBlender(); bTrisAdded = true; } PrepareTriangle(dwV0, dwV1, dwV2); } // Do second tri if (IsTriangleVisible(dwV3, dwV4, dwV5)) { DEBUG_DUMP_VERTEXES("Tri2 2/2", dwV3, dwV4, dwV5); if (!bTrisAdded) { if( bTexturesAreEnabled ) { PrepareTextures(); InitVertexTextureConstants(); } CRender::g_pRender->SetCombinerAndBlender(); bTrisAdded = true; } PrepareTriangle(dwV3, dwV4, dwV5); } gfx++; dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_TRI2); #else } while( gfx->words.cmd == (uint8)RSP_TRI2); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at GBI1 TRI1")); } extern XVECTOR4 g_vtxNonTransformed[MAX_VERTS]; void RSP_GBI1_BranchZ(Gfx *gfx) { SP_Timing(RSP_GBI1_BranchZ); uint32 vtx = ((gfx->words.w0)&0xFFF)>>1; float vtxdepth = g_vecProjected[vtx].z/g_vecProjected[vtx].w; #ifdef DEBUGGER if( debuggerEnableZBuffer==FALSE || vtxdepth <= (s32)gfx->words.w1 || g_curRomInfo.bForceDepthBuffer ) #else if( vtxdepth <= (s32)(gfx->words.w1) || g_curRomInfo.bForceDepthBuffer ) #endif { uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction uint32 dwDL = *(uint32 *)(g_pRDRAMu8 + dwPC-12); uint32 dwAddr = RSPSegmentAddr(dwDL); dwAddr = RSPSegmentAddr(dwDL);; LOG_UCODE("BranchZ to DisplayList 0x%08x", dwAddr); gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; } } #ifdef DEBUGGER void DumpUcodeInfo(UcodeInfo &info) { DebuggerAppendMsg("Loading Unknown Ucode:\n%08X-%08X-%08X-%08X, Size=0x%X, CRC=0x%08X\nCode:\n", info.ucDWORD1, info.ucDWORD2, info.ucDWORD3, info.ucDWORD4, info.ucSize, info.ucCRC); DumpHex(info.ucStart,20); TRACE0("Data:\n"); DumpHex(info.ucDStart,20); } #endif void RSP_GBI1_LoadUCode(Gfx *gfx) { SP_Timing(RSP_GBI1_LoadUCode); //TRACE0("Load ucode"); uint32 dwPC = gDlistStack[gDlistStackPointer].pc; uint32 dwUcStart = RSPSegmentAddr((gfx->words.w1)); uint32 dwSize = ((gfx->words.w0)&0xFFFF)+1; uint32 dwUcDStart = RSPSegmentAddr(*(uint32 *)(g_pRDRAMu8 + dwPC-12)); uint32 ucode = DLParser_CheckUcode(dwUcStart, dwUcDStart, dwSize, 8); RSP_SetUcode(ucode, dwUcStart, dwUcDStart, dwSize); DEBUGGER_PAUSE_AND_DUMP(NEXT_SWITCH_UCODE,{DebuggerAppendMsg("Pause at loading ucode");}); } void RSP_GFX_Force_Matrix(uint32 dwAddr) { if (dwAddr + 64 > g_dwRamSize) { DebuggerAppendMsg("ForceMtx: Address invalid (0x%08x)", dwAddr); return; } // Load matrix from dwAddr LoadMatrix(dwAddr); CRender::g_pRender->SetWorldProjectMatrix(matToLoad); DEBUGGER_PAUSE_AND_DUMP(NEXT_MATRIX_CMD,{TRACE0("Paused at ModMatrix Cmd");}); } void DisplayVertexInfo(uint32 dwAddr, uint32 dwV0, uint32 dwN) { #ifdef DEBUGGER s8 *pcSrc = (s8 *)(g_pRDRAMu8 + dwAddr); short *psSrc = (short *)(g_pRDRAMu8 + dwAddr); for (uint32 dwV = dwV0; dwV < dwV0 + dwN; dwV++) { float x = (float)psSrc[0^0x1]; float y = (float)psSrc[1^0x1]; float z = (float)psSrc[2^0x1]; //uint32 wFlags = g_dwVtxFlags[dwV]; //(uint16)psSrc[3^0x1]; uint32 wFlags = 0; uint8 a = pcSrc[12^0x3]; uint8 b = pcSrc[13^0x3]; uint8 c = pcSrc[14^0x3]; uint8 d = pcSrc[15^0x3]; //int nTU = (int)(short)(psSrc[4^0x1]<<4); //int nTV = (int)(short)(psSrc[5^0x1]<<4); //float tu = (float)(nTU>>4); //float tv = (float)(nTV>>4); float tu = (float)(short)(psSrc[4^0x1]); float tv = (float)(short)(psSrc[5^0x1]); XVECTOR4 & t = g_vecProjected[dwV]; psSrc += 8; // Increase by 16 bytes pcSrc += 16; LOG_UCODE(" #%02d Flags: 0x%04x Pos: {% 6f,% 6f,% 6f} Tex: {%+7.2f,%+7.2f}, Extra: %02x %02x %02x %02x (transf: {% 6f,% 6f,% 6f})", dwV, wFlags, x, y, z, tu, tv, a, b, c, d, t.x, t.y, t.z ); } #endif } void RSP_MoveMemLight(uint32 dwLight, uint32 dwAddr) { if( dwLight >= 16 ) { DebuggerAppendMsg("Warning: invalid light # = %d", dwLight); return; } s8 * pcBase = g_pRDRAMs8 + dwAddr; uint32 * pdwBase = (uint32 *)pcBase; float range = 0, x, y, z; if( options.enableHackForGames == HACK_FOR_ZELDA_MM && (pdwBase[0]&0xFF) == 0x08 && (pdwBase[1]&0xFF) == 0xFF ) { gRSPn64lights[dwLight].dwRGBA = pdwBase[0]; gRSPn64lights[dwLight].dwRGBACopy = pdwBase[1]; short* pdwBase16 = (short*)pcBase; x = pdwBase16[5]; y = pdwBase16[4]; z = pdwBase16[7]; range = pdwBase16[6]; } else { gRSPn64lights[dwLight].dwRGBA = pdwBase[0]; gRSPn64lights[dwLight].dwRGBACopy = pdwBase[1]; x = pcBase[8 ^ 0x3]; y = pcBase[9 ^ 0x3]; z = pcBase[10 ^ 0x3]; } LOG_UCODE(" RGBA: 0x%08x, RGBACopy: 0x%08x, x: %d, y: %d, z: %d", gRSPn64lights[dwLight].dwRGBA, gRSPn64lights[dwLight].dwRGBACopy, x, y, z); LIGHT_DUMP(TRACE3("Move Light: %08X, %08X, %08X", pdwBase[0], pdwBase[1], pdwBase[2])); if (dwLight == gRSP.ambientLightIndex) { LOG_UCODE(" (Ambient Light)"); uint32 dwCol = COLOR_RGBA( (gRSPn64lights[dwLight].dwRGBA >> 24)&0xFF, (gRSPn64lights[dwLight].dwRGBA >> 16)&0xFF, (gRSPn64lights[dwLight].dwRGBA >> 8)&0xFF, 0xff); SetAmbientLight( dwCol ); } else { LOG_UCODE(" (Normal Light)"); SetLightCol(dwLight, gRSPn64lights[dwLight].dwRGBA); if (pdwBase[2] == 0) // Direction is 0! { LOG_UCODE(" Light is invalid"); } SetLightDirection(dwLight, x, y, z, range); } } void RSP_MoveMemViewport(uint32 dwAddr) { if( dwAddr+16 >= g_dwRamSize ) { TRACE0("MoveMem Viewport, invalid memory"); return; } short scale[4]; short trans[4]; // dwAddr is offset into RD_RAM of 8 x 16bits of data... scale[0] = *(short *)(g_pRDRAMu8 + ((dwAddr+(0*2))^0x2)); scale[1] = *(short *)(g_pRDRAMu8 + ((dwAddr+(1*2))^0x2)); scale[2] = *(short *)(g_pRDRAMu8 + ((dwAddr+(2*2))^0x2)); scale[3] = *(short *)(g_pRDRAMu8 + ((dwAddr+(3*2))^0x2)); trans[0] = *(short *)(g_pRDRAMu8 + ((dwAddr+(4*2))^0x2)); trans[1] = *(short *)(g_pRDRAMu8 + ((dwAddr+(5*2))^0x2)); trans[2] = *(short *)(g_pRDRAMu8 + ((dwAddr+(6*2))^0x2)); trans[3] = *(short *)(g_pRDRAMu8 + ((dwAddr+(7*2))^0x2)); int nCenterX = trans[0]/4; int nCenterY = trans[1]/4; int nWidth = scale[0]/4; int nHeight = scale[1]/4; // Check for some strange games if( nWidth < 0 ) nWidth = -nWidth; if( nHeight < 0 ) nHeight = -nHeight; int nLeft = nCenterX - nWidth; int nTop = nCenterY - nHeight; int nRight= nCenterX + nWidth; int nBottom= nCenterY + nHeight; //int maxZ = scale[2]; int maxZ = 0x3FF; CRender::g_pRender->SetViewport(nLeft, nTop, nRight, nBottom, maxZ); LOG_UCODE(" Scale: %d %d %d %d = %d,%d", scale[0], scale[1], scale[2], scale[3], nWidth, nHeight); LOG_UCODE(" Trans: %d %d %d %d = %d,%d", trans[0], trans[1], trans[2], trans[3], nCenterX, nCenterY); } // S2DEX uses this - 0xc1 void RSP_S2DEX_SPObjLoadTxtr_Ucode1(Gfx *gfx) { SP_Timing(RSP_S2DEX_SPObjLoadTxtr_Ucode1); // Add S2DEX ucode supporting to F3DEX, see game DT and others status.bUseModifiedUcodeMap = true; RSP_SetUcode(1); memcpy( &LoadedUcodeMap, &ucodeMap1, sizeof(UcodeMap)); LoadedUcodeMap[S2DEX_OBJ_MOVEMEM] = &RSP_S2DEX_OBJ_MOVEMEM; LoadedUcodeMap[S2DEX_OBJ_LOADTXTR] = &RSP_S2DEX_SPObjLoadTxtr; LoadedUcodeMap[S2DEX_OBJ_LDTX_SPRITE] = &RSP_S2DEX_SPObjLoadTxSprite; LoadedUcodeMap[S2DEX_OBJ_LDTX_RECT] = &RSP_S2DEX_SPObjLoadTxRect; LoadedUcodeMap[S2DEX_OBJ_LDTX_RECT_R] = &RSP_S2DEX_SPObjLoadTxRectR; RSP_S2DEX_SPObjLoadTxtr(gfx); } mupen64plus-video-rice-src-2.0/src/RSP_GBI2.h0000644000000000000000000007003412165031100016654 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Render.h" #include "Timing.h" void RSP_GBI2_Vtx(Gfx *gfx) { uint32 addr = RSPSegmentAddr((gfx->gbi2vtx.addr)); int vend = gfx->gbi2vtx.vend/2; int n = gfx->gbi2vtx.n; int v0 = vend - n; LOG_UCODE(" Vtx: Address 0x%08x, vEnd: %d, v0: %d, Num: %d", addr, vend, v0, n); if( vend > 64 ) { DebuggerAppendMsg("Warning, attempting to load into invalid vertex positions, v0=%d, n=%d", v0, n); return; } if ((addr + (n*16)) > g_dwRamSize) { DebuggerAppendMsg("ProcessVertexData: Address out of range (0x%08x)", addr); } else { ProcessVertexData(addr, v0, n); status.dwNumVertices += n; DisplayVertexInfo(addr, v0, n); } } void RSP_GBI2_EndDL(Gfx *gfx) { SP_Timing(RSP_GBI1_EndDL); RDP_GFX_PopDL(); } void RSP_GBI2_CullDL(Gfx *gfx) { SP_Timing(RSP_GBI1_CullDL); #ifdef DEBUGGER if( !debuggerEnableCullFace ) { return; //Disable Culling } #endif if( g_curRomInfo.bDisableCulling ) { return; //Disable Culling } uint32 dwVFirst = (((gfx->words.w0)) & 0xfff) / gRSP.vertexMult; uint32 dwVLast = (((gfx->words.w1)) & 0xfff) / gRSP.vertexMult; LOG_UCODE(" Culling using verts %d to %d", dwVFirst, dwVLast); // Mask into range dwVFirst &= 0x1f; dwVLast &= 0x1f; if( dwVLast < dwVFirst ) return; if( !gRSP.bRejectVtx ) return; for (uint32 i = dwVFirst; i <= dwVLast; i++) { //if (g_dwVtxFlags[i] == 0) if (g_clipFlag[i] == 0) { LOG_UCODE(" Vertex %d is visible, returning", i); return; } } status.dwNumDListsCulled++; LOG_UCODE(" No vertices were visible, culling"); RDP_GFX_PopDL(); } void RSP_GBI2_MoveWord(Gfx *gfx) { SP_Timing(RSP_GBI1_MoveWord); switch (gfx->gbi2moveword.type) { case RSP_MOVE_WORD_MATRIX: RSP_RDP_InsertMatrix(gfx); break; case RSP_MOVE_WORD_NUMLIGHT: { uint32 dwNumLights = gfx->gbi2moveword.value/24; gRSP.ambientLightIndex = dwNumLights; SetNumLights(dwNumLights); } break; case RSP_MOVE_WORD_CLIP: { switch (gfx->gbi2moveword.offset) { case RSP_MV_WORD_OFFSET_CLIP_RNX: case RSP_MV_WORD_OFFSET_CLIP_RNY: case RSP_MV_WORD_OFFSET_CLIP_RPX: case RSP_MV_WORD_OFFSET_CLIP_RPY: CRender::g_pRender->SetClipRatio(gfx->gbi2moveword.offset, gfx->gbi2moveword.value); default: LOG_UCODE(" RSP_MOVE_WORD_CLIP ? : 0x%08x", gfx->words.w1); break; } } break; case RSP_MOVE_WORD_SEGMENT: { uint32 dwSeg = gfx->gbi2moveword.offset / 4; uint32 dwAddr = gfx->gbi2moveword.value & 0x00FFFFFF; // Hack - convert to physical LOG_UCODE(" RSP_MOVE_WORD_SEGMENT Segment[%d] = 0x%08x", dwSeg, dwAddr); if( dwAddr > g_dwRamSize ) { gRSP.segments[dwSeg] = dwAddr; #ifdef DEBUGGER if( pauseAtNext ) DebuggerAppendMsg("warning: Segment %d addr is %8X", dwSeg, dwAddr); #endif } else { gRSP.segments[dwSeg] = dwAddr; } } break; case RSP_MOVE_WORD_FOG: { uint16 wMult = (uint16)((gfx->gbi2moveword.value >> 16) & 0xFFFF); uint16 wOff = (uint16)((gfx->gbi2moveword.value ) & 0xFFFF); float fMult = (float)(short)wMult; float fOff = (float)(short)wOff; float rng = 128000.0f / fMult; float fMin = 500.0f - (fOff*rng/256.0f); float fMax = rng + fMin; FOG_DUMP(TRACE4("Set Fog: Min=%f, Max=%f, Mul=%f, Off=%f", fMin, fMax, fMult, fOff)); //if( fMult <= 0 || fMin > fMax || fMax < 0 || fMin > 1000 ) if( fMult <= 0 || fMax < 0 ) { // Hack fMin = 996; fMax = 1000; fMult = 0; fOff = 1; } SetFogMinMax(fMin, fMax, fMult, fOff); FOG_DUMP(TRACE3("Set Fog: Min=%f, Max=%f, Data=0x%08X", fMin, fMax, gfx->gbi2moveword.value)); } break; case RSP_MOVE_WORD_LIGHTCOL: { uint32 dwLight = gfx->gbi2moveword.offset / 0x18; uint32 dwField = (gfx->gbi2moveword.offset & 0x7); switch (dwField) { case 0: if (dwLight == gRSP.ambientLightIndex) { SetAmbientLight( (gfx->gbi2moveword.value>>8) ); } else { SetLightCol(dwLight, gfx->gbi2moveword.value); } break; case 4: break; default: DebuggerAppendMsg("RSP_MOVE_WORD_LIGHTCOL with unknown offset 0x%08x", dwField); break; } } break; case RSP_MOVE_WORD_PERSPNORM: LOG_UCODE(" RSP_MOVE_WORD_PERSPNORM 0x%04x", (short)gfx->words.w1); break; case RSP_MOVE_WORD_POINTS: LOG_UCODE(" 2nd cmd of Force Matrix"); break; default: { LOG_UCODE(" Ignored!!"); } break; } } void RSP_GBI2_Tri1(Gfx *gfx) { if( gfx->words.w0 == 0x05000017 && gfx->gbi2tri1.flag == 0x80 ) { // The ObjLoadTxtr / Tlut cmd for Evangelion.v64 RSP_S2DEX_SPObjLoadTxtr(gfx); DebuggerAppendMsg("Fix me, SPObjLoadTxtr as RSP_GBI2_Tri2"); } else { status.primitiveType = PRIM_TRI1; bool bTrisAdded = false; bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled(); // While the next command pair is Tri1, add vertices uint32 dwPC = gDlistStack[gDlistStackPointer].pc; //uint32 * pCmdBase = (uint32 *)(g_pRDRAMu8 + dwPC); do { uint32 dwV2 = gfx->gbi2tri1.v2/gRSP.vertexMult; uint32 dwV1 = gfx->gbi2tri1.v1/gRSP.vertexMult; uint32 dwV0 = gfx->gbi2tri1.v0/gRSP.vertexMult; if (IsTriangleVisible(dwV0, dwV1, dwV2)) { DEBUG_DUMP_VERTEXES("ZeldaTri1", dwV0, dwV1, dwV2); LOG_UCODE(" ZeldaTri1: 0x%08x 0x%08x %d,%d,%d", gfx->words.w0, gfx->words.w1, dwV0, dwV1, dwV2); if (!bTrisAdded) { if( bTexturesAreEnabled ) { PrepareTextures(); InitVertexTextureConstants(); } CRender::g_pRender->SetCombinerAndBlender(); bTrisAdded = true; } PrepareTriangle(dwV0, dwV1, dwV2); } gfx++; dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_ZELDATRI1); #else } while( gfx->words.cmd == (uint8)RSP_ZELDATRI1); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at GBI2 TRI1")); } } void RSP_GBI2_Tri2(Gfx *gfx) { if( gfx->words.w0 == 0x0600002f && gfx->gbi2tri2.flag == 0x80 ) { // The ObjTxSprite cmd for Evangelion.v64 RSP_S2DEX_SPObjLoadTxSprite(gfx); DebuggerAppendMsg("Fix me, SPObjLoadTxSprite as RSP_GBI2_Tri2"); } else { status.primitiveType = PRIM_TRI2; BOOL bTrisAdded = FALSE; // While the next command pair is Tri2, add vertices uint32 dwPC = gDlistStack[gDlistStackPointer].pc; bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled(); do { uint32 dwV2 = gfx->gbi2tri2.v2; uint32 dwV1 = gfx->gbi2tri2.v1; uint32 dwV0 = gfx->gbi2tri2.v0; uint32 dwV5 = gfx->gbi2tri2.v5; uint32 dwV4 = gfx->gbi2tri2.v4; uint32 dwV3 = gfx->gbi2tri2.v3; LOG_UCODE(" ZeldaTri2: 0x%08x 0x%08x", gfx->words.w0, gfx->words.w1); LOG_UCODE(" V0: %d, V1: %d, V2: %d", dwV0, dwV1, dwV2); LOG_UCODE(" V3: %d, V4: %d, V5: %d", dwV3, dwV4, dwV5); // Do first tri if (IsTriangleVisible(dwV0, dwV1, dwV2)) { DEBUG_DUMP_VERTEXES("ZeldaTri2 1/2", dwV0, dwV1, dwV2); if (!bTrisAdded) { if( bTexturesAreEnabled ) { PrepareTextures(); InitVertexTextureConstants(); } CRender::g_pRender->SetCombinerAndBlender(); bTrisAdded = true; } PrepareTriangle(dwV0, dwV1, dwV2); } // Do second tri if (IsTriangleVisible(dwV3, dwV4, dwV5)) { DEBUG_DUMP_VERTEXES("ZeldaTri2 2/2", dwV3, dwV4, dwV5); if (!bTrisAdded) { if( bTexturesAreEnabled ) { PrepareTextures(); InitVertexTextureConstants(); } CRender::g_pRender->SetCombinerAndBlender(); bTrisAdded = true; } PrepareTriangle(dwV3, dwV4, dwV5); } gfx++; dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_ZELDATRI2); #else } while ( gfx->words.cmd == (uint8)RSP_ZELDATRI2 );//&& status.dwNumTrisRendered < 50); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at GBI2 TRI2")); } } void RSP_GBI2_Line3D(Gfx *gfx) { if( gfx->words.w0 == 0x0700002f && (gfx->words.w1>>24) == 0x80 ) { // The ObjTxSprite cmd for Evangelion.v64 RSP_S2DEX_SPObjLoadTxRect(gfx); } else { status.primitiveType = PRIM_TRI3; uint32 dwPC = gDlistStack[gDlistStackPointer].pc; BOOL bTrisAdded = FALSE; do { uint32 dwV0 = gfx->gbi2line3d.v0/gRSP.vertexMult; uint32 dwV1 = gfx->gbi2line3d.v1/gRSP.vertexMult; uint32 dwV2 = gfx->gbi2line3d.v2/gRSP.vertexMult; uint32 dwV3 = gfx->gbi2line3d.v3/gRSP.vertexMult; uint32 dwV4 = gfx->gbi2line3d.v4/gRSP.vertexMult; uint32 dwV5 = gfx->gbi2line3d.v5/gRSP.vertexMult; LOG_UCODE(" ZeldaTri3: 0x%08x 0x%08x", gfx->words.w0, gfx->words.w1); LOG_UCODE(" V0: %d, V1: %d, V2: %d", dwV0, dwV1, dwV2); LOG_UCODE(" V3: %d, V4: %d, V5: %d", dwV3, dwV4, dwV5); // Do first tri if (IsTriangleVisible(dwV0, dwV1, dwV2)) { DEBUG_DUMP_VERTEXES("ZeldaTri3 1/2", dwV0, dwV1, dwV2); if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } if( !bTrisAdded ) { CRender::g_pRender->SetCombinerAndBlender(); } bTrisAdded = true; PrepareTriangle(dwV0, dwV1, dwV2); } // Do second tri if (IsTriangleVisible(dwV3, dwV4, dwV5)) { DEBUG_DUMP_VERTEXES("ZeldaTri3 2/2", dwV3, dwV4, dwV5); if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } if( !bTrisAdded ) { CRender::g_pRender->SetCombinerAndBlender(); } bTrisAdded = true; PrepareTriangle(dwV3, dwV4, dwV5); } gfx++; dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_LINE3D); #else } while ( gfx->words.cmd == (uint8)RSP_LINE3D); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at GBI2 Line3D")); } } void RSP_GBI2_Texture(Gfx *gfx) { SP_Timing(RSP_GBI1_Texture); float fTextureScaleS = (float)(gfx->texture.scaleS) / (65536.0f * 32.0f); float fTextureScaleT = (float)(gfx->texture.scaleT) / (65536.0f * 32.0f); if( (((gfx->words.w1)>>16)&0xFFFF) == 0xFFFF ) { fTextureScaleS = 1/32.0f; } else if( (((gfx->words.w1)>>16)&0xFFFF) == 0x8000 ) { fTextureScaleS = 1/64.0f; } if( (((gfx->words.w1) )&0xFFFF) == 0xFFFF ) { fTextureScaleT = 1/32.0f; } else if( (((gfx->words.w1) )&0xFFFF) == 0x8000 ) { fTextureScaleT = 1/64.0f; } CRender::g_pRender->SetTextureEnableAndScale(gfx->texture.tile, gfx->texture.enable_gbi2, fTextureScaleS, fTextureScaleT); /* if( g_curRomInfo.bTextureScaleHack ) { // Hack, need to verify, refer to N64 programming manual // that if scale = 0.5 (1/64), vtx s,t are also doubled if( ((word1>>16)&0xFFFF) == 0x8000 ) { fTextureScaleS = 1/128.0f; if( ((word1)&0xFFFF) == 0xFFFF ) { fTextureScaleT = 1/64.0f; } } if( ((word1 )&0xFFFF) == 0x8000 ) { fTextureScaleT = 1/128.0f; if( ((word1>>16)&0xFFFF) == 0xFFFF ) { fTextureScaleS = 1/64.0f; } } } */ CRender::g_pRender->SetTextureEnableAndScale(gfx->texture.tile, gfx->texture.enable_gbi2, fTextureScaleS, fTextureScaleT); LOG_TEXTURE( { DebuggerAppendMsg("SetTexture: Level: %d Tile: %d %s\n", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi2 ? "enabled":"disabled"); DebuggerAppendMsg(" ScaleS: %f, ScaleT: %f\n", fTextureScaleS*32.0f, fTextureScaleT*32.0f); }); DEBUGGER_PAUSE_COUNT_N(NEXT_SET_TEXTURE); LOG_UCODE(" Level: %d Tile: %d %s", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi2 ? "enabled":"disabled"); LOG_UCODE(" ScaleS: %f, ScaleT: %f", fTextureScaleS*32.0f, fTextureScaleT*32.0f); } void RSP_GBI2_PopMtx(Gfx *gfx) { SP_Timing(RSP_GBI1_PopMtx); uint8 nCommand = (uint8)(gfx->words.w0 & 0xFF); LOG_UCODE(" PopMtx: 0x%02x (%s)", nCommand, (nCommand & RSP_ZELDA_MTX_PROJECTION) ? "Projection" : "ModelView"); /* if (nCommand & RSP_ZELDA_MTX_PROJECTION) { CRender::g_pRender->PopProjection(); } else*/ { CRender::g_pRender->PopWorldView(); } #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) { pauseAtNext = false; debuggerPause = true; TRACE0("Pause after Pop GBI2_PopMtx:"); } else { if( pauseAtNext && logMatrix ) { TRACE0("Pause after Pop GBI2_PopMtx:"); } } #endif } #define RSP_ZELDA_ZBUFFER 0x00000001 // Guess #define RSP_ZELDA_CULL_BACK 0x00000200 #define RSP_ZELDA_CULL_FRONT 0x00000400 #define RSP_ZELDA_FOG 0x00010000 #define RSP_ZELDA_LIGHTING 0x00020000 #define RSP_ZELDA_TEXTURE_GEN 0x00040000 #define RSP_ZELDA_TEXTURE_GEN_LINEAR 0x00080000 #define RSP_ZELDA_SHADING_SMOOTH 0x00200000 void RSP_GBI2_GeometryMode(Gfx *gfx) { SP_Timing(RSP_GBI2_GeometryMode); uint32 dwAnd = ((gfx->words.w0)) & 0x00FFFFFF; uint32 dwOr = ((gfx->words.w1)) & 0x00FFFFFF; #ifdef DEBUGGER LOG_UCODE(" 0x%08x 0x%08x =(x & 0x%08x) | 0x%08x", gfx->words.w0, gfx->words.w1, dwAnd, dwOr); if ((~dwAnd) & RSP_ZELDA_ZBUFFER) LOG_UCODE(" Disabling ZBuffer"); //if ((~dwAnd) & RSP_ZELDA_TEXTURE_ENABLE) LOG_UCODE(" Disabling Texture"); //if ((~dwAnd) & RSP_ZELDA_SHADE) LOG_UCODE(" Disabling Shade"); if ((~dwAnd) & RSP_ZELDA_SHADING_SMOOTH) LOG_UCODE(" Disabling Flat Shading"); if ((~dwAnd) & RSP_ZELDA_CULL_FRONT) LOG_UCODE(" Disabling Front Culling"); if ((~dwAnd) & RSP_ZELDA_CULL_BACK) LOG_UCODE(" Disabling Back Culling"); if ((~dwAnd) & RSP_ZELDA_FOG) LOG_UCODE(" Disabling Fog"); if ((~dwAnd) & RSP_ZELDA_LIGHTING) LOG_UCODE(" Disabling Lighting"); if ((~dwAnd) & RSP_ZELDA_TEXTURE_GEN) LOG_UCODE(" Disabling Texture Gen"); if ((~dwAnd) & RSP_ZELDA_TEXTURE_GEN_LINEAR) LOG_UCODE(" Disabling Texture Gen Linear"); // if ((~dwAnd) & RSP_ZELDA_LOD) LOG_UCODE(" Disabling LOD (no impl)"); if (dwOr & RSP_ZELDA_ZBUFFER) LOG_UCODE(" Enabling ZBuffer"); //if (dwOr & RSP_ZELDA_TEXTURE_ENABLE) LOG_UCODE(" Enabling Texture"); //if (dwOr & RSP_ZELDA_SHADE) LOG_UCODE(" Enabling Shade"); if (dwOr & RSP_ZELDA_SHADING_SMOOTH) LOG_UCODE(" Enabling Flat Shading"); if (dwOr & RSP_ZELDA_CULL_FRONT) LOG_UCODE(" Enabling Front Culling"); if (dwOr & RSP_ZELDA_CULL_BACK) LOG_UCODE(" Enabling Back Culling"); if (dwOr & RSP_ZELDA_FOG) LOG_UCODE(" Enabling Fog"); if (dwOr & RSP_ZELDA_LIGHTING) LOG_UCODE(" Enabling Lighting"); if (dwOr & RSP_ZELDA_TEXTURE_GEN) LOG_UCODE(" Enabling Texture Gen"); if (dwOr & RSP_ZELDA_TEXTURE_GEN_LINEAR) LOG_UCODE(" Enabling Texture Gen Linear"); ///if (dwOr & RSP_ZELDA_LOD) LOG_UCODE(" Enabling LOD (no impl)"); #endif // DEBUGGER gRDP.geometryMode &= dwAnd; gRDP.geometryMode |= dwOr; bool bCullFront = (gRDP.geometryMode & RSP_ZELDA_CULL_FRONT) ? true : false; bool bCullBack = (gRDP.geometryMode & RSP_ZELDA_CULL_BACK) ? true : false; //BOOL bShade = (gRDP.geometryMode & G_SHADE) ? TRUE : FALSE; //BOOL bFlatShade = (gRDP.geometryMode & RSP_ZELDA_SHADING_SMOOTH) ? TRUE : FALSE; BOOL bFlatShade = (gRDP.geometryMode & RSP_ZELDA_TEXTURE_GEN_LINEAR) ? TRUE : FALSE; if( options.enableHackForGames == HACK_FOR_TIGER_HONEY_HUNT ) bFlatShade = FALSE; bool bFog = (gRDP.geometryMode & RSP_ZELDA_FOG) ? true : false; bool bTextureGen = (gRDP.geometryMode & RSP_ZELDA_TEXTURE_GEN) ? true : false; bool bLighting = (gRDP.geometryMode & RSP_ZELDA_LIGHTING) ? true : false; BOOL bZBuffer = (gRDP.geometryMode & RSP_ZELDA_ZBUFFER) ? TRUE : FALSE; CRender::g_pRender->SetCullMode(bCullFront, bCullBack); //if (bFlatShade||!bShade) CRender::g_pRender->SetShadeMode( SHADE_FLAT ); if (bFlatShade) CRender::g_pRender->SetShadeMode( SHADE_FLAT ); else CRender::g_pRender->SetShadeMode( SHADE_SMOOTH ); SetTextureGen(bTextureGen); SetLighting( bLighting ); CRender::g_pRender->ZBufferEnable( bZBuffer ); CRender::g_pRender->SetFogEnable( bFog ); } int dlistMtxCount=0; extern uint32 dwConkerVtxZAddr; void RSP_GBI2_Mtx(Gfx *gfx) { SP_Timing(RSP_GBI0_Mtx); dwConkerVtxZAddr = 0; // For Conker BFD uint32 addr = RSPSegmentAddr((gfx->gbi2matrix.addr)); if( gfx->gbi2matrix.param == 0 && gfx->gbi2matrix.len == 0 ) { DLParser_Bomberman2TextRect(gfx); return; } LOG_UCODE(" Mtx: %s %s %s Length %d Address 0x%08x", gfx->gbi2matrix.projection ? "Projection" : "ModelView", gfx->gbi2matrix.load ? "Load" : "Mul", gfx->gbi2matrix.nopush==0 ? "Push" : "No Push", gfx->gbi2matrix.len, addr); if (addr + 64 > g_dwRamSize) { DebuggerAppendMsg("ZeldaMtx: Address invalid (0x%08x)", addr); return; } LoadMatrix(addr); if (gfx->gbi2matrix.projection) { // So far only Extreme-G seems to Push/Pop projection matrices CRender::g_pRender->SetProjection(matToLoad, gfx->gbi2matrix.nopush==0, gfx->gbi2matrix.load); } else { CRender::g_pRender->SetWorldView(matToLoad, gfx->gbi2matrix.nopush==0, gfx->gbi2matrix.load); if( options.enableHackForGames == HACK_FOR_SOUTH_PARK_RALLY ) { dlistMtxCount++; if( dlistMtxCount == 2 ) { CRender::g_pRender->ClearZBuffer(1.0f); } } } #ifdef DEBUGGER const char *loadstr = gfx->gbi2matrix.load?"Load":"Mul"; const char *pushstr = gfx->gbi2matrix.nopush==0?"Push":"Nopush"; int projlevel = CRender::g_pRender->GetProjectMatrixLevel(); int worldlevel = CRender::g_pRender->GetWorldViewMatrixLevel(); if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) { pauseAtNext = false; debuggerPause = true; if (gfx->gbi2matrix.projection) { DebuggerAppendMsg("Pause after %s and %s Matrix: Projection, level=%d\n", loadstr, pushstr, projlevel ); } else { DebuggerAppendMsg("Pause after %s and %s Matrix: WorldView level=%d\n", loadstr, pushstr, worldlevel); } } else { if( pauseAtNext && logMatrix ) { if (gfx->gbi2matrix.projection) { DebuggerAppendMsg("Matrix: %s and %s Projection level=%d\n", loadstr, pushstr, projlevel); } else { DebuggerAppendMsg("Matrix: %s and %s WorldView\n level=%d", loadstr, pushstr, worldlevel); } } } #endif } void RSP_GBI2_MoveMem(Gfx *gfx) { SP_Timing(RSP_GBI1_MoveMem); uint32 addr = RSPSegmentAddr((gfx->words.w1)); uint32 type = ((gfx->words.w0) ) & 0xFE; //uint32 dwLen = ((gfx->words.w0) >> 16) & 0xFF; //uint32 dwOffset = ((gfx->words.w0) >> 8) & 0xFFFF; switch (type) { case RSP_GBI2_MV_MEM__VIEWPORT: { RSP_MoveMemViewport(addr); } break; case RSP_GBI2_MV_MEM__LIGHT: { uint32 dwOffset2 = ((gfx->words.w0) >> 5) & 0x3FFF; switch (dwOffset2) { case 0x00: { s8 * pcBase = g_pRDRAMs8 + addr; LOG_UCODE(" RSP_GBI1_MV_MEM_LOOKATX %f %f %f", (float)pcBase[8 ^ 0x3], (float)pcBase[9 ^ 0x3], (float)pcBase[10 ^ 0x3]); } break; case 0x18: { s8 * pcBase = g_pRDRAMs8 + addr; LOG_UCODE(" RSP_GBI1_MV_MEM_LOOKATY %f %f %f", (float)pcBase[8 ^ 0x3], (float)pcBase[9 ^ 0x3], (float)pcBase[10 ^ 0x3]); } break; default: //0x30/48/60 { uint32 dwLight = (dwOffset2 - 0x30)/0x18; LOG_UCODE(" Light %d:", dwLight); RSP_MoveMemLight(dwLight, addr); } break; } break; } case RSP_GBI2_MV_MEM__MATRIX: LOG_UCODE("Force Matrix: addr=%08X", addr); RSP_GFX_Force_Matrix(addr); break; case RSP_GBI2_MV_MEM_O_L0: case RSP_GBI2_MV_MEM_O_L1: case RSP_GBI2_MV_MEM_O_L2: case RSP_GBI2_MV_MEM_O_L3: case RSP_GBI2_MV_MEM_O_L4: case RSP_GBI2_MV_MEM_O_L5: case RSP_GBI2_MV_MEM_O_L6: case RSP_GBI2_MV_MEM_O_L7: LOG_UCODE("Zelda Move Light"); RDP_NOIMPL_WARN("Zelda Move Light"); break; case RSP_GBI2_MV_MEM__POINT: LOG_UCODE("Zelda Move Point"); void RDP_NOIMPL_WARN(const char* op); RDP_NOIMPL_WARN("Zelda Move Point"); break; case RSP_GBI2_MV_MEM_O_LOOKATX: if( (gfx->words.w0) == 0xDC170000 && ((gfx->words.w1)&0xFF000000) == 0x80000000 ) { // Ucode for Evangelion.v64, the ObjMatrix cmd RSP_S2DEX_OBJ_MOVEMEM(gfx); } break; case RSP_GBI2_MV_MEM_O_LOOKATY: RSP_RDP_NOIMPL("Not implemented ZeldaMoveMem LOOKATY, Cmd0=0x%08X, Cmd1=0x%08X", gfx->words.w0, gfx->words.w1); break; case 0x02: if( (gfx->words.w0) == 0xDC070002 && ((gfx->words.w1)&0xFF000000) == 0x80000000 ) { RSP_S2DEX_OBJ_MOVEMEM(gfx); break; } default: LOG_UCODE("ZeldaMoveMem Type: Unknown"); RSP_RDP_NOIMPL("Unknown ZeldaMoveMem Type, type=0x%X, Addr=%08X", type, addr); break; } } void RSP_GBI2_DL(Gfx *gfx) { SP_Timing(RSP_GBI0_DL); uint32 dwPush = ((gfx->words.w0) >> 16) & 0xFF; uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); if( dwAddr > g_dwRamSize ) { RSP_RDP_NOIMPL("Error: DL addr = %08X out of range, PC=%08X", dwAddr, gDlistStack[gDlistStackPointer].pc ); dwAddr &= (g_dwRamSize-1); DebuggerPauseCountN( NEXT_DLIST ); } LOG_UCODE(" DL: Push:0x%02x Addr: 0x%08x", dwPush, dwAddr); switch (dwPush) { case RSP_DLIST_PUSH: LOG_UCODE(" Pushing ZeldaDisplayList 0x%08x", dwAddr); gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; break; case RSP_DLIST_NOPUSH: LOG_UCODE(" Jumping to ZeldaDisplayList 0x%08x", dwAddr); if( gDlistStack[gDlistStackPointer].pc == dwAddr+8 ) //Is this a loop { //Hack for Gauntlet Legends gDlistStack[gDlistStackPointer].pc = dwAddr+8; } else gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; break; } LOG_UCODE(""); LOG_UCODE("\\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/"); LOG_UCODE("#############################################"); } void RSP_GBI2_SetOtherModeL(Gfx *gfx) { SP_Timing(RSP_GBI1_SetOtherModeL); uint32 dwShift = ((gfx->words.w0)>>8)&0xFF; uint32 dwLength= ((gfx->words.w0) )&0xFF; uint32 dwData = (gfx->words.w1); // Mask is constructed slightly differently uint32 dwMask = (uint32)((s32)(0x80000000)>>dwLength)>>dwShift; dwData &= dwMask; uint32 modeL = gRDP.otherModeL; modeL = (modeL&(~dwMask)) | dwData; Gfx tempgfx; tempgfx.words.w0 = gRDP.otherModeH; tempgfx.words.w1 = modeL; DLParser_RDPSetOtherMode(&tempgfx ); } void RSP_GBI2_SetOtherModeH(Gfx *gfx) { SP_Timing(RSP_GBI1_SetOtherModeH); uint32 dwLength= (((gfx->words.w0))&0xFF)+1; uint32 dwShift = 32 - (((gfx->words.w0)>>8)&0xFF) - dwLength; uint32 dwData = (gfx->words.w1); uint32 dwMask2 = ((1<words.w0), (gfx->words.w1)); } mupen64plus-video-rice-src-2.0/src/RSP_GBI2_ext.h0000644000000000000000000000256412165031100017537 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // Some new GBI2 extension ucodes void RSP_GBI2_DL_Count(Gfx *gfx) { SP_Timing(DP_Minimal); DP_Timing(DP_Minimal); // This cmd is likely to execute number of ucode at the given address uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); { gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = ((gfx->words.w0)&0xFFFF); } } void RSP_GBI2_0x8(Gfx *gfx) { if( ((gfx->words.w0)&0x00FFFFFF) == 0x2F && ((gfx->words.w1)&0xFF000000) == 0x80000000 ) { // V-Rally 64 RSP_S2DEX_SPObjLoadTxRectR(gfx); } else { RSP_RDP_Nothing(gfx); } } mupen64plus-video-rice-src-2.0/src/RSP_GBI_Others.h0000644000000000000000000015101612165031100020116 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // A few ucode used in DKR and Others Special games #include #include "Render.h" #include "Timing.h" #include "osal_preproc.h" uint32 dwConkerVtxZAddr=0; static void RDP_GFX_DumpVtxInfoDKR(uint32 dwAddr, uint32 dwV0, uint32 dwN); void RDP_GFX_DLInMem(Gfx *gfx) { uint32 dwLimit = ((gfx->words.w0) >> 16) & 0xFF; uint32 dwPush = RSP_DLIST_PUSH; //((gfx->words.w0) >> 16) & 0xFF; uint32 dwAddr = 0x00000000 | (gfx->words.w1); //RSPSegmentAddr((gfx->words.w1)); LOG_UCODE(" Address=0x%08x Push: 0x%02x", dwAddr, dwPush); switch (dwPush) { case RSP_DLIST_PUSH: LOG_UCODE(" Pushing DisplayList 0x%08x", dwAddr); gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = dwLimit; break; case RSP_DLIST_NOPUSH: LOG_UCODE(" Jumping to DisplayList 0x%08x", dwAddr); gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = dwLimit; break; } LOG_UCODE(""); LOG_UCODE("\\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/"); LOG_UCODE("#############################################"); } extern Matrix ALIGN(16, dkrMatrixTransposed) void RSP_Mtx_DKR(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwCommand = ((gfx->words.w0)>>16)&0xFF; //uint32 dwLength = ((gfx->words.w0)) &0xFFFF; dwAddr = (gfx->words.w1)+RSPSegmentAddr(gRSP.dwDKRMatrixAddr); //gRSP.DKRCMatrixIndex = ((gfx->words.w0)>>22)&3; bool mul=false; int index = 0; switch( dwCommand ) { case 0xC0: // DKR gRSP.DKRCMatrixIndex = index = 3; break; case 0x80: // DKR gRSP.DKRCMatrixIndex = index = 2; break; case 0x40: // DKR gRSP.DKRCMatrixIndex = index = 1; break; case 0x20: // DKR gRSP.DKRCMatrixIndex = index = 0; break; case 0x00: gRSP.DKRCMatrixIndex = index = 0; break; case 0x01: //mul = true; gRSP.DKRCMatrixIndex = index = 1; break; case 0x02: //mul = true; gRSP.DKRCMatrixIndex = index = 2; break; case 0x03: //mul = true; gRSP.DKRCMatrixIndex = index = 3; break; case 0x81: index = 1; mul = true; break; case 0x82: index = 2; mul = true; break; case 0x83: index = 3; mul = true; break; default: DebuggerAppendMsg("Fix me, mtx DKR, cmd=%08X", dwCommand); break; } // Load matrix from dwAddr Matrix &mat = gRSP.DKRMatrixes[index]; LoadMatrix(dwAddr); if( mul ) { mat = matToLoad*gRSP.DKRMatrixes[0]; } else { mat = matToLoad; } if( status.isSSEEnabled ) MatrixTranspose(&dkrMatrixTransposed, &mat); DEBUGGER_IF_DUMP(logMatrix,TRACE3("DKR Matrix: cmd=0x%X, idx = %d, mul=%d", dwCommand, index, mul)); LOG_UCODE(" DKR Loading Mtx: %d, command=%d", index, dwCommand); DEBUGGER_PAUSE_AND_DUMP(NEXT_MATRIX_CMD,{TRACE0("Paused at DKR Matrix Cmd");}); } void RSP_Vtx_DKR(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwV0 = (((gfx->words.w0) >> 9 )&0x1F); uint32 dwN = (((gfx->words.w0) >>19 )&0x1F)+1; if( gfx->words.w0 & 0x00010000 ) { if( gRSP.DKRBillBoard ) gRSP.DKRVtxCount = 1; } else { gRSP.DKRVtxCount = 0; } dwV0 += gRSP.DKRVtxCount; LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d", dwAddr, dwV0, dwN); DEBUGGER_ONLY_IF( (pauseAtNext && (eventToPause==NEXT_VERTEX_CMD||eventToPause==NEXT_MATRIX_CMD)), {DebuggerAppendMsg("DKR Vtx: Cmd0=%08X, Cmd1=%08X", (gfx->words.w0), (gfx->words.w1));}); VTX_DUMP(TRACE2("Vtx_DKR, cmd0=%08X cmd1=%08X", (gfx->words.w0), (gfx->words.w1))); VTX_DUMP(TRACE2("Vtx_DKR, v0=%d n=%d", dwV0, dwN)); if (dwV0 >= 32) dwV0 = 31; if ((dwV0 + dwN) > 32) { WARNING(TRACE0("Warning, attempting to load into invalid vertex positions")); dwN = 32 - dwV0; } //if( dwAddr == 0 || dwAddr < 0x2000) { dwAddr = (gfx->words.w1)+RSPSegmentAddr(gRSP.dwDKRVtxAddr); } // Check that address is valid... if ((dwAddr + (dwN*16)) > g_dwRamSize) { WARNING(TRACE1("ProcessVertexData: Address out of range (0x%08x)", dwAddr)); } else { ProcessVertexDataDKR(dwAddr, dwV0, dwN); status.dwNumVertices += dwN; RDP_GFX_DumpVtxInfoDKR(dwAddr, dwV0, dwN); } } void RSP_Vtx_Gemini(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwV0 = (((gfx->words.w0)>>9)&0x1F); uint32 dwN = (((gfx->words.w0) >>19 )&0x1F); LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d", dwAddr, dwV0, dwN); DEBUGGER_ONLY_IF( (pauseAtNext && (eventToPause==NEXT_VERTEX_CMD||eventToPause==NEXT_MATRIX_CMD)), {DebuggerAppendMsg("DKR Vtx: Cmd0=%08X, Cmd1=%08X", (gfx->words.w0), (gfx->words.w1));}); VTX_DUMP(TRACE2("Vtx_DKR, cmd0=%08X cmd1=%08X", (gfx->words.w0), (gfx->words.w1))); if (dwV0 >= 32) dwV0 = 31; if ((dwV0 + dwN) > 32) { TRACE0("Warning, attempting to load into invalid vertex positions"); dwN = 32 - dwV0; } //if( dwAddr == 0 || dwAddr < 0x2000) { dwAddr = (gfx->words.w1)+RSPSegmentAddr(gRSP.dwDKRVtxAddr); } // Check that address is valid... if ((dwAddr + (dwN*16)) > g_dwRamSize) { TRACE1("ProcessVertexData: Address out of range (0x%08x)", dwAddr); } else { ProcessVertexDataDKR(dwAddr, dwV0, dwN); status.dwNumVertices += dwN; RDP_GFX_DumpVtxInfoDKR(dwAddr, dwV0, dwN); } } // DKR verts are extra 4 bytes void RDP_GFX_DumpVtxInfoDKR(uint32 dwAddr, uint32 dwV0, uint32 dwN) { #ifdef DEBUGGER uint32 dwV; int i; short * psSrc = (short *)(g_pRDRAMu8 + dwAddr); i = 0; for (dwV = dwV0; dwV < dwV0 + dwN; dwV++) { float x = (float)psSrc[(i + 0) ^ 1]; float y = (float)psSrc[(i + 1) ^ 1]; float z = (float)psSrc[(i + 2) ^ 1]; //uint16 wFlags = CRender::g_pRender->m_dwVecFlags[dwV]; //(uint16)psSrc[3^0x1]; uint16 wA = psSrc[(i + 3) ^ 1]; uint16 wB = psSrc[(i + 4) ^ 1]; uint8 a = wA>>8; uint8 b = (uint8)wA; uint8 c = wB>>8; uint8 d = (uint8)wB; XVECTOR4 & t = g_vecProjected[dwV]; LOG_UCODE(" #%02d Pos: {% 6f,% 6f,% 6f} Extra: %02x %02x %02x %02x (transf: {% 6f,% 6f,% 6f})", dwV, x, y, z, a, b, c, d, t.x, t.y, t.z ); i+=5; } uint16 * pwSrc = (uint16 *)(g_pRDRAMu8 + dwAddr); i = 0; for (dwV = dwV0; dwV < dwV0 + dwN; dwV++) { LOG_UCODE(" #%02d %04x %04x %04x %04x %04x", dwV, pwSrc[(i + 0) ^ 1], pwSrc[(i + 1) ^ 1], pwSrc[(i + 2) ^ 1], pwSrc[(i + 3) ^ 1], pwSrc[(i + 4) ^ 1]); i += 5; } #endif // DEBUGGER } void DLParser_Set_Addr_Ucode6(Gfx *gfx) { gRSP.dwDKRMatrixAddr = (gfx->words.w0)&0x00FFFFFF; gRSP.dwDKRVtxAddr = (gfx->words.w1)&0x00FFFFFF; gRSP.DKRVtxCount=0; } void RSP_Vtx_WRUS(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwLength = ((gfx->words.w0))&0xFFFF; uint32 dwN= (dwLength + 1) / 0x210; //uint32 dwN= (dwLength >> 9); //uint32 dwV0 = (((gfx->words.w0)>>16)&0x3f)/5; uint32 dwV0 = (((gfx->words.w0)>>16)&0xFF)/5; LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d, Length: 0x%04x", dwAddr, dwV0, dwN, dwLength); if (dwV0 >= 32) dwV0 = 31; if ((dwV0 + dwN) > 32) { TRACE0("Warning, attempting to load into invalid vertex positions"); dwN = 32 - dwV0; } ProcessVertexData(dwAddr, dwV0, dwN); status.dwNumVertices += dwN; DisplayVertexInfo(dwAddr, dwV0, dwN); } void RSP_Vtx_ShadowOfEmpire(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwLength = ((gfx->words.w0))&0xFFFF; uint32 dwN= (((gfx->words.w0) >> 4) & 0xFFF) / 33 + 1; uint32 dwV0 = 0; LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d, Length: 0x%04x", dwAddr, dwV0, dwN, dwLength); if (dwV0 >= 32) dwV0 = 31; if ((dwV0 + dwN) > 32) { TRACE0("Warning, attempting to load into invalid vertex positions"); dwN = 32 - dwV0; } ProcessVertexData(dwAddr, dwV0, dwN); status.dwNumVertices += dwN; DisplayVertexInfo(dwAddr, dwV0, dwN); } void RSP_DL_In_MEM_DKR(Gfx *gfx) { // This cmd is likely to execute number of ucode at the given address uint32 dwAddr = (gfx->words.w1);//RSPSegmentAddr((gfx->words.w1)); { gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = (((gfx->words.w0)>>16)&0xFF); } } uint16 ConvertYUVtoR5G5B5X1(int y, int u, int v) { float r = y + (1.370705f * (v-128)); float g = y - (0.698001f * (v-128)) - (0.337633f * (u-128)); float b = y + (1.732446f * (u-128)); r *= 0.125f; g *= 0.125f; b *= 0.125f; //clipping the result if (r > 32) r = 32; if (g > 32) g = 32; if (b > 32) b = 32; if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0; uint16 c = (uint16)(((uint16)(r) << 11) | ((uint16)(g) << 6) | ((uint16)(b) << 1) | 1); return c; } void TexRectToN64FrameBuffer_YUV_16b(uint32 x0, uint32 y0, uint32 width, uint32 height) { // Convert YUV image at TImg and Copy the texture into the N64 RDRAM framebuffer memory uint32 n64CIaddr = g_CI.dwAddr; uint32 n64CIwidth = g_CI.dwWidth; for (uint32 y = 0; y < height; y++) { uint32* pN64Src = (uint32*)(g_pRDRAMu8+(g_TI.dwAddr&(g_dwRamSize-1)))+y*(g_TI.dwWidth>>1); uint16* pN64Dst = (uint16*)(g_pRDRAMu8+(n64CIaddr&(g_dwRamSize-1)))+(y+y0)*n64CIwidth; for (uint32 x = 0; x < width; x+=2) { uint32 val = *pN64Src++; int y0 = (uint8)val&0xFF; int v = (uint8)(val>>8)&0xFF; int y1 = (uint8)(val>>16)&0xFF; int u = (uint8)(val>>24)&0xFF; pN64Dst[x+x0] = ConvertYUVtoR5G5B5X1(y0,u,v); pN64Dst[x+x0+1] = ConvertYUVtoR5G5B5X1(y1,u,v); } } } extern uObjMtxReal gObjMtxReal; void DLParser_OgreBatter64BG(Gfx *gfx) { #ifdef DEBUGGER uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjTxSprite *ptr = (uObjTxSprite*)(g_pRDRAMu8+dwAddr); #endif PrepareTextures(); CTexture *ptexture = g_textures[0].m_pCTexture; TexRectToN64FrameBuffer_16b( (uint32)gObjMtxReal.X, (uint32)gObjMtxReal.Y, ptexture->m_dwWidth, ptexture->m_dwHeight, gRSP.curTile); #ifdef DEBUGGER CRender::g_pRender->DrawSpriteR(*ptr, false); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((pauseAtNext && (eventToPause==NEXT_OBJ_TXT_CMD|| eventToPause==NEXT_FLUSH_TRI)), {DebuggerAppendMsg("OgreBatter 64 BG: Addr=%08X\n", dwAddr);}); #endif } void DLParser_Bomberman2TextRect(Gfx *gfx) { // Bomberman 64 - The Second Attack! (U) [!] // The 0x02 cmd, list a TexRect cmd if( options.enableHackForGames == HACK_FOR_OGRE_BATTLE && gRDP.tiles[7].dwFormat == TXT_FMT_YUV ) { TexRectToN64FrameBuffer_YUV_16b( (uint32)gObjMtxReal.X, (uint32)gObjMtxReal.Y, 16, 16); //DLParser_OgreBatter64BG((gfx->words.w0), (gfx->words.w1)); return; } uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjSprite *info = (uObjSprite*)(g_pRDRAMu8+dwAddr); uint32 dwTile = gRSP.curTile; PrepareTextures(); //CRender::g_pRender->SetCombinerAndBlender(); uObjTxSprite drawinfo; memcpy( &(drawinfo.sprite), info, sizeof(uObjSprite)); CRender::g_pRender->DrawSpriteR(drawinfo, false, dwTile, 0, 0, drawinfo.sprite.imageW/32, drawinfo.sprite.imageH/32); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((pauseAtNext && (eventToPause==NEXT_TRIANGLE|| eventToPause==NEXT_FLUSH_TRI)), { DebuggerAppendMsg("Bomberman 64 - TextRect: Addr=%08X\n", dwAddr); dwAddr &= (g_dwRamSize-1); DebuggerAppendMsg("%08X-%08X-%08X-%08X-%08X-%08X\n", RDRAM_UWORD(dwAddr), RDRAM_UWORD(dwAddr+4), RDRAM_UWORD(dwAddr+8), RDRAM_UWORD(dwAddr+12), RDRAM_UWORD(dwAddr+16), RDRAM_UWORD(dwAddr+20) ); } ); } void RSP_MoveWord_DKR(Gfx *gfx) { SP_Timing(RSP_GBI1_MoveWord); uint32 dwNumLights; switch ((gfx->words.w0) & 0xFF) { case RSP_MOVE_WORD_NUMLIGHT: dwNumLights = (gfx->words.w1)&0x7; LOG_UCODE(" RSP_MOVE_WORD_NUMLIGHT: Val:%d", dwNumLights); gRSP.ambientLightIndex = dwNumLights; SetNumLights(dwNumLights); //gRSP.DKRBillBoard = (gfx->words.w1)&0x1 ? true : false; gRSP.DKRBillBoard = (gfx->words.w1)&0x7 ? true : false; LOG_UCODE(" gRSP.DKRBillBoard = %d", gRSP.DKRBillBoard); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_MATRIX_CMD, {DebuggerAppendMsg("DKR Moveword, select gRSP.DKRBillBoard %s, cmd0=%08X, cmd1=%08X", gRSP.DKRBillBoard?"true":"false", (gfx->words.w0), (gfx->words.w1));}); break; case RSP_MOVE_WORD_LIGHTCOL: gRSP.DKRCMatrixIndex = ((gfx->words.w1)>>6)&7; //gRSP.DKRCMatrixIndex = ((gfx->words.w1)>>6)&3; LOG_UCODE(" gRSP.DKRCMatrixIndex = %d", gRSP.DKRCMatrixIndex); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_MATRIX_CMD, {DebuggerAppendMsg("DKR Moveword, select matrix %d, cmd0=%08X, cmd1=%08X", gRSP.DKRCMatrixIndex, (gfx->words.w0), (gfx->words.w1));}); break; default: RSP_GBI1_MoveWord(gfx); break; } } void RSP_DMA_Tri_DKR(Gfx *gfx) { BOOL bTrisAdded = FALSE; uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 flag = ((gfx->words.w0) & 0xFF0000) >> 16; if (flag&1) CRender::g_pRender->SetCullMode(false,true); else CRender::g_pRender->SetCullMode(false,false); uint32 dwNum = (((gfx->words.w0) & 0xFFF0) >>4 ); uint32 * pData = (uint32*)&g_pRDRAMu32[dwAddr/4]; if( dwAddr+16*dwNum >= g_dwRamSize ) { TRACE0("DMATRI invalid memory pointer"); return; } TRI_DUMP(TRACE2("DMATRI, addr=%08X, Cmd0=%08X\n", dwAddr, (gfx->words.w0))); status.primitiveType = PRIM_DMA_TRI; for (uint32 i = 0; i < dwNum; i++) { LOG_UCODE(" 0x%08x: %08x %08x %08x %08x", dwAddr + i*16, pData[0], pData[1], pData[2], pData[3]); uint32 dwInfo = pData[0]; uint32 dwV0 = (dwInfo >> 16) & 0x1F; uint32 dwV1 = (dwInfo >> 8) & 0x1F; uint32 dwV2 = (dwInfo ) & 0x1F; TRI_DUMP(TRACE5("DMATRI: %d, %d, %d (%08X-%08X)", dwV0,dwV1,dwV2,(gfx->words.w0),(gfx->words.w1))); //if (IsTriangleVisible(dwV0, dwV1, dwV2)) { DEBUG_DUMP_VERTEXES("DmaTri", dwV0, dwV1, dwV2); LOG_UCODE(" Tri: %d,%d,%d", dwV0, dwV1, dwV2); if (!bTrisAdded )//&& CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } // Generate texture coordinates short s0 = ((short)(pData[1]>>16)); short t0 = ((short)(pData[1]&0xFFFF)); short s1 = ((short)(pData[2]>>16)); short t1 = ((short)(pData[2]&0xFFFF)); short s2 = ((short)(pData[3]>>16)); short t2 = ((short)(pData[3]&0xFFFF)); TRI_DUMP( { DebuggerAppendMsg(" (%d,%d), (%d,%d), (%d,%d)",s0,t0,s1,t1,s2,t2); DebuggerAppendMsg(" (%08X), (%08X), (%08X), (%08X)",pData[0],pData[1],pData[2],pData[3]); }); CRender::g_pRender->SetVtxTextureCoord(dwV0, s0, t0); CRender::g_pRender->SetVtxTextureCoord(dwV1, s1, t1); CRender::g_pRender->SetVtxTextureCoord(dwV2, s2, t2); if( !bTrisAdded ) { CRender::g_pRender->SetCombinerAndBlender(); } bTrisAdded = true; PrepareTriangle(dwV0, dwV1, dwV2); } pData += 4; } if (bTrisAdded) { CRender::g_pRender->DrawTriangles(); } gRSP.DKRVtxCount=0; } uint32 dwPDCIAddr = 0; void ProcessVertexDataPD(uint32 dwAddr, uint32 dwV0, uint32 dwNum); void RSP_Vtx_PD(Gfx *gfx) { SP_Timing(RSP_GBI0_Vtx); uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwV0 = ((gfx->words.w0)>>16)&0x0F; uint32 dwN = (((gfx->words.w0)>>20)&0x0F)+1; //uint32 dwLength = ((gfx->words.w0))&0xFFFF; LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d", dwAddr, dwV0, dwN); ProcessVertexDataPD(dwAddr, dwV0, dwN); status.dwNumVertices += dwN; } void RSP_Set_Vtx_CI_PD(Gfx *gfx) { // Color index buf address dwPDCIAddr = RSPSegmentAddr((gfx->words.w1)); } void RSP_Tri4_PD(Gfx *gfx) { uint32 w0 = gfx->words.w0; uint32 w1 = gfx->words.w1; status.primitiveType = PRIM_TRI2; // While the next command pair is Tri2, add vertices uint32 dwPC = gDlistStack[gDlistStackPointer].pc; BOOL bTrisAdded = FALSE; do { uint32 dwFlag = (w0>>16)&0xFF; LOG_UCODE(" PD Tri4: 0x%08x 0x%08x Flag: 0x%02x", w0, w1, dwFlag); BOOL bVisible; for( uint32 i=0; i<4; i++) { uint32 v0 = (w1>>(4+(i<<3))) & 0xF; uint32 v1 = (w1>>( (i<<3))) & 0xF; uint32 v2 = (w0>>( (i<<2))) & 0xF; bVisible = IsTriangleVisible(v0, v2, v1); LOG_UCODE(" (%d, %d, %d) %s", v0, v1, v2, bVisible ? "": "(clipped)"); if (bVisible) { DEBUG_DUMP_VERTEXES("Tri4_PerfectDark 1/2", v0, v1, v2); if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } if( !bTrisAdded ) { CRender::g_pRender->SetCombinerAndBlender(); } bTrisAdded = true; PrepareTriangle(v0, v2, v1); } } w0 = *(uint32 *)(g_pRDRAMu8 + dwPC+0); w1 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && (w0>>24) == (uint8)RSP_TRI2); #else } while ((w0>>24) == (uint8)RSP_TRI2); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at PD Tri4")); } void DLParser_Tri4_Conker(Gfx *gfx) { uint32 w0 = gfx->words.w0; uint32 w1 = gfx->words.w1; status.primitiveType = PRIM_TRI2; // While the next command pair is Tri2, add vertices uint32 dwPC = gDlistStack[gDlistStackPointer].pc; BOOL bTrisAdded = FALSE; do { LOG_UCODE(" Conker Tri4: 0x%08x 0x%08x", w0, w1); uint32 idx[12]; idx[0] = (w1 )&0x1F; idx[1] = (w1>> 5)&0x1F; idx[2] = (w1>>10)&0x1F; idx[3] = (w1>>15)&0x1F; idx[4] = (w1>>20)&0x1F; idx[5] = (w1>>25)&0x1F; idx[6] = (w0 )&0x1F; idx[7] = (w0>> 5)&0x1F; idx[8] = (w0>>10)&0x1F; idx[ 9] = (((w0>>15)&0x7)<<2)|(w1>>30); idx[10] = (w0>>18)&0x1F; idx[11] = (w0>>23)&0x1F; BOOL bVisible; for( uint32 i=0; i<4; i++) { uint32 v0=idx[i*3 ]; uint32 v1=idx[i*3+1]; uint32 v2=idx[i*3+2]; bVisible = IsTriangleVisible(v0, v1, v2); LOG_UCODE(" (%d, %d, %d) %s", v0, v1, v2, bVisible ? "": "(clipped)"); if (bVisible) { DEBUG_DUMP_VERTEXES("Tri4 Conker:", v0, v1, v2); if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } if( !bTrisAdded ) { CRender::g_pRender->SetCombinerAndBlender(); } bTrisAdded = true; PrepareTriangle(v0, v1, v2); } } w0 = *(uint32 *)(g_pRDRAMu8 + dwPC+0); w1 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && (w0>>28) == 1 ); #else } while ((w0>>28) == 1); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at Conker Tri4")); } void RDP_GFX_Force_Vertex_Z_Conker(uint32 dwAddr) { VTX_DUMP( { s8 * pcBase = g_pRDRAMs8 + (dwAddr&(g_dwRamSize-1)); uint32 * pdwBase = (uint32 *)pcBase; for (int i = 0; i < 4; i++) { DebuggerAppendMsg(" %08x %08x %08x %08x", pdwBase[0], pdwBase[1], pdwBase[2], pdwBase[3]); pdwBase+=4; } }); dwConkerVtxZAddr = dwAddr; DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{TRACE0("Paused at RDP_GFX_Force_Matrix_Conker Cmd");}); } void DLParser_MoveMem_Conker(Gfx *gfx) { uint32 dwType = ((gfx->words.w0) ) & 0xFE; uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); if( dwType == RSP_GBI2_MV_MEM__MATRIX ) { LOG_UCODE(" DLParser_MoveMem_Conker"); RDP_GFX_Force_Vertex_Z_Conker(dwAddr); } else if( dwType == RSP_GBI2_MV_MEM__LIGHT ) { LOG_UCODE(" MoveMem Light Conker"); uint32 dwOffset2 = ((gfx->words.w0) >> 5) & 0x3FFF; uint32 dwLight=0xFF; if( dwOffset2 >= 0x30 ) { dwLight = (dwOffset2 - 0x30)/0x30; LOG_UCODE(" Light %d:", dwLight); RSP_MoveMemLight(dwLight, dwAddr); } else { // fix me //TRACE0("Check me in DLParser_MoveMem_Conker - MoveMem Light"); } DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_SET_LIGHT, { DebuggerAppendMsg("RSP_MoveMemLight: %d, Addr=%08X, cmd0=%08X", dwLight, dwAddr, (gfx->words.w0)); TRACE0("Pause after MoveMemLight"); }); } else { RSP_GBI2_MoveMem(gfx); } } extern void ProcessVertexDataConker(uint32 dwAddr, uint32 dwV0, uint32 dwNum); void RSP_Vtx_Conker(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwVEnd = (((gfx->words.w0) )&0xFFF)/2; uint32 dwN = (((gfx->words.w0)>>12)&0xFFF); uint32 dwV0 = dwVEnd - dwN; LOG_UCODE(" Vtx: Address 0x%08x, vEnd: %d, v0: %d, Num: %d", dwAddr, dwVEnd, dwV0, dwN); ProcessVertexDataConker(dwAddr, dwV0, dwN); status.dwNumVertices += dwN; DisplayVertexInfo(dwAddr, dwV0, dwN); } void DLParser_MoveWord_Conker(Gfx *gfx) { uint32 dwType = ((gfx->words.w0) >> 16) & 0xFF; if( dwType != RSP_MOVE_WORD_NUMLIGHT ) { RSP_GBI2_MoveWord(gfx); } else { uint32 dwNumLights = ((gfx->words.w1)/48); LOG_UCODE("Conker RSP_MOVE_WORD_NUMLIGHT: %d", dwNumLights); gRSP.ambientLightIndex = dwNumLights+1; SetNumLights(dwNumLights); DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_SET_LIGHT, { DebuggerAppendMsg("SetNumLights: %d", dwNumLights); TRACE0("Pause after SetNumLights"); }); } } void DLParser_Ucode8_0x0(Gfx *gfx) { LOG_UCODE("DLParser_Ucode8_0x0"); if( (gfx->words.w0) == 0 && (gfx->words.w1) ) { uint32 newaddr = RSPSegmentAddr((gfx->words.w1)); if( newaddr && newaddr < g_dwRamSize) { if( gDlistStackPointer < MAX_DL_STACK_SIZE-1 ) { gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = newaddr+8; // Always skip the first 2 entries gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; } else { DebuggerAppendMsg("Error, gDlistStackPointer overflow"); } } } else { LOG_UCODE("DLParser_Ucode8_0x0, skip 0x%08X, 0x%08x", (gfx->words.w0), (gfx->words.w1)); gDlistStack[gDlistStackPointer].pc += 8; } } uint32 Rogue_Squadron_Vtx_XYZ_Cmd; uint32 Rogue_Squadron_Vtx_XYZ_Addr; uint32 Rogue_Squadron_Vtx_Color_Cmd; uint32 Rogue_Squadron_Vtx_Color_Addr; uint32 GSBlkAddrSaves[100][2]; void ProcessVertexData_Rogue_Squadron(uint32 dwXYZAddr, uint32 dwColorAddr, uint32 dwXYZCmd, uint32 dwColorCmd); void DLParser_RS_Color_Buffer(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); if( dwAddr > g_dwRamSize ) { TRACE0("DL, addr is wrong"); dwAddr = (gfx->words.w1)&(g_dwRamSize-1); } Rogue_Squadron_Vtx_Color_Cmd = (gfx->words.w0); Rogue_Squadron_Vtx_Color_Addr = dwAddr; LOG_UCODE("Vtx_Color at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1)); #ifdef DEBUGGER if( pauseAtNext && (eventToPause == NEXT_VERTEX_CMD ) ) { DebuggerAppendMsg("Vtx_Color at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1)); if( dwAddr < g_dwRamSize ) { DumpHex(dwAddr, min(64, g_dwRamSize-dwAddr)); } } #endif ProcessVertexData_Rogue_Squadron(Rogue_Squadron_Vtx_XYZ_Addr, Rogue_Squadron_Vtx_Color_Addr, Rogue_Squadron_Vtx_XYZ_Cmd, Rogue_Squadron_Vtx_Color_Cmd); } void DLParser_RS_Vtx_Buffer(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); if( dwAddr > g_dwRamSize ) { TRACE0("DL, addr is wrong"); dwAddr = (gfx->words.w1)&(g_dwRamSize-1); } LOG_UCODE("Vtx_XYZ at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1)); Rogue_Squadron_Vtx_XYZ_Cmd = (gfx->words.w0); Rogue_Squadron_Vtx_XYZ_Addr = dwAddr; #ifdef DEBUGGER if( pauseAtNext && (eventToPause == NEXT_VERTEX_CMD ) ) { DebuggerAppendMsg("Vtx_XYZ at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1)); if( dwAddr < g_dwRamSize ) { DumpHex(dwAddr, min(64, g_dwRamSize-dwAddr)); } } #endif } void DLParser_RS_Block(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode 0x80 at PC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1)); } void DLParser_RS_MoveMem(Gfx *gfx) { //uint32 dwPC = gDlistStack[gDlistStackPointer].pc; //uint32 cmd1 = ((dwPC)&0x00FFFFFF)|0x80000000; RSP_GBI1_MoveMem(gfx); /* LOG_UCODE("RS_MoveMem", ((gfx->words.w0)>>24)); LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, dwCmd2, dwCmd3); dwPC+=8; uint32 dwCmd4 = *(uint32 *)(g_pRDRAMu8 + dwPC); uint32 dwCmd5 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, dwCmd4, dwCmd5); */ gDlistStack[gDlistStackPointer].pc += 16; //DEBUGGER_PAUSE_AND_DUMP(NEXT_SET_MODE_CMD, { // DebuggerAppendMsg("Pause after RS_MoveMem at: %08X\n", dwPC-8); //}); } void DLParser_RS_0xbe(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode %02X, skip 1", ((gfx->words.w0)>>24)); LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, dwCmd2, dwCmd3); gDlistStack[gDlistStackPointer].pc += 8; DEBUGGER_PAUSE_AND_DUMP(NEXT_SET_MODE_CMD, { DebuggerAppendMsg("Pause after RS_0xbe at: %08X\n", dwPC-8); DebuggerAppendMsg("\t0x%08x 0x%08x", (gfx->words.w0), (gfx->words.w1)); DebuggerAppendMsg("\t0x%08x 0x%08x", dwCmd2, dwCmd3); }); } void DLParser_Ucode8_EndDL(Gfx *gfx) { #ifdef DEBUGGER uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; #endif RDP_GFX_PopDL(); DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, DebuggerAppendMsg("PC=%08X: EndDL, return to %08X\n\n", dwPC, gDlistStack[gDlistStackPointer].pc)); } void DLParser_Ucode8_DL(Gfx *gfx) // DL Function Call { #ifdef DEBUGGER uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; #endif uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwAddr); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwAddr+4); if( dwAddr > g_dwRamSize ) { TRACE0("DL, addr is wrong"); dwAddr = (gfx->words.w1)&(g_dwRamSize-1); } // Detect looping /*if(gDlistStackPointer>0 ) { for( int i=0; i>24) == 0x80 ) { GSBlkAddrSaves[gDlistStackPointer][0] = dwCmd2; GSBlkAddrSaves[gDlistStackPointer][1] = dwCmd3; } DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, DebuggerAppendMsg("\nPC=%08X: Call DL at Address %08X - %08X, %08X\n\n", dwPC, dwAddr, dwCmd2, dwCmd3)); } void DLParser_Ucode8_JUMP(Gfx *gfx) // DL Function Call { if( ((gfx->words.w0)&0x00FFFFFF) == 0 ) { #ifdef DEBUGGER uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; #endif uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); if( dwAddr > g_dwRamSize ) { TRACE0("DL, addr is wrong"); dwAddr = (gfx->words.w1)&(g_dwRamSize-1); } #ifdef DEBUGGER uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwAddr); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwAddr+4); #endif gDlistStack[gDlistStackPointer].pc = dwAddr+8; // Jump to new address DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, DebuggerAppendMsg("\nPC=%08X: Jump to Address %08X - %08X, %08X\n\n", dwPC, dwAddr, dwCmd2, dwCmd3)); } else { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode 0x07 at PC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1)); } } void DLParser_Ucode8_Unknown(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode %02X at PC=%08X: 0x%08x 0x%08x\n", ((gfx->words.w0)>>24), dwPC, (gfx->words.w0), (gfx->words.w1)); } void DLParser_Unknown_Skip1(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode %02X, skip 1", ((gfx->words.w0)>>24)); gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1)); gDlistStack[gDlistStackPointer].pc += 8; } void DLParser_Unknown_Skip2(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode %02X, skip 2", ((gfx->words.w0)>>24)); gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1)); gDlistStack[gDlistStackPointer].pc += 16; } void DLParser_Unknown_Skip3(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode %02X, skip 3", ((gfx->words.w0)>>24)); gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1)); gDlistStack[gDlistStackPointer].pc += 24; } void DLParser_Unknown_Skip4(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode %02X, skip 4", ((gfx->words.w0)>>24)); gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1)); gDlistStack[gDlistStackPointer].pc += 32; } void DLParser_Ucode8_0x05(Gfx *gfx) { // Be careful, 0x05 is variable length ucode /* 0028E4E0: 05020088, 04D0000F - Reserved1 0028E4E8: 6BDC0306, 00000000 - G_NOTHING 0028E4F0: 05010130, 01B0000F - Reserved1 0028E4F8: 918A01CA, 1EC5FF3B - G_NOTHING 0028E500: 05088C68, F5021809 - Reserved1 0028E508: 04000405, 00000000 - RSP_VTX 0028E510: 102ECE60, 202F2AA0 - G_NOTHING 0028E518: 05088C90, F5021609 - Reserved1 0028E520: 04050405, F0F0F0F0 - RSP_VTX 0028E528: 102ED0C0, 202F2D00 - G_NOTHING 0028E530: B5000000, 00000000 - RSP_LINE3D 0028E538: 8028E640, 8028E430 - G_NOTHING 0028E540: 00000000, 00000000 - RSP_SPNOOP */ if((gfx->words.w1) == 0) return; else DLParser_Unknown_Skip4(gfx); } void DLParser_Ucode8_0xb4(Gfx *gfx) { #ifdef DEBUGGER uint32 dwPC = gDlistStack[gDlistStackPointer].pc; #endif if(((gfx->words.w0)&0xFF) == 0x06) DLParser_Unknown_Skip3(gfx); else if(((gfx->words.w0)&0xFF) == 0x04) DLParser_Unknown_Skip1(gfx); else if(((gfx->words.w0)&0xFFF) == 0x600) DLParser_Unknown_Skip3(gfx); else { #ifdef DEBUGGER if(pauseAtNext) { DebuggerAppendMsg("ucode 0xb4 at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1)); } #endif DLParser_Unknown_Skip3(gfx); } } void DLParser_Ucode8_0xb5(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode 0xB5 at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1)); uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC+8); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+12); LOG_UCODE(" : 0x%08x 0x%08x\n", dwCmd2, dwCmd3); //if( dwCmd2 == 0 && dwCmd3 == 0 ) { DLParser_Ucode8_EndDL(gfx); // Check me return; } gDlistStack[gDlistStackPointer].pc += 8; return; if( GSBlkAddrSaves[gDlistStackPointer][0] == 0 || GSBlkAddrSaves[gDlistStackPointer][1] == 0 ) { #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_DLIST) { DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, no next blk\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); } #endif DLParser_Ucode8_EndDL(gfx); // Check me return; } if( ((dwCmd2>>24)!=0x80 && (dwCmd2>>24)!=0x00 ) || ((dwCmd3>>24)!=0x80 && (dwCmd3>>24)!=0x00 ) ) { #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_DLIST) { DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, Unknown\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); } #endif DLParser_Ucode8_EndDL(gfx); // Check me return; } if( (dwCmd2>>24)!= (dwCmd3>>24) ) { #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_DLIST) { DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, Unknown\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); } #endif DLParser_Ucode8_EndDL(gfx); // Check me return; } if( (dwCmd2>>24)==0x80 && (dwCmd3>>24)==0x80 ) { if( dwCmd2 < dwCmd3 ) { // All right, the next block is not ucode, but data #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_DLIST) { DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, next blk is data\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); } #endif DLParser_Ucode8_EndDL(gfx); // Check me return; } uint32 dwCmd4 = *(uint32 *)(g_pRDRAMu8 + (dwCmd2&0x00FFFFFF)); uint32 dwCmd5 = *(uint32 *)(g_pRDRAMu8 + (dwCmd2&0x00FFFFFF)+4); uint32 dwCmd6 = *(uint32 *)(g_pRDRAMu8 + (dwCmd3&0x00FFFFFF)); uint32 dwCmd7 = *(uint32 *)(g_pRDRAMu8 + (dwCmd3&0x00FFFFFF)+4); if( (dwCmd4>>24) != 0x80 || (dwCmd5>>24) != 0x80 || (dwCmd6>>24) != 0x80 || (dwCmd7>>24) != 0x80 || dwCmd4 < dwCmd5 || dwCmd6 < dwCmd7 ) { // All right, the next block is not ucode, but data #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_DLIST) { DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, next blk is data\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); DebuggerAppendMsg("%08X, %08X %08X,%08X\n", dwCmd4, dwCmd5, dwCmd6, dwCmd7); } #endif DLParser_Ucode8_EndDL(gfx); // Check me return; } gDlistStack[gDlistStackPointer].pc += 8; DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, continue\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); ); return; } else if( (dwCmd2>>24)==0x00 && (dwCmd3>>24)==0x00 ) { #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_DLIST) { DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, next blk is data\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); } #endif DLParser_Ucode8_EndDL(gfx); // Check me return; } else if( (dwCmd2>>24)==0x00 && (dwCmd3>>24)==0x00 ) { dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC+16); dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+20); if( (dwCmd2>>24)==0x80 && (dwCmd3>>24)==0x80 && dwCmd2 < dwCmd3 ) { // All right, the next block is not ucode, but data #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_DLIST) { DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, next blk is data\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); } #endif DLParser_Ucode8_EndDL(gfx); // Check me return; } else { gDlistStack[gDlistStackPointer].pc += 8; DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, continue\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3) ); return; } } #ifdef DEBUGGER uint32 dwAddr1 = RSPSegmentAddr(dwCmd2); uint32 dwAddr2 = RSPSegmentAddr(dwCmd3); if( (gfx->words.w1) != 0 ) { DebuggerAppendMsg("!!!! PC=%08X: 0xB5 - %08X : %08X, %08X\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); } #endif DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, continue\n", dwPC, (gfx->words.w1), dwAddr1, dwAddr2) ); return; } void DLParser_Ucode8_0xbc(Gfx *gfx) { if( ((gfx->words.w0)&0xFFF) == 0x58C ) { DLParser_Ucode8_DL(gfx); } else { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode 0xBC at PC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1)); } } void DLParser_Ucode8_0xbd(Gfx *gfx) { /* 00359A68: BD000000, DB5B0077 - RSP_POPMTX 00359A70: C8C0A000, 00240024 - RDP_TriFill 00359A78: 01000100, 00000000 - RSP_MTX 00359A80: BD000501, DB5B0077 - RSP_POPMTX 00359A88: C8C0A000, 00240024 - RDP_TriFill 00359A90: 01000100, 00000000 - RSP_MTX 00359A98: BD000A02, DB5B0077 - RSP_POPMTX 00359AA0: C8C0A000, 00240024 - RDP_TriFill 00359AA8: 01000100, 00000000 - RSP_MTX 00359AB0: BD000F04, EB6F0087 - RSP_POPMTX 00359AB8: C8C0A000, 00280028 - RDP_TriFill 00359AC0: 01000100, 00000000 - RSP_MTX 00359AC8: BD001403, DB5B0077 - RSP_POPMTX 00359AD0: C8C0A000, 00240024 - RDP_TriFill 00359AD8: 01000100, 00000000 - RSP_MTX 00359AE0: B5000000, 00000000 - RSP_LINE3D 00359AE8: 1A000000, 16000200 - G_NOTHING */ if( (gfx->words.w1) != 0 ) { DLParser_Unknown_Skip2(gfx); return; } uint32 dwPC = gDlistStack[gDlistStackPointer].pc; LOG_UCODE("ucode 0xbd at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1)); } void DLParser_Ucode8_0xbf(Gfx *gfx) { if( ((gfx->words.w0)&0xFF) == 0x02 ) DLParser_Unknown_Skip3(gfx); else DLParser_Unknown_Skip1(gfx); } void PD_LoadMatrix_0xb4(uint32 addr) { const float fRecip = 1.0f / 65536.0f; uint32 data[16]; data[0] = *(uint32*)(g_pRDRAMu8+addr+4+ 0); data[1] = *(uint32*)(g_pRDRAMu8+addr+4+ 8); data[2] = *(uint32*)(g_pRDRAMu8+addr+4+16); data[3] = *(uint32*)(g_pRDRAMu8+addr+4+24); data[8] = *(uint32*)(g_pRDRAMu8+addr+4+32); data[9] = *(uint32*)(g_pRDRAMu8+addr+4+40); data[10] = *(uint32*)(g_pRDRAMu8+addr+4+48); data[11] = *(uint32*)(g_pRDRAMu8+addr+4+56); data[4] = *(uint32*)(g_pRDRAMu8+addr+4+ 0+64); data[5] = *(uint32*)(g_pRDRAMu8+addr+4+ 8+64); data[6] = *(uint32*)(g_pRDRAMu8+addr+4+16+64); data[7] = *(uint32*)(g_pRDRAMu8+addr+4+24+64); data[12] = *(uint32*)(g_pRDRAMu8+addr+4+32+64); data[13] = *(uint32*)(g_pRDRAMu8+addr+4+40+64); data[14] = *(uint32*)(g_pRDRAMu8+addr+4+48+64); data[15] = *(uint32*)(g_pRDRAMu8+addr+4+56+64); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { int hi = *(short *)((unsigned char*)data + (((i<<3)+(j<<1) )^0x2)); int lo = *(uint16*)((unsigned char*)data + (((i<<3)+(j<<1) + 32)^0x2)); matToLoad.m[i][j] = (float)((hi<<16) | lo) * fRecip; } } #ifdef DEBUGGER LOG_UCODE( " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n", matToLoad.m[0][0], matToLoad.m[0][1], matToLoad.m[0][2], matToLoad.m[0][3], matToLoad.m[1][0], matToLoad.m[1][1], matToLoad.m[1][2], matToLoad.m[1][3], matToLoad.m[2][0], matToLoad.m[2][1], matToLoad.m[2][2], matToLoad.m[2][3], matToLoad.m[3][0], matToLoad.m[3][1], matToLoad.m[3][2], matToLoad.m[3][3]); #endif // DEBUGGER } void DLParser_RDPHalf_1_0xb4_GoldenEye(Gfx *gfx) { SP_Timing(RSP_GBI1_RDPHalf_1); if( ((gfx->words.w1)>>24) == 0xce ) { PrepareTextures(); CRender::g_pRender->SetCombinerAndBlender(); uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction //PD_LoadMatrix_0xb4(dwPC + 8*16 - 8); uint32 dw1 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*0+4); //uint32 dw2 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*1+4); //uint32 dw3 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*2+4); //uint32 dw4 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*3+4); //uint32 dw5 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*4+4); //uint32 dw6 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*5+4); //uint32 dw7 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*6+4); uint32 dw8 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*7+4); uint32 dw9 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*8+4); uint32 r = (dw8>>16)&0xFF; uint32 g = (dw8 )&0xFF; uint32 b = (dw9>>16)&0xFF; uint32 a = (dw9 )&0xFF; uint32 color = COLOR_RGBA(r, g, b, a); //int x0 = 0; //int x1 = gRDP.scissor.right; int x0 = gRSP.nVPLeftN; int x1 = gRSP.nVPRightN; int y0 = int(dw1&0xFFFF)/4; int y1 = int(dw1>>16)/4; float xscale = g_textures[0].m_pCTexture->m_dwWidth / (float)(x1-x0); float yscale = g_textures[0].m_pCTexture->m_dwHeight / (float)(y1-y0); //float fs0 = (short)(dw3&0xFFFF)/32768.0f*g_textures[0].m_pCTexture->m_dwWidth; //float ft0 = (short)(dw3>>16)/32768.0f*256; CRender::g_pRender->TexRect(x0,y0,x1,y1,0,0,xscale,yscale,true,color); gDlistStack[gDlistStackPointer].pc += 312; #ifdef DEBUGGER if( logUcodes) { dwPC -= 8; LOG_UCODE("GoldenEye Sky at PC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); uint32 *ptr = (uint32 *)(g_pRDRAMu8 + dwPC); for( int i=0; i<21; i++, dwPC+=16,ptr+=4 ) { LOG_UCODE("%08X: %08X %08X %08X %08X", dwPC, ptr[0], ptr[1], ptr[2], ptr[3]); } } #endif DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_FLUSH_TRI, { TRACE0("Pause after Golden Sky Drawing\n"); }); } } void DLParser_RSP_DL_WorldDriver(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); if( dwAddr > g_dwRamSize ) { RSP_RDP_NOIMPL("Error: DL addr = %08X out of range, PC=%08X", dwAddr, gDlistStack[gDlistStackPointer].pc ); dwAddr &= (g_dwRamSize-1); DebuggerPauseCountN( NEXT_DLIST ); } LOG_UCODE(" WorldDriver DisplayList 0x%08x", dwAddr); gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; LOG_UCODE("Level=%d", gDlistStackPointer+1); LOG_UCODE("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); } void DLParser_RSP_Pop_DL_WorldDriver(Gfx *gfx) { RDP_GFX_PopDL(); } void DLParser_RSP_Last_Legion_0x80(Gfx *gfx) { gDlistStack[gDlistStackPointer].pc += 16; LOG_UCODE("DLParser_RSP_Last_Legion_0x80"); } void DLParser_RSP_Last_Legion_0x00(Gfx *gfx) { LOG_UCODE("DLParser_RSP_Last_Legion_0x00"); gDlistStack[gDlistStackPointer].pc += 16; if( (gfx->words.w0) == 0 && (gfx->words.w1) ) { uint32 newaddr = RSPSegmentAddr((gfx->words.w1)); if( newaddr >= g_dwRamSize ) { RDP_GFX_PopDL(); return; } //uint32 dw1 = *(uint32 *)(g_pRDRAMu8 + newaddr+8*0+4); uint32 pc1 = *(uint32 *)(g_pRDRAMu8 + newaddr+8*1+4); uint32 pc2 = *(uint32 *)(g_pRDRAMu8 + newaddr+8*4+4); pc1 = RSPSegmentAddr(pc1); pc2 = RSPSegmentAddr(pc2); if( pc1 && pc1 != 0xffffff && pc1 < g_dwRamSize) { // Need to call both DL gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = pc1; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; } if( pc2 && pc2 != 0xffffff && pc2 < g_dwRamSize ) { gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = pc2; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; } } else if( (gfx->words.w1) == 0 ) { RDP_GFX_PopDL(); } else { // (gfx->words.w0) != 0 RSP_RDP_Nothing(gfx); RDP_GFX_PopDL(); } } void DLParser_TexRect_Last_Legion(Gfx *gfx) { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); status.primitiveType = PRIM_TEXTRECT; // This command used 128bits, and not 64 bits. This means that we have to look one // Command ahead in the buffer, and update the PC. uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); gDlistStack[gDlistStackPointer].pc += 8; LOG_UCODE("0x%08x: %08x %08x", dwPC, *(uint32 *)(g_pRDRAMu8 + dwPC+0), *(uint32 *)(g_pRDRAMu8 + dwPC+4)); uint32 dwXH = (((gfx->words.w0)>>12)&0x0FFF)/4; uint32 dwYH = (((gfx->words.w0) )&0x0FFF)/4; uint32 tileno = ((gfx->words.w1)>>24)&0x07; uint32 dwXL = (((gfx->words.w1)>>12)&0x0FFF)/4; uint32 dwYL = (((gfx->words.w1) )&0x0FFF)/4; if( (int)dwXL >= gRDP.scissor.right || (int)dwYL >= gRDP.scissor.bottom || (int)dwXH < gRDP.scissor.left || (int)dwYH < gRDP.scissor.top ) { // Clipping return; } uint16 uS = (uint16)( dwCmd2>>16)&0xFFFF; uint16 uT = (uint16)( dwCmd2 )&0xFFFF; short s16S = *(short*)(&uS); short s16T = *(short*)(&uT); uint16 uDSDX = (uint16)(( dwCmd3>>16)&0xFFFF); uint16 uDTDY = (uint16)(( dwCmd3 )&0xFFFF); short s16DSDX = *(short*)(&uDSDX); short s16DTDY = *(short*)(&uDTDY); uint32 curTile = gRSP.curTile; ForceMainTextureIndex(tileno); float fS0 = s16S / 32.0f; float fT0 = s16T / 32.0f; float fDSDX = s16DSDX / 1024.0f; float fDTDY = s16DTDY / 1024.0f; uint32 cycletype = gRDP.otherMode.cycle_type; if (cycletype == CYCLE_TYPE_COPY) { fDSDX /= 4.0f; // In copy mode 4 pixels are copied at once. dwXH++; dwYH++; } else if (cycletype == CYCLE_TYPE_FILL) { dwXH++; dwYH++; } if( fDSDX == 0 ) fDSDX = 1; if( fDTDY == 0 ) fDTDY = 1; float fS1 = fS0 + (fDSDX * (dwXH - dwXL)); float fT1 = fT0 + (fDTDY * (dwYH - dwYL)); LOG_UCODE(" Tile:%d Screen(%d,%d) -> (%d,%d)", tileno, dwXL, dwYL, dwXH, dwYH); LOG_UCODE(" Tex:(%#5f,%#5f) -> (%#5f,%#5f) (DSDX:%#5f DTDY:%#5f)", fS0, fT0, fS1, fT1, fDSDX, fDTDY); LOG_UCODE(""); float t0u0 = (fS0-gRDP.tiles[tileno].hilite_sl) * gRDP.tiles[tileno].fShiftScaleS; float t0v0 = (fT0-gRDP.tiles[tileno].hilite_tl) * gRDP.tiles[tileno].fShiftScaleT; float t0u1 = t0u0 + (fDSDX * (dwXH - dwXL))*gRDP.tiles[tileno].fShiftScaleS; float t0v1 = t0v0 + (fDTDY * (dwYH - dwYL))*gRDP.tiles[tileno].fShiftScaleT; if( dwXL==0 && dwYL==0 && dwXH==windowSetting.fViWidth-1 && dwYH==windowSetting.fViHeight-1 && t0u0 == 0 && t0v0==0 && t0u1==0 && t0v1==0 ) { //Using TextRect to clear the screen } else { if( status.bHandleN64RenderTexture && //status.bDirectWriteIntoRDRAM && g_pRenderTextureInfo->CI_Info.dwFormat == gRDP.tiles[tileno].dwFormat && g_pRenderTextureInfo->CI_Info.dwSize == gRDP.tiles[tileno].dwSize && gRDP.tiles[tileno].dwFormat == TXT_FMT_CI && gRDP.tiles[tileno].dwSize == TXT_SIZE_8b ) { if( options.enableHackForGames == HACK_FOR_YOSHI ) { // Hack for Yoshi background image PrepareTextures(); TexRectToFrameBuffer_8b(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_FLUSH_TRI || eventToPause == NEXT_TEXTRECT), { DebuggerAppendMsg("TexRect: tile=%d, X0=%d, Y0=%d, X1=%d, Y1=%d,\nfS0=%f, fT0=%f, ScaleS=%f, ScaleT=%f\n", gRSP.curTile, dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY); DebuggerAppendMsg("Pause after TexRect for Yoshi\n"); }); } else { if( frameBufferOptions.bUpdateCIInfo ) { PrepareTextures(); TexRectToFrameBuffer_8b(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno); } if( !status.bDirectWriteIntoRDRAM ) { CRender::g_pRender->TexRect(dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY); status.dwNumTrisRendered += 2; } } } else { CRender::g_pRender->TexRect(dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY); status.bFrameBufferDrawnByTriangles = true; status.dwNumTrisRendered += 2; } } if( status.bHandleN64RenderTexture ) g_pRenderTextureInfo->maxUsedHeight = max(g_pRenderTextureInfo->maxUsedHeight,(int)dwYH); ForceMainTextureIndex(curTile); } mupen64plus-video-rice-src-2.0/src/RSP_GBI_Sprite2D.h0000644000000000000000000001243212165031100020304 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // Sprite2D Ucodes #include "Render.h" Sprite2DInfo g_Sprite2DInfo; uint32 g_SavedUcode=1; void RSP_GBI_Sprite2DBase(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); dwAddr &= (g_dwRamSize-1); //RSP_RDP_NOIMPL("RDP: Sprite2D (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); g_Sprite2DInfo.spritePtr = (SpriteStruct *)(g_pRDRAMs8+dwAddr); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_SPRITE_2D, {DebuggerAppendMsg("Pause after Sprite2DBase: Addr=%08X\n", dwAddr);}); } typedef struct{ uint32 SourceImagePointer; uint32 TlutPointer; short SubImageWidth; short Stride; char SourceImageBitSize; char SourceImageType; short SubImageHeight; short scaleY; short scaleX; short SourceImageOffsetS; char dummy1[2]; short px; short SourceImageOffsetT; char dummy2[2]; short py; } PuzzleMasterSprite; void RSP_GBI_Sprite2D_PuzzleMaster64(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); dwAddr &= (g_dwRamSize-1); g_Sprite2DInfo.spritePtr = (SpriteStruct *)(g_pRDRAMs8+dwAddr); g_Sprite2DInfo.flipX = 0; g_Sprite2DInfo.flipY = 0; g_Sprite2DInfo.px = 0; g_Sprite2DInfo.py = 0; SpriteStruct tempInfo; memcpy(&tempInfo, g_Sprite2DInfo.spritePtr, sizeof(SpriteStruct)); PuzzleMasterSprite info; memcpy(&info, g_Sprite2DInfo.spritePtr, sizeof(PuzzleMasterSprite)); g_Sprite2DInfo.px = info.px>>2; g_Sprite2DInfo.py = info.py>>2; g_Sprite2DInfo.scaleX = info.scaleX / 1024.0f; g_Sprite2DInfo.scaleY = info.scaleY / 1024.0f; tempInfo.SourceImageOffsetS = info.SourceImageOffsetS; tempInfo.SourceImageOffsetT = info.SourceImageOffsetT; g_Sprite2DInfo.spritePtr = &tempInfo; CRender::g_pRender->DrawSprite2D(g_Sprite2DInfo, 1); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_SPRITE_2D, {DebuggerAppendMsg("Pause after Sprite2DBase: Addr=%08X\n", dwAddr);}); } void RSP_GBI1_Sprite2DDraw(Gfx *gfx) { // This ucode is shared by PopMtx and gSPSprite2DDraw g_Sprite2DInfo.px = (short)(((gfx->words.w1)>>16)&0xFFFF)/4; g_Sprite2DInfo.py = (short)((gfx->words.w1)&0xFFFF)/4; //RSP_RDP_NOIMPL("gSPSprite2DDraw is not implemented", (gfx->words.w0), (gfx->words.w1)); CRender::g_pRender->DrawSprite2D(g_Sprite2DInfo, 1); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_SPRITE_2D, {DebuggerAppendMsg("Pause after Sprite2DDraw at (%d, %d)\n", g_Sprite2DInfo.px, g_Sprite2DInfo.py);}); LoadedUcodeMap[RSP_SPRITE2D_SCALEFLIP] = &RSP_GBI1_CullDL; LoadedUcodeMap[RSP_SPRITE2D_DRAW] = &RSP_GBI1_PopMtx; LoadedUcodeMap[RSP_SPRITE2D_BASE] = &RSP_GBI1_Sprite2DBase; } void RSP_GBI0_Sprite2DDraw(Gfx *gfx) { // This ucode is shared by PopMtx and gSPSprite2DDraw g_Sprite2DInfo.px = (short)(((gfx->words.w1)>>16)&0xFFFF)/4; g_Sprite2DInfo.py = (short)((gfx->words.w1)&0xFFFF)/4; //RSP_RDP_NOIMPL("gSPSprite2DDraw is not implemented", (gfx->words.w0), (gfx->words.w1)); CRender::g_pRender->DrawSprite2D(g_Sprite2DInfo, 0); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_SPRITE_2D, {TRACE0("Pause after Sprite2DDraw\n");}); } void RSP_GBI1_Sprite2DScaleFlip(Gfx *gfx) { g_Sprite2DInfo.scaleX = (((gfx->words.w1)>>16)&0xFFFF)/1024.0f; g_Sprite2DInfo.scaleY = ((gfx->words.w1)&0xFFFF)/1024.0f; if( ((gfx->words.w1)&0xFFFF) < 0x100 ) { g_Sprite2DInfo.scaleY = g_Sprite2DInfo.scaleX; } g_Sprite2DInfo.flipX = (uint8)(((gfx->words.w0)>>8)&0xFF); g_Sprite2DInfo.flipY = (uint8)((gfx->words.w0)&0xFF); //RSP_RDP_NOIMPL("RSP_SPRITE2D_SCALEFLIP is not implemented", (gfx->words.w0), (gfx->words.w1)); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_SPRITE_2D, {DebuggerAppendMsg("Pause after Sprite2DScaleFlip, Flip (%d,%d), Scale (%f, %f)\n", g_Sprite2DInfo.flipX, g_Sprite2DInfo.flipY, g_Sprite2DInfo.scaleX, g_Sprite2DInfo.scaleY);}); } void RSP_GBI1_Sprite2DBase(Gfx *gfx) { if( !status.bUseModifiedUcodeMap ) { memcpy( &LoadedUcodeMap, &ucodeMap1, sizeof(UcodeMap)); status.bUseModifiedUcodeMap = true; } LoadedUcodeMap[RSP_SPRITE2D_BASE] = &RSP_GBI_Sprite2DBase; LoadedUcodeMap[RSP_SPRITE2D_SCALEFLIP] = &RSP_GBI1_Sprite2DScaleFlip; LoadedUcodeMap[RSP_SPRITE2D_DRAW] = &RSP_GBI1_Sprite2DDraw; TRACE0("Adding Sprite2D ucodes to ucode 1"); RSP_GBI_Sprite2DBase(gfx); } void RSP_GBI0_Sprite2DBase(Gfx *gfx) { //Weired, this ucode 0 game is using ucode 1, but sprite2D cmd is working differently from //normal ucode1 sprite2D game TRACE0("Ucode 0 game is using Sprite2D, and using ucode 1 codes, create a new ucode for me"); RSP_GBI_Sprite2DBase(gfx); } mupen64plus-video-rice-src-2.0/src/RSP_Parser.cpp0000644000000000000000000021136012165031100017757 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "ConvertImage.h" #include "GraphicsContext.h" #include "Render.h" #include "RenderTexture.h" #include "Video.h" #include "ucode.h" #include ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// // uCode Config // ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// #define MAX_UCODE_INFO 16 UcodeInfo ucodeInfo[MAX_UCODE_INFO]; RDPInstruction LoadedUcodeMap[256]; char* LoadedUcodeNameMap[256]; OSTask *g_pOSTask = NULL; UcodeInfo lastUcodeInfo; UcodeInfo UsedUcodes[MAX_UCODE_INFO]; const uint32 maxUsedUcodes = sizeof(UsedUcodes)/sizeof(UcodeInfo); ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// // Ucodes // ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// UcodeMap *ucodeMaps[] = { &ucodeMap0, // ucode 0 - Mario &ucodeMap1, // ucode 1 - GBI1 NULL, // ucode 2 - Golden Eye &ucodeMap3, // ucode 3 - S2DEX GBI2 NULL, // ucode 4 - Wave Racer &ucodeMap5, // ucode 5 - BGI2 NULL, // ucode 6 - DKR &ucodeMap7, // ucode 7 - S2DEX NULL, // ucode 8 - ucode 0 with sprite2D, for Demo Puzzle Master 64 NULL, // ucode 9 - Perfect Dark NULL, // ucode 10 - Conker NULL, // ucode 11 - Gemini NULL, // ucode 12 - Silicon Valley, Spacestation NULL, // ucode 13 - modified ucode S2DEX NULL, // ucode 14 - OgreBattle Background NULL, // ucode 15 - ucode 0 with sprite2D NULL, // ucode 16 - Star War, Shadow of Empire NULL, // ucode 17 - Star Wars - Rogue Squadron, NULL, // ucode 18 - World Driver Championship NULL, // ucode 19 - Last Legion UX &ucodeMap1, // ucode 20 - ZSortp }; uint32 vertexMultVals[] = { 10, // ucode 0 - Mario 2, // ucode 1 - GBI1 10, // ucode 2 - Golden Eye 2, // ucode 3 - S2DEX GBI2 5, // ucode 4 - Wave Racer 2, // ucode 5 - BGI2 10, // ucode 6 - DKR 2, // ucode 7 - S2DEX 10, // ucode 8 - ucode 0 with sprite2D, for Demo Puzzle Master 64 10, // ucode 9 - Perfect Dark 2, // ucode 10 - Conker 10, // ucode 11 - Gemini 2, // ucode 12 - Silicon Valley, Spacestation 2, // ucode 13 - modified ucode S2DEX 2, // ucode 14 - OgreBattle Background 10, // ucode 15 - ucode 0 with sprite2D 5, // ucode 16 - Star War, Shadow of Empire 2, // ucode 17 - Star Wars - Rogue Squadron, 2, // ucode 18 - World Driver Championship, check me here 2, // ucode 19 - Last Legion UX, check me here 2, // ucode 20 - ZSortp }; unsigned char gLastMicrocodeString[ 300 ] = ""; //***************************************************************************** // //***************************************************************************** static UcodeData g_UcodeData[] = { //crc_size, crc_800; {0, 0x150c3ce8, 0x150c3ce8, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Super Mario 64 {4, 0x2b94276f, 0x2b94276f, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Wave Race 64 (v1.0) {16,0xb1870454, 0xb1870454, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Star Wars - Shadows of the Empire (v1.0), {0, 0x51671ae4, 0x51671ae4, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Pilot Wings 64, {0, 0x67b5ac55, 0x67b5ac55, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Wibble, {0, 0x64dc8104, 0x64dc8104, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Dark Rift, {0, 0x309f363d, 0x309f363d, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Killer Instinct Gold, {0, 0xfcb57e57, 0xfcb57e57, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Blast Corps, {0, 0xb420f35a, 0xb420f35a, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Blast Corps, {0, 0x6e26c1df, 0x7c98e9c2, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, {2, 0xc02ac7bc, 0xc02ac7bc, (unsigned char*)"RSP SW Version: 2.0G, 09-30-96",}, // GoldenEye 007, {0, 0xe5fee3bc, 0xe5fee3bc, (unsigned char*)"RSP SW Version: 2.0G, 09-30-96",}, // Aero Fighters Assault, {8, 0xe4bb5ad8, 0x80129845, (unsigned char*)"RSP SW Version: 2.0G, 09-30-96",}, // Puzzle Master 64, {0, 0x72109ec6, 0x72109ec6, (unsigned char*)"RSP SW Version: 2.0H, 02-12-97",}, // Duke Nukem 64, {0, 0xf24a9a04, 0xf24a9a04, (unsigned char*)"RSP SW Version: 2.0H, 02-12-97",}, // Tetrisphere, {15,0x700de42e, 0x700de42e, (unsigned char*)"RSP SW Version: 2.0H, 02-12-97",}, // Wipeout 64 (uses GBI1 too!), {15,0x1b304a74, 0x1b304a74, (unsigned char*)"RSP SW Version: 2.0H, 02-12-97",}, // Flying Dragon, {15,0xe4bb5ad8, 0xa7b2f704, (unsigned char*)"RSP SW Version: 2.0H, 02-12-97",}, // Silicon Valley, {15,0xe4bb5ad8, 0x88202781, (unsigned char*)"RSP SW Version: 2.0H, 02-12-97",}, // Glover, {0, 0xe466b5bd, 0xe466b5bd, (unsigned char*)"Unknown 0xe466b5bd, 0xe466b5bd",}, // Dark Rift, {9, 0x7064a163, 0x7064a163, (unsigned char*)"Unknown 0x7064a163, 0x7064a163",}, // Perfect Dark (v1.0), {0, 0x6522df69, 0x71bd078d, (unsigned char*)"Unknown 0x6522df69, 0x71bd078d",}, // Tetris {0, 0x6522df69, 0x1b0c23a8, (unsigned char*)"Unknown 0x6522df69, 0x1b0c23a8",}, // Pachinko Nichi // GBI1 {1, 0x45ca328e, 0x45ca328e, (unsigned char*)"RSP Gfx ucode F3DLX 0.95 Yoshitaka Yasumoto Nintendo.",}, // Mario Kart 64, {1, 0x98e3b909, 0x98e3b909, (unsigned char*)"RSP Gfx ucode F3DEX 0.95 Yoshitaka Yasumoto Nintendo.",}, // Mario Kart 64 {1, 0x5d446090, 0x5d446090, (unsigned char*)"RSP Gfx ucode F3DLP.Rej 0.96 Yoshitaka Yasumoto Nintendo.",0,1}, // Jikkyou J. League Perfect Striker, {1, 0x244f5ca3, 0x244f5ca3, (unsigned char*)"RSP Gfx ucode F3DEX 1.00 Yoshitaka Yasumoto Nintendo.",}, // F-1 Pole Position 64, {1, 0x6a022585, 0x6a022585, (unsigned char*)"RSP Gfx ucode F3DEX.NoN 1.00 Yoshitaka Yasumoto Nintendo.",1}, // Turok - The Dinosaur Hunter (v1.0), {1, 0x150706be, 0x150706be, (unsigned char*)"RSP Gfx ucode F3DLX.NoN 1.00 Yoshitaka Yasumoto Nintendo.",1}, // Extreme-G, {1, 0x503f2c53, 0x503f2c53, (unsigned char*)"RSP Gfx ucode F3DEX.NoN 1.21 Yoshitaka Yasumoto Nintendo.",1}, // Bomberman 64, {1, 0xc705c37c, 0xc705c37c, (unsigned char*)"RSP Gfx ucode F3DLX 1.21 Yoshitaka Yasumoto Nintendo.",}, // Fighting Force 64, Wipeout 64 {1, 0xa2146075, 0xa2146075, (unsigned char*)"RSP Gfx ucode F3DLX.NoN 1.21 Yoshitaka Yasumoto Nintendo.",1}, // San Francisco Rush - Extreme Racing, {1, 0xb65aa2da, 0xb65aa2da, (unsigned char*)"RSP Gfx ucode L3DEX 1.21 Yoshitaka Yasumoto Nintendo.",}, // Wipeout 64, {1, 0x0c8e5ec9, 0x0c8e5ec9, (unsigned char*)"RSP Gfx ucode F3DEX 1.21 Yoshitaka Yasumoto Nintendo.",}, // {1, 0xe30795f2, 0xa53df3c4, (unsigned char*)"RSP Gfx ucode F3DLP.Rej 1.21 Yoshitaka Yasumoto Nintendo.",0,1}, {1, 0xaebeda7d, 0xaebeda7d, (unsigned char*)"RSP Gfx ucode F3DLX.Rej 1.21 Yoshitaka Yasumoto Nintendo.",0,1}, // Jikkyou World Soccer 3, {1, 0x0c8e5ec9, 0x0c8e5ec9, (unsigned char*)"RSP Gfx ucode F3DEX 1.23 Yoshitaka Yasumoto Nintendo" ,}, // Wave Race 64 (Rev. 2) - Shindou Rumble Edition (JAP) {1, 0xc705c37c, 0xc705c37c, (unsigned char*)"RSP Gfx ucode F3DLX 1.23 Yoshitaka Yasumoto Nintendo.",}, // GT {1, 0x2a61350d, 0x2a61350d, (unsigned char*)"RSP Gfx ucode F3DLX 1.23 Yoshitaka Yasumoto Nintendo.",}, // Toy Story2 {1, 0x0c8e5ec9, 0x0c8e5ec9, (unsigned char*)"RSP Gfx ucode F3DEX 1.23 Yoshitaka Yasumoto Nintendo.",}, // Wave Race 64 Shindou Edition {12,0xfc6529aa, 0xfc6529aa, (unsigned char*)"RSP Gfx ucode F3DEX 1.23 Yoshitaka Yasumoto Nintendo.",}, // Superman - The Animated Series, {1, 0xa56cf996, 0xa56cf996, (unsigned char*)"RSP Gfx ucode L3DEX 1.23 Yoshitaka Yasumoto Nintendo.",}, // Flying Dragon, {1, 0xcc83b43f, 0xcc83b43f, (unsigned char*)"RSP Gfx ucode F3DEX.NoN 1.23 Yoshitaka Yasumoto Nintendo.",1}, // AeroGauge, {1, 0xca8927a0, 0xca8927a0, (unsigned char*)"RSP Gfx ucode F3DLX.Rej 1.23 Yoshitaka Yasumoto Nintendo.",0,1}, // Puzzle Bobble 64, {1, 0x25689c75, 0xbe481ae8, (unsigned char*)"RSP Gfx ucode F3DLP.Rej 1.23 Yoshitaka Yasumoto Nintendo.",0,1}, {1, 0xd2d747b7, 0xd2d747b7, (unsigned char*)"RSP Gfx ucode F3DLX.NoN 1.23 Yoshitaka Yasumoto Nintendo.",1}, // Penny Racers, {1, 0xa849c858, 0x5bd32b5a, (unsigned char*)"RSP Gfx ucode F3DTEX/A 1.23 Yoshitaka Yasumoto Nintendo.",}, // Tamagotchi {7, 0xecd8b772, 0xecd8b772, (unsigned char*)"RSP Gfx ucode S2DEX 1.06 Yoshitaka Yasumoto Nintendo.",}, // Yoshi's Story, {7, 0xf59132f5, 0xf59132f5, (unsigned char*)"RSP Gfx ucode S2DEX 1.07 Yoshitaka Yasumoto Nintendo.",}, // Bakuretsu Muteki Bangaioh, {7, 0x961dd811, 0x961dd811, (unsigned char*)"RSP Gfx ucode S2DEX 1.03 Yoshitaka Yasumoto Nintendo.",}, // GT {5, 0x3e083afa, 0x722f97cc, (unsigned char*)"RSP Gfx ucode F3DEX.NoN fifo 2.03 Yoshitaka Yasumoto 1998 Nintendo.",1}, // F-Zero X, {5, 0xa8050bd1, 0xa8050bd1, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.03 Yoshitaka Yasumoto 1998 Nintendo.",}, // F-Zero X, {5, 0x4e8055f0, 0x4e8055f0, (unsigned char*)"RSP Gfx ucode F3DLX.Rej fifo 2.03 Yoshitaka Yasumoto 1998 Nintendo.",0,1}, // F-Zero X, {5, 0xabf001f5, 0xabf001f5, (unsigned char*)"RSP Gfx ucode F3DFLX.Rej fifo 2.03F Yoshitaka Yasumoto 1998 Nintendo.",0,1}, // F-Zero X, {5, 0xadb4b686, 0xadb4b686, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.04 Yoshitaka Yasumoto 1998 Nintendo.",}, // Top Gear Rally 2, {5, 0x779e2a9b, 0x779e2a9b, (unsigned char*)"RSP Gfx ucode F3DEX.NoN fifo 2.04 Yoshitaka Yasumoto 1998 Nintendo.",1}, // California Speed, {5, 0xa8cb3e09, 0xa8cb3e09, (unsigned char*)"RSP Gfx ucode L3DEX fifo 2.04 Yoshitaka Yasumoto 1998 Nintendo.",}, // In-Fisherman Bass Hunter 64, {5, 0x2a1341d6, 0x2a1341d6, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.04H Yoshitaka Yasumoto 1998 Nintendo.",}, // Kirby 64 - The Crystal Shards, {5, 0x3e083afa, 0x89a8e0ed, (unsigned char*)"RSP Gfx ucode F3DEX.NoN fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo.",1}, // Carmageddon 64 (uncensored), {5, 0x4964b75d, 0x4964b75d, (unsigned char*)"RSP Gfx ucode F3DEX.NoN fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo.",1}, {5, 0x39e3e95a, 0x39e3e95a, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo."}, // Knife Edge - Nose Gunner, {5, 0xd2913522, 0xd2913522, (unsigned char*)"RSP Gfx ucode F3DAM fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo."}, // Hey You, Pikachu!, {5, 0x3e083afa, 0xc998443f, (unsigned char*)"RSP Gfx ucode F3DEX xbus 2.05 Yoshitaka Yasumoto 1998 Nintendo."}, //Triple play {5, 0xf4184a7d, 0xf4184a7d, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.06 Yoshitaka Yasumoto 1998 Nintendo.",}, // Hey You, Pikachu!, {5, 0x595a88de, 0x595a88de, (unsigned char*)"RSP Gfx ucode F3DEX.Rej fifo 2.06 Yoshitaka Yasumoto 1998 Nintendo.",0,1}, // Bio Hazard 2, {5, 0x0259f764, 0x0259f764, (unsigned char*)"RSP Gfx ucode F3DLX.Rej fifo 2.06 Yoshitaka Yasumoto 1998 Nintendo.",0,1}, // Mario Party, {5, 0xe1a5477a, 0xe1a5477a, (unsigned char*)"RSP Gfx ucode F3DEX.NoN xbus 2.06 Yoshitaka Yasumoto 1998 Nintendo.",1}, // Command & Conquer, {5, 0x4cfa0a19, 0x4cfa0a19, (unsigned char*)"RSP Gfx ucode F3DZEX.NoN fifo 2.06H Yoshitaka Yasumoto 1998 Nintendo.",1}, // The Legend of Zelda - Ocarina of Time (v1.0), {5, 0x2cbd9514, 0x5f40b9f5, (unsigned char*)"RSP Gfx ucode F3DZEX.NoN fifo 2.06H Yoshitaka Yasumoto 1998 Nintendo.",1}, {5, 0x3e083afa, 0x882680f4, (unsigned char*)"RSP Gfx ucode L3DEX fifo 2.07 Yoshitaka Yasumoto 1998 Nintendo."}, // Polaris Sno {5, 0xdeb1cac0, 0xdeb1cac0, (unsigned char*)"RSP Gfx ucode F3DEX.NoN fifo 2.07 Yoshitaka Yasumoto 1998 Nintendo.",1}, // Knockout Kings 2000, {5, 0xf4184a7d, 0xf4184a7d, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.07 Yoshitaka Yasumoto 1998 Nintendo.",}, // Xena Warrior Princess - Talisman of Fate, Army Men - Air Combat, Destruction Derby {5, 0x4b013e60, 0x4b013e60, (unsigned char*)"RSP Gfx ucode F3DEX xbus 2.07 Yoshitaka Yasumoto 1998 Nintendo.",}, // Lode Runner 3-D, {5, 0xd1a63836, 0xd1a63836, (unsigned char*)"RSP Gfx ucode L3DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // Hey You, Pikachu!, {5, 0x97193667, 0x97193667, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // Top Gear Hyper-Bike, {5, 0x92149ba8, 0x92149ba8, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.08 Yoshitaka Yasumoto/Kawasedo 1999.",}, // Paper Mario, {5, 0xae0fb88f, 0xae0fb88f, (unsigned char*)"RSP Gfx ucode F3DEX xbus 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // WWF WrestleMania 2000, {5, 0xc572f368, 0xc572f368, (unsigned char*)"RSP Gfx ucode F3DLX.Rej xbus 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // WWF No Mercy, {5, 0x3e083afa, 0x74252492, (unsigned char*)"RSP Gfx ucode F3DEX.NoN xbus 2.08 Yoshitaka Yasumoto 1999 Nintendo.",1}, {5, 0x9c2edb70, 0xea98e740, (unsigned char*)"RSP Gfx ucode F3DEX.NoN fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",1}, // LEGO Racers, {5, 0x79e004a6, 0x79e004a6, (unsigned char*)"RSP Gfx ucode F3DLX.Rej fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",0,1}, // Mario Party 2, {5, 0xaa6ab3ca, 0xaa6ab3ca, (unsigned char*)"RSP Gfx ucode F3DEX.Rej fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",0,1}, // V-Rally Edition 99, {5, 0x2c597e0f, 0x2c597e0f, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // Cruis'n Exotica, {10, 0x4e5f3e3b, 0x4e5f3e3b,(unsigned char*)"RSP Gfx ucode F3DEXBG.NoN fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",1}, // Conker The Bad Fur Day {5, 0x61f31862, 0x61f31862, (unsigned char*)"RSP Gfx ucode F3DEX.NoN fifo 2.08H Yoshitaka Yasumoto 1999 Nintendo.",1}, // Pokemon Snap, {5, 0x005f5b71, 0x005f5b71, (unsigned char*)"RSP Gfx ucode F3DZEX.NoN fifo 2.08I Yoshitaka Yasumoto/Kawasedo 1999.",1}, // The Legend of Zelda 2 - Majora's Mask, {3, 0x41839d1e, 0x41839d1e, (unsigned char*)"RSP Gfx ucode S2DEX fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo.",}, // Chou Snobow Kids, {3, 0x2cbd9514, 0xc639dbb9, (unsigned char*)"RSP Gfx ucode S2DEX xbus 2.06 Yoshitaka Yasumoto 1998 Nintendo.",}, {3, 0xec89e273, 0xec89e273, (unsigned char*)"RSP Gfx ucode S2DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // V-Rally Edition 99, {3, 0x9429b7d6, 0x9429b7d6, (unsigned char*)"RSP Gfx ucode S2DEX xbus 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // Star Craft, //{14,0x5a72397b, 0xec89e273, "RSP Gfx ucode S2DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // OgreBattle Background, {3, 0x2cbd9514, 0xec89e273, (unsigned char*)"RSP Gfx ucode S2DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // Zelda MM, {6, 0x6aef74f8, 0x6aef74f8, (unsigned char*)"Unknown 0x6aef74f8, 0x6aef74f8",}, // Diddy Kong Racing (v1.0), {6, 0x4c4eead8, 0x4c4eead8, (unsigned char*)"Unknown 0x4c4eead8, 0x4c4eead8",}, // Diddy Kong Racing (v1.1), {1, 0xed421e9a, 0xed421e9a, (unsigned char*)"Unknown 0xed421e9a, 0xed421e9a",}, // Kuiki Uhabi Suigo, {5, 0x37751932, 0x55c0fd25, (unsigned char*)"Unknown 0x37751932, 0x55c0fd25",}, // Bio Hazard 2, {11,0xbe0b83e7, 0xbe0b83e7,(unsigned char*)"Unknown 0xbe0b83e7, 0xbe0b83e7",}, // Jet Force Gemini, {17, 0x02e882cf, 0x2ad17281, (unsigned char*)"Unknown 0x02e882cf, 0x2ad17281",}, // Indiana Jones, {17, 0x1f7d9118, 0xdab2199b, (unsigned char*)"Unknown 0x1f7d9118, 0xdab2199b",}, // Battle Naboo, {17, 0x74583614, 0x74583614, (unsigned char*)"Unknown 0x74583614, 0x74583614",}, // Star Wars - Rogue Squadron, {17, 0xe37e2f49, 0x1eb63fd8, (unsigned char*)"Unknown 0xe37e2f49, 0x1eb63fd8",}, // Star Wars - Rogue Squadron, {17, 0x8ce1af3d, 0xb2760ea2, (unsigned char*)"Unknown 0x8ce1af3d, 0xb2760ea2",}, // Star Wars - Rogue Squadron, {18, 0x7b685972, 0x57b8095a, (unsigned char*)"Unknown 0x7b685972, 0x57b8095a",}, // World Driver Championship {18, 0xe92dbb9b, 0x57b8095a, (unsigned char*)"Unknown 0xe92dbb9b, 0x57b8095a",}, // World Driver Championship {18, 0xe6c9acc1, 0x65f80845, (unsigned char*)"Unknown 0xe6c9acc1, 0x65f80845",}, // World Driver Championship {18, 0x6522df69, 0x720b88a0, (unsigned char*)"Unknown 0x6522df69, 0x720b88a0",}, // World Driver Championship {18, 0x6522df69, 0xf1e8ba9e, (unsigned char*)"Unknown 0x6522df69, 0xf1e8ba9e",}, // World Driver Championship {19, 0xa486bed3, 0xa486bed3, (unsigned char*)"Unknown 0xa486bed3, 0xa486bed3",}, // Last Legion UX, {19, 0x6b519381, 0xfebacfd8, (unsigned char*)"Unknown in Toukan Road",}, // I don't know which ucode {20, 0x6d2a01b1, 0x6d2a01b1, (unsigned char*)"RSP Gfx ucode ZSortp 0.33 Yoshitaka Yasumoto Nintendo.",}, // Mia Hamm Soccer 64, }; FiddledVtx * g_pVtxBase=NULL; SetImgInfo g_TI = { TXT_FMT_RGBA, TXT_SIZE_16b, 1, 0 }; SetImgInfo g_CI = { TXT_FMT_RGBA, TXT_SIZE_16b, 1, 0 }; SetImgInfo g_ZI = { TXT_FMT_RGBA, TXT_SIZE_16b, 1, 0 }; RenderTextureInfo g_ZI_saves[2]; DListStack gDlistStack[MAX_DL_STACK_SIZE]; int gDlistStackPointer= -1; TMEMLoadMapInfo g_tmemLoadAddrMap[0x200]; // Totally 4KB TMEM TMEMLoadMapInfo g_tmemInfo0; // Info for Tmem=0 TMEMLoadMapInfo g_tmemInfo1; // Info for Tmem=0x100 const char *pszImgSize[4] = {"4", "8", "16", "32"}; const char *textluttype[4] = {"RGB16", "I16?", "RGBA16", "IA16"}; uint16 g_wRDPTlut[0x200]; uint32 g_dwRDPPalCrc[16]; #include "FrameBuffer.h" #include "RSP_GBI0.h" #include "RSP_GBI1.h" #include "RSP_GBI2.h" #include "RSP_GBI2_ext.h" #include "RSP_GBI_Others.h" #include "RSP_GBI_Sprite2D.h" #include "RDP_Texture.h" ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// // Init and Reset // ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// void DLParser_Init() { int i; status.gRDPTime = 0; status.gDlistCount = 0; status.gUcodeCount = 0; status.frameReadByCPU = FALSE; status.frameWriteByCPU = FALSE; status.SPCycleCount = 0; status.DPCycleCount = 0; status.bN64IsDrawingTextureBuffer = false; status.bDirectWriteIntoRDRAM = false; status.bHandleN64RenderTexture = false; status.bUcodeIsKnown = FALSE; status.lastPurgeTimeTime = status.gRDPTime; status.curRenderBuffer = 0; status.curDisplayBuffer = 0; status.curVIOriginReg = 0; status.primitiveType = PRIM_TRI1; status.lastPurgeTimeTime = 0; // Time textures were last purged status.UseLargerTile[0] = false; status.LargerTileRealLeft[0] = status.LargerTileRealLeft[1] = 0; memset(&g_ZI_saves, 0, sizeof(RenderTextureInfo)*2); for( i=0; i<8; i++ ) { memset(&gRDP.tiles[i], 0, sizeof(Tile)); } memset(g_tmemLoadAddrMap, 0, sizeof(g_tmemLoadAddrMap)); for( i=0; iCloseRenderTexture(false); } } void RDP_SetUcodeMap(int ucode) { status.bUseModifiedUcodeMap = false; switch( ucode ) { case 0: // Mario and demos break; case 1: // F3DEX GBI1 case 20: break; case 2: // Golden Eye memcpy( &LoadedUcodeMap, &ucodeMap0, sizeof(UcodeMap)); //LoadedUcodeMap[9]=RSP_GBI1_Sprite2DBase; //LoadedUcodeMap[0xaf]=RSP_GBI1_LoadUCode; //LoadedUcodeMap[0xb0]=RSP_GBI1_BranchZ; LoadedUcodeMap[0xb4]=DLParser_RDPHalf_1_0xb4_GoldenEye; status.bUseModifiedUcodeMap = true; break; case 3: // S2DEX GBI2 break; case 4: memcpy( &LoadedUcodeMap, &ucodeMap0, sizeof(UcodeMap)); LoadedUcodeMap[4]=RSP_Vtx_WRUS; LoadedUcodeMap[0xb1]=RSP_GBI1_Tri2; //LoadedUcodeMap[9]=RSP_GBI1_Sprite2DBase; //LoadedUcodeMap[0xaf]=RSP_GBI1_LoadUCode; //LoadedUcodeMap[0xb0]=RSP_GBI1_BranchZ; //LoadedUcodeMap[0xb2]=RSP_GBI1_ModifyVtx; status.bUseModifiedUcodeMap = true; break; case 5: // F3DEX GBI2 break; case 6: // DKR, Jet Force Gemini, Mickey case 11: // DKR, Jet Force Gemini, Mickey memcpy( &LoadedUcodeMap, &ucodeMap0, sizeof(UcodeMap)); LoadedUcodeMap[1]=RSP_Mtx_DKR; LoadedUcodeMap[4]=RSP_Vtx_DKR; if( ucode == 11 ) LoadedUcodeMap[4]=RSP_Vtx_Gemini; LoadedUcodeMap[5]=RSP_DMA_Tri_DKR; LoadedUcodeMap[7]=RSP_DL_In_MEM_DKR; LoadedUcodeMap[0xbc]=RSP_MoveWord_DKR; LoadedUcodeMap[0xbf]=DLParser_Set_Addr_Ucode6; //LoadedUcodeMap[9]=RSP_GBI1_Sprite2DBase; //LoadedUcodeMap[0xb0]=RSP_GBI1_BranchZ; //LoadedUcodeMap[0xb2]=RSP_GBI1_ModifyVtx; status.bUseModifiedUcodeMap = true; break; case 7: // S2DEX GBI1 break; case 8: // Ucode 0 with Sprite2D, Puzzle Master 64 memcpy( &LoadedUcodeMap, &ucodeMap0, sizeof(UcodeMap)); LoadedUcodeMap[RSP_SPRITE2D_BASE] = RSP_GBI_Sprite2D_PuzzleMaster64; LoadedUcodeMap[RSP_SPRITE2D_SCALEFLIP] = RSP_GBI1_Sprite2DScaleFlip; LoadedUcodeMap[RSP_SPRITE2D_DRAW] = RSP_GBI0_Sprite2DDraw; status.bUseModifiedUcodeMap = true; break; case 9: // Perfect Dark memcpy( &LoadedUcodeMap, &ucodeMap0, sizeof(UcodeMap)); LoadedUcodeMap[4]=RSP_Vtx_PD; LoadedUcodeMap[7]=RSP_Set_Vtx_CI_PD; LoadedUcodeMap[0xb1]=RSP_Tri4_PD; LoadedUcodeMap[0xb4]=DLParser_RDPHalf_1_0xb4_GoldenEye; status.bUseModifiedUcodeMap = true; break; case 10: // Conker BFD memcpy( &LoadedUcodeMap, &ucodeMap5, sizeof(UcodeMap)); LoadedUcodeMap[1]=RSP_Vtx_Conker; LoadedUcodeMap[0x10]=DLParser_Tri4_Conker; LoadedUcodeMap[0x11]=DLParser_Tri4_Conker; LoadedUcodeMap[0x12]=DLParser_Tri4_Conker; LoadedUcodeMap[0x13]=DLParser_Tri4_Conker; LoadedUcodeMap[0x14]=DLParser_Tri4_Conker; LoadedUcodeMap[0x15]=DLParser_Tri4_Conker; LoadedUcodeMap[0x16]=DLParser_Tri4_Conker; LoadedUcodeMap[0x17]=DLParser_Tri4_Conker; LoadedUcodeMap[0x18]=DLParser_Tri4_Conker; LoadedUcodeMap[0x19]=DLParser_Tri4_Conker; LoadedUcodeMap[0x1a]=DLParser_Tri4_Conker; LoadedUcodeMap[0x1b]=DLParser_Tri4_Conker; LoadedUcodeMap[0x1c]=DLParser_Tri4_Conker; LoadedUcodeMap[0x1d]=DLParser_Tri4_Conker; LoadedUcodeMap[0x1e]=DLParser_Tri4_Conker; LoadedUcodeMap[0x1f]=DLParser_Tri4_Conker; LoadedUcodeMap[0xdb]=DLParser_MoveWord_Conker; LoadedUcodeMap[0xdc]=DLParser_MoveMem_Conker; status.bUseModifiedUcodeMap = true; break; case 12: // Silicon Velley, Space Station memcpy( &LoadedUcodeMap, &ucodeMap1, sizeof(UcodeMap)); LoadedUcodeMap[0x01]=RSP_GBI0_Mtx; status.bUseModifiedUcodeMap = true; break; case 13: // modified S2DEX memcpy( &LoadedUcodeMap, &ucodeMap7, sizeof(UcodeMap)); //LoadedUcodeMap[S2DEX_BG_1CYC] = ucodeMap1[S2DEX_BG_1CYC]; LoadedUcodeMap[S2DEX_OBJ_RECTANGLE] = ucodeMap1[S2DEX_OBJ_RECTANGLE]; LoadedUcodeMap[S2DEX_OBJ_SPRITE] = ucodeMap1[S2DEX_OBJ_SPRITE]; //LoadedUcodeMap[S2DEX_OBJ_RENDERMODE] = ucodeMap1[S2DEX_OBJ_RENDERMODE]; //LoadedUcodeMap[S2DEX_OBJ_RECTANGLE_R] = ucodeMap1[S2DEX_OBJ_RECTANGLE_R]; LoadedUcodeMap[S2DEX_RDPHALF_0] = ucodeMap1[S2DEX_RDPHALF_0]; status.bUseModifiedUcodeMap = true; break; case 14: // OgreBattle Background memcpy( &LoadedUcodeMap, &ucodeMap5, sizeof(UcodeMap)); LoadedUcodeMap[0xda] = DLParser_OgreBatter64BG; LoadedUcodeMap[0xdc] = RSP_S2DEX_OBJ_MOVEMEM; status.bUseModifiedUcodeMap = true; break; case 15: // Ucode 0 with Sprite2D memcpy( &LoadedUcodeMap, &ucodeMap0, sizeof(UcodeMap)); LoadedUcodeMap[RSP_SPRITE2D_BASE] = RSP_GBI_Sprite2DBase; LoadedUcodeMap[RSP_SPRITE2D_SCALEFLIP] = RSP_GBI1_Sprite2DScaleFlip; LoadedUcodeMap[RSP_SPRITE2D_DRAW] = RSP_GBI0_Sprite2DDraw; status.bUseModifiedUcodeMap = true; break; case 16: // Star War, Shadow Of Empire memcpy( &LoadedUcodeMap, &ucodeMap0, sizeof(UcodeMap)); LoadedUcodeMap[4]=RSP_Vtx_ShadowOfEmpire; status.bUseModifiedUcodeMap = true; break; case 17: //Indiana Jones, does not work anyway memcpy( &LoadedUcodeMap, &ucodeMap1, sizeof(UcodeMap)); LoadedUcodeMap[0]=DLParser_Ucode8_0x0; //LoadedUcodeMap[1]=RSP_RDP_Nothing; LoadedUcodeMap[2]=DLParser_RS_Color_Buffer; LoadedUcodeMap[3]=DLParser_RS_MoveMem; LoadedUcodeMap[4]=DLParser_RS_Vtx_Buffer; LoadedUcodeMap[5]=DLParser_Ucode8_0x05; LoadedUcodeMap[6]=DLParser_Ucode8_DL; LoadedUcodeMap[7]=DLParser_Ucode8_JUMP; LoadedUcodeMap[8]=RSP_RDP_Nothing; LoadedUcodeMap[9]=RSP_RDP_Nothing; LoadedUcodeMap[10]=RSP_RDP_Nothing; LoadedUcodeMap[11]=RSP_RDP_Nothing; LoadedUcodeMap[0x80]=DLParser_RS_Block; LoadedUcodeMap[0xb4]=DLParser_Ucode8_0xb4; LoadedUcodeMap[0xb5]=DLParser_Ucode8_0xb5; LoadedUcodeMap[0xb8]=DLParser_Ucode8_EndDL; LoadedUcodeMap[0xbc]=DLParser_Ucode8_0xbc; LoadedUcodeMap[0xbd]=DLParser_Ucode8_0xbd; LoadedUcodeMap[0xbe]=DLParser_RS_0xbe; LoadedUcodeMap[0xbF]=DLParser_Ucode8_0xbf; LoadedUcodeMap[0xe4]=DLParser_TexRect_Last_Legion; status.bUseModifiedUcodeMap = true; break; case 18: // World Driver Championship memcpy( &LoadedUcodeMap, &ucodeMap1, sizeof(UcodeMap)); LoadedUcodeMap[0xe]=DLParser_RSP_DL_WorldDriver; LoadedUcodeMap[0x2]=DLParser_RSP_Pop_DL_WorldDriver; LoadedUcodeMap[0xdf]=DLParser_RSP_Pop_DL_WorldDriver; LoadedUcodeMap[0x6]=RSP_RDP_Nothing; status.bUseModifiedUcodeMap = true; break; case 19: // Last Legion UX memcpy( &LoadedUcodeMap, &ucodeMap1, sizeof(UcodeMap)); LoadedUcodeMap[0x80]=DLParser_RSP_Last_Legion_0x80; LoadedUcodeMap[0x00]=DLParser_RSP_Last_Legion_0x00; LoadedUcodeMap[0xe4]=DLParser_TexRect_Last_Legion; status.bUseModifiedUcodeMap = true; break; default: memcpy( &LoadedUcodeMap, &ucodeMap5, sizeof(UcodeMap)); status.bUseModifiedUcodeMap = true; break; } #ifdef DEBUGGER if( logMicrocode ) TRACE1("Using ucode %d", ucode); #endif } void RSP_SetUcode(int ucode, uint32 ucStart, uint32 ucDStart, uint32 ucSize) { if( status.ucodeHasBeenSet && gRSP.ucode == ucode ) return; status.ucodeHasBeenSet = true; if( ucode < 0 ) ucode = 5; RDP_SetUcodeMap(ucode); if( status.bUseModifiedUcodeMap ) { currentUcodeMap = &LoadedUcodeMap[0]; } else { currentUcodeMap = *ucodeMaps[ucode]; } gRSP.vertexMult = vertexMultVals[ucode]; //if( gRSP.ucode != ucode ) DebuggerAppendMsg("Set to ucode: %d", ucode); gRSP.ucode = ucode; lastUcodeInfo.used = true; if( ucStart == 0 ) { lastUcodeInfo.ucStart = g_pOSTask->t.ucode; lastUcodeInfo.ucDStart = g_pOSTask->t.ucode_data; lastUcodeInfo.ucSize = g_pOSTask->t.ucode_size; } else { lastUcodeInfo.ucStart = ucStart; lastUcodeInfo.ucDStart = ucDStart; lastUcodeInfo.ucSize = ucSize; } } //***************************************************************************** // //***************************************************************************** static uint32 DLParser_IdentifyUcodeFromString( const unsigned char * str_ucode ) { const unsigned char str_ucode0[] = "RSP SW Version: 2.0"; const unsigned char str_ucode1[] = "RSP Gfx ucode "; if ( strncasecmp( (char*)str_ucode, (char*)str_ucode0, strlen((char*)str_ucode0) ) == 0 ) { return 0; } if ( strncasecmp( (char*)str_ucode, (char*)str_ucode1, strlen((char*)str_ucode1) ) == 0 ) { if( strstr((char*)str_ucode,"1.") != 0 ) { if( strstr((char*)str_ucode,"S2DEX") != 0 ) { return 7; } else return 1; } else if( strstr((char*)str_ucode,"2.") != 0 ) { if( strstr((char*)str_ucode,"S2DEX") != 0 ) { return 3; } else return 5; } } return 5; } //***************************************************************************** // //***************************************************************************** static uint32 DLParser_IdentifyUcode( uint32 crc_size, uint32 crc_800, char* str ) { for ( uint32 i = 0; i < sizeof(g_UcodeData)/sizeof(UcodeData); i++ ) { #ifdef DEBUGGER if ( crc_800 == g_UcodeData[i].crc_800 ) { if( strlen(str)==0 || strcmp((const char *) g_UcodeData[i].ucode_name, str) == 0 ) { TRACE0((const char *) g_UcodeData[i].ucode_name); } else { DebuggerAppendMsg("Incorrect description for this ucode:\n%x, %x, %s",crc_800, crc_size, str); } status.bUcodeIsKnown = TRUE; gRSP.bNearClip = !g_UcodeData[i].non_nearclip; gRSP.bRejectVtx = g_UcodeData[i].reject; DebuggerAppendMsg("Identify ucode = %d, crc = %08X, %s", g_UcodeData[i].ucode, crc_800, str); return g_UcodeData[i].ucode; } #else if ( crc_800 == g_UcodeData[i].crc_800 ) { status.bUcodeIsKnown = TRUE; gRSP.bNearClip = !g_UcodeData[i].non_nearclip; gRSP.bRejectVtx = g_UcodeData[i].reject; return g_UcodeData[i].ucode; } #endif } #ifdef DEBUGGER { static bool warned = false; if( warned == false ) { warned = true; TRACE0("Can not identify ucode for this game"); } } #endif gRSP.bNearClip = false; gRSP.bRejectVtx = false; status.bUcodeIsKnown = FALSE; return ~0; } uint32 DLParser_CheckUcode(uint32 ucStart, uint32 ucDStart, uint32 ucSize, uint32 ucDSize) { if( options.enableHackForGames == HACK_FOR_ROGUE_SQUADRON ) { return 17; } // Check the used ucode table first int usedUcodeIndex = 0; for( usedUcodeIndex=0; (unsigned int)usedUcodeIndex= ' ') { *p++ = g_pRDRAMs8[ base + (i ^ 3) ]; i++; } *p++ = 0; break; } } } //if ( strcmp( str, gLastMicrocodeString ) != 0 ) { //uint32 size = ucDSize; base = ucStart & 0x1fffffff; uint32 crc_size = ComputeCRC32( 0, &g_pRDRAMu8[ base ], 8);//size ); uint32 crc_800 = ComputeCRC32( 0, &g_pRDRAMu8[ base ], 0x800 ); uint32 ucode; ucode = DLParser_IdentifyUcode( crc_size, crc_800, (char*)str ); if ( (int)ucode == ~0 ) { #ifdef DEBUGGER static bool warned=false; //if( warned == false ) { char message[300]; sprintf(message, "Unable to find ucode to use for '%s' CRCSize: 0x%08x CRC800: 0x%08x", str, crc_size, crc_800); TRACE0(message); DebugMessage(M64MSG_ERROR, message); warned = true; } #endif ucode = DLParser_IdentifyUcodeFromString(str); if ( (int)ucode == ~0 ) { ucode=5; } } //DLParser_SetuCode( ucode ); #ifdef DEBUGGER { static bool warned=false; if( warned == false ) { warned = true; if( strlen((char *) str) == 0 ) DebuggerAppendMsg("Can not find RSP string in the DLIST, CRC800: 0x%08x, CRCSize: 0x%08x", crc_800, crc_size); else TRACE0((char *) str); } } #endif strcpy( (char*)gLastMicrocodeString, (char*)str ); if( usedUcodeIndex >= MAX_UCODE_INFO ) { usedUcodeIndex = rand()%MAX_UCODE_INFO; } UsedUcodes[usedUcodeIndex].ucStart = ucStart; UsedUcodes[usedUcodeIndex].ucSize = ucSize; UsedUcodes[usedUcodeIndex].ucDStart = ucDStart; UsedUcodes[usedUcodeIndex].ucDSize = ucDSize; UsedUcodes[usedUcodeIndex].ucode = ucode; UsedUcodes[usedUcodeIndex].crc_800 = crc_800; UsedUcodes[usedUcodeIndex].crc_size = crc_size; UsedUcodes[usedUcodeIndex].used = true; strcpy( UsedUcodes[usedUcodeIndex].rspstr, (char*)str ); TRACE2("New ucode has been detected:\n%s, ucode=%d", str, ucode); return ucode; } } extern int dlistMtxCount; extern bool bHalfTxtScale; void DLParser_Process(OSTask * pTask) { static int skipframe=0; //BOOL menuWaiting = FALSE; dlistMtxCount = 0; bHalfTxtScale = false; if ( CRender::g_pRender == NULL) { TriggerDPInterrupt(); TriggerSPInterrupt(); return; } status.bScreenIsDrawn = true; if( options.bSkipFrame ) { skipframe++; if(skipframe%2) { TriggerDPInterrupt(); TriggerSPInterrupt(); return; } } if( currentRomOptions.N64RenderToTextureEmuType != TXT_BUF_NONE && defaultRomOptions.bSaveVRAM ) { g_pFrameBufferManager->CheckRenderTextureCRCInRDRAM(); } g_pOSTask = pTask; DebuggerPauseCountN( NEXT_DLIST ); status.gRDPTime = (uint32) SDL_GetTicks(); status.gDlistCount++; if ( lastUcodeInfo.ucStart != (uint32)(pTask->t.ucode) ) { uint32 ucode = DLParser_CheckUcode(pTask->t.ucode, pTask->t.ucode_data, pTask->t.ucode_size, pTask->t.ucode_data_size); RSP_SetUcode(ucode, pTask->t.ucode, pTask->t.ucode_data, pTask->t.ucode_size); DEBUGGER_PAUSE_AND_DUMP(NEXT_SWITCH_UCODE,{DebuggerAppendMsg("Pause at switching ucode");}); } // Initialize stack status.bN64FrameBufferIsUsed = false; gDlistStackPointer=0; gDlistStack[gDlistStackPointer].pc = (uint32)pTask->t.data_ptr; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((gDlistStack[gDlistStackPointer].pc == 0 && pauseAtNext && eventToPause==NEXT_UNKNOWN_OP), {DebuggerAppendMsg("Start Task without DLIST: ucode=%08X, data=%08X", (uint32)pTask->t.ucode, (uint32)pTask->t.ucode_data);}); // Check if we need to purge (every 5 milliseconds) if (status.gRDPTime - status.lastPurgeTimeTime > 5) { gTextureManager.PurgeOldTextures(); status.lastPurgeTimeTime = status.gRDPTime; } status.dwNumDListsCulled = 0; status.dwNumTrisRendered = 0; status.dwNumTrisClipped = 0; status.dwNumVertices = 0; status.dwBiggestVertexIndex = 0; if( g_curRomInfo.bForceScreenClear && CGraphicsContext::needCleanScene ) { CRender::g_pRender->ClearBuffer(true,true); CGraphicsContext::needCleanScene = false; } SetVIScales(); CRender::g_pRender->RenderReset(); CRender::g_pRender->BeginRendering(); CRender::g_pRender->SetViewport(0, 0, windowSetting.uViWidth, windowSetting.uViHeight, 0x3FF); CRender::g_pRender->SetFillMode(options.bWinFrameMode? RICE_FILLMODE_WINFRAME : RICE_FILLMODE_SOLID); try { // The main loop while( gDlistStackPointer >= 0 ) { #ifdef DEBUGGER DEBUGGER_PAUSE_COUNT_N(NEXT_UCODE); if( debuggerPause ) { DebuggerPause(); CRender::g_pRender->SetFillMode(options.bWinFrameMode? RICE_FILLMODE_WINFRAME : RICE_FILLMODE_SOLID); } if (gDlistStack[gDlistStackPointer].pc > g_dwRamSize) { DebuggerAppendMsg("Error: dwPC is %08X", gDlistStack[gDlistStackPointer].pc ); break; } #endif status.gUcodeCount++; Gfx *pgfx = (Gfx*)&g_pRDRAMu32[(gDlistStack[gDlistStackPointer].pc>>2)]; #ifdef DEBUGGER LOG_UCODE("0x%08x: %08x %08x %-10s", gDlistStack[gDlistStackPointer].pc, pgfx->words.w0, pgfx->words.w1, (gRSP.ucode!=5&&gRSP.ucode!=10)?ucodeNames_GBI1[(pgfx->words.w0>>24)]:ucodeNames_GBI2[(pgfx->words.w0>>24)]); #endif gDlistStack[gDlistStackPointer].pc += 8; currentUcodeMap[pgfx->words.w0 >>24](pgfx); if ( gDlistStackPointer >= 0 && --gDlistStack[gDlistStackPointer].countdown < 0 ) { LOG_UCODE("**EndDLInMem"); gDlistStackPointer--; } } } catch(...) { TRACE0("Unknown exception happens in ProcessDList"); TriggerDPInterrupt(); } CRender::g_pRender->EndRendering(); if( gRSP.ucode >= 17) TriggerDPInterrupt(); TriggerSPInterrupt(); } ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// // Util Functions // ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// void RDP_NOIMPL_Real(const char* op, uint32 word0, uint32 word1) { #ifdef DEBUGGER if( logWarning ) { TRACE0("Stack Trace"); for( int i=0; iSetCullMode(bCullFront, bCullBack); BOOL bShade = (gRDP.geometryMode & G_SHADE) ? TRUE : FALSE; BOOL bShadeSmooth = (gRDP.geometryMode & G_SHADING_SMOOTH) ? TRUE : FALSE; if (bShade && bShadeSmooth) CRender::g_pRender->SetShadeMode( SHADE_SMOOTH ); else CRender::g_pRender->SetShadeMode( SHADE_FLAT ); CRender::g_pRender->SetFogEnable( gRDP.geometryMode & G_FOG ? true : false ); SetTextureGen((gRDP.geometryMode & G_TEXTURE_GEN) ? true : false ); SetLighting( (gRDP.geometryMode & G_LIGHTING ) ? true : false ); CRender::g_pRender->ZBufferEnable( gRDP.geometryMode & G_ZBUFFER ); } ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// // DP Ucodes // ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// void DLParser_SetKeyGB(Gfx *gfx) { DP_Timing(DLParser_SetKeyGB); gRDP.keyB = ((gfx->words.w1)>>8)&0xFF; gRDP.keyG = ((gfx->words.w1)>>24)&0xFF; gRDP.keyA = (gRDP.keyR+gRDP.keyG+gRDP.keyB)/3; gRDP.fKeyA = gRDP.keyA/255.0f; } void DLParser_SetKeyR(Gfx *gfx) { DP_Timing(DLParser_SetKeyR); gRDP.keyR = ((gfx->words.w1)>>8)&0xFF; gRDP.keyA = (gRDP.keyR+gRDP.keyG+gRDP.keyB)/3; gRDP.fKeyA = gRDP.keyA/255.0f; } int g_convk0,g_convk1,g_convk2,g_convk3,g_convk4,g_convk5; float g_convc0,g_convc1,g_convc2,g_convc3,g_convc4,g_convc5; void DLParser_SetConvert(Gfx *gfx) { DP_Timing(DLParser_SetConvert); int temp; temp = ((gfx->words.w0)>>13)&0x1FF; g_convk0 = temp>0xFF ? -(temp-0x100) : temp; temp = ((gfx->words.w0)>>4)&0x1FF; g_convk1 = temp>0xFF ? -(temp-0x100) : temp; temp = (gfx->words.w0)&0xF; temp = (temp<<5)|(((gfx->words.w1)>>27)&0x1F); g_convk2 = temp>0xFF ? -(temp-0x100) : temp; temp = ((gfx->words.w1)>>18)&0x1FF; g_convk3 = temp>0xFF ? -(temp-0x100) : temp; temp = ((gfx->words.w1)>>9)&0x1FF; g_convk4 = temp>0xFF ? -(temp-0x100) : temp; temp = (gfx->words.w1)&0x1FF; g_convk5 = temp>0xFF ? -(temp-0x100) : temp; g_convc0 = g_convk5/255.0f+1.0f; g_convc1 = g_convk0/255.0f*g_convc0; g_convc2 = g_convk1/255.0f*g_convc0; g_convc3 = g_convk2/255.0f*g_convc0; g_convc4 = g_convk3/255.0f*g_convc0; } void DLParser_SetPrimDepth(Gfx *gfx) { DP_Timing(DLParser_SetPrimDepth); uint32 dwZ = ((gfx->words.w1) >> 16) & 0xFFFF; uint32 dwDZ = ((gfx->words.w1) ) & 0xFFFF; LOG_UCODE("SetPrimDepth: 0x%08x 0x%08x - z: 0x%04x dz: 0x%04x", gfx->words.w0, gfx->words.w1, dwZ, dwDZ); SetPrimitiveDepth(dwZ, dwDZ); DEBUGGER_PAUSE(NEXT_SET_PRIM_COLOR); } void DLParser_RDPSetOtherMode(Gfx *gfx) { DP_Timing(DLParser_RDPSetOtherMode); gRDP.otherMode._u32[1] = (gfx->words.w0); // High gRDP.otherMode._u32[0] = (gfx->words.w1); // Low if( gRDP.otherModeH != ((gfx->words.w0) & 0x0FFFFFFF) ) { gRDP.otherModeH = ((gfx->words.w0) & 0x0FFFFFFF); uint32 dwTextFilt = (gRDP.otherModeH>>RSP_SETOTHERMODE_SHIFT_TEXTFILT)&0x3; CRender::g_pRender->SetTextureFilter(dwTextFilt<words.w1) ) { if( (gRDP.otherModeL&ZMODE_DEC) != ((gfx->words.w1)&ZMODE_DEC) ) { if( ((gfx->words.w1)&ZMODE_DEC) == ZMODE_DEC ) CRender::g_pRender->SetZBias( 2 ); else CRender::g_pRender->SetZBias( 0 ); } gRDP.otherModeL = (gfx->words.w1); BOOL bZCompare = (gRDP.otherModeL & Z_COMPARE) ? TRUE : FALSE; BOOL bZUpdate = (gRDP.otherModeL & Z_UPDATE) ? TRUE : FALSE; CRender::g_pRender->SetZCompare( bZCompare ); CRender::g_pRender->SetZUpdate( bZUpdate ); uint32 dwAlphaTestMode = (gRDP.otherModeL >> RSP_SETOTHERMODE_SHIFT_ALPHACOMPARE) & 0x3; if ((dwAlphaTestMode) != 0) CRender::g_pRender->SetAlphaTestEnable( TRUE ); else CRender::g_pRender->SetAlphaTestEnable( FALSE ); } uint16 blender = gRDP.otherMode.blender; RDP_BlenderSetting &bl = *(RDP_BlenderSetting*)(&(blender)); if( bl.c1_m1a==3 || bl.c1_m2a == 3 || bl.c2_m1a == 3 || bl.c2_m2a == 3 ) { gRDP.bFogEnableInBlender = true; } else { gRDP.bFogEnableInBlender = false; } } void DLParser_RDPLoadSync(Gfx *gfx) { DP_Timing(DLParser_RDPLoadSync); LOG_UCODE("LoadSync: (Ignored)"); } void DLParser_RDPPipeSync(Gfx *gfx) { DP_Timing(DLParser_RDPPipeSync); LOG_UCODE("PipeSync: (Ignored)"); } void DLParser_RDPTileSync(Gfx *gfx) { DP_Timing(DLParser_RDPTileSync); LOG_UCODE("TileSync: (Ignored)"); } void DLParser_RDPFullSync(Gfx *gfx) { DP_Timing(DLParser_RDPFullSync); TriggerDPInterrupt(); } void DLParser_SetScissor(Gfx *gfx) { DP_Timing(DLParser_SetScissor); ScissorType tempScissor; // The coords are all in 8:2 fixed point tempScissor.x0 = ((gfx->words.w0)>>12)&0xFFF; tempScissor.y0 = ((gfx->words.w0)>>0 )&0xFFF; tempScissor.mode = ((gfx->words.w1)>>24)&0x03; tempScissor.x1 = ((gfx->words.w1)>>12)&0xFFF; tempScissor.y1 = ((gfx->words.w1)>>0 )&0xFFF; tempScissor.left = tempScissor.x0/4; tempScissor.top = tempScissor.y0/4; tempScissor.right = tempScissor.x1/4; tempScissor.bottom = tempScissor.y1/4; if( options.bEnableHacks ) { if( g_CI.dwWidth == 0x200 && tempScissor.right == 0x200 ) { uint32 width = *g_GraphicsInfo.VI_WIDTH_REG & 0xFFF; if( width != 0x200 ) { // Hack for RE2 tempScissor.bottom = tempScissor.right*tempScissor.bottom/width; tempScissor.right = width; } } } if( gRDP.scissor.left != tempScissor.left || gRDP.scissor.top != tempScissor.top || gRDP.scissor.right != tempScissor.right || gRDP.scissor.bottom != tempScissor.bottom || gRSP.real_clip_scissor_left != tempScissor.left || gRSP.real_clip_scissor_top != tempScissor.top || gRSP.real_clip_scissor_right != tempScissor.right || gRSP.real_clip_scissor_bottom != tempScissor.bottom) { memcpy(&(gRDP.scissor), &tempScissor, sizeof(ScissorType) ); if( !status.bHandleN64RenderTexture ) SetVIScales(); if( options.enableHackForGames == HACK_FOR_SUPER_BOWLING && g_CI.dwAddr%0x100 != 0 ) { // right half screen gRDP.scissor.left += 160; gRDP.scissor.right += 160; CRender::g_pRender->SetViewport(160, 0, 320, 240, 0xFFFF); } CRender::g_pRender->UpdateClipRectangle(); CRender::g_pRender->UpdateScissor(); CRender::g_pRender->SetViewportRender(); } LOG_UCODE("SetScissor: x0=%d y0=%d x1=%d y1=%d mode=%d", gRDP.scissor.left, gRDP.scissor.top, gRDP.scissor.right, gRDP.scissor.bottom, gRDP.scissor.mode); ///TXTRBUF_DETAIL_DUMP(DebuggerAppendMsg("SetScissor: x0=%d y0=%d x1=%d y1=%d mode=%d", gRDP.scissor.left, gRDP.scissor.top, //gRDP.scissor.right, gRDP.scissor.bottom, gRDP.scissor.mode);); } void DLParser_FillRect(Gfx *gfx) { DP_Timing(DLParser_FillRect); // fix me status.primitiveType = PRIM_FILLRECT; if( status.bN64IsDrawingTextureBuffer && frameBufferOptions.bIgnore ) { return; } if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS ) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction uint32 w2 = *(uint32 *)(g_pRDRAMu8 + dwPC); if( (w2>>24) == RDP_FILLRECT ) { // Mario Tennis, a lot of FillRect ucodes, skip all of them while( (w2>>24) == RDP_FILLRECT ) { dwPC += 8; w2 = *(uint32 *)(g_pRDRAMu8 + dwPC); } gDlistStack[gDlistStackPointer].pc = dwPC; return; } } uint32 x0 = (((gfx->words.w1)>>12)&0xFFF)/4; uint32 y0 = (((gfx->words.w1)>>0 )&0xFFF)/4; uint32 x1 = (((gfx->words.w0)>>12)&0xFFF)/4; uint32 y1 = (((gfx->words.w0)>>0 )&0xFFF)/4; // Note, in some modes, the right/bottom lines aren't drawn LOG_UCODE(" (%d,%d) (%d,%d)", x0, y0, x1, y1); if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY ) { x1++; y1++; } //TXTRBUF_DETAIL_DUMP(DebuggerAppendMsg("FillRect: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%08X", x0, y0, x1, y1, gRDP.originalFillColor);); if( status.bHandleN64RenderTexture && options.enableHackForGames == HACK_FOR_BANJO_TOOIE ) { // Skip this return; } if (IsUsedAsDI(g_CI.dwAddr)) { // Clear the Z Buffer if( x0!=0 || y0!=0 || windowSetting.uViWidth-x1>1 || windowSetting.uViHeight-y1>1) { if( options.enableHackForGames == HACK_FOR_GOLDEN_EYE ) { // GoldenEye is using double zbuffer if( g_CI.dwAddr == g_ZI.dwAddr ) { // The zbuffer is the upper screen COORDRECT rect={int(x0*windowSetting.fMultX),int(y0*windowSetting.fMultY),int(x1*windowSetting.fMultX),int(y1*windowSetting.fMultY)}; CRender::g_pRender->ClearBuffer(false,true,rect); //Check me LOG_UCODE(" Clearing ZBuffer"); } else { // The zbuffer is the lower screen int h = (g_CI.dwAddr-g_ZI.dwAddr)/g_CI.dwWidth/2; COORDRECT rect={int(x0*windowSetting.fMultX),int((y0+h)*windowSetting.fMultY),int(x1*windowSetting.fMultX),int((y1+h)*windowSetting.fMultY)}; CRender::g_pRender->ClearBuffer(false,true,rect); //Check me LOG_UCODE(" Clearing ZBuffer"); } } else { COORDRECT rect={int(x0*windowSetting.fMultX),int(y0*windowSetting.fMultY),int(x1*windowSetting.fMultX),int(y1*windowSetting.fMultY)}; CRender::g_pRender->ClearBuffer(false,true,rect); //Check me LOG_UCODE(" Clearing ZBuffer"); } } else { CRender::g_pRender->ClearBuffer(false,true); //Check me LOG_UCODE(" Clearing ZBuffer"); } DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FLUSH_TRI,{TRACE0("Pause after FillRect: ClearZbuffer\n");}); DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FILLRECT, {DebuggerAppendMsg("ClearZbuffer: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%08X", x0, y0, x1, y1, gRDP.originalFillColor); DebuggerAppendMsg("Pause after ClearZbuffer: Color=%08X\n", gRDP.originalFillColor);}); if( g_curRomInfo.bEmulateClear ) { // Emulating Clear, by write the memory in RDRAM uint16 color = (uint16)gRDP.originalFillColor; uint32 pitch = g_CI.dwWidth<<1; long long base = (long long) (g_pRDRAMu8 + g_CI.dwAddr); for( uint32 i =y0; iActiveTextureBuffer(); status.leftRendered = status.leftRendered<0 ? x0 : min((int)x0,status.leftRendered); status.topRendered = status.topRendered<0 ? y0 : min((int)y0,status.topRendered); status.rightRendered = status.rightRendered<0 ? x1 : max((int)x1,status.rightRendered); status.bottomRendered = status.bottomRendered<0 ? y1 : max((int)y1,status.bottomRendered); g_pRenderTextureInfo->maxUsedHeight = max(g_pRenderTextureInfo->maxUsedHeight,(int)y1); if( status.bDirectWriteIntoRDRAM || ( x0==0 && y0==0 && (x1 == g_pRenderTextureInfo->N64Width || x1 == g_pRenderTextureInfo->N64Width-1 ) ) ) { if( g_pRenderTextureInfo->CI_Info.dwSize == TXT_SIZE_16b ) { uint16 color = (uint16)gRDP.originalFillColor; uint32 pitch = g_pRenderTextureInfo->N64Width<<1; long long base = (long long) (g_pRDRAMu8 + g_pRenderTextureInfo->CI_Info.dwAddr); for( uint32 i =y0; iN64Width; long long base = (long long) (g_pRDRAMu8 + g_pRenderTextureInfo->CI_Info.dwAddr); for( uint32 i=y0; iN64Width || x1 == g_pRenderTextureInfo->N64Width-1 ) && gRDP.fillColor == 0) //{ // CRender::g_pRender->ClearBuffer(true,false); //} //else { if( gRDP.otherMode.cycle_type == CYCLE_TYPE_FILL ) { CRender::g_pRender->FillRect(x0, y0, x1, y1, gRDP.fillColor); } else { COLOR primColor = GetPrimitiveColor(); CRender::g_pRender->FillRect(x0, y0, x1, y1, primColor); } } } DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FLUSH_TRI,{TRACE0("Pause after FillRect\n");}); DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FILLRECT, {DebuggerAppendMsg("FillRect: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%08X", x0, y0, x1, y1, gRDP.originalFillColor); DebuggerAppendMsg("Pause after FillRect: Color=%08X\n", gRDP.originalFillColor);}); } else { LOG_UCODE(" Filling Rectangle"); if( frameBufferOptions.bSupportRenderTextures || frameBufferOptions.bCheckBackBufs ) { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); status.leftRendered = status.leftRendered<0 ? x0 : min((int)x0,status.leftRendered); status.topRendered = status.topRendered<0 ? y0 : min((int)y0,status.topRendered); status.rightRendered = status.rightRendered<0 ? x1 : max((int)x1,status.rightRendered); status.bottomRendered = status.bottomRendered<0 ? y1 : max((int)y1,status.bottomRendered); } if( gRDP.otherMode.cycle_type == CYCLE_TYPE_FILL ) { if( !status.bHandleN64RenderTexture || g_pRenderTextureInfo->CI_Info.dwSize == TXT_SIZE_16b ) { CRender::g_pRender->FillRect(x0, y0, x1, y1, gRDP.fillColor); } } else { COLOR primColor = GetPrimitiveColor(); //if( RGBA_GETALPHA(primColor) != 0 ) { CRender::g_pRender->FillRect(x0, y0, x1, y1, primColor); } } DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FLUSH_TRI,{TRACE0("Pause after FillRect\n");}); DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FILLRECT, {DebuggerAppendMsg("FillRect: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%08X", x0, y0, x1, y1, gRDP.originalFillColor); DebuggerAppendMsg("Pause after FillRect: Color=%08X\n", gRDP.originalFillColor);}); } } #define STORE_CI {g_CI.dwAddr = dwNewAddr;g_CI.dwFormat = dwFmt;g_CI.dwSize = dwSiz;g_CI.dwWidth = dwWidth;g_CI.bpl=dwBpl;} void DLParser_SetCImg(Gfx *gfx) { uint32 dwFmt = gfx->setimg.fmt; uint32 dwSiz = gfx->setimg.siz; uint32 dwWidth = gfx->setimg.width + 1; uint32 dwNewAddr = RSPSegmentAddr((gfx->setimg.addr)) & 0x00FFFFFF ; uint32 dwBpl = dwWidth << dwSiz >> 1; TXTRBUF_DETAIL_DUMP(DebuggerAppendMsg("SetCImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", dwNewAddr, pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth);); if( dwFmt == TXT_FMT_YUV || dwFmt == TXT_FMT_IA ) { WARNING(TRACE4("Check me: SetCImg Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_CI.dwAddr, pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth)); } LOG_UCODE(" Image: 0x%08x", RSPSegmentAddr(gfx->words.w1)); LOG_UCODE(" Fmt: %s Size: %s Width: %d", pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth); if( g_CI.dwAddr == dwNewAddr && g_CI.dwFormat == dwFmt && g_CI.dwSize == dwSiz && g_CI.dwWidth == dwWidth ) { TXTRBUF_OR_CI_DETAIL_DUMP({ TRACE0("Set CIMG to the same address, no change, skipped"); DebuggerAppendMsg("Pause after SetCImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_CI.dwAddr, pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth); }); return; } if( status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_1ST_CI_CHANGE ) { status.bVIOriginIsUpdated=false; CGraphicsContext::Get()->UpdateFrame(); TXTRBUF_OR_CI_DETAIL_DUMP(TRACE0("Screen Update at 1st CI change");); } if( options.enableHackForGames == HACK_FOR_SUPER_BOWLING ) { if( dwNewAddr%0x100 == 0 ) { if( dwWidth < 320 ) { // Left half screen gRDP.scissor.left = 0; gRDP.scissor.right = 160; CRender::g_pRender->SetViewport(0, 0, 160, 240, 0xFFFF); CRender::g_pRender->UpdateClipRectangle(); CRender::g_pRender->UpdateScissor(); } else { gRDP.scissor.left = 0; gRDP.scissor.right = 320; CRender::g_pRender->SetViewport(0, 0, 320, 240, 0xFFFF); CRender::g_pRender->UpdateClipRectangle(); CRender::g_pRender->UpdateScissor(); } } else { // right half screen gRDP.scissor.left = 160; gRDP.scissor.right = 320; gRSP.nVPLeftN = 160; gRSP.nVPRightN = 320; CRender::g_pRender->UpdateClipRectangle(); CRender::g_pRender->UpdateScissor(); CRender::g_pRender->SetViewport(160, 0, 320, 240, 0xFFFF); } } if( !frameBufferOptions.bUpdateCIInfo ) { STORE_CI; status.bCIBufferIsRendered = false; status.bN64IsDrawingTextureBuffer = false; TXTRBUF_DUMP(TRACE4("SetCImg : Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_CI.dwAddr, pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth)); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG, { DebuggerAppendMsg("Pause after SetCImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", dwNewAddr, pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth); } ); return; } SetImgInfo newCI; newCI.bpl = dwBpl; newCI.dwAddr = dwNewAddr; newCI.dwFormat = dwFmt; newCI.dwSize = dwSiz; newCI.dwWidth = dwWidth; g_pFrameBufferManager->Set_CI_addr(newCI); } void DLParser_SetZImg(Gfx *gfx) { DP_Timing(DLParser_SetZImg); LOG_UCODE(" Image: 0x%08x", RSPSegmentAddr(gfx->words.w1)); uint32 dwFmt = gfx->setimg.fmt; uint32 dwSiz = gfx->setimg.siz; uint32 dwWidth = gfx->setimg.width + 1; uint32 dwAddr = RSPSegmentAddr((gfx->setimg.addr)); if( dwAddr != g_ZI_saves[0].CI_Info.dwAddr ) { g_ZI_saves[1].CI_Info.dwAddr = g_ZI.dwAddr; g_ZI_saves[1].CI_Info.dwFormat = g_ZI.dwFormat; g_ZI_saves[1].CI_Info.dwSize = g_ZI.dwSize; g_ZI_saves[1].CI_Info.dwWidth = g_ZI.dwWidth; g_ZI_saves[1].updateAtFrame = g_ZI_saves[0].updateAtFrame; g_ZI_saves[0].CI_Info.dwAddr = g_ZI.dwAddr = dwAddr; g_ZI_saves[0].CI_Info.dwFormat = g_ZI.dwFormat = dwFmt; g_ZI_saves[0].CI_Info.dwSize = g_ZI.dwSize = dwSiz; g_ZI_saves[0].CI_Info.dwWidth = g_ZI.dwWidth = dwWidth; g_ZI_saves[0].updateAtFrame = status.gDlistCount; } else { g_ZI.dwAddr = dwAddr; g_ZI.dwFormat = dwFmt; g_ZI.dwSize = dwSiz; g_ZI.dwWidth = dwWidth; } DEBUGGER_IF_DUMP((pauseAtNext) , {DebuggerAppendMsg("SetZImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_ZI.dwAddr, pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth);} ); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG, { DebuggerAppendMsg("Pause after SetZImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_ZI.dwAddr, pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth); } ); } bool IsUsedAsDI(uint32 addr) { if( addr == g_ZI_saves[0].CI_Info.dwAddr ) return true; else if( addr == g_ZI_saves[1].CI_Info.dwAddr && status.gDlistCount - g_ZI_saves[1].updateAtFrame < 10 && g_ZI_saves[1].CI_Info.dwAddr != 0 ) return true; else return false; } void DLParser_SetCombine(Gfx *gfx) { DP_Timing(DLParser_SetCombine); uint32 dwMux0 = (gfx->words.w0)&0x00FFFFFF; uint32 dwMux1 = (gfx->words.w1); CRender::g_pRender->SetMux(dwMux0, dwMux1); } void DLParser_SetFillColor(Gfx *gfx) { DP_Timing(DLParser_SetFillColor); gRDP.fillColor = Convert555ToRGBA(gfx->setcolor.fillcolor); gRDP.originalFillColor = (gfx->setcolor.color); LOG_UCODE(" Color5551=0x%04x = 0x%08x", (uint16)gfx->words.w1, gRDP.fillColor); } void DLParser_SetFogColor(Gfx *gfx) { DP_Timing(DLParser_SetFogColor); CRender::g_pRender->SetFogColor( gfx->setcolor.r, gfx->setcolor.g, gfx->setcolor.b, gfx->setcolor.a ); FOG_DUMP(TRACE1("Set Fog color: %08X", gfx->setcolor.color)); } void DLParser_SetBlendColor(Gfx *gfx) { DP_Timing(DLParser_SetBlendColor); CRender::g_pRender->SetAlphaRef(gfx->setcolor.a); } void DLParser_SetPrimColor(Gfx *gfx) { DP_Timing(DLParser_SetPrimColor); SetPrimitiveColor( COLOR_RGBA(gfx->setcolor.r, gfx->setcolor.g, gfx->setcolor.b, gfx->setcolor.a), gfx->setcolor.prim_min_level, gfx->setcolor.prim_level); } void DLParser_SetEnvColor(Gfx *gfx) { DP_Timing(DLParser_SetEnvColor); SetEnvColor( COLOR_RGBA(gfx->setcolor.r, gfx->setcolor.g, gfx->setcolor.b, gfx->setcolor.a) ); } void RDP_DLParser_Process(void) { status.gRDPTime = (uint32) SDL_GetTicks(); status.gDlistCount++; uint32 start = *(g_GraphicsInfo.DPC_START_REG); uint32 end = *(g_GraphicsInfo.DPC_END_REG); gDlistStackPointer=0; gDlistStack[gDlistStackPointer].pc = start; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; // Check if we need to purge (every 5 milliseconds) if (status.gRDPTime - status.lastPurgeTimeTime > 5) { gTextureManager.PurgeOldTextures(); status.lastPurgeTimeTime = status.gRDPTime; } // Lock the graphics context here. CRender::g_pRender->SetFillMode(RICE_FILLMODE_SOLID); SetVIScales(); CRender::g_pRender->RenderReset(); CRender::g_pRender->BeginRendering(); CRender::g_pRender->SetViewport(0, 0, windowSetting.uViWidth, windowSetting.uViHeight, 0x3FF); while( gDlistStack[gDlistStackPointer].pc < end ) { Gfx *pgfx = (Gfx*)&g_pRDRAMu32[(gDlistStack[gDlistStackPointer].pc>>2)]; gDlistStack[gDlistStackPointer].pc += 8; currentUcodeMap[pgfx->words.w0 >>24](pgfx); } CRender::g_pRender->EndRendering(); } void RDP_TriFill(Gfx *gfx) { } void RDP_TriFillZ(Gfx *gfx) { } void RDP_TriTxtr(Gfx *gfx) { } void RDP_TriTxtrZ(Gfx *gfx) { } void RDP_TriShade(Gfx *gfx) { } void RDP_TriShadeZ(Gfx *gfx) { } void RDP_TriShadeTxtr(Gfx *gfx) { } void RDP_TriShadeTxtrZ(Gfx *gfx) { } static int crc_table_empty = 1; static unsigned int crc_table[256]; static void make_crc_table(void); static void make_crc_table() { unsigned int c; int n, k; unsigned int poly; /* polynomial exclusive-or pattern */ /* terms of polynomial defining this crc (except x^32): */ static const uint8 p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; /* make exclusive-or pattern from polynomial (0xedb88320L) */ poly = 0L; for (n = 0; (unsigned int)n < sizeof(p)/sizeof(uint8); n++) poly |= 1L << (31 - p[n]); for (n = 0; n < 256; n++) { c = (unsigned int)n; for (k = 0; k < 8; k++) c = (c & 1) ? (poly ^ (c >> 1)) : c >> 1; crc_table[n] = c; } crc_table_empty = 0; } /* ========================================================================= */ #define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); #define DO2(buf) DO1(buf); DO1(buf); #define DO4(buf) DO2(buf); DO2(buf); #define DO8(buf) DO4(buf); DO4(buf); /* ========================================================================= */ unsigned int ComputeCRC32(unsigned int crc, const uint8 *buf, unsigned int len) { if (buf == NULL) return 0L; if (crc_table_empty) make_crc_table(); crc = crc ^ 0xffffffffL; while (len >= 8) { DO8(buf); len -= 8; } if (len) do { DO1(buf); } while (--len); return crc ^ 0xffffffffL; } Matrix matToLoad; void LoadMatrix(uint32 addr) { const float fRecip = 1.0f / 65536.0f; if (addr + 64 > g_dwRamSize) { TRACE1("Mtx: Address invalid (0x%08x)", addr); return; } for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { int hi = *(short *)(g_pRDRAMu8 + ((addr+(i<<3)+(j<<1) )^0x2)); int lo = *(unsigned short *)(g_pRDRAMu8 + ((addr+(i<<3)+(j<<1) + 32)^0x2)); matToLoad.m[i][j] = (float)((hi<<16) | lo) * fRecip; } } #ifdef DEBUGGER LOG_UCODE( " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n", matToLoad.m[0][0], matToLoad.m[0][1], matToLoad.m[0][2], matToLoad.m[0][3], matToLoad.m[1][0], matToLoad.m[1][1], matToLoad.m[1][2], matToLoad.m[1][3], matToLoad.m[2][0], matToLoad.m[2][1], matToLoad.m[2][2], matToLoad.m[2][3], matToLoad.m[3][0], matToLoad.m[3][1], matToLoad.m[3][2], matToLoad.m[3][3]); #endif // DEBUGGER } mupen64plus-video-rice-src-2.0/src/RSP_Parser.h0000644000000000000000000004561312165031100017432 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __RICE_RDP_GFX_H__ #define __RICE_RDP_GFX_H__ #define RSP_SPNOOP 0 // handle 0 gracefully #define RSP_MTX 1 #define RSP_RESERVED0 2 // unknown #define RSP_MOVEMEM 3 // move a block of memory (up to 4 words) to dmem #define RSP_VTX 4 #define RSP_RESERVED1 5 // unknown #define RSP_DL 6 #define RSP_RESERVED2 7 // unknown #define RSP_RESERVED3 8 // unknown #define RSP_SPRITE2D 9 // sprite command #define RSP_SPRITE2D_BASE 9 // sprite command #define RSP_1ST 0xBF #define RSP_TRI1 (RSP_1ST-0) #define RSP_CULLDL (RSP_1ST-1) #define RSP_POPMTX (RSP_1ST-2) #define RSP_MOVEWORD (RSP_1ST-3) #define RSP_TEXTURE (RSP_1ST-4) #define RSP_SETOTHERMODE_H (RSP_1ST-5) #define RSP_SETOTHERMODE_L (RSP_1ST-6) #define RSP_ENDDL (RSP_1ST-7) #define RSP_SETGEOMETRYMODE (RSP_1ST-8) #define RSP_CLEARGEOMETRYMODE (RSP_1ST-9) #define RSP_LINE3D (RSP_1ST-10) #define RSP_RDPHALF_1 (RSP_1ST-11) #define RSP_RDPHALF_2 (RSP_1ST-12) #define RSP_RDPHALF_CONT (RSP_1ST-13) #define RSP_MODIFYVTX (RSP_1ST-13) #define RSP_TRI2 (RSP_1ST-14) #define RSP_BRANCH_Z (RSP_1ST-15) #define RSP_LOAD_UCODE (RSP_1ST-16) #define RSP_SPRITE2D_SCALEFLIP (RSP_1ST-1) #define RSP_SPRITE2D_DRAW (RSP_1ST-2) #define RSP_ZELDAVTX 1 #define RSP_ZELDAMODIFYVTX 2 #define RSP_ZELDACULLDL 3 #define RSP_ZELDABRANCHZ 4 #define RSP_ZELDATRI1 5 #define RSP_ZELDATRI2 6 #define RSP_ZELDALINE3D 7 #define RSP_ZELDARDPHALF_2 0xf1 #define RSP_ZELDASETOTHERMODE_H 0xe3 #define RSP_ZELDASETOTHERMODE_L 0xe2 #define RSP_ZELDARDPHALF_1 0xe1 #define RSP_ZELDASPNOOP 0xe0 #define RSP_ZELDAENDDL 0xdf #define RSP_ZELDADL 0xde #define RSP_ZELDALOAD_UCODE 0xdd #define RSP_ZELDAMOVEMEM 0xdc #define RSP_ZELDAMOVEWORD 0xdb #define RSP_ZELDAMTX 0xda #define RSP_ZELDAGEOMETRYMODE 0xd9 #define RSP_ZELDAPOPMTX 0xd8 #define RSP_ZELDATEXTURE 0xd7 #define RSP_ZELDASUBMODULE 0xd6 // 4 is something like a conditional DL #define RSP_DMATRI 0x05 #define G_DLINMEM 0x07 // RDP commands: #define RDP_NOOP 0xc0 #define RDP_SETCIMG 0xff #define RDP_SETZIMG 0xfe #define RDP_SETTIMG 0xfd #define RDP_SETCOMBINE 0xfc #define RDP_SETENVCOLOR 0xfb #define RDP_SETPRIMCOLOR 0xfa #define RDP_SETBLENDCOLOR 0xf9 #define RDP_SETFOGCOLOR 0xf8 #define RDP_SETFILLCOLOR 0xf7 #define RDP_FILLRECT 0xf6 #define RDP_SETTILE 0xf5 #define RDP_LOADTILE 0xf4 #define RDP_LOADBLOCK 0xf3 #define RDP_SETTILESIZE 0xf2 #define RDP_LOADTLUT 0xf0 #define RDP_RDPSETOTHERMODE 0xef #define RDP_SETPRIMDEPTH 0xee #define RDP_SETSCISSOR 0xed #define RDP_SETCONVERT 0xec #define RDP_SETKEYR 0xeb #define RDP_SETKEYGB 0xea #define RDP_FULLSYNC 0xe9 #define RDP_TILESYNC 0xe8 #define RDP_PIPESYNC 0xe7 #define RDP_LOADSYNC 0xe6 #define RDP_TEXRECT_FLIP 0xe5 #define RDP_TEXRECT 0xe4 #define RSP_ZELDA_MTX_MODELVIEW 0x00 #define RSP_ZELDA_MTX_PROJECTION 0x04 #define RSP_ZELDA_MTX_MUL 0x00 #define RSP_ZELDA_MTX_LOAD 0x02 #define RSP_ZELDA_MTX_PUSH 0x00 #define RSP_ZELDA_MTX_NOPUSH 0x01 // // RSP_SETOTHERMODE_L sft: shift count #define RSP_SETOTHERMODE_SHIFT_ALPHACOMPARE 0 #define RSP_SETOTHERMODE_SHIFT_ZSRCSEL 2 #define RSP_SETOTHERMODE_SHIFT_RENDERMODE 3 #define RSP_SETOTHERMODE_SHIFT_BLENDER 16 // // RSP_SETOTHERMODE_H sft: shift count #define RSP_SETOTHERMODE_SHIFT_BLENDMASK 0 // unsupported #define RSP_SETOTHERMODE_SHIFT_ALPHADITHER 4 #define RSP_SETOTHERMODE_SHIFT_RGBDITHER 6 #define RSP_SETOTHERMODE_SHIFT_COMBKEY 8 #define RSP_SETOTHERMODE_SHIFT_TEXTCONV 9 #define RSP_SETOTHERMODE_SHIFT_TEXTFILT 12 #define RSP_SETOTHERMODE_SHIFT_TEXTLUT 14 #define RSP_SETOTHERMODE_SHIFT_TEXTLOD 16 #define RSP_SETOTHERMODE_SHIFT_TEXTDETAIL 17 #define RSP_SETOTHERMODE_SHIFT_TEXTPERSP 19 #define RSP_SETOTHERMODE_SHIFT_CYCLETYPE 20 #define RSP_SETOTHERMODE_SHIFT_COLORDITHER 22 // unsupported in HW 2.0 #define RSP_SETOTHERMODE_SHIFT_PIPELINE 23 // RSP_SETOTHERMODE_H gPipelineMode #define RSP_PIPELINE_MODE_1PRIMITIVE (1 << RSP_SETOTHERMODE_SHIFT_PIPELINE) #define RSP_PIPELINE_MODE_NPRIMITIVE (0 << RSP_SETOTHERMODE_SHIFT_PIPELINE) // RSP_SETOTHERMODE_H gSetCycleType #define CYCLE_TYPE_1 0 #define CYCLE_TYPE_2 1 #define CYCLE_TYPE_COPY 2 #define CYCLE_TYPE_FILL 3 // RSP_SETOTHERMODE_H gSetTextureLUT #define TLUT_FMT_NONE (0 << RSP_SETOTHERMODE_SHIFT_TEXTLUT) #define TLUT_FMT_UNKNOWN (1 << RSP_SETOTHERMODE_SHIFT_TEXTLUT) #define TLUT_FMT_RGBA16 (2 << RSP_SETOTHERMODE_SHIFT_TEXTLUT) #define TLUT_FMT_IA16 (3 << RSP_SETOTHERMODE_SHIFT_TEXTLUT) // RSP_SETOTHERMODE_H gSetTextureFilter #define RDP_TFILTER_POINT (0 << RSP_SETOTHERMODE_SHIFT_TEXTFILT) #define RDP_TFILTER_AVERAGE (3 << RSP_SETOTHERMODE_SHIFT_TEXTFILT) #define RDP_TFILTER_BILERP (2 << RSP_SETOTHERMODE_SHIFT_TEXTFILT) // RSP_SETOTHERMODE_L gSetAlphaCompare #define RDP_ALPHA_COMPARE_NONE (0 << RSP_SETOTHERMODE_SHIFT_ALPHACOMPARE) #define RDP_ALPHA_COMPARE_THRESHOLD (1 << RSP_SETOTHERMODE_SHIFT_ALPHACOMPARE) #define RDP_ALPHA_COMPARE_DITHER (3 << RSP_SETOTHERMODE_SHIFT_ALPHACOMPARE) // RSP_SETOTHERMODE_L gSetRenderMode #define Z_COMPARE 0x0010 #define Z_UPDATE 0x0020 #define ZMODE_DEC 0x0c00 // // flags for RSP_SETGEOMETRYMODE // #define G_ZBUFFER 0x00000001 #define G_TEXTURE_ENABLE 0x00000002 // Microcode use only #define G_SHADE 0x00000004 // enable Gouraud interp // #define G_SHADING_SMOOTH 0x00000200 // flat or smooth shaded #define G_CULL_FRONT 0x00001000 #define G_CULL_BACK 0x00002000 #define G_CULL_BOTH 0x00003000 // To make code cleaner #define G_FOG 0x00010000 #define G_LIGHTING 0x00020000 #define G_TEXTURE_GEN 0x00040000 #define G_TEXTURE_GEN_LINEAR 0x00080000 #define G_LOD 0x00100000 // NOT IMPLEMENTED // // G_SETIMG fmt: set image formats // #define TXT_FMT_RGBA 0 #define TXT_FMT_YUV 1 #define TXT_FMT_CI 2 #define TXT_FMT_IA 3 #define TXT_FMT_I 4 // // G_SETIMG siz: set image pixel size // #define TXT_SIZE_4b 0 #define TXT_SIZE_8b 1 #define TXT_SIZE_16b 2 #define TXT_SIZE_32b 3 // // Texturing macros // #define RDP_TXT_LOADTILE 7 #define RDP_TXT_RENDERTILE 0 #define RDP_TXT_NOMIRROR 0 #define RDP_TXT_WRAP 0 #define RDP_TXT_MIRROR 0x1 #define RDP_TXT_CLAMP 0x2 #define RDP_TXT_NOMASK 0 #define RDP_TXT_NOLOD 0 // // MOVEMEM indices // // Each of these indexes an entry in a dmem table // which points to a 1-4 word block of dmem in // which to store a 1-4 word DMA. // // #define RSP_GBI1_MV_MEM_VIEWPORT 0x80 #define RSP_GBI1_MV_MEM_LOOKATY 0x82 #define RSP_GBI1_MV_MEM_LOOKATX 0x84 #define RSP_GBI1_MV_MEM_L0 0x86 #define RSP_GBI1_MV_MEM_L1 0x88 #define RSP_GBI1_MV_MEM_L2 0x8a #define RSP_GBI1_MV_MEM_L3 0x8c #define RSP_GBI1_MV_MEM_L4 0x8e #define RSP_GBI1_MV_MEM_L5 0x90 #define RSP_GBI1_MV_MEM_L6 0x92 #define RSP_GBI1_MV_MEM_L7 0x94 #define RSP_GBI1_MV_MEM_TXTATT 0x96 #define RSP_GBI1_MV_MEM_MATRIX_1 0x9e // NOTE: this is in moveword table #define RSP_GBI1_MV_MEM_MATRIX_2 0x98 #define RSP_GBI1_MV_MEM_MATRIX_3 0x9a #define RSP_GBI1_MV_MEM_MATRIX_4 0x9c # define RSP_GBI2_MV_MEM__VIEWPORT 8 # define RSP_GBI2_MV_MEM__LIGHT 10 # define RSP_GBI2_MV_MEM__POINT 12 # define RSP_GBI2_MV_MEM__MATRIX 14 /* NOTE: this is in moveword table */ # define RSP_GBI2_MV_MEM_O_LOOKATX (0*24) # define RSP_GBI2_MV_MEM_O_LOOKATY (1*24) # define RSP_GBI2_MV_MEM_O_L0 (2*24) # define RSP_GBI2_MV_MEM_O_L1 (3*24) # define RSP_GBI2_MV_MEM_O_L2 (4*24) # define RSP_GBI2_MV_MEM_O_L3 (5*24) # define RSP_GBI2_MV_MEM_O_L4 (6*24) # define RSP_GBI2_MV_MEM_O_L5 (7*24) # define RSP_GBI2_MV_MEM_O_L6 (8*24) # define RSP_GBI2_MV_MEM_O_L7 (9*24) // // MOVEWORD indices // // Each of these indexes an entry in a dmem table // which points to a word in dmem in dmem where // an immediate word will be stored. // // #define RSP_MOVE_WORD_MATRIX 0x00 // NOTE: also used by movemem #define RSP_MOVE_WORD_NUMLIGHT 0x02 #define RSP_MOVE_WORD_CLIP 0x04 #define RSP_MOVE_WORD_SEGMENT 0x06 #define RSP_MOVE_WORD_FOG 0x08 #define RSP_MOVE_WORD_LIGHTCOL 0x0a #define RSP_MOVE_WORD_POINTS 0x0c #define RSP_MOVE_WORD_PERSPNORM 0x0e // // These are offsets from the address in the dmem table // #define RSP_MV_WORD_OFFSET_NUMLIGHT 0x00 #define RSP_MV_WORD_OFFSET_CLIP_RNX 0x04 #define RSP_MV_WORD_OFFSET_CLIP_RNY 0x0c #define RSP_MV_WORD_OFFSET_CLIP_RPX 0x14 #define RSP_MV_WORD_OFFSET_CLIP_RPY 0x1c #define RSP_MV_WORD_OFFSET_FOG 0x00 #define RSP_MV_WORD_OFFSET_POINT_RGBA 0x10 #define RSP_MV_WORD_OFFSET_POINT_ST 0x14 #define RSP_MV_WORD_OFFSET_POINT_XYSCREEN 0x18 #define RSP_MV_WORD_OFFSET_POINT_ZSCREEN 0x1c // flags to inhibit pushing of the display list (on branch) #define RSP_DLIST_PUSH 0x00 #define RSP_DLIST_NOPUSH 0x01 // // RSP_MTX: parameter flags // #define RSP_MATRIX_MODELVIEW 0x00 #define RSP_MATRIX_PROJECTION 0x01 #define RSP_MATRIX_MUL 0x00 #define RSP_MATRIX_LOAD 0x02 #define RSP_MATRIX_NOPUSH 0x00 #define RSP_MATRIX_PUSH 0x04 typedef struct { uint32 type; uint32 flags; uint32 ucode_boot; uint32 ucode_boot_size; uint32 ucode; uint32 ucode_size; uint32 ucode_data; uint32 ucode_data_size; uint32 dram_stack; uint32 dram_stack_size; uint32 output_buff; uint32 output_buff_size; uint32 data_ptr; uint32 data_size; uint32 yield_data_ptr; uint32 yield_data_size; } OSTask_t; typedef union { OSTask_t t; uint64 force_structure_alignment; } OSTask; #define MAX_DL_STACK_SIZE 32 #define MAX_DL_COUNT 1000000 typedef struct { bool used; uint32 crc_size; uint32 crc_800; uint32 ucode; uint32 minor_ver; uint32 variant; char rspstr[200]; uint32 ucStart; uint32 ucSize; uint32 ucDStart; uint32 ucDSize; uint32 ucCRC; uint32 ucDWORD1; uint32 ucDWORD2; uint32 ucDWORD3; uint32 ucDWORD4; } UcodeInfo; typedef struct { uint32 ucode; uint32 crc_size; uint32 crc_800; const unsigned char * ucode_name; bool non_nearclip; bool reject; } UcodeData; struct TileDescriptor { // Set by SetTile unsigned int dwFormat :3; // e.g. RGBA, YUV etc unsigned int dwSize :2; // e.g 4/8/16/32bpp unsigned int dwLine :9; // Ummm... unsigned int dwPalette :4; // 0..15 - a palette index? uint32 dwTMem; // Texture memory location unsigned int bClampS :1; unsigned int bClampT :1; unsigned int bMirrorS :1; unsigned int bMirrorT :1; unsigned int dwMaskS :4; unsigned int dwMaskT :4; unsigned int dwShiftS :4; unsigned int dwShiftT :4; // Set by SetTileSize unsigned int sl :10; // Upper left S - 8:3 unsigned int tl :10; // Upper Left T - 8:3 unsigned int sh :10; // Lower Right S unsigned int th :10; // Lower Right T }; enum LoadType { BY_NEVER_SET, BY_LOAD_BLOCK, BY_LOAD_TILE, BY_LOAD_TLUT, }; struct LoadCmdInfo { LoadType loadtype; unsigned int sl :10; // Upper left S - 8:3 unsigned int tl :10; // Upper Left T - 8:3 unsigned int sh :10; // Lower Right S unsigned int th :10; // Lower Right T unsigned int dxt :12; }; typedef struct { // This is in Intel format uint32 SourceImagePointer; uint32 TlutPointer; short SubImageWidth; short Stride; char SourceImageBitSize; char SourceImageType; short SubImageHeight; short SourceImageOffsetT; short SourceImageOffsetS; char dummy[4]; } SpriteStruct; //Converted Sprint struct in Intel format typedef struct{ short px; short py; float scaleX; float scaleY; uint8 flipX; uint8 flipY; SpriteStruct *spritePtr; } Sprite2DInfo; typedef struct { unsigned int c2_m2b:2; unsigned int c1_m2b:2; unsigned int c2_m2a:2; unsigned int c1_m2a:2; unsigned int c2_m1b:2; unsigned int c1_m1b:2; unsigned int c2_m1a:2; unsigned int c1_m1a:2; } RDP_BlenderSetting; typedef struct { union { struct { // Low bits unsigned int alpha_compare : 2; // 0..1 unsigned int depth_source : 1; // 2..2 // unsigned int render_mode : 13; // 3..15 unsigned int aa_en : 1; // 3 unsigned int z_cmp : 1; // 4 unsigned int z_upd : 1; // 5 unsigned int im_rd : 1; // 6 unsigned int clr_on_cvg : 1; // 7 unsigned int cvg_dst : 2; // 8..9 unsigned int zmode : 2; // 10..11 unsigned int cvg_x_alpha : 1; // 12 unsigned int alpha_cvg_sel : 1; // 13 unsigned int force_bl : 1; // 14 unsigned int tex_edge : 1; // 15 - Not used unsigned int blender : 16; // 16..31 // High bits unsigned int blend_mask : 4; // 0..3 - not supported unsigned int alpha_dither : 2; // 4..5 unsigned int rgb_dither : 2; // 6..7 unsigned int key_en : 1; // 8..8 unsigned int text_conv : 3; // 9..11 unsigned int text_filt : 2; // 12..13 unsigned int text_tlut : 2; // 14..15 unsigned int text_lod : 1; // 16..16 unsigned int text_sharpen : 1; // 17..18 unsigned int text_detail : 1; // 17..18 unsigned int text_persp : 1; // 19..19 unsigned int cycle_type : 2; // 20..21 unsigned int reserved : 1; // 22..22 - not supported unsigned int atomic_prim : 1; // 23..23 unsigned int pad : 8; // 24..31 - padding }; uint64 _u64; uint32 _u32[2]; }; } RDP_OtherMode; typedef enum { CMD_SETTILE, CMD_SETTILE_SIZE, CMD_LOADBLOCK, CMD_LOADTILE, CMD_LOADTLUT, CMD_SET_TEXTURE, CMD_LOAD_OBJ_TXTR, } SetTileCmdType; // The display list PC stack. Before this was an array of 10 // items, but this way we can nest as deeply as necessary. typedef struct { uint32 pc; int countdown; } DListStack; typedef struct { int x0, y0, x1, y1, mode; int left, top, right, bottom; } ScissorType; // Mask down to 0x003FFFFF? #define RSPSegmentAddr(seg) ( gRSP.segments[((seg)>>24)&0x0F] + ((seg)&0x00FFFFFF) ) #define RDRAM_UWORD(addr) (*(uint32 *)((addr)+g_pRDRAMu8)) #define RDRAM_SWORD(addr) (*(s32 *)((addr)+g_pRDRAMu8)) #define RDRAM_UHALF(addr) (*(uint16 *)(((addr)^2)+g_pRDRAMu8)) #define RDRAM_SHALF(addr) (*(short *)(((addr)^2)+g_pRDRAMu8)) #define RDRAM_UBYTE(addr) (*(uint8 *)(((addr)^3)+g_pRDRAMu8)) #define RDRAM_SBYTE(addr) (*(s8 *)(((addr)^3)+g_pRDRAMu8)) #define pRDRAM_UWORD(addr) ((uint32 *)((addr)+g_pRDRAMu8)) #define pRDRAM_SWORD(addr) ((s32 *)((addr)+g_pRDRAMu8)) #define pRDRAM_UHALF(addr) ((uint16 *)(((addr)^2)+g_pRDRAMu8)) #define pRDRAM_SHALF(addr) ((short *)(((addr)^2)+g_pRDRAMu8)) #define pRDRAM_UBYTE(addr) ((uint8 *)(((addr)^3)+g_pRDRAMu8)) #define pRDRAM_SBYTE(addr) ((s8 *)(((addr)^3)+g_pRDRAMu8)) extern uint16 g_wRDPTlut[]; extern const char *textluttype[4]; extern const char *pszImgFormat[8]; extern const char *pszImgSize[4]; extern uint8 pnImgSize[4]; extern const char *textlutname[4]; extern SetImgInfo g_CI; extern SetImgInfo g_ZI; extern SetImgInfo g_TI; extern TmemType g_Tmem; extern DListStack gDlistStack[MAX_DL_STACK_SIZE]; extern int gDlistStackPointer; void DLParser_Init(); void RDP_GFX_Reset(); void RDP_Cleanup(); void DLParser_Process(OSTask * pTask); void RDP_DLParser_Process(void); void PrepareTextures(); void RDP_InitRenderState(); void DisplayVertexInfo(uint32 dwAddr, uint32 dwV0, uint32 dwN); void RSP_MoveMemLight(uint32 dwLight, uint32 dwAddr); void RSP_MoveMemViewport(uint32 dwAddr); void RDP_NOIMPL_WARN(const char* op); void RSP_GFX_Force_Matrix(uint32 dwAddr); void RSP_GFX_InitGeometryMode(); void RSP_SetUcode(int ucode, uint32 ucStart=0, uint32 ucDStart=0, uint32 cdSize=0); uint32 CalcalateCRC(uint32* srcPtr, uint32 srcSize); void RDP_GFX_PopDL(); extern Matrix matToLoad; void LoadMatrix(uint32 addr); unsigned int ComputeCRC32(unsigned int crc, const uint8 *buf, unsigned int len); void TriggerDPInterrupt(); void TriggerSPInterrupt(); uint32 DLParser_CheckUcode(uint32 ucStart, uint32 ucDStart, uint32 ucSize, uint32 ucDSize); bool IsUsedAsDI(uint32 addr); #if defined(DEBUGGER) void __cdecl LOG_UCODE(const char* szFormat, ...); #else inline void LOG_UCODE(...) {} #endif #endif // __RICE_RDP_GFX_H__ mupen64plus-video-rice-src-2.0/src/RSP_S2DEX.cpp0000644000000000000000000004346412165031100017360 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // This file implements the S2DEX ucode, Yoshi story is using this ucodes #include "UcodeDefs.h" #include "Render.h" #include "Timing.h" uObjTxtr *gObjTxtr = NULL; uObjTxtrTLUT *gObjTlut = NULL; uint32 gObjTlutAddr = 0; uObjMtx *gObjMtx = NULL; uObjSubMtx *gSubObjMtx = NULL; uObjMtxReal gObjMtxReal = {1, 0, 0, 1, 0, 0, 0, 0}; Matrix g_MtxReal(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1); uint32 g_TxtLoadBy = CMD_LOAD_OBJ_TXTR; // Yoshi's Story uses this - 0x02 void RSP_S2DEX_BG_COPY(Gfx *gfx) { SP_Timing(DP_Minimal16); DP_Timing(DP_Minimal16); uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjBg *sbgPtr = (uObjBg*)(g_pRDRAMu8+dwAddr); CRender::g_pRender->LoadObjBGCopy(*sbgPtr); CRender::g_pRender->DrawObjBGCopy(*sbgPtr); } // Yoshi's Story uses this - 0x03 void RSP_S2DEX_OBJ_RECTANGLE(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjSprite *ptr = (uObjSprite*)(g_pRDRAMu8+dwAddr); uObjTxSprite objtx; memcpy(&objtx.sprite,ptr,sizeof(uObjSprite)); if( g_TxtLoadBy == CMD_LOAD_OBJ_TXTR ) { memcpy(&(objtx.txtr.block),&(gObjTxtr->block),sizeof(uObjTxtr)); CRender::g_pRender->LoadObjSprite(objtx,true); } else { PrepareTextures(); } CRender::g_pRender->DrawSprite(objtx, false); #ifdef DEBUGGER if( (pauseAtNext && (eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI)) || logTextures ) { if( debuggerPauseCount > 0 ) debuggerPauseCount--; if( debuggerPauseCount == 0 ) { eventToPause = false; debuggerPause = true; TRACE3("Paused at RSP_S2DEX_OBJ_RECTANGLE\nptr=%08X, img=%08X, Tmem=%08X", dwAddr,objtx.txtr.block.image, ptr->imageAdrs); CGraphicsContext::g_pGraphicsContext->UpdateFrame(); } } #endif } // Yoshi's Story uses this - 0x04 void RSP_S2DEX_OBJ_SPRITE(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjSprite *info = (uObjSprite*)(g_pRDRAMu8+dwAddr); uint32 dwTile = gRSP.curTile; status.bAllowLoadFromTMEM = false; // Because we need to use TLUT loaded by ObjTlut cmd PrepareTextures(); status.bAllowLoadFromTMEM = true; //CRender::g_pRender->SetCombinerAndBlender(); uObjTxSprite drawinfo; memcpy( &(drawinfo.sprite), info, sizeof(uObjSprite)); CRender::g_pRender->DrawSpriteR(drawinfo, false, dwTile, 0, 0, drawinfo.sprite.imageW/32, drawinfo.sprite.imageH/32); /* static BOOL bWarned = FALSE; //if (!bWarned) { RSP_RDP_NOIMPL("RDP: RSP_S2DEX_OBJ_SPRITE (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); bWarned = TRUE; } */ #ifdef DEBUGGER if( (pauseAtNext && (eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI)) || logTextures ) { eventToPause = false; debuggerPause = true; TRACE0("Paused at RSP_S2DEX_OBJ_SPRITE"); CGraphicsContext::g_pGraphicsContext->UpdateFrame(); } #endif } // Yoshi's Story uses this - 0xb0 void RSP_S2DEX_SELECT_DL(Gfx *gfx) { //static BOOL bWarned = FALSE; //if (!bWarned) { RSP_RDP_NOIMPL("RDP: RSP_S2DEX_SELECT_DL (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); //bWarned = TRUE; } DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_OBJ_TXT_CMD, {DebuggerAppendMsg("Paused at RSP_S2DEX_SELECT_DL");}); } void RSP_S2DEX_OBJ_RENDERMODE(Gfx *gfx) { /* static BOOL bWarned = FALSE; //if (!bWarned) { RSP_RDP_NOIMPL("RDP: RSP_S2DEX_OBJ_RENDERMODE (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); bWarned = TRUE; } */ } // Yoshi's Story uses this - 0xb1 void RSP_GBI1_Tri2(Gfx *gfx); void RSP_S2DEX_OBJ_RENDERMODE_2(Gfx *gfx) { if( ((gfx->words.w0)&0xFFFFFF) != 0 || ((gfx->words.w1)&0xFFFFFF00) != 0 ) { // This is a TRI2 cmd RSP_GBI1_Tri2(gfx); return; } RSP_S2DEX_OBJ_RENDERMODE(gfx); } #ifdef DEBUGGER void DumpBlockParameters(uObjTxtrBlock &ptr) { /* typedef struct { //Intel format uint32 type; // S2DEX_OBJLT_TXTRBLOCK divided into types. uint64 *image; // The texture source address on DRAM. uint16 tsize; // The Texture size. Specified by the macro GS_TB_TSIZE(). uint16 tmem; // The transferred TMEM word address. (8byteWORD) uint16 sid; // STATE ID Multipled by 4. Either one of 0,4,8 and 12. uint16 tline; // The width of the Texture 1-line. Specified by the macro GS_TB_TLINE() uint32 flag; // STATE flag uint32 mask; // STATE mask } uObjTxtrBlock; // 24 bytes */ DebuggerAppendMsg("uObjTxtrBlock Header in RDRAM: 0x%08X", (uint32) ((char *) &ptr - (char *) g_pRDRAMu8)); DebuggerAppendMsg("ImgAddr=0x%08X(0x%08X), tsize=0x%X, \nTMEM=0x%X, sid=%d, tline=%d, flag=0x%X, mask=0x%X\n\n", RSPSegmentAddr(ptr.image), ptr.image, ptr.tsize, ptr.tmem, ptr.sid/4, ptr.tline, ptr.flag, ptr.mask); } void DumpSpriteParameters(uObjSprite &ptr) { /* typedef struct { // Intel format uint16 scaleW; // Scaling of the u5.10 width direction. short objX; // The x-coordinate of the upper-left end. s10.2 OBJ uint16 paddingX; // Unused. Always 0. uint16 imageW; // The width of the u10.5 texture. (The length of the S-direction.) uint16 scaleH; // Scaling of the u5.10 height direction. short objY; // The y-coordinate of the s10.2 OBJ upper-left end. uint16 paddingY; // Unused. Always 0. uint16 imageH; // The height of the u10.5 texture. (The length of the T-direction.) uint16 imageAdrs; // The texture header position in TMEM. (In units of 64bit word.) uint16 imageStride; // The folding width of the texel. (In units of 64bit word.) uint8 imageFlags; // The display flag. S2DEX_OBJ_FLAG_FLIP* uint8 imagePal; //The pallet number. 0-7 uint8 imageSiz; // The size of the texel. TXT_SIZE_* uint8 imageFmt; // The format of the texel. TXT_FMT_* } uObjSprite; // 24 bytes */ if( logTextures || (pauseAtNext && eventToPause == NEXT_OBJ_TXT_CMD) ) { DebuggerAppendMsg("uObjSprite Header in RDRAM: 0x%08X", (uint32) ((char *) &ptr - (char *) g_pRDRAMu8)); DebuggerAppendMsg("X=%d, Y=%d, W=%d, H=%d, scaleW=%f, scaleH=%f\n" "TAddr=0x%X, Stride=%d, Flag=0x%X, Pal=%d, Fmt=%s-%db\n\n", ptr.objX/4, ptr.objY/4, ptr.imageW/32, ptr.imageH/32, ptr.scaleW/1024.0f, ptr.scaleH/1024.0f, ptr.imageAdrs, ptr.imageStride, ptr.imageFlags, ptr.imagePal, pszImgFormat[ptr.imageFmt], pnImgSize[ptr.imageSiz]); } } void DumpTileParameters(uObjTxtrTile &tile) { } void DumpTlutParameters(uObjTxtrTLUT &tlut) { /* typedef struct { // Intel Format uint32 type; // S2DEX_OBJLT_TLUT divided into types. uint32 image; uint16 pnum; // The loading pallet number -1. uint16 phead; // The pallet number of the load header. Between 256 and 511. uint16 sid; // STATE ID Multiplied by 4. Either one of 0,4,8 and 12. uint16 zero; // Assign 0 all the time. uint32 flag; // STATE flag uint32 mask; // STATE mask } uObjTxtrTLUT; // 24 bytes */ DebuggerAppendMsg("ImgAddr=0x%08X(0x%08X), pnum=%d, phead=%d, sid=%d, flag=0x%X, mask=0x%X\n\n", RSPSegmentAddr(tlut.image), tlut.image, tlut.pnum+1, tlut.phead, tlut.sid/4, tlut.flag, tlut.mask); } void DumpTxtrInfo(uObjTxtr *ptr) { if( logTextures || (pauseAtNext && eventToPause == NEXT_OBJ_TXT_CMD) ) { DebuggerAppendMsg("uObjTxtr Header in RDRAM: 0x%08X", (uint32) ((char *) ptr - (char *) g_pRDRAMu8)); switch( ptr->block.type ) { case S2DEX_OBJLT_TXTRBLOCK: TRACE0("Loading ObjTxtr: type=BLOCK"); DumpBlockParameters(ptr->block); break; case S2DEX_OBJLT_TXTRTILE: TRACE0("Loading ObjTxtr: type=TILE"); DumpTileParameters(ptr->tile); break; case S2DEX_OBJLT_TLUT: TRACE0("Loading ObjTxtr: type=TLUT"); DumpTlutParameters(ptr->tlut); break; } } } void DumpObjMtx(bool fullmtx = true) { if( logTextures || (pauseAtNext && eventToPause == NEXT_OBJ_TXT_CMD) ) { if( fullmtx ) DebuggerAppendMsg("A=%X, B=%X, C=%X, D=%X, X=%X, Y=%X, BaseX=%X, BaseY=%X", gObjMtx->A, gObjMtx->B, gObjMtx->C, gObjMtx->D, gObjMtx->X, gObjMtx->Y, gObjMtx->BaseScaleX, gObjMtx->BaseScaleY); else DebuggerAppendMsg("SubMatrix: X=%X, Y=%X, BaseX=%X, BaseY=%X", gSubObjMtx->X, gSubObjMtx->Y, gSubObjMtx->BaseScaleX, gSubObjMtx->BaseScaleY); DebuggerAppendMsg("A=%f, B=%f, C=%f, D=%f, X=%f, Y=%f, BaseX=%f, BaseY=%f", gObjMtxReal.A, gObjMtxReal.B, gObjMtxReal.C, gObjMtxReal.D, gObjMtxReal.X, gObjMtxReal.Y, gObjMtxReal.BaseScaleX, gObjMtxReal.BaseScaleY); } } #endif void ObjMtxTranslate(float &x, float &y) { float x1 = gObjMtxReal.A*x + gObjMtxReal.B*y + gObjMtxReal.X; float y1 = gObjMtxReal.C*x + gObjMtxReal.D*y + gObjMtxReal.Y; x = x1; y = y1; } void RSP_S2DEX_SPObjLoadTxtr(Gfx *gfx) { gObjTxtr = (uObjTxtr*)(g_pRDRAMu8+(RSPSegmentAddr((gfx->words.w1))&(g_dwRamSize-1))); if( gObjTxtr->block.type == S2DEX_OBJLT_TLUT ) { gObjTlut = (uObjTxtrTLUT*)gObjTxtr; gObjTlutAddr = (uint32)(RSPSegmentAddr(gObjTlut->image)); // Copy tlut int size = gObjTlut->pnum+1; int offset = gObjTlut->phead-0x100; if( offset+size>0x100) { size = 0x100 - offset; } uint32 addr = (gObjTlutAddr);//&0xFFFFFFFC); //if( addr & 3 ) addr = (addr&0xFFFFFFF0)+8;; //uint16 *srcPal = (uint16*)(g_pRDRAMu8 + (addr& (g_dwRamSize-1)) ); for( int i=offset; iwords.w1))&(g_dwRamSize-1))); gObjTxtr = (uObjTxtr*)ptr; //Now draw the sprite CRender::g_pRender->LoadObjSprite(*ptr); CRender::g_pRender->DrawSpriteR(*ptr); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI), { DumpTxtrInfo(gObjTxtr); DumpSpriteParameters(ptr->sprite); TRACE0("Paused at RSP_S2DEX_SPObjLoadTxSprite"); } ); } // Yoshi's Story uses this - 0xc3 void RSP_S2DEX_SPObjLoadTxRect(Gfx *gfx) { uObjTxSprite* ptr = (uObjTxSprite*)(g_pRDRAMu8+(RSPSegmentAddr((gfx->words.w1))&(g_dwRamSize-1))); gObjTxtr = (uObjTxtr*)ptr; //Now draw the sprite CRender::g_pRender->LoadObjSprite(*ptr); CRender::g_pRender->DrawSprite(*ptr, false); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI), { DumpTxtrInfo(gObjTxtr); DumpSpriteParameters(ptr->sprite); TRACE0("Paused at RSP_S2DEX_SPObjLoadTxRect"); } ); } // Yoshi's Story uses this - 0xc4 void RSP_S2DEX_SPObjLoadTxRectR(Gfx *gfx) { uObjTxSprite* ptr = (uObjTxSprite*)(g_pRDRAMu8+(RSPSegmentAddr((gfx->words.w1))&(g_dwRamSize-1))); gObjTxtr = (uObjTxtr*)ptr; //Now draw the sprite CRender::g_pRender->LoadObjSprite(*ptr); CRender::g_pRender->DrawSprite(*ptr, true); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI), { DumpTxtrInfo(gObjTxtr); DumpSpriteParameters(ptr->sprite); TRACE0("Paused at RSP_S2DEX_SPObjLoadTxRect"); } ); } void DLParser_TexRect(Gfx *gfx); // Yoshi's Story uses this - 0xe4 void RSP_S2DEX_RDPHALF_0(Gfx *gfx) { //RDP: RSP_S2DEX_RDPHALF_0 (0xe449c0a8 0x003b40a4) //0x001d3c88: e449c0a8 003b40a4 RDP_TEXRECT //0x001d3c90: b4000000 00000000 RSP_RDPHALF_1 //0x001d3c98: b3000000 04000400 RSP_RDPHALF_2 uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction uint32 dwNextUcode = *(uint32 *)(g_pRDRAMu8 + dwPC); if( (dwNextUcode>>24) != S2DEX_SELECT_DL ) { // Pokemom Puzzle League if( (dwNextUcode>>24) == 0xB4 ) { DLParser_TexRect(gfx); } else { RSP_RDP_NOIMPL("RDP: RSP_S2DEX_RDPHALF_0 (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); } } else { RSP_RDP_NOIMPL("RDP: RSP_S2DEX_RDPHALF_0 (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); DEBUGGER_PAUSE_COUNT_N(NEXT_OBJ_TXT_CMD); } } // Yoshi's Story uses this - 0x05 void RSP_S2DEX_OBJ_MOVEMEM(Gfx *gfx) { uint32 dwCommand = ((gfx->words.w0)>>16)&0xFF; uint32 dwLength = ((gfx->words.w0)) &0xFFFF; uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); if( dwAddr >= g_dwRamSize ) { TRACE0("ObjMtx: memory ptr is invalid"); } if( dwLength == 0 && dwCommand == 23 ) { gObjMtx = (uObjMtx *)(dwAddr+g_pRDRAMu8); gObjMtxReal.A = gObjMtx->A/65536.0f; gObjMtxReal.B = gObjMtx->B/65536.0f; gObjMtxReal.C = gObjMtx->C/65536.0f; gObjMtxReal.D = gObjMtx->D/65536.0f; gObjMtxReal.X = float(gObjMtx->X>>2); gObjMtxReal.Y = float(gObjMtx->Y>>2); gObjMtxReal.BaseScaleX = gObjMtx->BaseScaleX/1024.0f; gObjMtxReal.BaseScaleY = gObjMtx->BaseScaleY/1024.0f; #ifdef DEBUGGER DumpObjMtx(); #endif } else if( dwLength == 2 && dwCommand == 7 ) { gSubObjMtx = (uObjSubMtx*)(dwAddr+g_pRDRAMu8); gObjMtxReal.X = float(gSubObjMtx->X>>2); gObjMtxReal.Y = float(gSubObjMtx->Y>>2); gObjMtxReal.BaseScaleX = gSubObjMtx->BaseScaleX/1024.0f; gObjMtxReal.BaseScaleY = gSubObjMtx->BaseScaleY/1024.0f; #ifdef DEBUGGER DumpObjMtx(false); #endif } g_MtxReal._11 = gObjMtxReal.A; g_MtxReal._12 = gObjMtxReal.C; g_MtxReal._13 = 0; g_MtxReal._14 = 0;//gObjMtxReal.X; g_MtxReal._21 = gObjMtxReal.B; g_MtxReal._22 = gObjMtxReal.D; g_MtxReal._23 = 0; g_MtxReal._24 = 0;//gObjMtxReal.Y; g_MtxReal._31 = 0; g_MtxReal._32 = 0; g_MtxReal._33 = 1.0; g_MtxReal._34 = 0; g_MtxReal._41 = gObjMtxReal.X; g_MtxReal._42 = gObjMtxReal.Y; g_MtxReal._43 = 0; g_MtxReal._44 = 1.0; DEBUGGER_PAUSE_COUNT_N(NEXT_OBJ_TXT_CMD); } // Yoshi's Story uses this - 0x01 extern void RSP_GBI0_Mtx(Gfx *gfx); void RSP_S2DEX_BG_1CYC(Gfx *gfx) { SP_Timing(DP_Minimal16); DP_Timing(DP_Minimal16); uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjScaleBg *sbgPtr = (uObjScaleBg *)(dwAddr+g_pRDRAMu8); CRender::g_pRender->LoadObjBG1CYC(*sbgPtr); CRender::g_pRender->DrawObjBG1CYC(*sbgPtr); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI||eventToPause == NEXT_OBJ_BG), { DebuggerAppendMsg("S2DEX BG 1CYC: %08X-%08X\n", (gfx->words.w0), (gfx->words.w1) ); TRACE0("Paused at RSP_S2DEX_BG_1CYC"); } ); } void RSP_S2DEX_BG_1CYC_2(Gfx *gfx) { if( ((gfx->words.w0)&0x00FFFFFF) != 0 ) { RSP_GBI0_Mtx(gfx); return; } RSP_S2DEX_BG_1CYC(gfx); } // Yoshi's Story uses this - 0xb2 void RSP_S2DEX_OBJ_RECTANGLE_R(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjSprite *ptr = (uObjSprite*)(g_pRDRAMu8+dwAddr); uObjTxSprite objtx; memcpy(&objtx.sprite,ptr,sizeof(uObjSprite)); //uObjTxSprite* ptr = (uObjTxSprite*)(g_pRDRAMu8+(RSPSegmentAddr((gfx->words.w1))&(g_dwRamSize-1))); //gObjTxtr = (uObjTxtr*)ptr; //Now draw the sprite if( g_TxtLoadBy == CMD_LOAD_OBJ_TXTR ) { memcpy(&(objtx.txtr.block),&(gObjTxtr->block),sizeof(uObjTxtr)); //CRender::g_pRender->LoadObjSprite(*ptr,true); CRender::g_pRender->LoadObjSprite(objtx,true); } else { PrepareTextures(); } //CRender::g_pRender->DrawSprite(*ptr, true); CRender::g_pRender->DrawSprite(objtx, true); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI), { DumpTxtrInfo(gObjTxtr); DumpSpriteParameters(*ptr); TRACE0("Paused at RSP_S2DEX_OBJ_RECTANGLE_R"); } ); } mupen64plus-video-rice-src-2.0/src/RSP_S2DEX.h0000644000000000000000000001045012165031100017012 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _RSP_S2DEX_H_ #define _RSP_S2DEX_H_ #define S2DEX_BG_1CYC 0x01 #define S2DEX_BG_COPY 0x02 #define S2DEX_OBJ_RECTANGLE 0x03 #define S2DEX_OBJ_SPRITE 0x04 #define S2DEX_OBJ_MOVEMEM 0x05 #define S2DEX_SELECT_DL 0xb0 #define S2DEX_OBJ_RENDERMODE 0xb1 #define S2DEX_OBJ_RECTANGLE_R 0xb2 #define S2DEX_OBJ_LOADTXTR 0xc1 #define S2DEX_OBJ_LDTX_SPRITE 0xc2 #define S2DEX_OBJ_LDTX_RECT 0xc3 #define S2DEX_OBJ_LDTX_RECT_R 0xc4 #define S2DEX_RDPHALF_0 0xe4 #define S2DEX_OBJLT_TXTRBLOCK 0x00001033 #define S2DEX_OBJLT_TXTRTILE 0x00fc1034 #define S2DEX_OBJLT_TLUT 0x00000030 #define S2DEX_BGLT_LOADBLOCK 0x0033 #define S2DEX_BGLT_LOADTILE 0xfff4 typedef struct { //Intel format uint32 type; uint32 image; uint16 tsize; uint16 tmem; uint16 sid; uint16 tline; uint32 flag; uint32 mask; } uObjTxtrBlock; typedef struct { //Intel Format uint32 type; uint32 image; uint16 twidth; uint16 tmem; uint16 sid; uint16 theight; uint32 flag; uint32 mask; } uObjTxtrTile; // 24 bytes typedef struct { // Intel Format uint32 type; uint32 image; uint16 pnum; uint16 phead; uint16 sid; uint16 zero; uint32 flag; uint32 mask; } uObjTxtrTLUT; typedef union { uObjTxtrBlock block; uObjTxtrTile tile; uObjTxtrTLUT tlut; } uObjTxtr; typedef struct { // Intel format uint16 scaleW; short objX; uint16 paddingX; uint16 imageW; uint16 scaleH; short objY; uint16 paddingY; uint16 imageH; uint16 imageAdrs; uint16 imageStride; uint8 imageFlags; uint8 imagePal; uint8 imageSiz; uint8 imageFmt; } uObjSprite; typedef struct { uObjTxtr txtr; uObjSprite sprite; } uObjTxSprite; /* 48 bytes */ typedef struct { // Intel format s32 A, B, C, D; short Y; short X; uint16 BaseScaleY; uint16 BaseScaleX; } uObjMtx; typedef struct { float A, B, C, D; float X; float Y; float BaseScaleX; float BaseScaleY; } uObjMtxReal; typedef struct { //Intel format short Y; short X; uint16 BaseScaleY; uint16 BaseScaleX; } uObjSubMtx; typedef struct { // Intel Format uint16 imageW; uint16 imageX; uint16 frameW; short frameX; uint16 imageH; uint16 imageY; uint16 frameH; short frameY; uint32 imagePtr; uint8 imageSiz; uint8 imageFmt; uint16 imageLoad; uint16 imageFlip; uint16 imagePal; uint16 tmemH; uint16 tmemW; uint16 tmemLoadTH; uint16 tmemLoadSH; uint16 tmemSize; uint16 tmemSizeW; } uObjBg; typedef struct { // Intel Format uint16 imageW; uint16 imageX; uint16 frameW; short frameX; uint16 imageH; uint16 imageY; uint16 frameH; short frameY; uint32 imagePtr; uint8 imageSiz; uint8 imageFmt; uint16 imageLoad; uint16 imageFlip; uint16 imagePal; uint16 scaleH; uint16 scaleW; s32 imageYorig; uint8 padding[4]; } uObjScaleBg; #endif mupen64plus-video-rice-src-2.0/src/Render.cpp0000644000000000000000000021114712165031100017221 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define M64P_PLUGIN_PROTOTYPES 1 #include "osal_preproc.h" #include "m64p_plugin.h" #include "ConvertImage.h" #include "DeviceBuilder.h" #include "FrameBuffer.h" #include "Render.h" #include "liblinux/BMGLibPNG.h" #include extern FiddledVtx * g_pVtxBase; CRender * CRender::g_pRender=NULL; int CRender::gRenderReferenceCount=0; XMATRIX reverseXY(-1,0,0,0,0,-1,0,0,0,0,1,0,0,0,0,1); XMATRIX reverseY(1,0,0,0,0,-1,0,0,0,0,1,0,0,0,0,1); extern char* right (const char * src, int nchars); #if defined(WIN32) #define strcasecmp _stricmp #endif #ifdef min #undef min #endif #ifdef max #undef max #endif //======================================================================== CRender * CRender::GetRender(void) { if( CRender::g_pRender == NULL ) { DebugMessage(M64MSG_ERROR, "g_pRender is NULL"); exit(0); } else return CRender::g_pRender; } bool CRender::IsAvailable() { return CRender::g_pRender != NULL; } CRender::CRender() : m_fScreenViewportMultX(2.0f), m_fScreenViewportMultY(2.0f), m_dwTexturePerspective(FALSE), m_bAlphaTestEnable(FALSE), m_bZUpdate(FALSE), m_bZCompare(FALSE), m_dwZBias(0), m_dwMinFilter(FILTER_POINT), m_dwMagFilter(FILTER_POINT), m_dwAlpha(0xFF), m_Mux(0), m_bBlendModeValid(FALSE) { int i; InitRenderBase(); for( i=0; iCreateColorCombiner(this); m_pColorCombiner->Initialize(); m_pAlphaBlender = CDeviceBuilder::GetBuilder()->CreateAlphaBlender(this); } CRender::~CRender() { if( m_pColorCombiner != NULL ) { CDeviceBuilder::GetBuilder()->DeleteColorCombiner(); m_pColorCombiner = NULL; } if( m_pAlphaBlender != NULL ) { CDeviceBuilder::GetBuilder()->DeleteAlphaBlender(); m_pAlphaBlender = NULL; } } void CRender::ResetMatrices() { Matrix mat; mat.m[0][1] = mat.m[0][2] = mat.m[0][3] = mat.m[1][0] = mat.m[1][2] = mat.m[1][3] = mat.m[2][0] = mat.m[2][1] = mat.m[2][3] = mat.m[3][0] = mat.m[3][1] = mat.m[3][2] = 0.0f; mat.m[0][0] = mat.m[1][1] = mat.m[2][2] = mat.m[3][3] = 1.0f; gRSP.projectionMtxTop = 0; gRSP.modelViewMtxTop = 0; gRSP.projectionMtxs[0] = mat; gRSP.modelviewMtxs[0] = mat; gRSP.bMatrixIsUpdated = true; gRSP.bWorldMatrixIsUpdated = true; UpdateCombinedMatrix(); } void CRender::SetProjection(const Matrix & mat, bool bPush, bool bReplace) { if (bPush) { if (gRSP.projectionMtxTop >= (RICE_MATRIX_STACK-1)) { TRACE0("Pushing past proj stack limits!"); } else gRSP.projectionMtxTop++; if (bReplace) { // Load projection matrix gRSP.projectionMtxs[gRSP.projectionMtxTop] = mat; } else { gRSP.projectionMtxs[gRSP.projectionMtxTop] = mat * gRSP.projectionMtxs[gRSP.projectionMtxTop-1]; } } else { if (bReplace) { // Load projection matrix gRSP.projectionMtxs[gRSP.projectionMtxTop] = mat; } else { gRSP.projectionMtxs[gRSP.projectionMtxTop] = mat * gRSP.projectionMtxs[gRSP.projectionMtxTop]; } } gRSP.bMatrixIsUpdated = true; DumpMatrix(mat,"Set Projection Matrix"); } bool mtxPopUpError = false; void CRender::SetWorldView(const Matrix & mat, bool bPush, bool bReplace) { if (bPush) { if (gRSP.modelViewMtxTop >= (RICE_MATRIX_STACK-1)) DebuggerAppendMsg("Pushing past modelview stack limits! %s", bReplace?"Load":"Mul"); else gRSP.modelViewMtxTop++; // We should store the current projection matrix... if (bReplace) { // Load projection matrix gRSP.modelviewMtxs[gRSP.modelViewMtxTop] = mat; } else // Multiply projection matrix { gRSP.modelviewMtxs[gRSP.modelViewMtxTop] = mat * gRSP.modelviewMtxs[gRSP.modelViewMtxTop-1]; } } else // NoPush { if (bReplace) { // Load projection matrix gRSP.modelviewMtxs[gRSP.modelViewMtxTop] = mat; } else { // Multiply projection matrix gRSP.modelviewMtxs[gRSP.modelViewMtxTop] = mat * gRSP.modelviewMtxs[gRSP.modelViewMtxTop]; } } gRSPmodelViewTop = gRSP.modelviewMtxs[gRSP.modelViewMtxTop]; if( options.enableHackForGames == HACK_REVERSE_XY_COOR ) { gRSPmodelViewTop = gRSPmodelViewTop * reverseXY; } if( options.enableHackForGames == HACK_REVERSE_Y_COOR ) { gRSPmodelViewTop = gRSPmodelViewTop * reverseY; } MatrixTranspose(&gRSPmodelViewTopTranspose, &gRSPmodelViewTop); gRSP.bMatrixIsUpdated = true; gRSP.bWorldMatrixIsUpdated = true; DumpMatrix(mat,"Set WorldView Matrix"); } void CRender::PopWorldView() { if (gRSP.modelViewMtxTop > 0) { gRSP.modelViewMtxTop--; gRSPmodelViewTop = gRSP.modelviewMtxs[gRSP.modelViewMtxTop]; if( options.enableHackForGames == HACK_REVERSE_XY_COOR ) { gRSPmodelViewTop = gRSPmodelViewTop * reverseXY; } if( options.enableHackForGames == HACK_REVERSE_Y_COOR ) { gRSPmodelViewTop = gRSPmodelViewTop * reverseY; } MatrixTranspose(&gRSPmodelViewTopTranspose, &gRSPmodelViewTop); gRSP.bMatrixIsUpdated = true; gRSP.bWorldMatrixIsUpdated = true; } else { #ifdef DEBUGGER if( pauseAtNext ) TRACE0("Popping past worldview stack limits"); #endif mtxPopUpError = true; } } Matrix & CRender::GetWorldProjectMatrix(void) { return gRSPworldProject; } void CRender::SetWorldProjectMatrix(Matrix &mtx) { #ifdef DEBUGGER if( pauseAtNext && (eventToPause == NEXT_TRIANGLE || eventToPause == NEXT_FLUSH_TRI || eventToPause == NEXT_MATRIX_CMD ) ) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; DebuggerAppendMsg("Force Matrix: pc=%08X", dwPC); DumpMatrix(mtx, "Force Matrix, loading new world-project matrix"); } #endif gRSPworldProject = mtx; gRSP.bMatrixIsUpdated = false; gRSP.bCombinedMatrixIsUpdated = true; } void CRender::SetMux(uint32 dwMux0, uint32 dwMux1) { uint64 tempmux = (((uint64)dwMux0) << 32) | (uint64)dwMux1; if( m_Mux != tempmux ) { m_Mux = tempmux; m_bBlendModeValid = FALSE; m_pColorCombiner->UpdateCombiner(dwMux0, dwMux1); } } void CRender::SetCombinerAndBlender() { InitOtherModes(); if( g_curRomInfo.bDisableBlender ) m_pAlphaBlender->DisableAlphaBlender(); else if( currentRomOptions.bNormalBlender ) m_pAlphaBlender->NormalAlphaBlender(); else m_pAlphaBlender->InitBlenderMode(); m_pColorCombiner->InitCombinerMode(); } void CRender::RenderReset() { UpdateClipRectangle(); ResetMatrices(); SetZBias(0); gRSP.numVertices = 0; gRSP.maxVertexID = 0; gRSP.curTile = 0; gRSP.fTexScaleX = 1/32.0f;; gRSP.fTexScaleY = 1/32.0f; } bool CRender::FillRect(int nX0, int nY0, int nX1, int nY1, uint32 dwColor) { LOG_UCODE("FillRect: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%8X", nX0, nY0, nX1, nY1, dwColor); if (g_CI.dwSize != TXT_SIZE_16b && frameBufferOptions.bIgnore) return true; if (status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM) status.bFrameBufferIsDrawn = true; if(status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_1ST_PRIMITIVE) { status.bVIOriginIsUpdated=false; CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG, {DebuggerAppendMsg("Screen Update at 1st FillRectangle");}); } if (status.bCIBufferIsRendered && status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_BEFORE_SCREEN_CLEAR ) { if ((nX0==0 && nY0 == 0 && (nX1 == (int) g_CI.dwWidth || nX1 == (int) g_CI.dwWidth-1)) || (nX0==gRDP.scissor.left && nY0 == gRDP.scissor.top && (nX1 == gRDP.scissor.right || nX1 == gRDP.scissor.right-1)) || ((nX0+nX1 == (int)g_CI.dwWidth || nX0+nX1 == (int)g_CI.dwWidth-1 || nX0+nX1 == gRDP.scissor.left+gRDP.scissor.right || nX0+nX1 == gRDP.scissor.left+gRDP.scissor.right-1) && (nY0 == gRDP.scissor.top || nY0 == 0 || nY0+nY1 == gRDP.scissor.top+gRDP.scissor.bottom || nY0+nY1 == gRDP.scissor.top+gRDP.scissor.bottom-1))) { status.bVIOriginIsUpdated=false; CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG,{DebuggerAppendMsg("Screen Update Before Screen Clear");}); } } SetFillMode(RICE_FILLMODE_SOLID); bool res=true; /* // I don't know why this does not work for OpenGL if( gRDP.otherMode.cycle_type == CYCLE_TYPE_FILL && nX0 == 0 && nY0 == 0 && ((nX1==windowSetting.uViWidth && nY1==windowSetting.uViHeight)||(nX1==windowSetting.uViWidth-1 && nY1==windowSetting.uViHeight-1)) ) { CGraphicsContext::g_pGraphicsContext->Clear(CLEAR_COLOR_BUFFER,dwColor); } else */ { //BOOL m_savedZBufferFlag = gRSP.bZBufferEnabled; // Save ZBuffer state ZBufferEnable( FALSE ); m_fillRectVtx[0].x = ViewPortTranslatei_x(nX0); m_fillRectVtx[0].y = ViewPortTranslatei_y(nY0); m_fillRectVtx[1].x = ViewPortTranslatei_x(nX1); m_fillRectVtx[1].y = ViewPortTranslatei_y(nY1); SetCombinerAndBlender(); if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY ) { ZBufferEnable(FALSE); } else { //dwColor = PostProcessDiffuseColor(0); dwColor = PostProcessDiffuseColor(gRDP.primitiveColor); } float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0 ); ApplyRDPScissor(); TurnFogOnOff(false); res = RenderFillRect(dwColor, depth); TurnFogOnOff(gRSP.bFogEnabled); if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY ) { ZBufferEnable(gRSP.bZBufferEnabled); } } if( options.bWinFrameMode ) SetFillMode(RICE_FILLMODE_WINFRAME ); DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FILLRECT, {DebuggerAppendMsg("FillRect: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%08X", nX0, nY0, nX1, nY1, dwColor); DebuggerAppendMsg("Pause after FillRect: Color=%08X\n", dwColor);if( logCombiners ) m_pColorCombiner->DisplayMuxString();}); DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FLUSH_TRI, {DebuggerAppendMsg("FillRect: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%08X", nX0, nY0, nX1, nY1, dwColor); DebuggerAppendMsg("Pause after FillRect: Color=%08X\n", dwColor);if( logCombiners ) m_pColorCombiner->DisplayMuxString();}); return res; } bool CRender::Line3D(uint32 dwV0, uint32 dwV1, uint32 dwWidth) { LOG_UCODE("Line3D: Vtx0=%d, Vtx1=%d, Width=%d", dwV0, dwV1, dwWidth); if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); m_line3DVtx[0].z = (g_vecProjected[dwV0].z + 1.0f) * 0.5f; m_line3DVtx[1].z = (g_vecProjected[dwV1].z + 1.0f) * 0.5f; if( m_line3DVtx[0].z != m_line3DVtx[1].z ) return false; if( status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM ) status.bFrameBufferIsDrawn = true; if( status.bHandleN64RenderTexture ) { g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height; if( status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } } m_line3DVtx[0].x = ViewPortTranslatef_x(g_vecProjected[dwV0].x); m_line3DVtx[0].y = ViewPortTranslatef_y(g_vecProjected[dwV0].y); m_line3DVtx[0].rhw = g_vecProjected[dwV0].w; m_line3DVtx[0].dcDiffuse = PostProcessDiffuseColor(g_dwVtxDifColor[dwV0]); m_line3DVtx[0].dcSpecular = PostProcessSpecularColor(); m_line3DVtx[1].x = ViewPortTranslatef_x(g_vecProjected[dwV1].x); m_line3DVtx[1].y = ViewPortTranslatef_y(g_vecProjected[dwV1].y); m_line3DVtx[1].rhw = g_vecProjected[dwV1].w; m_line3DVtx[1].dcDiffuse = PostProcessDiffuseColor(g_dwVtxDifColor[dwV1]); m_line3DVtx[1].dcSpecular = m_line3DVtx[0].dcSpecular; float width = dwWidth*0.5f+1.5f; if( m_line3DVtx[0].y == m_line3DVtx[1].y ) { m_line3DVector[0].x = m_line3DVector[1].x = m_line3DVtx[0].x; m_line3DVector[2].x = m_line3DVector[3].x = m_line3DVtx[1].x; m_line3DVector[0].y = m_line3DVector[2].y = m_line3DVtx[0].y-width/2*windowSetting.fMultY; m_line3DVector[1].y = m_line3DVector[3].y = m_line3DVtx[0].y+width/2*windowSetting.fMultY; } else { m_line3DVector[0].y = m_line3DVector[1].y = m_line3DVtx[0].y; m_line3DVector[2].y = m_line3DVector[3].y = m_line3DVtx[1].y; m_line3DVector[0].x = m_line3DVector[2].x = m_line3DVtx[0].x-width/2*windowSetting.fMultX; m_line3DVector[1].x = m_line3DVector[3].x = m_line3DVtx[0].x+width/2*windowSetting.fMultX; } SetCombinerAndBlender(); bool res=RenderLine3D(); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_FLUSH_TRI, { DebuggerAppendMsg("Pause after Line3D: v%d(%f,%f,%f), v%d(%f,%f,%f), Width=%d\n", dwV0, m_line3DVtx[0].x, m_line3DVtx[0].y, m_line3DVtx[0].z, dwV1, m_line3DVtx[1].x, m_line3DVtx[1].y, m_line3DVtx[1].z, dwWidth); }); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_OBJ_TXT_CMD, { DebuggerAppendMsg("Pause after Line3D: v%d(%f,%f,%f), v%d(%f,%f,%f), Width=%d\n", dwV0, m_line3DVtx[0].x, m_line3DVtx[0].y, m_line3DVtx[0].z, dwV1, m_line3DVtx[1].x, m_line3DVtx[1].y, m_line3DVtx[1].z, dwWidth); }); return res; } bool CRender::RemapTextureCoordinate (float t0, float t1, uint32 tileWidth, uint32 mask, float textureWidth, float &u0, float &u1) { int s0 = (int)t0; int s1 = (int)t1; int width = mask>0 ? (1< s0 ) divs0--; int divs1 = s1/width; if( divs1*width > s1 ) divs1--; if( divs0 == divs1 ) { s0 -= divs0*width; s1 -= divs1*width; //if( s0 > s1 ) // s0++; //else if( s1 > s0 ) // s1++; u0 = s0/textureWidth; u1 = s1/textureWidth; return true; } else if( divs0+1 == divs1 && s0%width==0 && s1%width == 0 ) { u0 = 0; u1 = tileWidth/textureWidth; return true; } else if( divs0 == divs1+1 && s0%width==0 && s1%width == 0 ) { u1 = 0; u0 = tileWidth/textureWidth; return true; } else { //if( s0 > s1 ) //{ //s0++; // u0 = s0/textureWidth; //} //else if( s1 > s0 ) //{ //s1++; // u1 = s1/textureWidth; //} return false; } } bool CRender::TexRect(int nX0, int nY0, int nX1, int nY1, float fS0, float fT0, float fScaleS, float fScaleT, bool colorFlag, uint32 diffuseColor) { if( options.enableHackForGames == HACK_FOR_DUKE_NUKEM ) { colorFlag = true; diffuseColor = 0; } if( status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_1ST_PRIMITIVE ) { status.bVIOriginIsUpdated=false; CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG,{DebuggerAppendMsg("Screen Update at 1st textRect");}); } if( options.enableHackForGames == HACK_FOR_BANJO_TOOIE ) { // Hack for Banjo shadow in Banjo Tooie if( g_TI.dwWidth == g_CI.dwWidth && g_TI.dwFormat == TXT_FMT_CI && g_TI.dwSize == TXT_SIZE_8b ) { if( nX0 == fS0 && nY0 == fT0 )//&& nX0 > 90 && nY0 > 130 && nX1-nX0 > 80 && nY1-nY0 > 20 ) { // Skip the text rect return true; } } } if( status.bN64IsDrawingTextureBuffer ) { if( frameBufferOptions.bIgnore || ( frameBufferOptions.bIgnoreRenderTextureIfHeightUnknown && newRenderTextureInfo.knownHeight == 0 ) ) { return true; } } PrepareTextures(); if( status.bHandleN64RenderTexture && g_pRenderTextureInfo->CI_Info.dwSize == TXT_SIZE_8b ) { return true; } if( !IsTextureEnabled() && gRDP.otherMode.cycle_type != CYCLE_TYPE_COPY ) { FillRect(nX0, nY0, nX1, nY1, gRDP.primitiveColor); return true; } if( IsUsedAsDI(g_CI.dwAddr) && !status.bHandleN64RenderTexture ) { status.bFrameBufferIsDrawn = true; } if( status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM ) status.bFrameBufferIsDrawn = true; LOG_UCODE("TexRect: X0=%d, Y0=%d, X1=%d, Y1=%d,\n\t\tfS0=%f, fT0=%f, ScaleS=%f, ScaleT=%f ", nX0, nY0, nX1, nY1, fS0, fT0, fScaleS, fScaleT); if( options.bEnableHacks ) { // Goldeneye HACK if( nY1 - nY0 < 2 ) nY1 = nY1+2; //// Text edge hack else if( gRDP.otherMode.cycle_type == CYCLE_TYPE_1 && fScaleS == 1 && fScaleT == 1 && (int)g_textures[gRSP.curTile].m_dwTileWidth == nX1-nX0+1 && (int)g_textures[gRSP.curTile].m_dwTileHeight == nY1-nY0+1 && g_textures[gRSP.curTile].m_dwTileWidth%2 == 0 && g_textures[gRSP.curTile].m_dwTileHeight%2 == 0 ) { nY1++; nX1++; } else if( g_curRomInfo.bIncTexRectEdge ) { nX1++; nY1++; } } // Scale to Actual texture coords // The two cases are to handle the oversized textures hack on voodoos SetCombinerAndBlender(); if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY || !gRDP.otherMode.z_cmp ) { ZBufferEnable(FALSE); } BOOL accurate = currentRomOptions.bAccurateTextureMapping; RenderTexture &tex0 = g_textures[gRSP.curTile]; Tile &tile0 = gRDP.tiles[gRSP.curTile]; float widthDiv = tex0.m_fTexWidth; float heightDiv = tex0.m_fTexHeight; float t0u0; if( options.enableHackForGames == HACK_FOR_ALL_STAR_BASEBALL || options.enableHackForGames == HACK_FOR_MLB ) { t0u0 = (fS0 -tile0.fhilite_sl); } else { t0u0 = (fS0 * tile0.fShiftScaleS -tile0.fhilite_sl); } float t0u1; if( accurate && gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY ) { t0u1 = t0u0 + (fScaleS * (nX1 - nX0 - 1))*tile0.fShiftScaleS; } else { t0u1 = t0u0 + (fScaleS * (nX1 - nX0))*tile0.fShiftScaleS; } if( status.UseLargerTile[0] ) { m_texRectTex1UV[0].u = (t0u0+status.LargerTileRealLeft[0])/widthDiv; m_texRectTex1UV[1].u = (t0u1+status.LargerTileRealLeft[0])/widthDiv; } else { m_texRectTex1UV[0].u = t0u0/widthDiv; m_texRectTex1UV[1].u = t0u1/widthDiv; if( accurate && !tile0.bMirrorS && RemapTextureCoordinate(t0u0, t0u1, tex0.m_dwTileWidth, tile0.dwMaskS, widthDiv, m_texRectTex1UV[0].u, m_texRectTex1UV[1].u) ) SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile); } float t0v0; if( options.enableHackForGames == HACK_FOR_ALL_STAR_BASEBALL || options.enableHackForGames == HACK_FOR_MLB ) { t0v0 = (fT0 -tile0.fhilite_tl); } else { t0v0 = (fT0 * tile0.fShiftScaleT -tile0.fhilite_tl); } float t0v1; if ( accurate && gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY) { t0v1 = t0v0 + (fScaleT * (nY1 - nY0-1))*tile0.fShiftScaleT; } else { t0v1 = t0v0 + (fScaleT * (nY1 - nY0))*tile0.fShiftScaleT; } m_texRectTex1UV[0].v = t0v0/heightDiv; m_texRectTex1UV[1].v = t0v1/heightDiv; if( accurate && !tile0.bMirrorT && RemapTextureCoordinate(t0v0, t0v1, tex0.m_dwTileHeight, tile0.dwMaskT, heightDiv, m_texRectTex1UV[0].v, m_texRectTex1UV[1].v) ) SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile); COLOR speColor = PostProcessSpecularColor(); COLOR difColor; if( colorFlag ) difColor = PostProcessDiffuseColor(diffuseColor); else //difColor = PostProcessDiffuseColor(0); difColor = PostProcessDiffuseColor(gRDP.primitiveColor); g_texRectTVtx[0].x = ViewPortTranslatei_x(nX0); g_texRectTVtx[0].y = ViewPortTranslatei_y(nY0); g_texRectTVtx[0].dcDiffuse = difColor; g_texRectTVtx[0].dcSpecular = speColor; g_texRectTVtx[1].x = ViewPortTranslatei_x(nX1); g_texRectTVtx[1].y = ViewPortTranslatei_y(nY0); g_texRectTVtx[1].dcDiffuse = difColor; g_texRectTVtx[1].dcSpecular = speColor; g_texRectTVtx[2].x = ViewPortTranslatei_x(nX1); g_texRectTVtx[2].y = ViewPortTranslatei_y(nY1); g_texRectTVtx[2].dcDiffuse = difColor; g_texRectTVtx[2].dcSpecular = speColor; g_texRectTVtx[3].x = ViewPortTranslatei_x(nX0); g_texRectTVtx[3].y = ViewPortTranslatei_y(nY1); g_texRectTVtx[3].dcDiffuse = difColor; g_texRectTVtx[3].dcSpecular = speColor; float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0 ); g_texRectTVtx[0].z = g_texRectTVtx[1].z = g_texRectTVtx[2].z = g_texRectTVtx[3].z = depth; g_texRectTVtx[0].rhw = g_texRectTVtx[1].rhw = g_texRectTVtx[2].rhw = g_texRectTVtx[3].rhw = 1; if( IsTexel1Enable() ) { RenderTexture &tex1 = g_textures[(gRSP.curTile+1)&7]; Tile &tile1 = gRDP.tiles[(gRSP.curTile+1)&7]; widthDiv = tex1.m_fTexWidth; heightDiv = tex1.m_fTexHeight; //if( tile1.dwMaskS == 0 ) widthDiv = tile1.dwWidth; //if( tile1.dwMaskT == 0 ) heightDiv = tile1.dwHeight; float t0u0 = fS0 * tile1.fShiftScaleS -tile1.fhilite_sl; float t0v0 = fT0 * tile1.fShiftScaleT -tile1.fhilite_tl; float t0u1; float t0v1; if ( accurate && gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY) { t0u1 = t0u0 + (fScaleS * (nX1 - nX0 - 1))*tile1.fShiftScaleS; t0v1 = t0v0 + (fScaleT * (nY1 - nY0 - 1))*tile1.fShiftScaleT; } else { t0u1 = t0u0 + (fScaleS * (nX1 - nX0))*tile1.fShiftScaleS; t0v1 = t0v0 + (fScaleT * (nY1 - nY0))*tile1.fShiftScaleT; } if( status.UseLargerTile[1] ) { m_texRectTex2UV[0].u = (t0u0+status.LargerTileRealLeft[1])/widthDiv; m_texRectTex2UV[1].u = (t0u1+status.LargerTileRealLeft[1])/widthDiv; } else { m_texRectTex2UV[0].u = t0u0/widthDiv; m_texRectTex2UV[1].u = t0u1/widthDiv; if( accurate && !tile1.bMirrorS && RemapTextureCoordinate(t0u0, t0u1, tex1.m_dwTileWidth, tile1.dwMaskS, widthDiv, m_texRectTex2UV[0].u, m_texRectTex2UV[1].u) ) SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, (gRSP.curTile+1)&7); } m_texRectTex2UV[0].v = t0v0/heightDiv; m_texRectTex2UV[1].v = t0v1/heightDiv; if( accurate && !tile1.bMirrorT && RemapTextureCoordinate(t0v0, t0v1, tex1.m_dwTileHeight, tile1.dwMaskT, heightDiv, m_texRectTex2UV[0].v, m_texRectTex2UV[1].v) ) SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, (gRSP.curTile+1)&7); SetVertexTextureUVCoord(g_texRectTVtx[0], m_texRectTex1UV[0].u, m_texRectTex1UV[0].v, m_texRectTex2UV[0].u, m_texRectTex2UV[0].v); SetVertexTextureUVCoord(g_texRectTVtx[1], m_texRectTex1UV[1].u, m_texRectTex1UV[0].v, m_texRectTex2UV[1].u, m_texRectTex2UV[0].v); SetVertexTextureUVCoord(g_texRectTVtx[2], m_texRectTex1UV[1].u, m_texRectTex1UV[1].v, m_texRectTex2UV[1].u, m_texRectTex2UV[1].v); SetVertexTextureUVCoord(g_texRectTVtx[3], m_texRectTex1UV[0].u, m_texRectTex1UV[1].v, m_texRectTex2UV[0].u, m_texRectTex2UV[1].v); } else { SetVertexTextureUVCoord(g_texRectTVtx[0], m_texRectTex1UV[0].u, m_texRectTex1UV[0].v); SetVertexTextureUVCoord(g_texRectTVtx[1], m_texRectTex1UV[1].u, m_texRectTex1UV[0].v); SetVertexTextureUVCoord(g_texRectTVtx[2], m_texRectTex1UV[1].u, m_texRectTex1UV[1].v); SetVertexTextureUVCoord(g_texRectTVtx[3], m_texRectTex1UV[0].u, m_texRectTex1UV[1].v); } bool res; TurnFogOnOff(false); if( TileUFlags[gRSP.curTile]==TEXTURE_UV_FLAG_CLAMP && TileVFlags[gRSP.curTile]==TEXTURE_UV_FLAG_CLAMP && options.forceTextureFilter == FORCE_DEFAULT_FILTER ) { TextureFilter dwFilter = m_dwMagFilter; m_dwMagFilter = m_dwMinFilter = FILTER_LINEAR; ApplyTextureFilter(); ApplyRDPScissor(); res = RenderTexRect(); m_dwMagFilter = m_dwMinFilter = dwFilter; ApplyTextureFilter(); } else if( fScaleS >= 1 && fScaleT >= 1 && options.forceTextureFilter == FORCE_DEFAULT_FILTER ) { TextureFilter dwFilter = m_dwMagFilter; m_dwMagFilter = m_dwMinFilter = FILTER_POINT; ApplyTextureFilter(); ApplyRDPScissor(); res = RenderTexRect(); m_dwMagFilter = m_dwMinFilter = dwFilter; ApplyTextureFilter(); } else { ApplyRDPScissor(); res = RenderTexRect(); } TurnFogOnOff(gRSP.bFogEnabled); if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY || !gRDP.otherMode.z_cmp ) { ZBufferEnable(gRSP.bZBufferEnabled); } DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_FLUSH_TRI || eventToPause == NEXT_TEXTRECT), { DebuggerAppendMsg("TexRect: tile=%d, X0=%d, Y0=%d, X1=%d, Y1=%d,\nfS0=%f, fT0=%f, ScaleS=%f, ScaleT=%f\n", gRSP.curTile, nX0, nY0, nX1, nY1, fS0, fT0, fScaleS, fScaleT); DebuggerAppendMsg(" : x0=%f, y0=%f, x1=%f, y1=%f\n", g_texRectTVtx[0].x, g_texRectTVtx[0].y, g_texRectTVtx[2].x, g_texRectTVtx[2].y); DebuggerAppendMsg(" Tex0: u0=%f, v0=%f, u1=%f, v1=%f\n", m_texRectTex1UV[0].u, m_texRectTex1UV[0].v, m_texRectTex1UV[1].u, m_texRectTex1UV[1].v); if( IsTexel1Enable() ) { DebuggerAppendMsg(" Tex1: u0=%f, v0=%f, u1=%f, v1=%f\n", m_texRectTex2UV[0].u, m_texRectTex2UV[0].v, m_texRectTex2UV[1].u, m_texRectTex2UV[1].v); } DebuggerAppendMsg("color=%08X, %08X\n", g_texRectTVtx[0].dcDiffuse, g_texRectTVtx[0].dcSpecular); DebuggerAppendMsg("Pause after TexRect\n"); if( logCombiners ) m_pColorCombiner->DisplayMuxString(); }); return res; } bool CRender::TexRectFlip(int nX0, int nY0, int nX1, int nY1, float fS0, float fT0, float fS1, float fT1) { LOG_UCODE("TexRectFlip: X0=%d, Y0=%d, X1=%d, Y1=%d,\n\t\tfS0=%f, fT0=%f, fS1=%f, fT1=%f ", nX0, nY0, nX1, nY1, fS0, fT0, fS1, fT1); if( status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } PrepareTextures(); // Save ZBuffer state m_savedZBufferFlag = gRSP.bZBufferEnabled; if( gRDP.otherMode.depth_source == 0 ) ZBufferEnable( FALSE ); float widthDiv = g_textures[gRSP.curTile].m_fTexWidth; float heightDiv = g_textures[gRSP.curTile].m_fTexHeight; //Tile &tile0 = gRDP.tiles[gRSP.curTile]; float t0u0 = fS0 / widthDiv; float t0v0 = fT0 / heightDiv; float t0u1 = (fS1 - fS0)/ widthDiv + t0u0; float t0v1 = (fT1 - fT0)/ heightDiv + t0v0; float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0 ); if( t0u0 >= 0 && t0u1 <= 1 && t0u1 >= t0u0 ) SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile); if( t0v0 >= 0 && t0v1 <= 1 && t0v1 >= t0v0 ) SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile); SetCombinerAndBlender(); COLOR speColor = PostProcessSpecularColor(); COLOR difColor = PostProcessDiffuseColor(gRDP.primitiveColor); // Same as TexRect, but with texcoords 0,2 swapped g_texRectTVtx[0].x = ViewPortTranslatei_x(nX0); g_texRectTVtx[0].y = ViewPortTranslatei_y(nY0); g_texRectTVtx[0].dcDiffuse = difColor; g_texRectTVtx[0].dcSpecular = speColor; g_texRectTVtx[1].x = ViewPortTranslatei_x(nX1); g_texRectTVtx[1].y = ViewPortTranslatei_y(nY0); g_texRectTVtx[1].dcDiffuse = difColor; g_texRectTVtx[1].dcSpecular = speColor; g_texRectTVtx[2].x = ViewPortTranslatei_x(nX1); g_texRectTVtx[2].y = ViewPortTranslatei_y(nY1); g_texRectTVtx[2].dcDiffuse = difColor; g_texRectTVtx[2].dcSpecular = speColor; g_texRectTVtx[3].x = ViewPortTranslatei_x(nX0); g_texRectTVtx[3].y = ViewPortTranslatei_y(nY1); g_texRectTVtx[3].dcDiffuse = difColor; g_texRectTVtx[3].dcSpecular = speColor; g_texRectTVtx[0].z = g_texRectTVtx[1].z = g_texRectTVtx[2].z = g_texRectTVtx[3].z = depth; g_texRectTVtx[0].rhw = g_texRectTVtx[1].rhw = g_texRectTVtx[2].rhw = g_texRectTVtx[3].rhw = 1.0f; SetVertexTextureUVCoord(g_texRectTVtx[0], t0u0, t0v0); SetVertexTextureUVCoord(g_texRectTVtx[1], t0u0, t0v1); SetVertexTextureUVCoord(g_texRectTVtx[2], t0u1, t0v1); SetVertexTextureUVCoord(g_texRectTVtx[3], t0u1, t0v0); TurnFogOnOff(false); ApplyRDPScissor(); bool res = RenderTexRect(); TurnFogOnOff(gRSP.bFogEnabled); // Restore state ZBufferEnable( m_savedZBufferFlag ); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_FLUSH_TRI || eventToPause == NEXT_TEXTRECT), { DebuggerAppendMsg("TexRectFlip: tile=%d, X0=%d, Y0=%d, X1=%d, Y1=%d,\nfS0=%f, fT0=%f, nfS1=%f, fT1=%f\n", gRSP.curTile, nX0, nY0, nX1, nY1, fS0, fT0, fS1, fT1); DebuggerAppendMsg(" : x0=%f, y0=%f, x1=%f, y1=%f\n", g_texRectTVtx[0].x, g_texRectTVtx[0].y, g_texRectTVtx[2].x, g_texRectTVtx[2].y); DebuggerAppendMsg(" Tex0: u0=%f, v0=%f, u1=%f, v1=%f\n", g_texRectTVtx[0].tcord[0].u, g_texRectTVtx[0].tcord[0].v, g_texRectTVtx[2].tcord[0].u, g_texRectTVtx[2].tcord[0].v); TRACE0("Pause after TexRectFlip\n"); if( logCombiners ) m_pColorCombiner->DisplayMuxString(); }); return res; } void CRender::StartDrawSimple2DTexture(float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, COLOR dif, COLOR spe, float z, float rhw) { g_texRectTVtx[0].x = ViewPortTranslatei_x(x0); // << Error here, shouldn't divid by 4 g_texRectTVtx[0].y = ViewPortTranslatei_y(y0); g_texRectTVtx[0].dcDiffuse = dif; g_texRectTVtx[0].dcSpecular = spe; g_texRectTVtx[0].tcord[0].u = u0; g_texRectTVtx[0].tcord[0].v = v0; g_texRectTVtx[1].x = ViewPortTranslatei_x(x1); g_texRectTVtx[1].y = ViewPortTranslatei_y(y0); g_texRectTVtx[1].dcDiffuse = dif; g_texRectTVtx[1].dcSpecular = spe; g_texRectTVtx[1].tcord[0].u = u1; g_texRectTVtx[1].tcord[0].v = v0; g_texRectTVtx[2].x = ViewPortTranslatei_x(x1); g_texRectTVtx[2].y = ViewPortTranslatei_y(y1); g_texRectTVtx[2].dcDiffuse = dif; g_texRectTVtx[2].dcSpecular = spe; g_texRectTVtx[2].tcord[0].u = u1; g_texRectTVtx[2].tcord[0].v = v1; g_texRectTVtx[3].x = ViewPortTranslatei_x(x0); g_texRectTVtx[3].y = ViewPortTranslatei_y(y1); g_texRectTVtx[3].dcDiffuse = dif; g_texRectTVtx[3].dcSpecular = spe; g_texRectTVtx[3].tcord[0].u = u0; g_texRectTVtx[3].tcord[0].v = v1; RenderTexture &txtr = g_textures[0]; if( txtr.pTextureEntry && txtr.pTextureEntry->txtrBufIdx > 0 ) { RenderTextureInfo &info = gRenderTextureInfos[txtr.pTextureEntry->txtrBufIdx-1]; g_texRectTVtx[0].tcord[0].u *= info.scaleX; g_texRectTVtx[0].tcord[0].v *= info.scaleY; g_texRectTVtx[1].tcord[0].u *= info.scaleX; g_texRectTVtx[1].tcord[0].v *= info.scaleY; g_texRectTVtx[2].tcord[0].u *= info.scaleX; g_texRectTVtx[2].tcord[0].v *= info.scaleY; g_texRectTVtx[3].tcord[0].u *= info.scaleX; g_texRectTVtx[3].tcord[0].v *= info.scaleY; } g_texRectTVtx[0].z = g_texRectTVtx[1].z = g_texRectTVtx[2].z = g_texRectTVtx[3].z = z; g_texRectTVtx[0].rhw = g_texRectTVtx[1].rhw = g_texRectTVtx[2].rhw = g_texRectTVtx[3].rhw = rhw; } void CRender::StartDrawSimpleRect(int nX0, int nY0, int nX1, int nY1, uint32 dwColor, float depth, float rhw) { m_simpleRectVtx[0].x = ViewPortTranslatei_x(nX0); m_simpleRectVtx[1].x = ViewPortTranslatei_x(nX1); m_simpleRectVtx[0].y = ViewPortTranslatei_y(nY0); m_simpleRectVtx[1].y = ViewPortTranslatei_y(nY1); } void CRender::SetAddressUAllStages(uint32 dwTile, TextureUVFlag dwFlag) { } void CRender::SetAddressVAllStages(uint32 dwTile, TextureUVFlag dwFlag) { } void CRender::SetAllTexelRepeatFlag() { if( IsTextureEnabled() ) { if( IsTexel0Enable() || gRDP.otherMode.cycle_type == CYCLE_TYPE_COPY ) SetTexelRepeatFlags(gRSP.curTile); if( IsTexel1Enable() ) SetTexelRepeatFlags((gRSP.curTile+1)&7); } } void CRender::SetTexelRepeatFlags(uint32 dwTile) { Tile &tile = gRDP.tiles[dwTile]; if( tile.bForceClampS ) SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, dwTile); else if( tile.bForceWrapS ) SetTextureUFlag(TEXTURE_UV_FLAG_WRAP, dwTile); else if( tile.dwMaskS == 0 || tile.bClampS ) { if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY ) SetTextureUFlag(TEXTURE_UV_FLAG_WRAP, dwTile); // Can not clamp in COPY/FILL mode else SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, dwTile); } else if (tile.bMirrorS ) SetTextureUFlag(TEXTURE_UV_FLAG_MIRROR, dwTile); else SetTextureUFlag(TEXTURE_UV_FLAG_WRAP, dwTile); if( tile.bForceClampT ) SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, dwTile); else if( tile.bForceWrapT ) SetTextureVFlag(TEXTURE_UV_FLAG_WRAP, dwTile); else if( tile.dwMaskT == 0 || tile.bClampT) { if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY ) SetTextureVFlag(TEXTURE_UV_FLAG_WRAP, dwTile); // Can not clamp in COPY/FILL mode else SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, dwTile); } else if (tile.bMirrorT ) SetTextureVFlag(TEXTURE_UV_FLAG_MIRROR, dwTile); else SetTextureVFlag(TEXTURE_UV_FLAG_WRAP, dwTile); } void CRender::Initialize(void) { ClearDeviceObjects(); InitDeviceObjects(); } void CRender::CleanUp(void) { m_pColorCombiner->CleanUp(); ClearDeviceObjects(); } void myVec3Transform(float *vecout, float *vecin, float* m) { float w = m[3]*vecin[0]+m[7]*vecin[1]+m[11]*vecin[2]+m[15]; vecout[0] = (m[0]*vecin[0]+m[4]*vecin[1]+m[8]*vecin[2]+m[12])/w; vecout[1] = (m[1]*vecin[0]+m[5]*vecin[1]+m[9]*vecin[2]+m[13])/w; vecout[2] = (m[2]*vecin[0]+m[6]*vecin[1]+m[10]*vecin[2]+m[14])/w; } void CRender::SetTextureEnableAndScale(int dwTile, bool bEnable, float fScaleX, float fScaleY) { gRSP.bTextureEnabled = bEnable; if( bEnable ) { if( gRSP.curTile != (unsigned int)dwTile ) gRDP.textureIsChanged = true; gRSP.curTile = dwTile; gRSP.fTexScaleX = fScaleX; gRSP.fTexScaleY = fScaleY; if( fScaleX == 0 || fScaleY == 0 ) { gRSP.fTexScaleX = 1/32.0f; gRSP.fTexScaleY = 1/32.0f; } } } void CRender::SetFogFlagForNegativeW() { if( !gRSP.bFogEnabled ) return; m_bFogStateSave = gRSP.bFogEnabled; bool flag=gRSP.bFogEnabled; for (uint32 i = 0; i < gRSP.numVertices; i++) { if( g_vtxBuffer[i].rhw < 0 ) flag = FALSE; } TurnFogOnOff(flag); } void CRender::RestoreFogFlag() { if( !gRSP.bFogEnabled ) return; TurnFogOnOff(m_bFogStateSave); } void CRender::SetViewport(int nLeft, int nTop, int nRight, int nBottom, int maxZ) { if( status.bHandleN64RenderTexture ) return; static float MultX=0, MultY=0; if( gRSP.nVPLeftN == nLeft && gRSP.nVPTopN == nTop && gRSP.nVPRightN == nRight && gRSP.nVPBottomN == nBottom && MultX==windowSetting.fMultX && MultY==windowSetting.fMultY) { // no changes return; } MultX=windowSetting.fMultX; MultY=windowSetting.fMultY; gRSP.maxZ = maxZ; gRSP.nVPLeftN = nLeft; gRSP.nVPTopN = nTop; gRSP.nVPRightN = nRight; gRSP.nVPBottomN = nBottom; gRSP.nVPWidthN = nRight - nLeft + 1; gRSP.nVPHeightN = nBottom - nTop + 1; UpdateClipRectangle(); SetViewportRender(); LOG_UCODE("SetViewport (%d,%d - %d,%d)",gRSP.nVPLeftN, gRSP.nVPTopN, gRSP.nVPRightN, gRSP.nVPBottomN); } extern bool bHalfTxtScale; bool CRender::DrawTriangles() { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); DEBUGGER_ONLY_IF( (!debuggerEnableZBuffer), {ZBufferEnable( FALSE );} ); if( status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_1ST_PRIMITIVE ) { status.bVIOriginIsUpdated=false; CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG,{DebuggerAppendMsg("Screen Update at 1st triangle");}); } // Hack for Pilotwings 64 (U) [!].v64 static bool skipNext=false; if( options.enableHackForGames == HACK_FOR_PILOT_WINGS ) { if( IsUsedAsDI(g_CI.dwAddr) && gRDP.otherMode.z_cmp+gRDP.otherMode.z_upd > 0 ) { TRACE0("Warning: using Flushtris to write Zbuffer" ); gRSP.numVertices = 0; gRSP.maxVertexID = 0; skipNext = true; return true; } else if( skipNext ) { skipNext = false; gRSP.numVertices = 0; gRSP.maxVertexID = 0; return true; } } if( status.bN64IsDrawingTextureBuffer && frameBufferOptions.bIgnore ) { gRSP.numVertices = 0; gRSP.maxVertexID = 0; return true; } extern bool bConkerHideShadow; if( options.enableHackForGames == HACK_FOR_CONKER && bConkerHideShadow ) { gRSP.numVertices = 0; gRSP.maxVertexID = 0; return true; } if( IsUsedAsDI(g_CI.dwAddr) && !status.bHandleN64RenderTexture ) { status.bFrameBufferIsDrawn = true; } /* if( status.bHandleN64RenderTexture && g_pRenderTextureInfo->CI_Info.dwSize == TXT_SIZE_8b ) { gRSP.numVertices = 0; gRSP.maxVertexID = 0; return true; } */ if (gRSP.numVertices == 0) return true; if( status.bHandleN64RenderTexture ) { g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height; if( !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } } if( !gRDP.bFogEnableInBlender && gRSP.bFogEnabled ) { TurnFogOnOff(false); } for( int t=0; t<2; t++ ) { float halfscaleS = 1; // This will get rid of the thin black lines if( t==0 && !(m_pColorCombiner->m_bTex0Enabled) ) continue; else { if( ( gRDP.tiles[gRSP.curTile].dwSize == TXT_SIZE_32b && options.enableHackForGames == HACK_FOR_RUMBLE ) || (bHalfTxtScale && g_curRomInfo.bTextureScaleHack ) || (options.enableHackForGames == HACK_FOR_POLARISSNOCROSS && gRDP.tiles[7].dwFormat == TXT_FMT_CI && gRDP.tiles[7].dwSize == TXT_SIZE_8b && gRDP.tiles[0].dwFormat == TXT_FMT_CI && gRDP.tiles[0].dwSize == TXT_SIZE_8b && gRSP.curTile == 0 )) { halfscaleS = 0.5; } } if( t==1 && !(m_pColorCombiner->m_bTex1Enabled) ) break; if( halfscaleS < 1 ) { for( uint32 i=0; i 1.0 || g_vtxBuffer[i].tcord[t].u < 0.0 ) { clampS = false; break; } } for( uint32 i=0; i 1.0 || g_vtxBuffer[i].tcord[t].v < 0.0 ) { clampT = false; break; } } if( clampS ) { SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile+t); } if( clampT ) { SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile+t); } */ } if( status.bHandleN64RenderTexture && g_pRenderTextureInfo->CI_Info.dwSize == TXT_SIZE_8b ) { ZBufferEnable(FALSE); } ApplyScissorWithClipRatio(); if( g_curRomInfo.bZHack ) { extern void HackZAll(); HackZAll(); } bool res = RenderFlushTris(); g_clippedVtxCount = 0; LOG_UCODE("DrawTriangles: Draw %d Triangles", gRSP.numVertices/3); gRSP.numVertices = 0; // Reset index gRSP.maxVertexID = 0; DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_FLUSH_TRI, { TRACE0("Pause after DrawTriangles\n"); if( logCombiners ) m_pColorCombiner->DisplayMuxString(); }); if( !gRDP.bFogEnableInBlender && gRSP.bFogEnabled ) { TurnFogOnOff(true); } return res; } inline int ReverseCITableLookup(uint32 *pTable, int size, uint32 val) { for( int i=0; i=2 || entry.ti.Format == TXT_FMT_CI || entry.ti.Format == TXT_FMT_RGBA) && entry.ti.Size <= TXT_SIZE_8b ) ) { // No a CI texture return false; } if ( entry.ti.TLutFmt != TLUT_FMT_RGBA16 && entry.ti.TLutFmt != TLUT_FMT_IA16 ) { TRACE0("Invalid Tlut format"); return false; } if( !entry.pTexture ) { TRACE0("Null texture"); return false; } uint32 *pTable = NULL; int tableSize; uint16 * pPal = (uint16 *)entry.ti.PalAddress; // Create the pallette table if( entry.ti.Size == TXT_SIZE_4b ) { // 4-bit table tableSize = 16; pTable = new uint32[16]; for( int i=0; i<16; i++ ) { pTable[i] = entry.ti.TLutFmt == TLUT_FMT_RGBA16 ? Convert555ToRGBA(pPal[i^1]) : ConvertIA16ToRGBA(pPal[i^1]); } } else { // 8-bit table tableSize = 256; pTable = new uint32[256]; for( int i=0; i<256; i++ ) { pTable[i] = entry.ti.TLutFmt == TLUT_FMT_RGBA16 ? Convert555ToRGBA(pPal[i^1]) : ConvertIA16ToRGBA(pPal[i^1]); } } // Reversely convert current texture to indexed textures CTexture &texture = *entry.pTexture; //int width = bWholeTexture ? texture.m_dwCreatedTextureWidth : texture.m_dwWidth; //int height = bWholeTexture ? texture.m_dwCreatedTextureHeight : texture.m_dwHeight; int width = bWholeTexture ? texture.m_dwCreatedTextureWidth : entry.ti.WidthToLoad; int height = bWholeTexture ? texture.m_dwCreatedTextureHeight : entry.ti.HeightToLoad; int bufSizePerLine = (((((width << entry.ti.Size) + 1 ) >> 1)+3) >> 2)*4; // pad to 32bit boundary int bufSize = bufSizePerLine*height; unsigned char *pbuf = new unsigned char[bufSize]; DrawInfo srcInfo; if( texture.StartUpdate(&srcInfo) ) { int idx = 0; for( int i=height-1; i>=0; i--) { uint32 *pSrc = (uint32*)((unsigned char*)srcInfo.lpSurface+srcInfo.lPitch * i); for( int j=0; j>1] = (pbuf[idx>>1]<<4) | val; idx++; } else { // 0 pbuf[idx>>1] = (unsigned char)val; idx++; } } else { // 8 bits pbuf[idx++] = (unsigned char)val; } } if( entry.ti.Size == TXT_SIZE_4b ) { if( idx%8 ) idx = (idx/8+1)*8; } else { if( idx%4 ) idx = (idx/4+1)*4; } } texture.EndUpdate(&srcInfo); } // Create BMP color indexed file if( strcasecmp(right(filename,4),".bmp") != 0 ) strcat(filename,".bmp"); BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; infoHeader.biSize = sizeof( BITMAPINFOHEADER ); infoHeader.biWidth = width; infoHeader.biHeight = height; infoHeader.biPlanes = 1; infoHeader.biBitCount = entry.ti.Size == TXT_SIZE_4b ? 4 : 8; infoHeader.biCompression = BI_RGB; infoHeader.biSizeImage = bufSize; infoHeader.biXPelsPerMeter = 0; infoHeader.biYPelsPerMeter = 0; infoHeader.biClrUsed = 0; infoHeader.biClrImportant = 0; fileHeader.bfType = 19778; fileHeader.bfSize = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) + infoHeader.biSizeImage + tableSize*4; fileHeader.bfReserved1 = fileHeader.bfReserved2 = 0; fileHeader.bfOffBits = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) + tableSize*4; FILE *f; f = fopen(filename, "wb"); if(f != NULL) { if (fwrite(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f) != 1 || fwrite(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f) != 1 || fwrite(pTable, tableSize*4, 1, f) != 1 || fwrite(pbuf, infoHeader.biSizeImage, 1, f) != 1) printf("failed to write out texture data to image file '%s'", filename); fclose(f); } else { // Do something TRACE1("Fail to create file %s", filename); } // Clean up delete [] pTable; delete [] pbuf; return true; } void CRender::SaveTextureToFile(CTexture &texture, char *filename, TextureChannel channel, bool bShow, bool bWholeTexture, int width, int height) { if( width < 0 || height < 0 ) { width = bWholeTexture ? texture.m_dwCreatedTextureWidth : texture.m_dwWidth; height = bWholeTexture ? texture.m_dwCreatedTextureHeight : texture.m_dwHeight; } unsigned char *pbuf = new unsigned char[width*height* (channel == TXT_RGBA ? 4 : 3)]; if( pbuf ) { DrawInfo srcInfo; if( texture.StartUpdate(&srcInfo) ) { if( channel == TXT_RGBA ) { uint32 *pbuf2 = (uint32*)pbuf; for( int i=height-1; i>=0; i--) { uint32 *pSrc = (uint32*)((unsigned char*)srcInfo.lpSurface+srcInfo.lPitch * i); for( int j=0; j=0; i--) { unsigned char *pSrc = (unsigned char*)srcInfo.lpSurface+srcInfo.lPitch * i; for( int j=0; j=2 || g_textures[tex].pTextureEntry->ti.Format == TXT_FMT_CI || g_textures[tex].pTextureEntry->ti.Format == TXT_FMT_RGBA) && g_textures[tex].pTextureEntry->ti.Size <= TXT_SIZE_8b ) { sprintf(filename, "\\%s#%08X#%d#%d_ci", g_curRomInfo.szGameName, g_textures[tex].pTextureEntry->dwCRC, g_textures[tex].pTextureEntry->ti.Format, g_textures[tex].pTextureEntry->ti.Size); SaveCITextureToFile(*(g_textures[tex].pTextureEntry), filename, bShow && bInWhole, false); sprintf(filename, "\\%s#%08X#%d#%d#%08X_ci", g_curRomInfo.szGameName, g_textures[tex].pTextureEntry->dwCRC, g_textures[tex].pTextureEntry->ti.Format, g_textures[tex].pTextureEntry->ti.Size, g_textures[tex].pTextureEntry->dwPalCRC); SaveCITextureToFile(*(g_textures[tex].pTextureEntry), filename, false, false); sprintf(filename, "\\%s#%08X#%d#%d#%08X_ciByRGBA", g_curRomInfo.szGameName, g_textures[tex].pTextureEntry->dwCRC, g_textures[tex].pTextureEntry->ti.Format, g_textures[tex].pTextureEntry->ti.Size, g_textures[tex].pTextureEntry->dwPalCRC); SaveTextureToFile(*pBaseTexture, filename, TXT_RGBA, false, false, g_textures[tex].pTextureEntry->ti.WidthToLoad, g_textures[tex].pTextureEntry->ti.HeightToLoad); DebuggerAppendMsg("Base texture is stored at: %s", filename); if( !bInWhole && bShow ) { sprintf(filename, "\\%s#%08X#%d#%d_ci_%s_debugger", g_curRomInfo.szGameName, g_textures[tex].pTextureEntry->dwCRC, g_textures[tex].pTextureEntry->ti.Format, g_textures[tex].pTextureEntry->ti.Size, channel == TXT_ALPHA ? "a" : channel == TXT_RGBA ? "all" : "rgb"); SaveTextureToFile(*pEnhancedTexture, filename, channel, true, true); DebuggerAppendMsg("Whole texture is stored at: %s", filename); } } else { sprintf(filename, "\\%s#%08X#%d#%d_%s", g_curRomInfo.szGameName, g_textures[tex].pTextureEntry->dwCRC, g_textures[tex].pTextureEntry->ti.Format, g_textures[tex].pTextureEntry->ti.Size, channel == TXT_ALPHA ? "a" : channel == TXT_RGBA ? "all" : "rgb"); SaveTextureToFile(*pBaseTexture, filename, channel, bShow && bInWhole, false,g_textures[tex].pTextureEntry->ti.WidthToLoad, g_textures[tex].pTextureEntry->ti.HeightToLoad); DebuggerAppendMsg("Base texture is stored at: %s", filename); if( !bInWhole && bShow ) { sprintf(filename, "\\%s#%08X#%d#%d_%s_debugger", g_curRomInfo.szGameName, g_textures[tex].pTextureEntry->dwCRC, g_textures[tex].pTextureEntry->ti.Format, g_textures[tex].pTextureEntry->ti.Size, channel == TXT_ALPHA ? "a" : channel == TXT_RGBA ? "all" : "rgb"); SaveTextureToFile(*pEnhancedTexture, filename, channel, true, true); DebuggerAppendMsg("Whole texture is stored at: %s", filename); } } } #endif extern RenderTextureInfo gRenderTextureInfos[]; void SetVertexTextureUVCoord(TexCord &dst, float s, float t, int tile, TxtrCacheEntry *pEntry) { RenderTexture &txtr = g_textures[tile]; RenderTextureInfo &info = gRenderTextureInfos[pEntry->txtrBufIdx-1]; uint32 addrOffset = g_TI.dwAddr-info.CI_Info.dwAddr; uint32 extraTop = (addrOffset>>(info.CI_Info.dwSize-1)) /info.CI_Info.dwWidth; uint32 extraLeft = (addrOffset>>(info.CI_Info.dwSize-1))%info.CI_Info.dwWidth; if( pEntry->txtrBufIdx > 0 ) { // Loading from render_texture or back buffer s += (extraLeft+pEntry->ti.LeftToLoad)/txtr.m_fTexWidth; t += (extraTop+pEntry->ti.TopToLoad)/txtr.m_fTexHeight; s *= info.scaleX; t *= info.scaleY; } dst.u = s; dst.v = t; } void CRender::SetVertexTextureUVCoord(TLITVERTEX &v, float fTex0S, float fTex0T) { RenderTexture &txtr = g_textures[0]; if( txtr.pTextureEntry && txtr.pTextureEntry->txtrBufIdx > 0 ) { ::SetVertexTextureUVCoord(v.tcord[0], fTex0S, fTex0T, 0, txtr.pTextureEntry); } else { v.tcord[0].u = fTex0S; v.tcord[0].v = fTex0T; } } void CRender::SetVertexTextureUVCoord(TLITVERTEX &v, float fTex0S, float fTex0T, float fTex1S, float fTex1T) { if( (options.enableHackForGames == HACK_FOR_ZELDA||options.enableHackForGames == HACK_FOR_ZELDA_MM) && m_Mux == 0x00262a60150c937fLL && gRSP.curTile == 0 ) { // Hack for Zelda Sun Tile &t0 = gRDP.tiles[0]; Tile &t1 = gRDP.tiles[1]; if( t0.dwFormat == TXT_FMT_I && t0.dwSize == TXT_SIZE_8b && t0.dwWidth == 64 && t1.dwFormat == TXT_FMT_I && t1.dwSize == TXT_SIZE_8b && t1.dwWidth == 64 && t0.dwHeight == t1.dwHeight ) { fTex0S /= 2; fTex0T /= 2; fTex1S /= 2; fTex1T /= 2; } } RenderTexture &txtr0 = g_textures[0]; if( txtr0.pTextureEntry && txtr0.pTextureEntry->txtrBufIdx > 0 ) { ::SetVertexTextureUVCoord(v.tcord[0], fTex0S, fTex0T, 0, txtr0.pTextureEntry); } else { v.tcord[0].u = fTex0S; v.tcord[0].v = fTex0T; } RenderTexture &txtr1 = g_textures[1]; if( txtr1.pTextureEntry && txtr1.pTextureEntry->txtrBufIdx > 0 ) { ::SetVertexTextureUVCoord(v.tcord[1], fTex1S, fTex1T, 1, txtr1.pTextureEntry); } else { v.tcord[1].u = fTex1S; v.tcord[1].v = fTex1T; } } void CRender::SetClipRatio(uint32 type, uint32 w1) { bool modified = false; switch(type) { case RSP_MV_WORD_OFFSET_CLIP_RNX: LOG_UCODE(" RSP_MOVE_WORD_CLIP NegX: %d", (int)(short)w1); if( gRSP.clip_ratio_negx != (short)w1 ) { gRSP.clip_ratio_negx = (short)w1; modified = true; } break; case RSP_MV_WORD_OFFSET_CLIP_RNY: LOG_UCODE(" RSP_MOVE_WORD_CLIP NegY: %d", (int)(short)w1); if( gRSP.clip_ratio_negy != (short)w1 ) { gRSP.clip_ratio_negy = (short)w1; modified = true; } break; case RSP_MV_WORD_OFFSET_CLIP_RPX: LOG_UCODE(" RSP_MOVE_WORD_CLIP PosX: %d", (int)(short)w1); if( gRSP.clip_ratio_posx != -(short)w1 ) { gRSP.clip_ratio_posx = -(short)w1; modified = true; } break; case RSP_MV_WORD_OFFSET_CLIP_RPY: LOG_UCODE(" RSP_MOVE_WORD_CLIP PosY: %d", (int)(short)w1); if( gRSP.clip_ratio_posy != -(short)w1 ) { gRSP.clip_ratio_posy = -(short)w1; modified = true; } break; } if( modified ) { UpdateClipRectangle(); } } void CRender::UpdateClipRectangle() { if( status.bHandleN64RenderTexture ) { //windowSetting.fMultX = windowSetting.fMultY = 1; windowSetting.vpLeftW = 0; windowSetting.vpTopW = 0; windowSetting.vpRightW = newRenderTextureInfo.bufferWidth; windowSetting.vpBottomW = newRenderTextureInfo.bufferHeight; windowSetting.vpWidthW = newRenderTextureInfo.bufferWidth; windowSetting.vpHeightW = newRenderTextureInfo.bufferHeight; gRSP.vtxXMul = windowSetting.vpWidthW/2.0f; gRSP.vtxXAdd = gRSP.vtxXMul + windowSetting.vpLeftW; gRSP.vtxYMul = -windowSetting.vpHeightW/2.0f; gRSP.vtxYAdd = windowSetting.vpHeightW/2.0f + windowSetting.vpTopW+windowSetting.toolbarHeightToUse; // Update clip rectangle by setting scissor int halfx = newRenderTextureInfo.bufferWidth/2; int halfy = newRenderTextureInfo.bufferHeight/2; int centerx = halfx; int centery = halfy; gRSP.clip_ratio_left = centerx - halfx * gRSP.clip_ratio_negx; gRSP.clip_ratio_top = centery - halfy * gRSP.clip_ratio_negy; gRSP.clip_ratio_right = centerx + halfx * gRSP.clip_ratio_posx; gRSP.clip_ratio_bottom = centery + halfy * gRSP.clip_ratio_posy; } else { windowSetting.vpLeftW = int(gRSP.nVPLeftN * windowSetting.fMultX); windowSetting.vpTopW = int(gRSP.nVPTopN * windowSetting.fMultY); windowSetting.vpRightW = int(gRSP.nVPRightN* windowSetting.fMultX); windowSetting.vpBottomW = int(gRSP.nVPBottomN* windowSetting.fMultY); windowSetting.vpWidthW = int((gRSP.nVPRightN - gRSP.nVPLeftN + 1) * windowSetting.fMultX); windowSetting.vpHeightW = int((gRSP.nVPBottomN - gRSP.nVPTopN + 1) * windowSetting.fMultY); gRSP.vtxXMul = windowSetting.vpWidthW/2.0f; gRSP.vtxXAdd = gRSP.vtxXMul + windowSetting.vpLeftW; gRSP.vtxYMul = -windowSetting.vpHeightW/2.0f; gRSP.vtxYAdd = windowSetting.vpHeightW/2.0f + windowSetting.vpTopW+windowSetting.toolbarHeightToUse; // Update clip rectangle by setting scissor int halfx = gRSP.nVPWidthN/2; int halfy = gRSP.nVPHeightN/2; int centerx = gRSP.nVPLeftN+halfx; int centery = gRSP.nVPTopN+halfy; gRSP.clip_ratio_left = centerx - halfx * gRSP.clip_ratio_negx; gRSP.clip_ratio_top = centery - halfy * gRSP.clip_ratio_negy; gRSP.clip_ratio_right = centerx + halfx * gRSP.clip_ratio_posx; gRSP.clip_ratio_bottom = centery + halfy * gRSP.clip_ratio_posy; } UpdateScissorWithClipRatio(); } void CRender::UpdateScissorWithClipRatio() { gRSP.real_clip_scissor_left = std::max(gRDP.scissor.left, gRSP.clip_ratio_left); gRSP.real_clip_scissor_top = std::max(gRDP.scissor.top, gRSP.clip_ratio_top); gRSP.real_clip_scissor_right = std::min(gRDP.scissor.right,gRSP.clip_ratio_right); gRSP.real_clip_scissor_bottom = std::min(gRDP.scissor.bottom, gRSP.clip_ratio_bottom); gRSP.real_clip_scissor_left = std::max(gRSP.real_clip_scissor_left, 0); gRSP.real_clip_scissor_top = std::max(gRSP.real_clip_scissor_top, 0); gRSP.real_clip_scissor_right = std::min(gRSP.real_clip_scissor_right,windowSetting.uViWidth-1); gRSP.real_clip_scissor_bottom = std::min(gRSP.real_clip_scissor_bottom, windowSetting.uViHeight-1); WindowSettingStruct &w = windowSetting; w.clipping.left = (uint32)(gRSP.real_clip_scissor_left*windowSetting.fMultX); w.clipping.top = (uint32)(gRSP.real_clip_scissor_top*windowSetting.fMultY); w.clipping.bottom = (uint32)(gRSP.real_clip_scissor_bottom*windowSetting.fMultY); w.clipping.right = (uint32)(gRSP.real_clip_scissor_right*windowSetting.fMultX); if( w.clipping.left > 0 || w.clipping.top > 0 || w.clipping.right < (uint32)windowSetting.uDisplayWidth-1 || w.clipping.bottom < (uint32)windowSetting.uDisplayHeight-1 ) { w.clipping.needToClip = true; } else { w.clipping.needToClip = false; } w.clipping.width = (uint32)((gRSP.real_clip_scissor_right-gRSP.real_clip_scissor_left+1)*windowSetting.fMultX); w.clipping.height = (uint32)((gRSP.real_clip_scissor_bottom-gRSP.real_clip_scissor_top+1)*windowSetting.fMultY); float halfx = gRSP.nVPWidthN/2.0f; float halfy = gRSP.nVPHeightN/2.0f; float centerx = gRSP.nVPLeftN+halfx; float centery = gRSP.nVPTopN+halfy; gRSP.real_clip_ratio_negx = (gRSP.real_clip_scissor_left - centerx)/halfx; gRSP.real_clip_ratio_negy = (gRSP.real_clip_scissor_top - centery)/halfy; gRSP.real_clip_ratio_posx = (gRSP.real_clip_scissor_right - centerx)/halfx; gRSP.real_clip_ratio_posy = (gRSP.real_clip_scissor_bottom - centery)/halfy; ApplyScissorWithClipRatio(true); } // Set other modes not covered by color combiner or alpha blender void CRender::InitOtherModes(void) { ApplyTextureFilter(); // // I can't think why the hand in mario's menu screen is rendered with an opaque rendermode, // and no alpha threshold. We set the alpha reference to 1 to ensure that the transparent pixels // don't get rendered. I hope this doesn't fuck anything else up. // if ( gRDP.otherMode.alpha_compare == 0 ) { if ( gRDP.otherMode.cvg_x_alpha && (gRDP.otherMode.alpha_cvg_sel || gRDP.otherMode.aa_en ) ) { ForceAlphaRef(128); // Strange, I have to use value=2 for pixel shader combiner for Nvidia FX5200 // for other video cards, value=1 is good enough. SetAlphaTestEnable(TRUE); } else { SetAlphaTestEnable(FALSE); } } else if ( gRDP.otherMode.alpha_compare == 3 ) { //RDP_ALPHA_COMPARE_DITHER SetAlphaTestEnable(FALSE); } else { if( (gRDP.otherMode.alpha_cvg_sel ) && !gRDP.otherMode.cvg_x_alpha ) { // Use CVG for pixel alpha SetAlphaTestEnable(FALSE); } else { // RDP_ALPHA_COMPARE_THRESHOLD || RDP_ALPHA_COMPARE_DITHER if( m_dwAlpha==0 ) ForceAlphaRef(1); else ForceAlphaRef(m_dwAlpha); SetAlphaTestEnable(TRUE); } } if( options.enableHackForGames == HACK_FOR_SOUTH_PARK_RALLY && m_Mux == 0x00121824ff33ffffLL && gRSP.bCullFront && gRDP.otherMode.aa_en && gRDP.otherMode.z_cmp && gRDP.otherMode.z_upd ) { SetZCompare(FALSE); } if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY ) { // Disable zbuffer for COPY and FILL mode SetZCompare(FALSE); } else { SetZCompare(gRDP.otherMode.z_cmp); SetZUpdate(gRDP.otherMode.z_upd); } /* if( options.enableHackForGames == HACK_FOR_SOUTH_PARK_RALLY && m_Mux == 0x00121824ff33ffff && gRSP.bCullFront && gRDP.otherMode.z_cmp && gRDP.otherMode.z_upd )//&& gRDP.otherMode.aa_en ) { SetZCompare(FALSE); SetZUpdate(FALSE); } */ } void CRender::SetTextureFilter(uint32 dwFilter) { if( options.forceTextureFilter == FORCE_DEFAULT_FILTER ) { switch(dwFilter) { case RDP_TFILTER_AVERAGE: //? case RDP_TFILTER_BILERP: m_dwMinFilter = m_dwMagFilter = FILTER_LINEAR; break; default: m_dwMinFilter = m_dwMagFilter = FILTER_POINT; break; } } else { switch( options.forceTextureFilter ) { case FORCE_POINT_FILTER: m_dwMinFilter = m_dwMagFilter = FILTER_POINT; break; case FORCE_LINEAR_FILTER: m_dwMinFilter = m_dwMagFilter = FILTER_LINEAR; break; } } ApplyTextureFilter(); } bool SaveRGBBufferToFile(char *filename, unsigned char *buf, int width, int height, int pitch) { if( pitch == -1 ) pitch = width*3; if( strcasecmp(right(filename,3),"bmp") == 0 ) { BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; infoHeader.biSize = sizeof( BITMAPINFOHEADER ); infoHeader.biWidth = width; infoHeader.biHeight = height; infoHeader.biPlanes = 1; infoHeader.biBitCount = 24; infoHeader.biCompression = BI_RGB; infoHeader.biSizeImage = width * height * 3; infoHeader.biXPelsPerMeter = 0; infoHeader.biYPelsPerMeter = 0; infoHeader.biClrUsed = 0; infoHeader.biClrImportant = 0; fileHeader.bfType = 19778; fileHeader.bfSize = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) + infoHeader.biSizeImage; fileHeader.bfReserved1 = fileHeader.bfReserved2 = 0; fileHeader.bfOffBits = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ); FILE *f; f = fopen(filename, "wb"); if(f != NULL) { if (fwrite(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f) != 1 || fwrite(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f) != 1 || fwrite(buf, infoHeader.biSizeImage, 1, f) != 1) printf("failed to write out texture data to image file '%s'", filename); fclose(f); return true; } else { // Do something TRACE1("Fail to create file %s", filename); return false; } } else { if( strcasecmp(right(filename,4),".png") != 0 ) strcat(filename,".png"); struct BMGImageStruct img; memset(&img, 0, sizeof(BMGImageStruct)); InitBMGImage(&img); img.bits = buf; img.bits_per_pixel = 24; img.height = height; img.width = width; img.scan_width = pitch; BMG_Error code = WritePNG(filename, img); if( code == BMG_OK ) return true; else return false; } } bool SaveRGBABufferToPNGFile(char *filename, unsigned char *buf, int width, int height, int pitch) { if( pitch == -1 ) pitch = width*4; if( strcasecmp(right(filename,4),".png") != 0 ) strcat(filename,".png"); struct BMGImageStruct img; memset(&img, 0, sizeof(BMGImageStruct)); InitBMGImage(&img); img.bits = buf; img.bits_per_pixel = 32; img.height = height; img.width = width; img.scan_width = pitch; BMG_Error code = WritePNG(filename, img); if( code == BMG_OK ) return true; else return false; } mupen64plus-video-rice-src-2.0/src/Render.h0000644000000000000000000002342512165031100016666 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _RICE_RENDER_H #define _RICE_RENDER_H #include "Blender.h" #include "Combiner.h" #include "Config.h" #include "Debugger.h" #include "RenderBase.h" #include "ExtendedRender.h" #include "RSP_Parser.h" #include "RSP_S2DEX.h" enum TextureChannel { TXT_RGB, TXT_ALPHA, TXT_RGBA, }; class CRender : public CExtendedRender { protected: CRender(); TextureUVFlag TileUFlags[8]; TextureUVFlag TileVFlags[8]; public: float m_fScreenViewportMultX; float m_fScreenViewportMultY; uint32 m_dwTexturePerspective; BOOL m_bAlphaTestEnable; BOOL m_bZUpdate; BOOL m_bZCompare; uint32 m_dwZBias; TextureFilter m_dwMinFilter; TextureFilter m_dwMagFilter; uint32 m_dwAlpha; uint64 m_Mux; BOOL m_bBlendModeValid; CColorCombiner *m_pColorCombiner; CBlender *m_pAlphaBlender; virtual ~CRender(); inline bool IsTexel0Enable() {return m_pColorCombiner->m_bTex0Enabled;} inline bool IsTexel1Enable() {return m_pColorCombiner->m_bTex1Enabled;} inline bool IsTextureEnabled() { return (m_pColorCombiner->m_bTex0Enabled||m_pColorCombiner->m_bTex1Enabled); } inline RenderTexture& GetCurrentTexture() { return g_textures[gRSP.curTile]; } inline RenderTexture& GetTexture(uint32 dwTile) { return g_textures[dwTile]; } void SetViewport(int nLeft, int nTop, int nRight, int nBottom, int maxZ); virtual void SetViewportRender() {} virtual void SetClipRatio(uint32 type, uint32 value); virtual void UpdateScissor() {} virtual void ApplyRDPScissor(bool force=false) {} virtual void UpdateClipRectangle(); virtual void UpdateScissorWithClipRatio(); virtual void ApplyScissorWithClipRatio(bool force=false) {} void SetTextureEnableAndScale(int dwTile, bool enable, float fScaleX, float fScaleY); virtual void SetFogEnable(bool bEnable) { DEBUGGER_IF_DUMP( (gRSP.bFogEnabled != bEnable && logFog ), TRACE1("Set Fog %s", bEnable? "enable":"disable")); gRSP.bFogEnabled = bEnable&&(options.fogMethod > 0); } virtual void SetFogMinMax(float fMin, float fMax) = 0; virtual void TurnFogOnOff(bool flag)=0; bool m_bFogStateSave; void SetFogFlagForNegativeW(); void RestoreFogFlag(); virtual void SetFogColor(uint32 r, uint32 g, uint32 b, uint32 a) { gRDP.fogColor = COLOR_RGBA(r, g, b, a); } uint32 GetFogColor() { return gRDP.fogColor; } void SetProjection(const Matrix & mat, bool bPush, bool bReplace); void SetWorldView(const Matrix & mat, bool bPush, bool bReplace); inline int GetProjectMatrixLevel(void) { return gRSP.projectionMtxTop; } inline int GetWorldViewMatrixLevel(void) { return gRSP.modelViewMtxTop; } inline void PopProjection() { if (gRSP.projectionMtxTop > 0) gRSP.projectionMtxTop--; else TRACE0("Popping past projection stack limits"); } void PopWorldView(); Matrix & GetWorldProjectMatrix(void); void SetWorldProjectMatrix(Matrix &mtx); void ResetMatrices(); inline RenderShadeMode GetShadeMode() { return gRSP.shadeMode; } void SetVtxTextureCoord(uint32 dwV, float tu, float tv) { g_fVtxTxtCoords[dwV].x = tu; g_fVtxTxtCoords[dwV].y = tv; } virtual void RenderReset(); virtual void SetCombinerAndBlender(); virtual void SetMux(uint32 dwMux0, uint32 dwMux1); virtual void SetCullMode(bool bCullFront, bool bCullBack) { gRSP.bCullFront = bCullFront; gRSP.bCullBack = bCullBack; } virtual void BeginRendering(void) {CRender::gRenderReferenceCount++;} // For DirectX only virtual void EndRendering(void) { if( CRender::gRenderReferenceCount > 0 ) CRender::gRenderReferenceCount--; } virtual void ClearBuffer(bool cbuffer, bool zbuffer)=0; virtual void ClearZBuffer(float depth)=0; virtual void ClearBuffer(bool cbuffer, bool zbuffer, COORDRECT &rect) { ClearBuffer(cbuffer, zbuffer); } virtual void ZBufferEnable(BOOL bZBuffer)=0; virtual void SetZCompare(BOOL bZCompare)=0; virtual void SetZUpdate(BOOL bZUpdate)=0; virtual void SetZBias(int bias)=0; virtual void SetAlphaTestEnable(BOOL bAlphaTestEnable)=0; void SetTextureFilter(uint32 dwFilter); virtual void ApplyTextureFilter() {} virtual void SetShadeMode(RenderShadeMode mode)=0; virtual void SetAlphaRef(uint32 dwAlpha)=0; virtual void ForceAlphaRef(uint32 dwAlpha)=0; virtual void InitOtherModes(void); void SetVertexTextureUVCoord(TLITVERTEX &v, float fTex0S, float fTex0T, float fTex1S, float fTex1T); void SetVertexTextureUVCoord(TLITVERTEX &v, float fTex0S, float fTex0T); virtual COLOR PostProcessDiffuseColor(COLOR curDiffuseColor)=0; virtual COLOR PostProcessSpecularColor()=0; bool DrawTriangles(); virtual bool RenderFlushTris()=0; bool TexRect(int nX0, int nY0, int nX1, int nY1, float fS0, float fT0, float fScaleS, float fScaleT, bool colorFlag=false, uint32 difcolor=0xFFFFFFFF); bool TexRectFlip(int nX0, int nY0, int nX1, int nY1, float fS0, float fT0, float fS1, float fT1); bool FillRect(int nX0, int nY0, int nX1, int nY1, uint32 dwColor); bool Line3D(uint32 dwV0, uint32 dwV1, uint32 dwWidth); virtual void SetAddressUAllStages(uint32 dwTile, TextureUVFlag dwFlag); // For DirectX only, fix me virtual void SetAddressVAllStages(uint32 dwTile, TextureUVFlag dwFlag); // For DirectX only, fix me virtual void SetTextureUFlag(TextureUVFlag dwFlag, uint32 tile)=0; virtual void SetTextureVFlag(TextureUVFlag dwFlag, uint32 tile)=0; virtual void SetTexelRepeatFlags(uint32 dwTile); virtual void SetAllTexelRepeatFlag(); virtual bool SetCurrentTexture(int tile, TxtrCacheEntry *pTextureEntry)=0; virtual bool SetCurrentTexture(int tile, CTexture *handler, uint32 dwTileWidth, uint32 dwTileHeight, TxtrCacheEntry *pTextureEntry) = 0; virtual bool InitDeviceObjects()=0; virtual bool ClearDeviceObjects()=0; virtual void Initialize(void); virtual void CleanUp(void); virtual void SetFillMode(FillMode mode)=0; #ifdef DEBUGGER virtual bool DrawTexture(int tex, TextureChannel channel = TXT_RGB ); virtual void SaveTextureToFile(int tex, TextureChannel channel = TXT_RGB, bool bShow = false); #endif virtual void SaveTextureToFile(CTexture &texture, char *filename, TextureChannel channel = TXT_RGB, bool bShow = false, bool bWholeTexture = true, int width = -1, int height = -1); void LoadSprite2D(Sprite2DInfo &info, uint32 ucode); void LoadObjBGCopy(uObjBg &info); void LoadObjBG1CYC(uObjScaleBg &info); void LoadObjSprite(uObjTxSprite &info, bool useTIAddr=false); void LoadFrameBuffer(bool useVIreg=false, uint32 left=0, uint32 top=0, uint32 width=0, uint32 height=0); void LoadTextureFromMemory(void *buf, uint32 left, uint32 top, uint32 width, uint32 height, uint32 pitch, uint32 format); void LoadTxtrBufIntoTexture(void); void DrawSprite2D(Sprite2DInfo &info, uint32 ucode); void DrawSpriteR(uObjTxSprite &sprite, bool initCombiner=true, uint32 tile=0, uint32 left=0, uint32 top=0, uint32 width=0, uint32 height=0); void DrawSprite(uObjTxSprite &sprite, bool rectR = true); void DrawObjBGCopy(uObjBg &info); virtual void DrawSpriteR_Render(){}; virtual void DrawSimple2DTexture(float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, COLOR dif, COLOR spe, float z, float rhw)=0; void DrawFrameBuffer(bool useVIreg=false, uint32 left=0, uint32 top=0, uint32 width=0, uint32 height=0); void DrawObjBG1CYC(uObjScaleBg &bg, bool scaled=true); static CRender * g_pRender; static int gRenderReferenceCount; static CRender * GetRender(void); static bool IsAvailable(); protected: BOOL m_savedZBufferFlag; uint32 m_savedMinFilter; uint32 m_savedMagFilter; // FillRect virtual bool RenderFillRect(uint32 dwColor, float depth)=0; VECTOR2 m_fillRectVtx[2]; // Line3D virtual bool RenderLine3D()=0; LITVERTEX m_line3DVtx[2]; VECTOR2 m_line3DVector[4]; // TexRect virtual bool RenderTexRect()=0; TexCord m_texRectTex1UV[2]; TexCord m_texRectTex2UV[2]; // DrawSimple2DTexture virtual void StartDrawSimple2DTexture(float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, COLOR dif, COLOR spe, float z, float rhw); // DrawSimpleRect virtual void StartDrawSimpleRect(int nX0, int nY0, int nX1, int nY1, uint32 dwColor, float depth, float rhw); VECTOR2 m_simpleRectVtx[2]; bool RemapTextureCoordinate(float s0, float s1, uint32 tileWidth, uint32 mask, float textureWidth, float &u0, float &u1); }; #define ffloor(a) (((int(a))<=(a))?(float)(int(a)):((float)(int(a))-1)) bool SaveRGBBufferToFile(char *filename, unsigned char *buf, int width, int height, int pitch = -1); bool SaveRGBABufferToPNGFile(char *filename, unsigned char *buf, int width, int height, int pitch = -1); #endif //_RICE_RENDER_H mupen64plus-video-rice-src-2.0/src/RenderBase.cpp0000644000000000000000000024471112165031100020017 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "osal_preproc.h" #include "float.h" #include "DeviceBuilder.h" #include "VertexShaderConstantDef.h" #include "Render.h" #include "Timing.h" extern FiddledVtx * g_pVtxBase; #define ENABLE_CLIP_TRI #define X_CLIP_MAX 0x1 #define X_CLIP_MIN 0x2 #define Y_CLIP_MAX 0x4 #define Y_CLIP_MIN 0x8 #define Z_CLIP_MAX 0x10 #define Z_CLIP_MIN 0x20 #ifdef ENABLE_CLIP_TRI inline void RSP_Vtx_Clipping(int i) { g_clipFlag[i] = 0; g_clipFlag2[i] = 0; if( g_vecProjected[i].w > 0 ) { /* if( gRSP.bRejectVtx ) { if( g_vecProjected[i].x > 1 ) { g_clipFlag2[i] |= X_CLIP_MAX; if( g_vecProjected[i].x > gRSP.real_clip_ratio_posx ) g_clipFlag[i] |= X_CLIP_MAX; } if( g_vecProjected[i].x < -1 ) { g_clipFlag2[i] |= X_CLIP_MIN; if( g_vecProjected[i].x < gRSP.real_clip_ratio_negx ) g_clipFlag[i] |= X_CLIP_MIN; } if( g_vecProjected[i].y > 1 ) { g_clipFlag2[i] |= Y_CLIP_MAX; if( g_vecProjected[i].y > gRSP.real_clip_ratio_posy ) g_clipFlag[i] |= Y_CLIP_MAX; } if( g_vecProjected[i].y < -1 ) { g_clipFlag2[i] |= Y_CLIP_MIN; if( g_vecProjected[i].y < gRSP.real_clip_ratio_negy ) g_clipFlag[i] |= Y_CLIP_MIN; } //if( g_vecProjected[i].z > 1.0f ) //{ // g_clipFlag2[i] |= Z_CLIP_MAX; // g_clipFlag[i] |= Z_CLIP_MAX; //} //if( gRSP.bNearClip && g_vecProjected[i].z < -1.0f ) //{ // g_clipFlag2[i] |= Z_CLIP_MIN; // g_clipFlag[i] |= Z_CLIP_MIN; //} } else */ { if( g_vecProjected[i].x > 1 ) g_clipFlag2[i] |= X_CLIP_MAX; if( g_vecProjected[i].x < -1 ) g_clipFlag2[i] |= X_CLIP_MIN; if( g_vecProjected[i].y > 1 ) g_clipFlag2[i] |= Y_CLIP_MAX; if( g_vecProjected[i].y < -1 ) g_clipFlag2[i] |= Y_CLIP_MIN; //if( g_vecProjected[i].z > 1.0f ) g_clipFlag2[i] |= Z_CLIP_MAX; //if( gRSP.bNearClip && g_vecProjected[i].z < -1.0f ) g_clipFlag2[i] |= Z_CLIP_MIN; } } } #else inline void RSP_Vtx_Clipping(int i) {} #endif /* * Global variables */ ALIGN(16,RSP_Options gRSP) ALIGN(16,RDP_Options gRDP) static ALIGN(16,XVECTOR4 g_normal) //static int norms[3]; ALIGN(16,XVECTOR4 g_vtxNonTransformed[MAX_VERTS]) ALIGN(16,XVECTOR4 g_vecProjected[MAX_VERTS]) ALIGN(16,XVECTOR4 g_vtxTransformed[MAX_VERTS]) float g_vtxProjected5[1000][5]; float g_vtxProjected5Clipped[2000][5]; //uint32 g_dwVtxFlags[MAX_VERTS]; // Z_POS Z_NEG etc VECTOR2 g_fVtxTxtCoords[MAX_VERTS]; uint32 g_dwVtxDifColor[MAX_VERTS]; uint32 g_clipFlag[MAX_VERTS]; uint32 g_clipFlag2[MAX_VERTS]; RenderTexture g_textures[MAX_TEXTURES]; float g_fFogCoord[MAX_VERTS]; EXTERNAL_VERTEX g_vtxForExternal[MAX_VERTS]; TLITVERTEX g_vtxBuffer[1000]; TLITVERTEX g_clippedVtxBuffer[2000]; uint8 g_oglVtxColors[1000][4]; int g_clippedVtxCount=0; TLITVERTEX g_texRectTVtx[4]; unsigned short g_vtxIndex[1000]; unsigned int g_minIndex, g_maxIndex; float gRSPfFogMin; float gRSPfFogMax; float gRSPfFogDivider; uint32 gRSPnumLights; Light gRSPlights[16]; ALIGN(16,Matrix gRSPworldProjectTransported) ALIGN(16,Matrix gRSPworldProject) ALIGN(16,Matrix gRSPmodelViewTop) ALIGN(16,Matrix gRSPmodelViewTopTranspose) ALIGN(16,Matrix dkrMatrixTransposed) N64Light gRSPn64lights[16]; void (*ProcessVertexData)(uint32 dwAddr, uint32 dwV0, uint32 dwNum)=NULL; /* * */ /*n.x = (g_normal.x * matWorld.m00) + (g_normal.y * matWorld.m10) + (g_normal.z * matWorld.m20); n.y = (g_normal.x * matWorld.m01) + (g_normal.y * matWorld.m11) + (g_normal.z * matWorld.m21); n.z = (g_normal.x * matWorld.m02) + (g_normal.y * matWorld.m12) + (g_normal.z * matWorld.m22);*/ // Multiply (x,y,z,0) by matrix m, then normalize #if defined(__INTEL_COMPILER) && !defined(NO_ASM) #define Vec3TransformNormal(vec, m) __asm \ { \ __asm fld dword ptr [vec + 0] \ __asm fmul dword ptr [m + 0] \ /* x m00*/ __asm fld dword ptr [vec + 0] \ __asm fmul dword ptr [m + 4] \ /* x m01 x m00*/ __asm fld dword ptr [vec + 0] \ __asm fmul dword ptr [m + 8] \ /* x m02 x m01 x m00*/ \ __asm fld dword ptr [vec + 4] \ __asm fmul dword ptr [m + 16] \ /* y m10 x m02 x m01 x m00*/ __asm fld dword ptr [vec + 4] \ __asm fmul dword ptr [m + 20] \ /* y m11 y m10 x m02 x m01 x m00*/ __asm fld dword ptr [vec + 4] \ __asm fmul dword ptr [m + 24] \ /* y m12 y m11 y m10 x m02 x m01 x m00*/ \ __asm fxch st(2) \ /* y m10 y m11 y m12 x m02 x m01 x m00*/ __asm faddp st(5), st(0) \ /* y m11 y m12 x m02 x m01 (x m00 + y m10)*/ __asm faddp st(3), st(0) \ /* y m12 x m02 (x m01 + ym11) (x m00 + y m10)*/ __asm faddp st(1), st(0) \ /* (x m02 + y m12) (x m01 + ym11) (x m00 + y m10)*/ \ __asm fld dword ptr [vec + 8] \ __asm fmul dword ptr [m + 32] \ /* z m20 (x m02 + y m12) (x m01 + ym11) (x m00 + y m10)*/ __asm fld dword ptr [vec + 8] \ __asm fmul dword ptr [m + 36] \ /* z m21 z m20 (x m02 + y m12) (x m01 + ym11) (x m00 + y m10)*/ __asm fld dword ptr [vec + 8] \ __asm fmul dword ptr [m + 40] \ /* z m22 z m21 z m20 (x m02 + y m12) (x m01 + ym11) (x m00 + y m10)*/ \ __asm fxch st(2) \ /* z m20 z m21 z m22 (x m02 + y m12) (x m01 + ym11) (x m00 + y m10)*/ __asm faddp st(5), st(0) \ /* z m21 z m22 (x m02 + y m12) (x m01 + ym11) (x m00 + y m10 + z m20)*/ __asm faddp st(3), st(0) \ /* z m22 (x m02 + y m12) (x m01 + ym11 + z m21) (x m00 + y m10 + z m20)*/ __asm faddp st(1), st(0) \ /* (x m02 + y m12 + z m 22) (x m01 + ym11 + z m21) (x m00 + y m10 + z m20)*/ \ __asm fxch st(2) \ /* (x m00 + y m10 + z m20) (x m01 + ym11 + z m21) (x m02 + y m12 + z m 22) */ \ __asm fld1 \ /* 1 x y z */ __asm fld st(1) \ /* x 1 x y z */ __asm fmul st(0),st(0) \ /* xx 1 x y z */ __asm fld st(3) \ /* y xx 1 x y z */ __asm fmul st(0),st(0) \ /* yy xx 1 x y z */ __asm fld st(5) \ /* z yy xx 1 x y z */ __asm fmul st(0),st(0) \ /* zz yy xx 1 x y z */ \ __asm fxch st(2) \ /* xx yy zz 1 x y z */ \ __asm faddp st(1),st(0) \ /* (xx+yy) zz 1 x y z */ __asm faddp st(1),st(0) \ /* (xx+yy+zz) 1 x y z */ \ __asm ftst \ /* Compare ST to 0 */ __asm fstsw ax \ /* Store FPU status word in a */ __asm sahf \ /* Transfer ax to flags register */ __asm jz l2 \ /* Skip if length is zero */ \ __asm fsqrt \ /* l 1 x y z */ \ __asm fdivp st(1),st(0) \ /* (1/l) x y z */ \ __asm fmul st(3),st(0) \ /* f x y fz */ __asm fmul st(2),st(0) \ /* f x fy fz */ __asm fmulp st(1),st(0) \ /* fx fy fz */ \ __asm fstp dword ptr [vec + 0] \ /* fy fz*/ __asm fstp dword ptr [vec + 4] \ /* fz */ __asm fstp dword ptr [vec + 8] \ /* done */ __asm jmp l3 \ __asm l2: \ __asm mov dword ptr [vec + 0], 0 \ __asm mov dword ptr [vec + 4], 0 \ __asm mov dword ptr [vec + 8], 0 \ __asm l3: \ } \ #else // use C code in other cases, this is probably faster anyway #define Vec3TransformNormal(vec, m) \ VECTOR3 temp; \ temp.x = (vec.x * m._11) + (vec.y * m._21) + (vec.z * m._31); \ temp.y = (vec.x * m._12) + (vec.y * m._22) + (vec.z * m._32); \ temp.z = (vec.x * m._13) + (vec.y * m._23) + (vec.z * m._33); \ float norm = sqrt(temp.x*temp.x+temp.y*temp.y+temp.z*temp.z); \ if (norm == 0.0) { vec.x = 0.0; vec.y = 0.0; vec.z = 0.0;} else \ { vec.x = temp.x/norm; vec.y = temp.y/norm; vec.z = temp.z/norm; } #endif #if !defined(__GNUC__) && !defined(NO_ASM) __declspec( naked ) void __fastcall SSEVec3Transform(int i) { __asm { shl ecx,4; // ecx = i movaps xmm1, DWORD PTR g_vtxNonTransformed [ecx]; // xmm1 as original vector movaps xmm4, DWORD PTR gRSPworldProjectTransported; // row1 movaps xmm5, DWORD PTR gRSPworldProjectTransported[0x10]; // row2 movaps xmm6, DWORD PTR gRSPworldProjectTransported[0x20]; // row3 movaps xmm7, DWORD PTR gRSPworldProjectTransported[0x30]; // row4 mulps xmm4, xmm1; // row 1 mulps xmm5, xmm1; // row 2 mulps xmm6, xmm1; // row 3 mulps xmm7, xmm1; // row 4 movhlps xmm0, xmm4; // xmm4 high to xmm0 low movlhps xmm0, xmm5; // xmm5 low to xmm0 high addps xmm4, xmm0; // result of add are in xmm4 low addps xmm5, xmm0; // result of add are in xmm5 high shufps xmm0, xmm4, 0x44; // move xmm4 low DWORDs to xmm0 high shufps xmm4, xmm5, 0xe4; // move xmm5 high DWORS to xmm4 movhlps xmm5, xmm0; // xmm4, xmm5 are mirrored shufps xmm4, xmm4, 0x08; // move xmm4's 3rd uint32 to its 2nd uint32 shufps xmm5, xmm5, 0x0d; // move xmm5's 4th uint32 to its 2nd uint32, // and move its 2nd uint32 to its 1st uint32 addps xmm4, xmm5; // results are in 1st and 2nd uint32 movhlps xmm0, xmm6; // xmm6 high to xmm0 low movlhps xmm0, xmm7; // xmm7 low to xmm0 high addps xmm6, xmm0; // result of add are in xmm6 low addps xmm7, xmm0; // result of add are in xmm7 high shufps xmm0, xmm6, 0x44; // move xmm6 low DWORDs to xmm0 high shufps xmm6, xmm7, 0xe4; // move xmm7 high DWORS to xmm6 movhlps xmm7, xmm0; // xmm6, xmm7 are mirrored shufps xmm6, xmm6, 0x08; // move xmm6's 3rd uint32 to its 2nd uint32 shufps xmm7, xmm7, 0x0d; // move xmm7's 4th uint32 to its 2nd uint32, // and move its 2nd uint32 to its 1st uint32 addps xmm6, xmm7; // results are in 1st and 2nd uint32 movlhps xmm4, xmm6; // final result is in xmm4 movaps DWORD PTR g_vtxTransformed [ecx], xmm4; movaps xmm0,xmm4; shufps xmm0,xmm0,0xff; divps xmm4,xmm0; rcpps xmm0,xmm0; movhlps xmm0,xmm4; shufps xmm0,xmm0,0xe8; movlhps xmm4,xmm0; movaps DWORD PTR g_vecProjected [ecx], xmm4; emms; ret; } } // Only used by DKR __declspec( naked ) void __fastcall SSEVec3TransformDKR(XVECTOR4 &pOut, const XVECTOR4 &pV) { __asm { movaps xmm1, DWORD PTR [edx]; // xmm1 as original vector movaps xmm4, DWORD PTR dkrMatrixTransposed; // row1 movaps xmm5, DWORD PTR dkrMatrixTransposed[0x10]; // row2 movaps xmm6, DWORD PTR dkrMatrixTransposed[0x20]; // row3 movaps xmm7, DWORD PTR dkrMatrixTransposed[0x30]; // row4 mulps xmm4, xmm1; // row 1 mulps xmm5, xmm1; // row 2 mulps xmm6, xmm1; // row 3 mulps xmm7, xmm1; // row 4 movhlps xmm0, xmm4; // xmm4 high to xmm0 low movlhps xmm0, xmm5; // xmm5 low to xmm0 high addps xmm4, xmm0; // result of add are in xmm4 low addps xmm5, xmm0; // result of add are in xmm5 high shufps xmm0, xmm4, 0x44; // move xmm4 low DWORDs to xmm0 high shufps xmm4, xmm5, 0xe4; // move xmm5 high DWORS to xmm4 movhlps xmm5, xmm0; // xmm4, xmm5 are mirrored shufps xmm4, xmm4, 0x08; // move xmm4's 3rd uint32 to its 2nd uint32 shufps xmm5, xmm5, 0x0d; // move xmm5's 4th uint32 to its 2nd uint32, // and move its 2nd uint32 to its 1st uint32 addps xmm4, xmm5; // results are in 1st and 2nd uint32 movhlps xmm0, xmm6; // xmm6 high to xmm0 low movlhps xmm0, xmm7; // xmm7 low to xmm0 high addps xmm6, xmm0; // result of add are in xmm6 low addps xmm7, xmm0; // result of add are in xmm7 high shufps xmm0, xmm6, 0x44; // move xmm6 low DWORDs to xmm0 high shufps xmm6, xmm7, 0xe4; // move xmm7 high DWORS to xmm6 movhlps xmm7, xmm0; // xmm6, xmm7 are mirrored shufps xmm6, xmm6, 0x08; // move xmm6's 3rd uint32 to its 2nd uint32 shufps xmm7, xmm7, 0x0d; // move xmm7's 4th uint32 to its 2nd uint32, // and move its 2nd uint32 to its 1st uint32 addps xmm6, xmm7; // results are in 1st and 2nd uint32 movlhps xmm4, xmm6; // final result is in xmm4 movaps DWORD PTR [ecx], xmm4; emms; ret; } } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) void SSEVec3Transform(int i) { asm volatile(" shl $4, %0 \n" " movslq %k0, %q0 \n" " movaps (%1,%q0), %%xmm1 \n" " movaps 0(%2), %%xmm4 \n" " movaps 16(%2), %%xmm5 \n" " movaps 32(%2), %%xmm6 \n" " movaps 48(%2), %%xmm7 \n" " mulps %%xmm1, %%xmm4 \n" " mulps %%xmm1, %%xmm5 \n" " mulps %%xmm1, %%xmm6 \n" " mulps %%xmm1, %%xmm7 \n" " movhlps %%xmm4, %%xmm0 \n" " movlhps %%xmm5, %%xmm0 \n" " addps %%xmm0, %%xmm4 \n" " addps %%xmm0, %%xmm5 \n" " shufps $0x44, %%xmm4, %%xmm0 \n" " shufps $0xe4, %%xmm5, %%xmm4 \n" " movhlps %%xmm0, %%xmm5 \n" " shufps $0x08, %%xmm4, %%xmm4 \n" " shufps $0x0d, %%xmm5, %%xmm5 \n" " addps %%xmm5, %%xmm4 \n" " movhlps %%xmm6, %%xmm0 \n" " movlhps %%xmm7, %%xmm0 \n" " addps %%xmm0, %%xmm6 \n" " addps %%xmm0, %%xmm7 \n" " shufps $0x44, %%xmm6, %%xmm0 \n" " shufps $0xe4, %%xmm7, %%xmm6 \n" " movhlps %%xmm0, %%xmm7 \n" " shufps $0x08, %%xmm6, %%xmm6 \n" " shufps $0x0d, %%xmm7, %%xmm7 \n" " addps %%xmm7, %%xmm6 \n" " movlhps %%xmm6, %%xmm4 \n" " movaps %%xmm4, (%3,%q0) \n" " movaps %%xmm4, %%xmm0 \n" " shufps $0xff, %%xmm0, %%xmm0 \n" " divps %%xmm0, %%xmm4 \n" " rcpps %%xmm0, %%xmm0 \n" " movhlps %%xmm4, %%xmm0 \n" " shufps $0xe8, %%xmm0, %%xmm0 \n" " movlhps %%xmm0, %%xmm4 \n" " movaps %%xmm4, (%4,%q0) \n" : "+r"(i) : "r"(g_vtxNonTransformed), "r"(&gRSPworldProjectTransported.m[0][0]), "r"(g_vtxTransformed), "r"(g_vecProjected) : "memory", "%xmm0", "%xmm1", "%xmm4", "%xmm5", "%xmm6", "%xmm7" ); } #elif !defined(NO_ASM) // 32-bit GCC assumed void SSEVec3Transform(int i) { asm volatile(" shl $4, %0 \n" " movaps (%1,%0), %%xmm1 \n" " movaps 0(%2), %%xmm4 \n" " movaps 16(%2), %%xmm5 \n" " movaps 32(%2), %%xmm6 \n" " movaps 48(%2), %%xmm7 \n" " mulps %%xmm1, %%xmm4 \n" " mulps %%xmm1, %%xmm5 \n" " mulps %%xmm1, %%xmm6 \n" " mulps %%xmm1, %%xmm7 \n" " movhlps %%xmm4, %%xmm0 \n" " movlhps %%xmm5, %%xmm0 \n" " addps %%xmm0, %%xmm4 \n" " addps %%xmm0, %%xmm5 \n" " shufps $0x44, %%xmm4, %%xmm0 \n" " shufps $0xe4, %%xmm5, %%xmm4 \n" " movhlps %%xmm0, %%xmm5 \n" " shufps $0x08, %%xmm4, %%xmm4 \n" " shufps $0x0d, %%xmm5, %%xmm5 \n" " addps %%xmm5, %%xmm4 \n" " movhlps %%xmm6, %%xmm0 \n" " movlhps %%xmm7, %%xmm0 \n" " addps %%xmm0, %%xmm6 \n" " addps %%xmm0, %%xmm7 \n" " shufps $0x44, %%xmm6, %%xmm0 \n" " shufps $0xe4, %%xmm7, %%xmm6 \n" " movhlps %%xmm0, %%xmm7 \n" " shufps $0x08, %%xmm6, %%xmm6 \n" " shufps $0x0d, %%xmm7, %%xmm7 \n" " addps %%xmm7, %%xmm6 \n" " movlhps %%xmm6, %%xmm4 \n" " movaps %%xmm4, (%3,%0) \n" " movaps %%xmm4, %%xmm0 \n" " shufps $0xff, %%xmm0, %%xmm0 \n" " divps %%xmm0, %%xmm4 \n" " rcpps %%xmm0, %%xmm0 \n" " movhlps %%xmm4, %%xmm0 \n" " shufps $0xe8, %%xmm0, %%xmm0 \n" " movlhps %%xmm0, %%xmm4 \n" " movaps %%xmm4, (%4,%0) \n" : "+r"(i) : "r"(g_vtxNonTransformed), "r"(&gRSPworldProjectTransported.m[0][0]), "r"(g_vtxTransformed), "r"(g_vecProjected) : "memory", "%xmm0", "%xmm1", "%xmm4", "%xmm5", "%xmm6", "%xmm7" ); } #endif float real255 = 255.0f; float real128 = 128.0f; #if !defined(__GNUC__) && !defined(NO_ASM) __declspec( naked ) void __fastcall SSEVec3TransformNormal() { __asm { mov DWORD PTR [g_normal][12], 0; movaps xmm4, DWORD PTR gRSPmodelViewTopTranspose; // row1 movaps xmm5, DWORD PTR gRSPmodelViewTopTranspose[0x10]; // row2 movaps xmm1, DWORD PTR [g_normal]; // xmm1 as the normal vector movaps xmm6, DWORD PTR gRSPmodelViewTopTranspose[0x20]; // row3 mulps xmm4, xmm1; // row 1 mulps xmm5, xmm1; // row 2 mulps xmm6, xmm1; // row 3 movhlps xmm0, xmm4; // xmm4 high to xmm0 low movlhps xmm0, xmm5; // xmm5 low to xmm0 high addps xmm4, xmm0; // result of add are in xmm4 low addps xmm5, xmm0; // result of add are in xmm5 high shufps xmm0, xmm4, 0x44; // move xmm4 low DWORDs to xmm0 high shufps xmm4, xmm5, 0xe4; // move xmm5 high DWORS to xmm4 movhlps xmm5, xmm0; // xmm4, xmm5 are mirrored shufps xmm4, xmm4, 0x08; // move xmm4's 3rd uint32 to its 2nd uint32 shufps xmm5, xmm5, 0x0d; // move xmm5's 4th uint32 to its 2nd uint32, addps xmm4, xmm5; // results are in 1st and 2nd uint32 movaps xmm1,xmm4; mulps xmm1,xmm1; //square movlhps xmm7, xmm1; shufps xmm7, xmm7,0x03; addss xmm7, xmm1; movhlps xmm0, xmm6; // xmm6 high to xmm0 low addps xmm6, xmm0; // result of add are in xmm6 low movlhps xmm0, xmm6; shufps xmm0, xmm0, 0x03; addss xmm0, xmm6; // result of add is at xmm0's 1st uint32 movlhps xmm4, xmm0; mulss xmm0,xmm0; addss xmm7,xmm0; // xmm7 1st uint32 is the sum of squares #ifdef DEBUGGER movaps DWORD PTR [g_normal], xmm4; movss DWORD PTR [g_normal][12], xmm7; #endif xorps xmm0,xmm0; ucomiss xmm0,xmm7; jz l2 rsqrtss xmm7,xmm7; shufps xmm7,xmm7,0; #ifdef DEBUGGER movss DWORD PTR [g_normal][12], xmm7; #endif mulps xmm4,xmm7; movaps DWORD PTR [g_normal], xmm4; // Normalized mov DWORD PTR [g_normal][12], 0; emms; ret; l2: movss DWORD PTR [g_normal], xmm0; movss DWORD PTR [g_normal][12], xmm0; emms; ret; } } #elif defined(__GNUC__) && !defined(NO_ASM) // this code should compile for both 64-bit and 32-bit architectures void SSEVec3TransformNormal(void) { asm volatile(" movl $0, 12(%0) \n" " movaps (%1), %%xmm4 \n" " movaps 16(%1), %%xmm5 \n" " movaps (%0), %%xmm1 \n" " movaps 32(%1), %%xmm6 \n" " mulps %%xmm1, %%xmm4 \n" " mulps %%xmm1, %%xmm5 \n" " mulps %%xmm1, %%xmm6 \n" " movhlps %%xmm4, %%xmm0 \n" " movlhps %%xmm5, %%xmm0 \n" " addps %%xmm0, %%xmm4 \n" " addps %%xmm0, %%xmm5 \n" " shufps $0x44, %%xmm4, %%xmm0 \n" " shufps $0xe4, %%xmm5, %%xmm4 \n" " movhlps %%xmm0, %%xmm5 \n" " shufps $0x08, %%xmm4, %%xmm4 \n" " shufps $0x0d, %%xmm5, %%xmm5 \n" " addps %%xmm5, %%xmm4 \n" " movaps %%xmm4, %%xmm1 \n" " mulps %%xmm1, %%xmm1 \n" " movlhps %%xmm1, %%xmm7 \n" " shufps $0x03, %%xmm7, %%xmm7 \n" " addss %%xmm1, %%xmm7 \n" " movhlps %%xmm6, %%xmm0 \n" " addps %%xmm0, %%xmm6 \n" " movlhps %%xmm6, %%xmm0 \n" " shufps $0x03, %%xmm0, %%xmm0 \n" " addss %%xmm6, %%xmm0 \n" " movlhps %%xmm0, %%xmm4 \n" " mulss %%xmm0, %%xmm0 \n" " addss %%xmm0, %%xmm7 \n" #ifdef DEBUGGER " movaps %%xmm4, (%0) \n" " movss %%xmm7, 12(%0) \n" #endif " xorps %%xmm0, %%xmm0 \n" " ucomiss %%xmm7, %%xmm0 \n" " jz 0f \n" " rsqrtss %%xmm7, %%xmm7 \n" " shufps $0x00, %%xmm7, %%xmm7 \n" #ifdef DEBUGGER " movss %%xmm7, 12(%0) \n" #endif " mulps %%xmm7, %%xmm4 \n" " movaps %%xmm4, (%0) \n" " movl $0, 12(%0) \n" " jmp 1f \n" "0: \n" " movss %%xmm0, (%0) \n" " movss %%xmm0, 12(%0) \n" "1: \n" : : "r"(&g_normal.x), "r"(&gRSPmodelViewTopTranspose.m[0][0]) : "memory", "cc", "%xmm0", "%xmm1", "%xmm4", "%xmm5", "%xmm6", "%xmm7" ); } #endif void NormalizeNormalVec() { float w = 1/sqrtf(g_normal.x*g_normal.x + g_normal.y*g_normal.y + g_normal.z*g_normal.z); g_normal.x *= w; g_normal.y *= w; g_normal.z *= w; } void InitRenderBase() { #if !defined(NO_ASM) if( status.isSSEEnabled && !g_curRomInfo.bPrimaryDepthHack && options.enableHackForGames != HACK_FOR_NASCAR) { ProcessVertexData = ProcessVertexDataSSE; } else #endif { ProcessVertexData = ProcessVertexDataNoSSE; } gRSPfFogMin = gRSPfFogMax = 0.0f; windowSetting.fMultX = windowSetting.fMultY = 2.0f; windowSetting.vpLeftW = windowSetting.vpTopW = 0; windowSetting.vpRightW = windowSetting.vpWidthW = 640; windowSetting.vpBottomW = windowSetting.vpHeightW = 480; gRSP.maxZ = 0; gRSP.nVPLeftN = gRSP.nVPTopN = 0; gRSP.nVPRightN = 640; gRSP.nVPBottomN = 640; gRSP.nVPWidthN = 640; gRSP.nVPHeightN = 640; gRDP.scissor.left=gRDP.scissor.top=0; gRDP.scissor.right=gRDP.scissor.bottom=640; gRSP.bLightingEnable = gRSP.bTextureGen = false; gRSP.curTile=gRSPnumLights=gRSP.ambientLightColor=gRSP.ambientLightIndex= 0; gRSP.fAmbientLightR=gRSP.fAmbientLightG=gRSP.fAmbientLightB=0; gRSP.projectionMtxTop = gRSP.modelViewMtxTop = 0; gRDP.fogColor = gRDP.primitiveColor = gRDP.envColor = gRDP.primitiveDepth = gRDP.primLODMin = gRDP.primLODFrac = gRDP.LODFrac = 0; gRDP.fPrimitiveDepth = 0; gRSP.numVertices = 0; gRSP.maxVertexID = 0; gRSP.bCullFront=false; gRSP.bCullBack=true; gRSP.bFogEnabled=gRDP.bFogEnableInBlender=false; gRSP.bZBufferEnabled=true; gRSP.shadeMode=SHADE_SMOOTH; gRDP.keyR=gRDP.keyG=gRDP.keyB=gRDP.keyA=gRDP.keyRGB=gRDP.keyRGBA = 0; gRDP.fKeyA = 0; gRSP.DKRCMatrixIndex = gRSP.dwDKRVtxAddr = gRSP.dwDKRMatrixAddr = 0; gRSP.DKRBillBoard = false; gRSP.fTexScaleX = 1/32.0f; gRSP.fTexScaleY = 1/32.0f; gRSP.bTextureEnabled = FALSE; gRSP.clip_ratio_left = 0; gRSP.clip_ratio_top = 0; gRSP.clip_ratio_right = 640; gRSP.clip_ratio_bottom = 480; gRSP.clip_ratio_negx = 1; gRSP.clip_ratio_negy = 1; gRSP.clip_ratio_posx = 1; gRSP.clip_ratio_posy = 1; gRSP.real_clip_scissor_left = 0; gRSP.real_clip_scissor_top = 0; gRSP.real_clip_scissor_right = 640; gRSP.real_clip_scissor_bottom = 480; windowSetting.clipping.left = 0; windowSetting.clipping.top = 0; windowSetting.clipping.right = 640; windowSetting.clipping.bottom = 480; windowSetting.clipping.width = 640; windowSetting.clipping.height = 480; windowSetting.clipping.needToClip = false; gRSP.real_clip_ratio_negx = 1; gRSP.real_clip_ratio_negy = 1; gRSP.real_clip_ratio_posx = 1; gRSP.real_clip_ratio_posy = 1; gRSP.DKRCMatrixIndex=0; gRSP.DKRVtxCount=0; gRSP.DKRBillBoard = false; gRSP.dwDKRVtxAddr=0; gRSP.dwDKRMatrixAddr=0; gRDP.geometryMode = 0; gRDP.otherModeL = 0; gRDP.otherModeH = 0; gRDP.fillColor = 0xFFFFFFFF; gRDP.originalFillColor =0; gRSP.ucode = 1; gRSP.vertexMult = 10; gRSP.bNearClip = false; gRSP.bRejectVtx = false; gRDP.texturesAreReloaded = false; gRDP.textureIsChanged = false; gRDP.colorsAreReloaded = false; memset(&gRDP.otherMode,0,sizeof(RDP_OtherMode)); memset(&gRDP.tiles,0,sizeof(Tile)*8); for( int i=0; i fMax ) { float temp = fMin; fMin = fMax; fMax = temp; } { gRSPfFogMin = max(0,fMin/500-1); gRSPfFogMax = fMax/500-1; } gRSPfFogDivider = 255/(gRSPfFogMax-gRSPfFogMin); CRender::g_pRender->SetFogMinMax(fMin, fMax); } void InitVertexColors() { } void InitVertexTextureConstants() { float scaleX; float scaleY; RenderTexture &tex0 = g_textures[gRSP.curTile]; //CTexture *surf = tex0.m_pCTexture; Tile &tile0 = gRDP.tiles[gRSP.curTile]; scaleX = gRSP.fTexScaleX; scaleY = gRSP.fTexScaleY; gRSP.tex0scaleX = scaleX * tile0.fShiftScaleS/tex0.m_fTexWidth; gRSP.tex0scaleY = scaleY * tile0.fShiftScaleT/tex0.m_fTexHeight; gRSP.tex0OffsetX = tile0.fhilite_sl/tex0.m_fTexWidth; gRSP.tex0OffsetY = tile0.fhilite_tl/tex0.m_fTexHeight; if( CRender::g_pRender->IsTexel1Enable() ) { RenderTexture &tex1 = g_textures[(gRSP.curTile+1)&7]; //CTexture *surf = tex1.m_pCTexture; Tile &tile1 = gRDP.tiles[(gRSP.curTile+1)&7]; gRSP.tex1scaleX = scaleX * tile1.fShiftScaleS/tex1.m_fTexWidth; gRSP.tex1scaleY = scaleY * tile1.fShiftScaleT/tex1.m_fTexHeight; gRSP.tex1OffsetX = tile1.fhilite_sl/tex1.m_fTexWidth; gRSP.tex1OffsetY = tile1.fhilite_tl/tex1.m_fTexHeight; } gRSP.texGenXRatio = tile0.fShiftScaleS; gRSP.texGenYRatio = gRSP.fTexScaleX/gRSP.fTexScaleY*tex0.m_fTexWidth/tex0.m_fTexHeight*tile0.fShiftScaleT; } void TexGen(float &s, float &t) { if (gRDP.geometryMode & G_TEXTURE_GEN_LINEAR) { s = acosf(g_normal.x) / 3.14159f; t = acosf(g_normal.y) / 3.14159f; } else { s = 0.5f * ( 1.0f + g_normal.x); t = 0.5f * ( 1.0f - g_normal.y); } } void ComputeLOD(bool openGL) { TLITVERTEX &v0 = g_vtxBuffer[0]; TLITVERTEX &v1 = g_vtxBuffer[1]; RenderTexture &tex0 = g_textures[gRSP.curTile]; float d,dt; if( openGL ) { float x = g_vtxProjected5[0][0] / g_vtxProjected5[0][4] - g_vtxProjected5[1][0] / g_vtxProjected5[1][4]; float y = g_vtxProjected5[0][1] / g_vtxProjected5[0][4] - g_vtxProjected5[1][1] / g_vtxProjected5[1][4]; x = windowSetting.vpWidthW*x/windowSetting.fMultX/2; y = windowSetting.vpHeightW*y/windowSetting.fMultY/2; d = sqrtf(x*x+y*y); } else { float x = (v0.x - v1.x)/ windowSetting.fMultX; float y = (v0.y - v1.y)/ windowSetting.fMultY; d = sqrtf(x*x+y*y); } float s0 = v0.tcord[0].u * tex0.m_fTexWidth; float t0 = v0.tcord[0].v * tex0.m_fTexHeight; float s1 = v1.tcord[0].u * tex0.m_fTexWidth; float t1 = v1.tcord[0].v * tex0.m_fTexHeight; dt = sqrtf((s0-s1)*(s0-s1)+(t0-t1)*(t0-t1)); float lod = dt/d; float frac = log10f(lod)/log10f(2.0f); //DEBUGGER_IF_DUMP(pauseAtNext,{DebuggerAppendMsg("LOD frac = %f", frac);}); frac = (lod / powf(2.0f,floorf(frac))); frac = frac - floorf(frac); //DEBUGGER_IF_DUMP(pauseAtNext,{DebuggerAppendMsg("LOD = %f, frac = %f", lod, frac);}); gRDP.LODFrac = (uint32)(frac*255); CRender::g_pRender->SetCombinerAndBlender(); } bool bHalfTxtScale=false; extern uint32 lastSetTile; void InitVertex(uint32 dwV, uint32 vtxIndex, bool bTexture, bool openGL) { VTX_DUMP(TRACE2("Init vertex (%d) to vtx buf[%d]:", dwV, vtxIndex)); TLITVERTEX &v = g_vtxBuffer[vtxIndex]; VTX_DUMP(TRACE4(" Trans: x=%f, y=%f, z=%f, w=%f", g_vtxTransformed[dwV].x,g_vtxTransformed[dwV].y,g_vtxTransformed[dwV].z,g_vtxTransformed[dwV].w)); if( openGL ) { g_vtxProjected5[vtxIndex][0] = g_vtxTransformed[dwV].x; g_vtxProjected5[vtxIndex][1] = g_vtxTransformed[dwV].y; g_vtxProjected5[vtxIndex][2] = g_vtxTransformed[dwV].z; g_vtxProjected5[vtxIndex][3] = g_vtxTransformed[dwV].w; g_vtxProjected5[vtxIndex][4] = g_vecProjected[dwV].z; if( g_vtxTransformed[dwV].w < 0 ) g_vtxProjected5[vtxIndex][4] = 0; g_vtxIndex[vtxIndex] = vtxIndex; } if( !openGL || options.bOGLVertexClipper == TRUE ) { v.x = g_vecProjected[dwV].x*gRSP.vtxXMul+gRSP.vtxXAdd; v.y = g_vecProjected[dwV].y*gRSP.vtxYMul+gRSP.vtxYAdd; v.z = (g_vecProjected[dwV].z + 1.0f) * 0.5f; // DirectX minZ=0, maxZ=1 //v.z = g_vecProjected[dwV].z; // DirectX minZ=0, maxZ=1 v.rhw = g_vecProjected[dwV].w; VTX_DUMP(TRACE4(" Proj : x=%f, y=%f, z=%f, rhw=%f", v.x,v.y,v.z,v.rhw)); if( gRSP.bProcessSpecularColor ) { v.dcSpecular = CRender::g_pRender->PostProcessSpecularColor(); if( gRSP.bFogEnabled ) { v.dcSpecular &= 0x00FFFFFF; uint32 fogFct = 0xFF-(uint8)((g_fFogCoord[dwV]-gRSPfFogMin)*gRSPfFogDivider); v.dcSpecular |= (fogFct<<24); } } else if( gRSP.bFogEnabled ) { uint32 fogFct = 0xFF-(uint8)((g_fFogCoord[dwV]-gRSPfFogMin)*gRSPfFogDivider); v.dcSpecular = (fogFct<<24); } } VTX_DUMP(TRACE2(" (U,V): %f, %f", g_fVtxTxtCoords[dwV].x,g_fVtxTxtCoords[dwV].y)); v.dcDiffuse = g_dwVtxDifColor[dwV]; if( gRDP.otherMode.key_en ) { v.dcDiffuse &= 0x00FFFFFF; v.dcDiffuse |= (gRDP.keyA<<24); } else if( gRDP.otherMode.aa_en && gRDP.otherMode.clr_on_cvg==0 ) { v.dcDiffuse |= 0xFF000000; } if( gRSP.bProcessDiffuseColor ) { v.dcDiffuse = CRender::g_pRender->PostProcessDiffuseColor(v.dcDiffuse); } if( options.bWinFrameMode ) { v.dcDiffuse = g_dwVtxDifColor[dwV]; } if( openGL ) { g_oglVtxColors[vtxIndex][0] = v.r; g_oglVtxColors[vtxIndex][1] = v.g; g_oglVtxColors[vtxIndex][2] = v.b; g_oglVtxColors[vtxIndex][3] = v.a; } if( bTexture ) { // If the vert is already lit, then there is no normal (and hence we can't generate tex coord) // Only scale if not generated automatically if (gRSP.bTextureGen && gRSP.bLightingEnable) { // Correction for texGen result float u0,u1,v0,v1; RenderTexture &tex0 = g_textures[gRSP.curTile]; u0 = g_fVtxTxtCoords[dwV].x * 32 * 1024 * gRSP.fTexScaleX / tex0.m_fTexWidth; v0 = g_fVtxTxtCoords[dwV].y * 32 * 1024 * gRSP.fTexScaleY / tex0.m_fTexHeight; u0 *= (gRDP.tiles[gRSP.curTile].fShiftScaleS); v0 *= (gRDP.tiles[gRSP.curTile].fShiftScaleT); if( CRender::g_pRender->IsTexel1Enable() ) { RenderTexture &tex1 = g_textures[(gRSP.curTile+1)&7]; u1 = g_fVtxTxtCoords[dwV].x * 32 * 1024 * gRSP.fTexScaleX / tex1.m_fTexWidth; v1 = g_fVtxTxtCoords[dwV].y * 32 * 1024 * gRSP.fTexScaleY / tex1.m_fTexHeight; u1 *= gRDP.tiles[(gRSP.curTile+1)&7].fShiftScaleS; v1 *= gRDP.tiles[(gRSP.curTile+1)&7].fShiftScaleT; CRender::g_pRender->SetVertexTextureUVCoord(v, u0, v0, u1, v1); } else { CRender::g_pRender->SetVertexTextureUVCoord(v, u0, v0); } } else { float tex0u = g_fVtxTxtCoords[dwV].x *gRSP.tex0scaleX - gRSP.tex0OffsetX ; float tex0v = g_fVtxTxtCoords[dwV].y *gRSP.tex0scaleY - gRSP.tex0OffsetY ; if( CRender::g_pRender->IsTexel1Enable() ) { float tex1u = g_fVtxTxtCoords[dwV].x *gRSP.tex1scaleX - gRSP.tex1OffsetX ; float tex1v = g_fVtxTxtCoords[dwV].y *gRSP.tex1scaleY - gRSP.tex1OffsetY ; CRender::g_pRender->SetVertexTextureUVCoord(v, tex0u, tex0v, tex1u, tex1v); VTX_DUMP(TRACE2(" (tex0): %f, %f", tex0u,tex0v)); VTX_DUMP(TRACE2(" (tex1): %f, %f", tex1u,tex1v)); } else { CRender::g_pRender->SetVertexTextureUVCoord(v, tex0u, tex0v); VTX_DUMP(TRACE2(" (tex0): %f, %f", tex0u,tex0v)); } } // Check for txt scale hack if( !bHalfTxtScale && g_curRomInfo.bTextureScaleHack && (gRDP.tiles[lastSetTile].dwSize == TXT_SIZE_32b || gRDP.tiles[lastSetTile].dwSize == TXT_SIZE_4b ) ) { int width = ((gRDP.tiles[lastSetTile].sh-gRDP.tiles[lastSetTile].sl+1)<<1); int height = ((gRDP.tiles[lastSetTile].th-gRDP.tiles[lastSetTile].tl+1)<<1); if( g_fVtxTxtCoords[dwV].x*gRSP.fTexScaleX == width || g_fVtxTxtCoords[dwV].y*gRSP.fTexScaleY == height ) { bHalfTxtScale=true; } } } if( g_curRomInfo.bEnableTxtLOD && vtxIndex == 1 && gRDP.otherMode.text_lod ) { if( CRender::g_pRender->IsTexel1Enable() && CRender::g_pRender->m_pColorCombiner->m_pDecodedMux->isUsed(MUX_LODFRAC) ) { ComputeLOD(openGL); } else { gRDP.LODFrac = 0; } } VTX_DUMP(TRACE2(" DIF(%08X), SPE(%08X)", v.dcDiffuse, v.dcSpecular)); VTX_DUMP(TRACE0("")); } uint32 LightVert(XVECTOR4 & norm, int vidx) { float fCosT; // Do ambient register float r = gRSP.fAmbientLightR; register float g = gRSP.fAmbientLightG; register float b = gRSP.fAmbientLightB; if( options.enableHackForGames != HACK_FOR_ZELDA_MM ) { for (register unsigned int l=0; l < gRSPnumLights; l++) { fCosT = norm.x*gRSPlights[l].x + norm.y*gRSPlights[l].y + norm.z*gRSPlights[l].z; if (fCosT > 0 ) { r += gRSPlights[l].fr * fCosT; g += gRSPlights[l].fg * fCosT; b += gRSPlights[l].fb * fCosT; } } } else { XVECTOR4 v; bool transformed = false; for (register unsigned int l=0; l < gRSPnumLights; l++) { if( gRSPlights[l].range == 0 ) { // Regular directional light fCosT = norm.x*gRSPlights[l].x + norm.y*gRSPlights[l].y + norm.z*gRSPlights[l].z; if (fCosT > 0 ) { r += gRSPlights[l].fr * fCosT; g += gRSPlights[l].fg * fCosT; b += gRSPlights[l].fb * fCosT; } } else //if( (gRSPlights[l].col&0x00FFFFFF) != 0x00FFFFFF ) { // Point light if( !transformed ) { Vec3Transform(&v, (XVECTOR3*)&g_vtxNonTransformed[vidx], &gRSPmodelViewTop); // Convert to w=1 transformed = true; } XVECTOR3 dir(gRSPlights[l].x - v.x, gRSPlights[l].y - v.y, gRSPlights[l].z - v.z); //XVECTOR3 dir(v.x-gRSPlights[l].x, v.y-gRSPlights[l].y, v.z-gRSPlights[l].z); float d2 = sqrtf(dir.x*dir.x+dir.y*dir.y+dir.z*dir.z); dir.x /= d2; dir.y /= d2; dir.z /= d2; fCosT = norm.x*dir.x + norm.y*dir.y + norm.z*dir.z; if (fCosT > 0 ) { //float f = d2/gRSPlights[l].range*50; float f = d2/15000*50; f = 1 - min(f,1); fCosT *= f*f; r += gRSPlights[l].fr * fCosT; g += gRSPlights[l].fg * fCosT; b += gRSPlights[l].fb * fCosT; } } } } if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; return ((0xff000000)|(((uint32)r)<<16)|(((uint32)g)<<8)|((uint32)b)); } uint32 LightVertNew(XVECTOR4 & norm) { float fCosT; // Do ambient register float r = gRSP.fAmbientLightR; register float g = gRSP.fAmbientLightG; register float b = gRSP.fAmbientLightB; for (register unsigned int l=0; l < gRSPnumLights; l++) { fCosT = norm.x*gRSPlights[l].tx + norm.y*gRSPlights[l].ty + norm.z*gRSPlights[l].tz; if (fCosT > 0 ) { r += gRSPlights[l].fr * fCosT; g += gRSPlights[l].fg * fCosT; b += gRSPlights[l].fb * fCosT; } } if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; return ((0xff000000)|(((uint32)r)<<16)|(((uint32)g)<<8)|((uint32)b)); } float zero = 0.0f; float onef = 1.0f; float fcosT; #if !defined(__GNUC__) && !defined(NO_ASM) __declspec( naked ) uint32 __fastcall SSELightVert() { __asm { movaps xmm3, DWORD PTR gRSP; // loading Ambient colors, xmm3 is the result color movaps xmm4, DWORD PTR [g_normal]; // xmm4 is the normal mov ecx, 0; loopback: cmp ecx, DWORD PTR gRSPnumLights; jae breakout; mov eax,ecx; imul eax,0x44; movups xmm5, DWORD PTR gRSPlights[eax]; // Light Dir movups xmm1, DWORD PTR gRSPlights[0x14][eax]; // Light color mulps xmm5, xmm4; // Lightdir * normals movhlps xmm0,xmm5; addps xmm0,xmm5; shufps xmm5,xmm0,0x01; addps xmm0,xmm5; comiss xmm0,zero; jc endloop shufps xmm0,xmm0,0; // fcosT mulps xmm1,xmm0; addps xmm3,xmm1; endloop: inc ecx; jmp loopback; breakout: movss xmm0,DWORD PTR real255; shufps xmm0,xmm0,0; minps xmm0,xmm3; // Without using a memory cvtss2si eax,xmm0; // move the 1st uint32 to eax shl eax,10h; or eax,0FF000000h; shufps xmm0,xmm0,0E5h; // move the 2nd uint32 to the 1st uint32 cvtss2si ecx,xmm0; // move the 1st uint32 to ecx shl ecx,8; or eax,ecx; shufps xmm0,xmm0,0E6h; // Move the 3rd uint32 to the 1st uint32 cvtss2si ecx,xmm0; or eax,ecx; ret; } } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) uint32 SSELightVert(void) { uint32 rval; float f255 = 255.0, fZero = 0.0; asm volatile(" movaps %1, %%xmm3 \n" // xmm3 == gRSP.fAmbientLight{RGBA} " movaps %2, %%xmm4 \n" // xmm4 == g_normal.{xyz} " xor %%rcx, %%rcx \n" "0: \n" " cmpl %3, %%ecx \n" " jae 2f \n" " mov %%rcx, %%rax \n" " imul $0x44, %%rax, %%rax \n" " movups (%4,%%rax,), %%xmm5 \n" // xmm5 == gRSPlights[l].{xyzr} " movups 20(%4,%%rax,), %%xmm1 \n" // xmm1 == gRSPlights[l].{frfgfbfa} " mulps %%xmm4, %%xmm5 \n" " movhlps %%xmm5, %%xmm0 \n" " addps %%xmm5, %%xmm0 \n" " shufps $0x01, %%xmm0, %%xmm5 \n" " addps %%xmm5, %%xmm0 \n" " comiss %6, %%xmm0 \n" " jc 1f \n" " shufps $0x00, %%xmm0, %%xmm0 \n" " mulps %%xmm0, %%xmm1 \n" " addps %%xmm1, %%xmm3 \n" "1: \n" " inc %%rcx \n" " jmp 0b \n" "2: \n" " movss %5, %%xmm0 \n" " shufps $0x00, %%xmm0, %%xmm0 \n" " minps %%xmm3, %%xmm0 \n" " cvtss2si %%xmm0, %%eax \n" " shll $0x10, %%eax \n" " orl $0xff000000, %%eax \n" " shufps $0xe5, %%xmm0, %%xmm0 \n" " cvtss2si %%xmm0, %%ecx \n" " shll $8, %%ecx \n" " orl %%ecx, %%eax \n" " shufps $0xe6, %%xmm0, %%xmm0 \n" " cvtss2si %%xmm0, %%ecx \n" " orl %%ecx, %%eax \n" : "=&a"(rval) : "m"(gRSP), "m"(g_normal), "m"(gRSPnumLights), "r"(gRSPlights), "m"(f255), "m"(fZero) : "%rcx", "memory", "cc", "%xmm0", "%xmm1", "%xmm3", "%xmm4", "%xmm5" ); return rval; } #elif !defined(NO_ASM) // 32-bit GCC assumed uint32 SSELightVert(void) { uint32 rval; float f255 = 255.0, fZero = 0.0; asm volatile(" movaps %1, %%xmm3 \n" " movaps %2, %%xmm4 \n" " xor %%ecx, %%ecx \n" "0: \n" " cmpl %3, %%ecx \n" " jae 2f \n" " mov %%ecx, %%eax \n" " imul $0x44, %%eax, %%eax \n" " movups (%4,%%eax,), %%xmm5 \n" " movups 20(%4,%%eax,), %%xmm1 \n" " mulps %%xmm4, %%xmm5 \n" " movhlps %%xmm5, %%xmm0 \n" " addps %%xmm5, %%xmm0 \n" " shufps $0x01, %%xmm0, %%xmm5 \n" " addps %%xmm5, %%xmm0 \n" " comiss %6, %%xmm0 \n" " jc 1f \n" " shufps $0x00, %%xmm0, %%xmm0 \n" " mulps %%xmm0, %%xmm1 \n" " addps %%xmm1, %%xmm3 \n" "1: \n" " inc %%ecx \n" " jmp 0b \n" "2: \n" " movss %5, %%xmm0 \n" " shufps $0x00, %%xmm0, %%xmm0 \n" " minps %%xmm3, %%xmm0 \n" " cvtss2si %%xmm0, %%eax \n" " shll $0x10, %%eax \n" " orl $0xff000000, %%eax \n" " shufps $0xe5, %%xmm0, %%xmm0 \n" " cvtss2si %%xmm0, %%ecx \n" " shll $8, %%ecx \n" " orl %%ecx, %%eax \n" " shufps $0xe6, %%xmm0, %%xmm0 \n" " cvtss2si %%xmm0, %%ecx \n" " orl %%ecx, %%eax \n" : "=&a"(rval) : "m"(gRSP), "m"(g_normal), "m"(gRSPnumLights), "r"(gRSPlights), "m"(f255), "m"(fZero) : "%rcx", "memory", "cc", "%xmm0", "%xmm1", "%xmm3", "%xmm4", "%xmm5" ); return rval; } #endif inline void ReplaceAlphaWithFogFactor(int i) { if( gRDP.geometryMode & G_FOG ) { // Use fog factor to replace vertex alpha if( g_vecProjected[i].z > 1 ) *(((uint8*)&(g_dwVtxDifColor[i]))+3) = 0xFF; if( g_vecProjected[i].z < 0 ) *(((uint8*)&(g_dwVtxDifColor[i]))+3) = 0; else *(((uint8*)&(g_dwVtxDifColor[i]))+3) = (uint8)(g_vecProjected[i].z*255); } } // Bits // +-+-+- // xxyyzz #define Z_NEG 0x01 #define Z_POS 0x02 #define Y_NEG 0x04 #define Y_POS 0x08 #define X_NEG 0x10 #define X_POS 0x20 // Assumes dwAddr has already been checked! // Don't inline - it's too big with the transform macros #if !defined(NO_ASM) void ProcessVertexDataSSE(uint32 dwAddr, uint32 dwV0, uint32 dwNum) { UpdateCombinedMatrix(); // This function is called upon SPvertex // - do vertex matrix transform // - do vertex lighting // - do texture cooridinate transform if needed // - calculate normal vector // Output: - g_vecProjected[i] -> transformed vertex x,y,z // - g_vecProjected[i].w -> saved vertex 1/w // - g_dwVtxFlags[i] -> flags // - g_dwVtxDifColor[i] -> vertex color // - g_fVtxTxtCoords[i] -> vertex texture cooridinates FiddledVtx * pVtxBase = (FiddledVtx*)(g_pRDRAMu8 + dwAddr); g_pVtxBase = pVtxBase; for (uint32 i = dwV0; i < dwV0 + dwNum; i++) { SP_Timing(RSP_GBI0_Vtx); FiddledVtx & vert = pVtxBase[i - dwV0]; g_vtxNonTransformed[i].x = (float)vert.x; g_vtxNonTransformed[i].y = (float)vert.y; g_vtxNonTransformed[i].z = (float)vert.z; SSEVec3Transform(i); if( gRSP.bFogEnabled ) { g_fFogCoord[i] = g_vecProjected[i].z; if( g_vecProjected[i].w < 0 || g_vecProjected[i].z < 0 || g_fFogCoord[i] < gRSPfFogMin ) g_fFogCoord[i] = gRSPfFogMin; } ReplaceAlphaWithFogFactor(i); VTX_DUMP( { uint32 *dat = (uint32*)(&vert); DebuggerAppendMsg("vtx %d: %08X %08X %08X %08X", i, dat[0],dat[1],dat[2],dat[3]); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vtxTransformed[i].x,g_vtxTransformed[i].y,g_vtxTransformed[i].z,g_vtxTransformed[i].w); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vecProjected[i].x,g_vecProjected[i].y,g_vecProjected[i].z,g_vecProjected[i].w); }); RSP_Vtx_Clipping(i); if( gRSP.bLightingEnable ) { g_normal.x = (float)vert.norma.nx; g_normal.y = (float)vert.norma.ny; g_normal.z = (float)vert.norma.nz; SSEVec3TransformNormal(); if( options.enableHackForGames != HACK_FOR_ZELDA_MM ) g_dwVtxDifColor[i] = SSELightVert(); else g_dwVtxDifColor[i] = LightVert(g_normal, i); *(((uint8*)&(g_dwVtxDifColor[i]))+3) = vert.rgba.a; // still use alpha from the vertex } else { if( (gRDP.geometryMode & G_SHADE) == 0 && gRSP.ucode < 5 ) //Shade is disabled { //FLAT shade g_dwVtxDifColor[i] = gRDP.primitiveColor; } else { register IColor &color = *(IColor*)&g_dwVtxDifColor[i]; color.b = vert.rgba.r; color.g = vert.rgba.g; color.r = vert.rgba.b; color.a = vert.rgba.a; } } if( options.bWinFrameMode ) { g_dwVtxDifColor[i] = COLOR_RGBA(vert.rgba.r, vert.rgba.g, vert.rgba.b, vert.rgba.a); } // Update texture coords n.b. need to divide tu/tv by bogus scale on addition to buffer // If the vert is already lit, then there is no normal (and hence we // can't generate tex coord) if (gRSP.bTextureGen && gRSP.bLightingEnable ) { TexGen(g_fVtxTxtCoords[i].x, g_fVtxTxtCoords[i].y); } else { g_fVtxTxtCoords[i].x = (float)vert.tu; g_fVtxTxtCoords[i].y = (float)vert.tv; } } VTX_DUMP(TRACE2("Setting Vertexes: %d - %d\n", dwV0, dwV0+dwNum-1)); DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{TRACE0("Paused at Vertex Cmd");}); } #endif void ProcessVertexDataNoSSE(uint32 dwAddr, uint32 dwV0, uint32 dwNum) { UpdateCombinedMatrix(); // This function is called upon SPvertex // - do vertex matrix transform // - do vertex lighting // - do texture cooridinate transform if needed // - calculate normal vector // Output: - g_vecProjected[i] -> transformed vertex x,y,z // - g_vecProjected[i].w -> saved vertex 1/w // - g_dwVtxFlags[i] -> flags // - g_dwVtxDifColor[i] -> vertex color // - g_fVtxTxtCoords[i] -> vertex texture cooridinates FiddledVtx * pVtxBase = (FiddledVtx*)(g_pRDRAMu8 + dwAddr); g_pVtxBase = pVtxBase; for (uint32 i = dwV0; i < dwV0 + dwNum; i++) { SP_Timing(RSP_GBI0_Vtx); FiddledVtx & vert = pVtxBase[i - dwV0]; g_vtxNonTransformed[i].x = (float)vert.x; g_vtxNonTransformed[i].y = (float)vert.y; g_vtxNonTransformed[i].z = (float)vert.z; Vec3Transform(&g_vtxTransformed[i], (XVECTOR3*)&g_vtxNonTransformed[i], &gRSPworldProject); // Convert to w=1 g_vecProjected[i].w = 1.0f / g_vtxTransformed[i].w; g_vecProjected[i].x = g_vtxTransformed[i].x * g_vecProjected[i].w; g_vecProjected[i].y = g_vtxTransformed[i].y * g_vecProjected[i].w; if ((g_curRomInfo.bPrimaryDepthHack || options.enableHackForGames == HACK_FOR_NASCAR ) && gRDP.otherMode.depth_source ) { g_vecProjected[i].z = gRDP.fPrimitiveDepth; g_vtxTransformed[i].z = gRDP.fPrimitiveDepth*g_vtxTransformed[i].w; } else { g_vecProjected[i].z = g_vtxTransformed[i].z * g_vecProjected[i].w; } if( gRSP.bFogEnabled ) { g_fFogCoord[i] = g_vecProjected[i].z; if( g_vecProjected[i].w < 0 || g_vecProjected[i].z < 0 || g_fFogCoord[i] < gRSPfFogMin ) g_fFogCoord[i] = gRSPfFogMin; } VTX_DUMP( { uint32 *dat = (uint32*)(&vert); DebuggerAppendMsg("vtx %d: %08X %08X %08X %08X", i, dat[0],dat[1],dat[2],dat[3]); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vtxTransformed[i].x,g_vtxTransformed[i].y,g_vtxTransformed[i].z,g_vtxTransformed[i].w); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vecProjected[i].x,g_vecProjected[i].y,g_vecProjected[i].z,g_vecProjected[i].w); }); RSP_Vtx_Clipping(i); if( gRSP.bLightingEnable ) { g_normal.x = (float)vert.norma.nx; g_normal.y = (float)vert.norma.ny; g_normal.z = (float)vert.norma.nz; Vec3TransformNormal(g_normal, gRSPmodelViewTop); g_dwVtxDifColor[i] = LightVert(g_normal, i); *(((uint8*)&(g_dwVtxDifColor[i]))+3) = vert.rgba.a; // still use alpha from the vertex } else { if( (gRDP.geometryMode & G_SHADE) == 0 && gRSP.ucode < 5 ) //Shade is disabled { //FLAT shade g_dwVtxDifColor[i] = gRDP.primitiveColor; } else { register IColor &color = *(IColor*)&g_dwVtxDifColor[i]; color.b = vert.rgba.r; color.g = vert.rgba.g; color.r = vert.rgba.b; color.a = vert.rgba.a; } } if( options.bWinFrameMode ) { g_dwVtxDifColor[i] = COLOR_RGBA(vert.rgba.r, vert.rgba.g, vert.rgba.b, vert.rgba.a); } ReplaceAlphaWithFogFactor(i); // Update texture coords n.b. need to divide tu/tv by bogus scale on addition to buffer // If the vert is already lit, then there is no normal (and hence we // can't generate tex coord) if (gRSP.bTextureGen && gRSP.bLightingEnable ) { TexGen(g_fVtxTxtCoords[i].x, g_fVtxTxtCoords[i].y); } else { g_fVtxTxtCoords[i].x = (float)vert.tu; g_fVtxTxtCoords[i].y = (float)vert.tv; } } VTX_DUMP(TRACE2("Setting Vertexes: %d - %d\n", dwV0, dwV0+dwNum-1)); DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{TRACE0("Paused at Vertex Cmd");}); } bool PrepareTriangle(uint32 dwV0, uint32 dwV1, uint32 dwV2) { if( status.isVertexShaderEnabled || status.bUseHW_T_L ) { g_vtxIndex[gRSP.numVertices++] = dwV0; g_vtxIndex[gRSP.numVertices++] = dwV1; g_vtxIndex[gRSP.numVertices++] = dwV2; status.dwNumTrisRendered++; gRSP.maxVertexID = max(gRSP.maxVertexID,max(dwV0,max(dwV1,dwV2))); } else { SP_Timing(SP_Each_Triangle); bool textureFlag = (CRender::g_pRender->IsTextureEnabled() || gRSP.ucode == 6 ); bool openGL = CDeviceBuilder::m_deviceGeneralType == OGL_DEVICE; InitVertex(dwV0, gRSP.numVertices, textureFlag, openGL); InitVertex(dwV1, gRSP.numVertices+1, textureFlag, openGL); InitVertex(dwV2, gRSP.numVertices+2, textureFlag, openGL); gRSP.numVertices += 3; status.dwNumTrisRendered++; } return true; } // Returns TRUE if it thinks the triangle is visible // Returns FALSE if it is clipped bool IsTriangleVisible(uint32 dwV0, uint32 dwV1, uint32 dwV2) { //return true; //fix me if( status.isVertexShaderEnabled || status.bUseHW_T_L ) return true; // We won't have access to transformed vertex data DEBUGGER_ONLY_IF( (!debuggerEnableTestTris || !debuggerEnableCullFace), {return TRUE;}); #ifdef DEBUGGER // Check vertices are valid! if (dwV0 >= MAX_VERTS || dwV1 >= MAX_VERTS || dwV2 >= MAX_VERTS) return false; #endif // Here we AND all the flags. If any of the bits is set for all // 3 vertices, it means that all three x, y or z lie outside of // the current viewing volume. // Currently disabled - still seems a bit dodgy if ((gRSP.bCullFront || gRSP.bCullBack) && gRDP.otherMode.zmode != 3) { XVECTOR4 & v0 = g_vecProjected[dwV0]; XVECTOR4 & v1 = g_vecProjected[dwV1]; XVECTOR4 & v2 = g_vecProjected[dwV2]; // Only try to clip if the tri is onscreen. For some reason, this // method doesnt' work well when the z value is outside of screenspace //if (v0.z < 1 && v1.z < 1 && v2.z < 1) { float V1 = v2.x - v0.x; float V2 = v2.y - v0.y; float W1 = v2.x - v1.x; float W2 = v2.y - v1.y; float fDirection = (V1 * W2) - (V2 * W1); fDirection = fDirection * v1.w * v2.w * v0.w; //float fDirection = v0.x*v1.y-v1.x*v0.y+v1.x*v2.y-v2.x*v1.y+v2.x*v0.y-v0.x*v2.y; if (fDirection < 0 && gRSP.bCullBack) { status.dwNumTrisClipped++; return false; } else if (fDirection > 0 && gRSP.bCullFront) { status.dwNumTrisClipped++; return false; } } } #ifdef ENABLE_CLIP_TRI //if( gRSP.bRejectVtx && (g_clipFlag[dwV0]|g_clipFlag[dwV1]|g_clipFlag[dwV2]) ) // return; if( g_clipFlag2[dwV0]&g_clipFlag2[dwV1]&g_clipFlag2[dwV2] ) { //DebuggerAppendMsg("Clipped"); return false; } #endif return true; } void SetPrimitiveColor(uint32 dwCol, uint32 LODMin, uint32 LODFrac) { gRDP.colorsAreReloaded = true; gRDP.primitiveColor = dwCol; gRDP.primLODMin = LODMin; gRDP.primLODFrac = LODFrac; if( gRDP.primLODFrac < gRDP.primLODMin ) { gRDP.primLODFrac = gRDP.primLODMin; } gRDP.fvPrimitiveColor[0] = ((dwCol>>16)&0xFF)/255.0f; //r gRDP.fvPrimitiveColor[1] = ((dwCol>>8)&0xFF)/255.0f; //g gRDP.fvPrimitiveColor[2] = ((dwCol)&0xFF)/255.0f; //b gRDP.fvPrimitiveColor[3] = ((dwCol>>24)&0xFF)/255.0f; //a } void SetPrimitiveDepth(uint32 z, uint32 dwDZ) { gRDP.primitiveDepth = z & 0x7FFF; gRDP.fPrimitiveDepth = (float)(gRDP.primitiveDepth)/(float)0x8000; //gRDP.fPrimitiveDepth = gRDP.fPrimitiveDepth*2-1; /* z=0xFFFF -> 1 the farest z=0 -> -1 the nearest */ //how to use dwDZ? #ifdef DEBUGGER if( (pauseAtNext && (eventToPause == NEXT_VERTEX_CMD || eventToPause == NEXT_FLUSH_TRI )) )//&& logTriangles ) { DebuggerAppendMsg("Set prim Depth: %f, (%08X, %08X)", gRDP.fPrimitiveDepth, z, dwDZ); } #endif } void SetVertexXYZ(uint32 vertex, float x, float y, float z) { g_vecProjected[vertex].x = x; g_vecProjected[vertex].y = y; g_vecProjected[vertex].z = z; g_vtxTransformed[vertex].x = x*g_vtxTransformed[vertex].w; g_vtxTransformed[vertex].y = y*g_vtxTransformed[vertex].w; g_vtxTransformed[vertex].z = z*g_vtxTransformed[vertex].w; } void ModifyVertexInfo(uint32 where, uint32 vertex, uint32 val) { switch (where) { case RSP_MV_WORD_OFFSET_POINT_RGBA: // Modify RGBA { uint32 r = (val>>24)&0xFF; uint32 g = (val>>16)&0xFF; uint32 b = (val>>8)&0xFF; uint32 a = val&0xFF; g_dwVtxDifColor[vertex] = COLOR_RGBA(r, g, b, a); LOG_UCODE("Modify vert %d color, 0x%08x", vertex, g_dwVtxDifColor[vertex]); } break; case RSP_MV_WORD_OFFSET_POINT_XYSCREEN: // Modify X,Y { uint16 nX = (uint16)(val>>16); short x = *((short*)&nX); x /= 4; uint16 nY = (uint16)(val&0xFFFF); short y = *((short*)&nY); y /= 4; // Should do viewport transform. x -= windowSetting.uViWidth/2; y = windowSetting.uViHeight/2-y; if( options.bEnableHacks && ((*g_GraphicsInfo.VI_X_SCALE_REG)&0xF) != 0 ) { // Tarzan // I don't know why Tarzan is different SetVertexXYZ(vertex, x/windowSetting.fViWidth, y/windowSetting.fViHeight, g_vecProjected[vertex].z); } else { // Toy Story 2 and other games SetVertexXYZ(vertex, x*2/windowSetting.fViWidth, y*2/windowSetting.fViHeight, g_vecProjected[vertex].z); } LOG_UCODE("Modify vert %d: x=%d, y=%d", vertex, x, y); VTX_DUMP(TRACE3("Modify vert %d: (%d,%d)", vertex, x, y)); } break; case RSP_MV_WORD_OFFSET_POINT_ZSCREEN: // Modify C { int z = val>>16; SetVertexXYZ(vertex, g_vecProjected[vertex].x, g_vecProjected[vertex].y, (((float)z/0x03FF)+0.5f)/2.0f ); LOG_UCODE("Modify vert %d: z=%d", vertex, z); VTX_DUMP(TRACE2("Modify vert %d: z=%d", vertex, z)); } break; case RSP_MV_WORD_OFFSET_POINT_ST: // Texture { short tu = short(val>>16); short tv = short(val & 0xFFFF); float ftu = tu / 32.0f; float ftv = tv / 32.0f; LOG_UCODE(" Setting vertex %d tu/tv to %f, %f", vertex, (float)tu, (float)tv); CRender::g_pRender->SetVtxTextureCoord(vertex, ftu/gRSP.fTexScaleX, ftv/gRSP.fTexScaleY); } break; } DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{TRACE0("Paused at ModVertex Cmd");}); } void ProcessVertexDataDKR(uint32 dwAddr, uint32 dwV0, uint32 dwNum) { UpdateCombinedMatrix(); long long pVtxBase = (long long) (g_pRDRAMu8 + dwAddr); g_pVtxBase = (FiddledVtx*)pVtxBase; Matrix &matWorldProject = gRSP.DKRMatrixes[gRSP.DKRCMatrixIndex]; int nOff; bool addbase=false; if ((!gRSP.DKRBillBoard) || (gRSP.DKRCMatrixIndex != 2) ) addbase = false; else addbase = true; if( addbase && gRSP.DKRVtxCount == 0 && dwNum > 1 ) { gRSP.DKRVtxCount++; } LOG_UCODE(" ProcessVertexDataDKR, CMatrix = %d, Add base=%s", gRSP.DKRCMatrixIndex, gRSP.DKRBillBoard?"true":"false"); VTX_DUMP(TRACE2("DKR Setting Vertexes\nCMatrix = %d, Add base=%s", gRSP.DKRCMatrixIndex, gRSP.DKRBillBoard?"true":"false")); nOff = 0; uint32 end = dwV0 + dwNum; for (uint32 i = dwV0; i < end; i++) { XVECTOR3 w; g_vtxNonTransformed[i].x = (float)*(short*)((pVtxBase+nOff + 0) ^ 2); g_vtxNonTransformed[i].y = (float)*(short*)((pVtxBase+nOff + 2) ^ 2); g_vtxNonTransformed[i].z = (float)*(short*)((pVtxBase+nOff + 4) ^ 2); //if( status.isSSEEnabled ) // SSEVec3TransformDKR(g_vtxTransformed[i], g_vtxNonTransformed[i]); //else Vec3Transform(&g_vtxTransformed[i], (XVECTOR3*)&g_vtxNonTransformed[i], &matWorldProject); // Convert to w=1 if( gRSP.DKRVtxCount == 0 && dwNum==1 ) { gRSP.DKRBaseVec.x = g_vtxTransformed[i].x; gRSP.DKRBaseVec.y = g_vtxTransformed[i].y; gRSP.DKRBaseVec.z = g_vtxTransformed[i].z; gRSP.DKRBaseVec.w = g_vtxTransformed[i].w; } else if( addbase ) { g_vtxTransformed[i].x += gRSP.DKRBaseVec.x; g_vtxTransformed[i].y += gRSP.DKRBaseVec.y; g_vtxTransformed[i].z += gRSP.DKRBaseVec.z; g_vtxTransformed[i].w = gRSP.DKRBaseVec.w; } g_vecProjected[i].w = 1.0f / g_vtxTransformed[i].w; g_vecProjected[i].x = g_vtxTransformed[i].x * g_vecProjected[i].w; g_vecProjected[i].y = g_vtxTransformed[i].y * g_vecProjected[i].w; g_vecProjected[i].z = g_vtxTransformed[i].z * g_vecProjected[i].w; gRSP.DKRVtxCount++; VTX_DUMP(TRACE5("vtx %d: %f, %f, %f, %f", i, g_vtxTransformed[i].x,g_vtxTransformed[i].y,g_vtxTransformed[i].z,g_vtxTransformed[i].w)); if( gRSP.bFogEnabled ) { g_fFogCoord[i] = g_vecProjected[i].z; if( g_vecProjected[i].w < 0 || g_vecProjected[i].z < 0 || g_fFogCoord[i] < gRSPfFogMin ) g_fFogCoord[i] = gRSPfFogMin; } RSP_Vtx_Clipping(i); short wA = *(short*)((pVtxBase+nOff + 6) ^ 2); short wB = *(short*)((pVtxBase+nOff + 8) ^ 2); s8 r = (s8)(wA >> 8); s8 g = (s8)(wA); s8 b = (s8)(wB >> 8); s8 a = (s8)(wB); if (gRSP.bLightingEnable) { g_normal.x = (char)r; //norma.nx; g_normal.y = (char)g; //norma.ny; g_normal.z = (char)b; //norma.nz; Vec3TransformNormal(g_normal, matWorldProject) #if !defined(NO_ASM) if( status.isSSEEnabled ) g_dwVtxDifColor[i] = SSELightVert(); else #endif g_dwVtxDifColor[i] = LightVert(g_normal, i); } else { int nR, nG, nB, nA; nR = r; nG = g; nB = b; nA = a; // Assign true vert colour after lighting/fogging g_dwVtxDifColor[i] = COLOR_RGBA(nR, nG, nB, nA); } ReplaceAlphaWithFogFactor(i); g_fVtxTxtCoords[i].x = g_fVtxTxtCoords[i].y = 1; nOff += 10; } DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{DebuggerAppendMsg("Paused at DKR Vertex Cmd, v0=%d, vn=%d, addr=%08X", dwV0, dwNum, dwAddr);}); } extern uint32 dwPDCIAddr; void ProcessVertexDataPD(uint32 dwAddr, uint32 dwV0, uint32 dwNum) { UpdateCombinedMatrix(); N64VtxPD * pVtxBase = (N64VtxPD*)(g_pRDRAMu8 + dwAddr); g_pVtxBase = (FiddledVtx*)pVtxBase; // Fix me for (uint32 i = dwV0; i < dwV0 + dwNum; i++) { N64VtxPD &vert = pVtxBase[i - dwV0]; g_vtxNonTransformed[i].x = (float)vert.x; g_vtxNonTransformed[i].y = (float)vert.y; g_vtxNonTransformed[i].z = (float)vert.z; #if !defined(NO_ASM) if( status.isSSEEnabled ) SSEVec3Transform(i); else #endif { Vec3Transform(&g_vtxTransformed[i], (XVECTOR3*)&g_vtxNonTransformed[i], &gRSPworldProject); // Convert to w=1 g_vecProjected[i].w = 1.0f / g_vtxTransformed[i].w; g_vecProjected[i].x = g_vtxTransformed[i].x * g_vecProjected[i].w; g_vecProjected[i].y = g_vtxTransformed[i].y * g_vecProjected[i].w; g_vecProjected[i].z = g_vtxTransformed[i].z * g_vecProjected[i].w; } g_fFogCoord[i] = g_vecProjected[i].z; if( g_vecProjected[i].w < 0 || g_vecProjected[i].z < 0 || g_fFogCoord[i] < gRSPfFogMin ) g_fFogCoord[i] = gRSPfFogMin; RSP_Vtx_Clipping(i); uint8 *addr = g_pRDRAMu8+dwPDCIAddr+ (vert.cidx&0xFF); uint32 a = addr[0]; uint32 r = addr[3]; uint32 g = addr[2]; uint32 b = addr[1]; if( gRSP.bLightingEnable ) { g_normal.x = (char)r; g_normal.y = (char)g; g_normal.z = (char)b; #if !defined(NO_ASM) if( status.isSSEEnabled ) { SSEVec3TransformNormal(); g_dwVtxDifColor[i] = SSELightVert(); } else #endif { Vec3TransformNormal(g_normal, gRSPmodelViewTop); g_dwVtxDifColor[i] = LightVert(g_normal, i); } *(((uint8*)&(g_dwVtxDifColor[i]))+3) = (uint8)a; // still use alpha from the vertex } else { if( (gRDP.geometryMode & G_SHADE) == 0 && gRSP.ucode < 5 ) //Shade is disabled { g_dwVtxDifColor[i] = gRDP.primitiveColor; } else //FLAT shade { g_dwVtxDifColor[i] = COLOR_RGBA(r, g, b, a); } } if( options.bWinFrameMode ) { g_dwVtxDifColor[i] = COLOR_RGBA(r, g, b, a); } ReplaceAlphaWithFogFactor(i); VECTOR2 & t = g_fVtxTxtCoords[i]; if (gRSP.bTextureGen && gRSP.bLightingEnable ) { // Not sure if we should transform the normal here //Matrix & matWV = gRSP.projectionMtxs[gRSP.projectionMtxTop]; //Vec3TransformNormal(g_normal, matWV); TexGen(g_fVtxTxtCoords[i].x, g_fVtxTxtCoords[i].y); } else { t.x = vert.s; t.y = vert.t; } VTX_DUMP( { DebuggerAppendMsg("vtx %d: %d %d %d", i, vert.x,vert.y,vert.z); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vtxTransformed[i].x,g_vtxTransformed[i].y,g_vtxTransformed[i].z,g_vtxTransformed[i].w); DebuggerAppendMsg(" : %X, %X, %X, %X", r,g,b,a); DebuggerAppendMsg(" : u=%f, v=%f", t.x, t.y); }); } VTX_DUMP(TRACE2("Setting Vertexes: %d - %d\n", dwV0, dwV0+dwNum-1)); DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{TRACE0("Paused at Vertex Cmd");}); } extern uint32 dwConkerVtxZAddr; void ProcessVertexDataConker(uint32 dwAddr, uint32 dwV0, uint32 dwNum) { UpdateCombinedMatrix(); FiddledVtx * pVtxBase = (FiddledVtx*)(g_pRDRAMu8 + dwAddr); g_pVtxBase = pVtxBase; //short *vertexColoraddr = (short*)(g_pRDRAMu8+dwConkerVtxZAddr); for (uint32 i = dwV0; i < dwV0 + dwNum; i++) { SP_Timing(RSP_GBI0_Vtx); FiddledVtx & vert = pVtxBase[i - dwV0]; g_vtxNonTransformed[i].x = (float)vert.x; g_vtxNonTransformed[i].y = (float)vert.y; g_vtxNonTransformed[i].z = (float)vert.z; #if !defined(NO_ASM) if( status.isSSEEnabled ) SSEVec3Transform(i); else #endif { Vec3Transform(&g_vtxTransformed[i], (XVECTOR3*)&g_vtxNonTransformed[i], &gRSPworldProject); // Convert to w=1 g_vecProjected[i].w = 1.0f / g_vtxTransformed[i].w; g_vecProjected[i].x = g_vtxTransformed[i].x * g_vecProjected[i].w; g_vecProjected[i].y = g_vtxTransformed[i].y * g_vecProjected[i].w; g_vecProjected[i].z = g_vtxTransformed[i].z * g_vecProjected[i].w; } g_fFogCoord[i] = g_vecProjected[i].z; if( g_vecProjected[i].w < 0 || g_vecProjected[i].z < 0 || g_fFogCoord[i] < gRSPfFogMin ) g_fFogCoord[i] = gRSPfFogMin; VTX_DUMP( { uint32 *dat = (uint32*)(&vert); DebuggerAppendMsg("vtx %d: %08X %08X %08X %08X", i, dat[0],dat[1],dat[2],dat[3]); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vtxTransformed[i].x,g_vtxTransformed[i].y,g_vtxTransformed[i].z,g_vtxTransformed[i].w); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vecProjected[i].x,g_vecProjected[i].y,g_vecProjected[i].z,g_vecProjected[i].w); }); RSP_Vtx_Clipping(i); if( gRSP.bLightingEnable ) { { uint32 r= ((gRSP.ambientLightColor>>16)&0xFF); uint32 g= ((gRSP.ambientLightColor>> 8)&0xFF); uint32 b= ((gRSP.ambientLightColor )&0xFF); for( uint32 k=1; k<=gRSPnumLights; k++) { r += gRSPlights[k].r; g += gRSPlights[k].g; b += gRSPlights[k].b; } if( r>255 ) r=255; if( g>255 ) g=255; if( b>255 ) b=255; r *= vert.rgba.r ; g *= vert.rgba.g ; b *= vert.rgba.b ; r >>= 8; g >>= 8; b >>= 8; g_dwVtxDifColor[i] = 0xFF000000; g_dwVtxDifColor[i] |= (r<<16); g_dwVtxDifColor[i] |= (g<< 8); g_dwVtxDifColor[i] |= (b ); } *(((uint8*)&(g_dwVtxDifColor[i]))+3) = vert.rgba.a; // still use alpha from the vertex } else { if( (gRDP.geometryMode & G_SHADE) == 0 && gRSP.ucode < 5 ) //Shade is disabled { g_dwVtxDifColor[i] = gRDP.primitiveColor; } else //FLAT shade { g_dwVtxDifColor[i] = COLOR_RGBA(vert.rgba.r, vert.rgba.g, vert.rgba.b, vert.rgba.a); } } if( options.bWinFrameMode ) { //g_vecProjected[i].z = 0; g_dwVtxDifColor[i] = COLOR_RGBA(vert.rgba.r, vert.rgba.g, vert.rgba.b, vert.rgba.a); } ReplaceAlphaWithFogFactor(i); // Update texture coords n.b. need to divide tu/tv by bogus scale on addition to buffer //VECTOR2 & t = g_fVtxTxtCoords[i]; // If the vert is already lit, then there is no normal (and hence we // can't generate tex coord) if (gRSP.bTextureGen && gRSP.bLightingEnable ) { g_normal.x = (float)*(char*)(g_pRDRAMu8+ (((i<<1)+0)^3)+dwConkerVtxZAddr); g_normal.y = (float)*(char*)(g_pRDRAMu8+ (((i<<1)+1)^3)+dwConkerVtxZAddr); g_normal.z = (float)*(char*)(g_pRDRAMu8+ (((i<<1)+2)^3)+dwConkerVtxZAddr); Vec3TransformNormal(g_normal, gRSPmodelViewTop); TexGen(g_fVtxTxtCoords[i].x, g_fVtxTxtCoords[i].y); } else { g_fVtxTxtCoords[i].x = (float)vert.tu; g_fVtxTxtCoords[i].y = (float)vert.tv; } } VTX_DUMP(TRACE2("Setting Vertexes: %d - %d\n", dwV0, dwV0+dwNum-1)); DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{DebuggerAppendMsg("Paused at Vertex Cmd");}); } typedef struct{ short y; short x; short flag; short z; } RS_Vtx_XYZ; typedef union { struct { uint8 a; uint8 b; uint8 g; uint8 r; }; struct { char na; //a char nz; //b char ny; //g char nx; //r }; } RS_Vtx_Color; void ProcessVertexData_Rogue_Squadron(uint32 dwXYZAddr, uint32 dwColorAddr, uint32 dwXYZCmd, uint32 dwColorCmd) { UpdateCombinedMatrix(); uint32 dwV0 = 0; uint32 dwNum = (dwXYZCmd&0xFF00)>>10; RS_Vtx_XYZ * pVtxXYZBase = (RS_Vtx_XYZ*)(g_pRDRAMu8 + dwXYZAddr); RS_Vtx_Color * pVtxColorBase = (RS_Vtx_Color*)(g_pRDRAMu8 + dwColorAddr); uint32 i; for (i = dwV0; i < dwV0 + dwNum; i++) { RS_Vtx_XYZ & vertxyz = pVtxXYZBase[i - dwV0]; RS_Vtx_Color & vertcolors = pVtxColorBase[i - dwV0]; g_vtxNonTransformed[i].x = (float)vertxyz.x; g_vtxNonTransformed[i].y = (float)vertxyz.y; g_vtxNonTransformed[i].z = (float)vertxyz.z; #if !defined(NO_ASM) if( status.isSSEEnabled ) SSEVec3Transform(i); else #endif { Vec3Transform(&g_vtxTransformed[i], (XVECTOR3*)&g_vtxNonTransformed[i], &gRSPworldProject); // Convert to w=1 g_vecProjected[i].w = 1.0f / g_vtxTransformed[i].w; g_vecProjected[i].x = g_vtxTransformed[i].x * g_vecProjected[i].w; g_vecProjected[i].y = g_vtxTransformed[i].y * g_vecProjected[i].w; g_vecProjected[i].z = g_vtxTransformed[i].z * g_vecProjected[i].w; } VTX_DUMP( { DebuggerAppendMsg(" : %f, %f, %f, %f", g_vtxTransformed[i].x,g_vtxTransformed[i].y,g_vtxTransformed[i].z,g_vtxTransformed[i].w); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vecProjected[i].x,g_vecProjected[i].y,g_vecProjected[i].z,g_vecProjected[i].w); }); g_fFogCoord[i] = g_vecProjected[i].z; if( g_vecProjected[i].w < 0 || g_vecProjected[i].z < 0 || g_fFogCoord[i] < gRSPfFogMin ) g_fFogCoord[i] = gRSPfFogMin; RSP_Vtx_Clipping(i); if( gRSP.bLightingEnable ) { g_normal.x = (float)vertcolors.nx; g_normal.y = (float)vertcolors.ny; g_normal.z = (float)vertcolors.nz; #if !defined(NO_ASM) if( status.isSSEEnabled ) { SSEVec3TransformNormal(); g_dwVtxDifColor[i] = SSELightVert(); } else #endif { Vec3TransformNormal(g_normal, gRSPmodelViewTop); g_dwVtxDifColor[i] = LightVert(g_normal, i); } *(((uint8*)&(g_dwVtxDifColor[i]))+3) = vertcolors.a; // still use alpha from the vertex } else { if( (gRDP.geometryMode & G_SHADE) == 0 && gRSP.ucode < 5 ) //Shade is disabled { g_dwVtxDifColor[i] = gRDP.primitiveColor; } else //FLAT shade { g_dwVtxDifColor[i] = COLOR_RGBA(vertcolors.r, vertcolors.g, vertcolors.b, vertcolors.a); } } if( options.bWinFrameMode ) { g_dwVtxDifColor[i] = COLOR_RGBA(vertcolors.r, vertcolors.g, vertcolors.b, vertcolors.a); } ReplaceAlphaWithFogFactor(i); /* // Update texture coords n.b. need to divide tu/tv by bogus scale on addition to buffer VECTOR2 & t = g_fVtxTxtCoords[i]; // If the vert is already lit, then there is no normal (and hence we // can't generate tex coord) if (gRSP.bTextureGen && gRSP.bLightingEnable && g_textures[gRSP.curTile].m_bTextureEnable ) { TexGen(g_fVtxTxtCoords[i].x, g_fVtxTxtCoords[i].y); } else { t.x = (float)vert.tu; t.y = (float)vert.tv; } */ } VTX_DUMP(TRACE2("Setting Vertexes: %d - %d\n", dwV0, dwV0+dwNum-1)); DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{TRACE0("Paused at Vertex Cmd");}); } void SetLightCol(uint32 dwLight, uint32 dwCol) { gRSPlights[dwLight].r = (uint8)((dwCol >> 24)&0xFF); gRSPlights[dwLight].g = (uint8)((dwCol >> 16)&0xFF); gRSPlights[dwLight].b = (uint8)((dwCol >> 8)&0xFF); gRSPlights[dwLight].a = 255; // Ignore light alpha gRSPlights[dwLight].fr = (float)gRSPlights[dwLight].r; gRSPlights[dwLight].fg = (float)gRSPlights[dwLight].g; gRSPlights[dwLight].fb = (float)gRSPlights[dwLight].b; gRSPlights[dwLight].fa = 255; // Ignore light alpha //TRACE1("Set light %d color", dwLight); LIGHT_DUMP(TRACE2("Set Light %d color: %08X", dwLight, dwCol)); } void SetLightDirection(uint32 dwLight, float x, float y, float z, float range) { //gRSP.bLightIsUpdated = true; //gRSPlights[dwLight].ox = x; //gRSPlights[dwLight].oy = y; //gRSPlights[dwLight].oz = z; register float w = range == 0 ? (float)sqrt(x*x+y*y+z*z) : 1; gRSPlights[dwLight].x = x/w; gRSPlights[dwLight].y = y/w; gRSPlights[dwLight].z = z/w; gRSPlights[dwLight].range = range; DEBUGGER_PAUSE_AND_DUMP(NEXT_SET_LIGHT,TRACE5("Set Light %d dir: %.4f, %.4f, %.4f, %.4f", dwLight, x, y, z, range)); } static float maxS0, maxT0; static float maxS1, maxT1; static bool validS0, validT0; static bool validS1, validT1; void LogTextureCoords(float fTex0S, float fTex0T, float fTex1S, float fTex1T) { if( validS0 ) { if( fTex0S<0 || fTex0S>maxS0 ) validS0 = false; } if( validT0 ) { if( fTex0T<0 || fTex0T>maxT0 ) validT0 = false; } if( validS1 ) { if( fTex1S<0 || fTex1S>maxS1 ) validS1 = false; } if( validT1 ) { if( fTex1T<0 || fTex1T>maxT1 ) validT1 = false; } } bool CheckTextureCoords(int tex) { if( tex==0 ) { return validS0&&validT0; } else { return validS1&&validT1; } } void ResetTextureCoordsLog(float maxs0, float maxt0, float maxs1, float maxt1) { maxS0 = maxs0; maxT0 = maxt0; maxS1 = maxs1; maxT1 = maxt1; validS0 = validT0 = true; validS1 = validT1 = true; } void ForceMainTextureIndex(int dwTile) { if( dwTile == 1 && !(CRender::g_pRender->IsTexel0Enable()) && CRender::g_pRender->IsTexel1Enable() ) { // Hack gRSP.curTile = 0; } else { gRSP.curTile = dwTile; } } float HackZ2(float z) { z = (z+9)/10; return z; } float HackZ(float z) { return HackZ2(z); if( z < 0.1 && z >= 0 ) z = (.1f+z)/2; else if( z < 0 ) //return (10+z)/100; z = (expf(z)/20); return z; } void HackZ(std::vector& points) { int size = points.size(); for( int i=0; i>16)&0xFF)/255.0f; //r gRDP.fvEnvColor[1] = ((dwCol>>8)&0xFF)/255.0f; //g gRDP.fvEnvColor[2] = ((dwCol)&0xFF)/255.0f; //b gRDP.fvEnvColor[3] = ((dwCol>>24)&0xFF)/255.0f; //a } inline uint32 GetEnvColor() { return gRDP.envColor; } inline float* GetEnvColorfv() { return gRDP.fvEnvColor; } inline void SetAmbientLight(uint32 color) { gRSP.ambientLightColor = color; gRSP.fAmbientLightR = (float)RGBA_GETRED(gRSP.ambientLightColor); gRSP.fAmbientLightG = (float)RGBA_GETGREEN(gRSP.ambientLightColor); gRSP.fAmbientLightB = (float)RGBA_GETBLUE(gRSP.ambientLightColor); LIGHT_DUMP(TRACE1("Set Ambient Light: %08X", color)); } inline void SetLighting(bool bLighting) { gRSP.bLightingEnable = bLighting; } // Generate texture coords? inline void SetTextureGen(bool bTextureGen) { gRSP.bTextureGen = bTextureGen; } inline void SetNumLights(uint32 dwNumLights) { gRSPnumLights = dwNumLights; DEBUGGER_PAUSE_AND_DUMP(NEXT_SET_LIGHT,TRACE1("Set Num Of Light: %d", dwNumLights)); } inline uint32 GetNumLights() { return gRSPnumLights; } inline COLOR GetVertexDiffuseColor(uint32 ver) { return g_dwVtxDifColor[ver]; } inline void SetScreenMult(float fMultX, float fMultY) { windowSetting.fMultX = fMultX; windowSetting.fMultY = fMultY; } inline COLOR GetLightCol(uint32 dwLight) { return gRSPlights[dwLight].col; } #endif mupen64plus-video-rice-src-2.0/src/RenderExt.cpp0000644000000000000000000007563512165031100017714 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "osal_opengl.h" #include "OGLDebug.h" #include "FrameBuffer.h" #include "Render.h" extern uObjMtxReal gObjMtxReal; extern Matrix g_MtxReal; //======================================================================== void CRender::LoadFrameBuffer(bool useVIreg, uint32 left, uint32 top, uint32 width, uint32 height) { uint32 VIwidth = *g_GraphicsInfo.VI_WIDTH_REG; TxtrInfo gti; gti.clampS = gti.clampT = 0; gti.maskS = gti.maskT = gti.mirrorS = gti.mirrorT = 0; gti.TLutFmt = TLUT_FMT_RGBA16; //RGBA16 gti.bSwapped = FALSE; gti.Palette = 0; if( useVIreg && *g_GraphicsInfo.VI_ORIGIN_REG > VIwidth*2 ) { gti.Format = 0; gti.Size = 2; gti.Address = (*g_GraphicsInfo.VI_ORIGIN_REG & (g_dwRamSize-1) ) - VIwidth*2; gti.LeftToLoad = 0; gti.TopToLoad = 0; gti.PalAddress = (uchar *) &g_wRDPTlut[0]; gti.WidthToCreate = windowSetting.uViWidth;; gti.HeightToCreate = windowSetting.uViHeight; if( gti.WidthToCreate == 0 || gti.HeightToCreate == 0 ) { TRACE0("Loading frame buffer: size = 0 x 0"); return; } gti.Pitch = VIwidth << gti.Size >> 1; } else { gti.Format = g_CI.dwFormat; gti.Size = g_CI.dwSize; gti.PalAddress = (uchar *) &g_wRDPTlut[0]; gti.Address = RSPSegmentAddr(g_CI.dwAddr); if( width == 0 || height == 0 ) { gti.LeftToLoad = 0; gti.TopToLoad = 0; gti.WidthToCreate = g_CI.dwWidth; gti.HeightToCreate = g_CI.dwWidth*3/4; } else { gti.LeftToLoad = left; gti.TopToLoad = top; gti.WidthToCreate = width; gti.HeightToCreate = height; } if( gti.Size == TXT_SIZE_4b ) { gti.Pitch = g_CI.dwWidth >> 1; } else { gti.Pitch = g_CI.dwWidth << (gti.Size-1); } } if( gti.Address + gti.Pitch*gti.HeightToCreate > g_dwRamSize ) { TRACE0("Skip frame buffer loading, memory out of bound"); return; } #ifdef DEBUGGER if( pauseAtNext ) { DebuggerAppendMsg("Load Frame Buffer Imag at: %08X, (%d, %d) - (%d, %d)", gti.Address, gti.LeftToLoad, gti.TopToLoad, gti.WidthToCreate, gti.HeightToCreate ); } #endif gti.HeightToLoad = gti.HeightToCreate; gti.WidthToLoad = gti.WidthToCreate; gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address; gti.tileNo = -1; TxtrCacheEntry *pEntry = gTextureManager.GetTexture(>i, false, true, false); if( pEntry ) SetCurrentTexture( 0, pEntry->pTexture, pEntry->ti.WidthToCreate, pEntry->ti.HeightToCreate, pEntry); } void CRender::LoadTextureFromMemory(void *buf, uint32 left, uint32 top, uint32 width, uint32 height, uint32 pitch, uint32 format) { TxtrInfo gti; gti.Format = g_CI.dwFormat; gti.Size = g_CI.dwSize; gti.Palette = 0; gti.TLutFmt = TLUT_FMT_RGBA16; //RGBA16 gti.PalAddress = 0; gti.bSwapped = FALSE; gti.Address = 0; gti.LeftToLoad = 0; gti.TopToLoad = 0; gti.WidthToCreate = width; gti.HeightToCreate = height; gti.Pitch = pitch; gti.HeightToLoad = height; gti.WidthToLoad = width; gti.pPhysicalAddress = (uint8*)buf; gti.tileNo = -1; TxtrCacheEntry *pEntry = gTextureManager.GetTexture(>i, false); //Upto here, the texture is loaded wrong because the format is wrong DrawInfo info; if( pEntry->pTexture->StartUpdate(&info) ) { for( uint32 i=0; ipTexture->EndUpdate(&info); } SetCurrentTexture( 0, pEntry->pTexture, width, height, pEntry); } void CRender::LoadObjBGCopy(uObjBg &info) { TxtrInfo gti; gti.Format = info.imageFmt; gti.Size = info.imageSiz; gti.Address = RSPSegmentAddr(info.imagePtr); gti.LeftToLoad = 0; gti.TopToLoad = 0; gti.Palette = info.imagePal; gti.PalAddress = (uchar *) &g_wRDPTlut[0]; gti.bSwapped = FALSE; gti.TLutFmt = TLUT_FMT_RGBA16; //RGBA16 gti.WidthToCreate = info.imageW/4; gti.HeightToCreate = info.imageH/4; if( options.bEnableHacks ) { if( g_CI.dwWidth == 0x200 && gti.Format == g_CI.dwFormat && gti.Size == g_CI.dwSize && gti.WidthToCreate == 0x200 ) { // Hack for RE2 uint32 w = *g_GraphicsInfo.VI_WIDTH_REG & 0xFFF; gti.HeightToCreate = (gti.WidthToCreate*gti.HeightToCreate)/w; gti.WidthToCreate = w; } } gti.Pitch = gti.WidthToCreate << gti.Size >> 1; gti.Pitch = (gti.Pitch>>3)<<3; // Align to 8 bytes if( gti.Address + gti.Pitch*gti.HeightToCreate > g_dwRamSize ) { TRACE0("Skip BG copy loading, memory out of bound"); return; } gti.HeightToLoad = gti.HeightToCreate; gti.WidthToLoad = gti.WidthToCreate; gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address; gti.tileNo = -1; TxtrCacheEntry *pEntry = gTextureManager.GetTexture(>i, false); SetCurrentTexture(0,pEntry); DEBUGGER_IF_DUMP((pauseAtNext && (eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI||eventToPause == NEXT_OBJ_BG)), { TRACE0("Load Obj BG Copy:\n"); DebuggerAppendMsg("Addr=0x%08X, W=%d, H=%d, Left=%d, Top=%d\n", gti.Address, gti.WidthToCreate, gti.HeightToCreate, gti.LeftToLoad, gti.TopToLoad); DebuggerAppendMsg("Fmt=%s-%db, Pal=%d\n", pszImgFormat[gti.Format], pnImgSize[gti.Size], gti.Palette); } ); } void CRender::LoadTxtrBufIntoTexture(void) { TxtrInfo gti; gti.Format = g_pRenderTextureInfo->CI_Info.dwFormat; gti.Size = g_pRenderTextureInfo->CI_Info.dwSize; gti.Address = RSPSegmentAddr(g_pRenderTextureInfo->CI_Info.dwAddr); gti.LeftToLoad = 0; gti.TopToLoad = 0; gti.Palette = 0; gti.PalAddress = (uchar *) &g_wRDPTlut[0]; gti.bSwapped = FALSE; gti.WidthToCreate = g_pRenderTextureInfo->N64Width; gti.HeightToCreate = g_pRenderTextureInfo->N64Height; gti.TLutFmt = TLUT_FMT_RGBA16; //RGBA16 gti.Pitch = gti.WidthToCreate << (gti.Size-1); gti.HeightToLoad = gti.HeightToCreate; gti.WidthToLoad = gti.WidthToCreate; gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address; gti.tileNo = -1; TxtrCacheEntry *pEntry = gTextureManager.GetTexture(>i, false); SetCurrentTexture(0,pEntry); } void CRender::LoadSprite2D(Sprite2DInfo &info, uint32 ucode) { TxtrInfo gti; gti.Format = info.spritePtr->SourceImageType; gti.Size = info.spritePtr->SourceImageBitSize; gti.Address = RSPSegmentAddr(info.spritePtr->SourceImagePointer); gti.Palette = 0; gti.PalAddress = (uchar *) (g_pRDRAMu8 + RSPSegmentAddr(info.spritePtr->TlutPointer)); if( options.enableHackForGames == HACK_FOR_NITRO ) { gti.WidthToCreate = (uint32)(info.spritePtr->SubImageWidth/info.scaleX); gti.HeightToCreate = (uint32)(info.spritePtr->SubImageHeight/info.scaleY); gti.LeftToLoad = (uint32)(info.spritePtr->SourceImageOffsetS/info.scaleX); gti.TopToLoad = (uint32)(info.spritePtr->SourceImageOffsetT/info.scaleY); gti.Pitch = info.spritePtr->Stride << gti.Size >> 1; gti.Pitch = (uint32)(gti.Pitch*info.scaleY); } else { gti.WidthToCreate = info.spritePtr->SubImageWidth; gti.HeightToCreate = info.spritePtr->SubImageHeight; gti.LeftToLoad = info.spritePtr->SourceImageOffsetS; gti.TopToLoad = info.spritePtr->SourceImageOffsetT; gti.Pitch = info.spritePtr->Stride << gti.Size >> 1; } if( gti.Address + gti.Pitch*gti.HeightToCreate > g_dwRamSize ) { TRACE0("Skip Sprite image decompress, memory out of bound"); return; } gti.HeightToLoad = gti.HeightToCreate; gti.WidthToLoad = gti.WidthToCreate; gti.TLutFmt = TLUT_FMT_RGBA16; //RGBA16 gti.bSwapped = FALSE; gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address; gti.tileNo = -1; TxtrCacheEntry *pEntry = gTextureManager.GetTexture(>i, false); SetCurrentTexture(0,pEntry); DEBUGGER_IF_DUMP((pauseAtNext && (eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI||eventToPause == NEXT_SPRITE_2D)), { TRACE0("Load Sprite 2D\n"); DebuggerAppendMsg("Addr=0x%08X, W=%d, H=%d, Left=%d, Top=%d\n", gti.Address, gti.WidthToCreate, gti.HeightToCreate, gti.LeftToLoad, gti.TopToLoad); DebuggerAppendMsg("Fmt=%s-%db, Pal=%d, Pitch=%d\n", pszImgFormat[gti.Format], pnImgSize[gti.Size], gti.Palette, gti.Pitch); } ); } void CRender::DrawSprite2D(Sprite2DInfo &info, uint32 ucode) { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); if( status.bHandleN64RenderTexture ) { g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height; if( !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } } LoadSprite2D(info, ucode); info.scaleX = 1/info.scaleX; info.scaleY = 1/info.scaleY; int x0, y0, x1, y1; float t0, s0, t1, s1; if( info.flipX ) { //x0 = info.px*info.scaleX + info.spritePtr->SubImageWidth*info.scaleX; //x1 = info.px*info.scaleX; x0 = info.px + int(info.spritePtr->SubImageWidth*info.scaleX); x1 = info.px; } else { //x0 = info.px*info.scaleX; //x1 = info.px*info.scaleX + info.spritePtr->SubImageWidth*info.scaleX; x0 = info.px; x1 = info.px + int(info.spritePtr->SubImageWidth*info.scaleX); } if( info.flipY ) { //y0 = info.py*info.scaleY + info.spritePtr->SubImageHeight*info.scaleY; //y1 = info.py*info.scaleY; y0 = info.py + int(info.spritePtr->SubImageHeight*info.scaleY); y1 = info.py; } else { //y0 = info.py*info.scaleY; //y1 = info.py*info.scaleY + info.spritePtr->SubImageHeight*info.scaleY; y0 = info.py; y1 = info.py + int(info.spritePtr->SubImageHeight*info.scaleY); } t0 = s0 = 0; if( options.enableHackForGames == HACK_FOR_NITRO ) { t1 = info.spritePtr->SubImageWidth*info.scaleX/g_textures[0].m_fTexWidth; s1 = info.spritePtr->SubImageHeight*info.scaleY/g_textures[0].m_fTexHeight; } else { t1 = info.spritePtr->SubImageWidth/g_textures[0].m_fTexWidth; s1 = info.spritePtr->SubImageHeight/g_textures[0].m_fTexHeight; } //InitCombinerBlenderForSimpleTextureDraw(); SetCombinerAndBlender(); SetAddressUAllStages( 0, TEXTURE_UV_FLAG_CLAMP ); SetAddressVAllStages( 0, TEXTURE_UV_FLAG_CLAMP ); COLOR speColor = PostProcessSpecularColor(); COLOR difColor = PostProcessDiffuseColor(0xffffffff); float depth = ( gRDP.otherMode.depth_source == 1 ) ? gRDP.fPrimitiveDepth : 0; DrawSimple2DTexture((float)x0, (float)y0, (float)x1, (float)y1, t0, s0, t1, s1, speColor, difColor, depth, 1.0f); } void CRender::DrawSpriteR(uObjTxSprite &sprite, bool initCombiner, uint32 tile, uint32 left, uint32 top, uint32 width, uint32 height) // With Rotation { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); if( status.bHandleN64RenderTexture ) { g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height; if( !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } } SetCombinerAndBlender(); float scaleX = sprite.sprite.scaleW/1024.0f; float scaleY = sprite.sprite.scaleH/1024.0f; if( width == 0 || height == 0 ) { width = g_textures[tile].m_dwTileWidth; height = g_textures[tile].m_dwTileHeight; } //RECT src = {left,top,width, height}; float depth = 0.0; if (gRDP.otherMode.depth_source==1) depth = gRDP.fPrimitiveDepth; float x0 = sprite.sprite.objX/4.0f; float y0 = sprite.sprite.objY/4.0f; float x1 = sprite.sprite.imageW / 32.0f / scaleX + x0; float y1 = sprite.sprite.imageH / 32.0f / scaleY + y0; if( sprite.sprite.imageFlags&1 ) { float temp = x0; x0 = x1; x1 = temp; } // flip X if( sprite.sprite.imageFlags&0x10 ) { float temp = y0; y0 = y1; y1 = temp; } // flip Y g_texRectTVtx[0].x = (gObjMtxReal.A*x0 + gObjMtxReal.B*y0 + gObjMtxReal.X)*windowSetting.fMultX; g_texRectTVtx[0].y = (gObjMtxReal.C*x0 + gObjMtxReal.D*y0 + gObjMtxReal.Y)*windowSetting.fMultY; g_texRectTVtx[0].z = depth; g_texRectTVtx[0].rhw = 1; g_texRectTVtx[1].x = (gObjMtxReal.A*x1 + gObjMtxReal.B*y0 + gObjMtxReal.X)*windowSetting.fMultX; g_texRectTVtx[1].y = (gObjMtxReal.C*x1 + gObjMtxReal.D*y0 + gObjMtxReal.Y)*windowSetting.fMultY; g_texRectTVtx[1].z = depth; g_texRectTVtx[1].rhw = 1; g_texRectTVtx[2].x = (gObjMtxReal.A*x1 + gObjMtxReal.B*y1 + gObjMtxReal.X)*windowSetting.fMultX; g_texRectTVtx[2].y = (gObjMtxReal.C*x1 + gObjMtxReal.D*y1 + gObjMtxReal.Y)*windowSetting.fMultY; g_texRectTVtx[2].z = depth; g_texRectTVtx[2].rhw = 1; g_texRectTVtx[3].x = (gObjMtxReal.A*x0 + gObjMtxReal.B*y1 + gObjMtxReal.X)*windowSetting.fMultX; g_texRectTVtx[3].y = (gObjMtxReal.C*x0 + gObjMtxReal.D*y1 + gObjMtxReal.Y)*windowSetting.fMultY; g_texRectTVtx[3].z = depth; g_texRectTVtx[3].rhw = 1; g_texRectTVtx[0].tcord[0].u = left/g_textures[tile].m_fTexWidth; g_texRectTVtx[0].tcord[0].v = top/g_textures[tile].m_fTexHeight; g_texRectTVtx[1].tcord[0].u = (left+width)/g_textures[tile].m_fTexWidth; g_texRectTVtx[1].tcord[0].v = top/g_textures[tile].m_fTexHeight; g_texRectTVtx[2].tcord[0].u = (left+width)/g_textures[tile].m_fTexWidth; g_texRectTVtx[2].tcord[0].v = (top+height)/g_textures[tile].m_fTexHeight; g_texRectTVtx[3].tcord[0].u = left/g_textures[tile].m_fTexWidth; g_texRectTVtx[3].tcord[0].v = (top+height)/g_textures[tile].m_fTexHeight; //COLOR speColor = PostProcessSpecularColor(); COLOR difColor = PostProcessDiffuseColor(0xffffffff); g_texRectTVtx[0].dcDiffuse = g_texRectTVtx[1].dcDiffuse = g_texRectTVtx[2].dcDiffuse = g_texRectTVtx[3].dcDiffuse = difColor; g_texRectTVtx[0].dcSpecular = g_texRectTVtx[1].dcSpecular = g_texRectTVtx[2].dcSpecular = g_texRectTVtx[3].dcSpecular = difColor; DrawSpriteR_Render(); } void CRender::DrawFrameBuffer(bool useVIreg, uint32 left, uint32 top, uint32 width, uint32 height) { BeginRendering(); LoadFrameBuffer(useVIreg, left, top, width, height); m_pColorCombiner->InitCombinerBlenderForSimpleTextureDraw(0); ZBufferEnable(FALSE); SetZUpdate(FALSE); if( left == 0 ) SetAlphaTestEnable(FALSE); else SetAlphaTestEnable(TRUE); // use Alpha Test for partial frame buffer draw, for Dr. Mario 64 m_pAlphaBlender->Disable(); CTexture *pTexture = g_textures[0].m_pCTexture; if( pTexture ) { if( useVIreg ) { // Draw the whole frame buffer DrawSimple2DTexture(0, 0, windowSetting.uViWidth, windowSetting.uViHeight, 0, 0, 1/pTexture->m_fXScale, 1/pTexture->m_fYScale, 0xFFFFFFFF, 0xFFFFFFFF, 0, 1); } else { // Draw a small texture in frame buffer DrawSimple2DTexture((float)left, (float)top, (float)(left+width), (float)(top+height), 0, 0, 1/pTexture->m_fXScale, 1/pTexture->m_fYScale, 0xFFFFFFFF, 0xFFFFFFFF, 0, 1); } } TXTRBUF_OR_CI_DUMP(TRACE0("Draw Frame Buffer Img")); #ifdef DEBUGGER if( pauseAtNext && ( eventToPause == NEXT_FRAME || eventToPause == NEXT_FLUSH_TRI ) ) { TRACE0("Draw Frame Buffer Img"); debuggerPause = true; DebuggerPause(); } #endif EndRendering(); } void CRender::DrawObjBGCopy(uObjBg &info) { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); if( status.bHandleN64RenderTexture ) { g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height; if( !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } } SetCombinerAndBlender(); uint32 frameH = info.frameH; uint32 frameW = info.frameW; uint32 imageH = info.imageH; uint32 imageW = info.imageW; if( options.bEnableHacks ) { if( g_CI.dwWidth == 0x200 && info.imageFmt == g_CI.dwFormat && info.imageSiz == g_CI.dwSize && frameW == 0x800 ) { // Hack for RE2 uint32 width = *g_GraphicsInfo.VI_WIDTH_REG & 0xFFF; imageH = frameH = (frameW/4*frameH/4)/width*4; imageW = frameW = width*4; } } float x0 = info.frameX / 4.0f; float y0 = info.frameY / 4.0f; float x1 = frameW / 4.0f + x0; float y1 = frameH / 4.0f + y0; float s0 = info.imageX / 32.0f; float t0 = info.imageY / 32.0f; float texwidth = imageW/4.0f; float texheight = imageH/4.0f; float u0 = s0/g_textures[0].m_fTexWidth; float v0 = t0/g_textures[0].m_fTexHeight; float maxu = texwidth/g_textures[0].m_fTexWidth; float maxv = texheight/g_textures[0].m_fTexHeight; float x2 = x0 + (texwidth-s0); float y2 = y0 + (texheight-t0); float u1 = (x1-x2)/g_textures[0].m_fTexWidth; float v1 = (y1-y2)/g_textures[0].m_fTexHeight; float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0.0f); COLOR speColor = PostProcessSpecularColor(); COLOR difColor = PostProcessDiffuseColor(0xffffffff); if( options.enableHackForGames == HACK_FOR_COMMANDCONQUER ) { float s1 = (x1-x0) + s0; float t1 = (y1-y0) + t0; DrawSimple2DTexture(x0, y0, x1, y1, u0, v0, s1/g_textures[0].m_fTexWidth, t1/g_textures[0].m_fTexHeight, difColor, speColor, depth, 1); } else if( x2 >= x1 ) { float s1 = (x1-x0) + s0; if( y2 >= y1 ) { float t1 = (y1-y0) + t0; DrawSimple2DTexture(x0, y0, x1, y1, u0, v0, s1/g_textures[0].m_fTexWidth, t1/g_textures[0].m_fTexHeight, difColor, speColor, depth, 1); } else { DrawSimple2DTexture(x0, y0, x1, y2, u0, v0, s1/g_textures[0].m_fTexWidth, maxv, difColor, speColor, depth, 1); DrawSimple2DTexture(x0, y2, x1, y1, u0, 0, s1/g_textures[0].m_fTexWidth, v1, difColor, speColor, depth, 1); } } else { if( y2 >= y1 ) { float t1 = (y1-y0) + t0; DrawSimple2DTexture(x0, y0, x2, y1, u0, v0, maxu, t1/g_textures[0].m_fTexHeight, difColor, speColor, depth, 1); DrawSimple2DTexture(x2, y0, x1, y1, 0, v0, u1, t1/g_textures[0].m_fTexHeight, difColor, speColor, depth, 1); } else { DrawSimple2DTexture(x0, y0, x2, y2, u0, v0, maxu, maxv, difColor, speColor, depth, 1); DrawSimple2DTexture(x2, y0, x1, y2, 0, v0, u1, maxv, difColor, speColor, depth, 1); DrawSimple2DTexture(x0, y2, x2, y1, u0, 0, maxu, v1, difColor, speColor, depth, 1); DrawSimple2DTexture(x2, y2, x1, y1, 0, 0, u1, v1, difColor, speColor, depth, 1); } } DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N( (pauseAtNext&&(eventToPause==NEXT_OBJ_BG||eventToPause==NEXT_FLUSH_TRI||eventToPause==NEXT_OBJ_TXT_CMD)), { TRACE0("Pause ObjBG Copy"); } ); } void CRender::DrawObjBG1CYC(uObjScaleBg &bg, bool scaled) //Without Ratation { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); if( g_curRomInfo.bDisableObjBG ) return; if( status.bHandleN64RenderTexture ) { g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height; if( !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } } SetCombinerAndBlender(); float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0.0f); float x0 = bg.frameX / 4.0f; float y0 = bg.frameY / 4.0f; float x1 = bg.frameW / 4.0f + x0; float y1 = bg.frameH / 4.0f + y0; float s0 = bg.imageX / 32.0f; float t0 = bg.imageY / 32.0f; float scaleX = bg.scaleW/1024.0f; float scaleY = bg.scaleH/1024.0f; float texwidth = bg.imageW/4.0f; float texheight = bg.imageH/4.0f; float u0 = s0/g_textures[0].m_fTexWidth; float v0 = t0/g_textures[0].m_fTexHeight; float maxu = texwidth/g_textures[0].m_fTexWidth; float maxv = texheight/g_textures[0].m_fTexHeight; float x2 = x0 + (texwidth-s0)/scaleX; float y2 = y0 + (texheight-t0)/scaleY; float u1 = (x1-x2)*scaleX/g_textures[0].m_fTexWidth; float v1 = (y1-y2)*scaleY/g_textures[0].m_fTexHeight; COLOR speColor = PostProcessSpecularColor(); COLOR difColor = PostProcessDiffuseColor(0xffffffff); SetAlphaTestEnable(FALSE); if( options.enableHackForGames != HACK_FOR_YOSHI ) { float s1 = (x1-x0)*scaleX + s0; float t1 = (y1-y0)*scaleY + t0; DrawSimple2DTexture(x0, y0, x1, y1, u0, v0, s1/g_textures[0].m_fTexWidth, t1/g_textures[0].m_fTexHeight, difColor, speColor, depth, 1); } else if( x2 >= x1 ) { float s1 = (x1-x0)*scaleX + s0; if( y2 >= y1 ) { float t1 = (y1-y0)*scaleY + t0; DrawSimple2DTexture(x0, y0, x1, y1, u0, v0, s1/g_textures[0].m_fTexWidth, t1/g_textures[0].m_fTexHeight, difColor, speColor, depth, 1); } else { DrawSimple2DTexture(x0, y0, x1, y2, u0, v0, s1/g_textures[0].m_fTexWidth, maxv, difColor, speColor, depth, 1); DrawSimple2DTexture(x0, y2, x1, y1, u0, 0, s1/g_textures[0].m_fTexWidth, v1, difColor, speColor, depth, 1); } } else { if( y2 >= y1 ) { float t1 = (y1-y0)*scaleY + t0; DrawSimple2DTexture(x0, y0, x2, y1, u0, v0, maxu, t1/g_textures[0].m_fTexHeight, difColor, speColor, depth, 1); DrawSimple2DTexture(x2, y0, x1, y1, 0, v0, u1, t1/g_textures[0].m_fTexHeight, difColor, speColor, depth, 1); } else { DrawSimple2DTexture(x0, y0, x2, y2, u0, v0, maxu, maxv, difColor, speColor, depth, 1); DrawSimple2DTexture(x2, y0, x1, y2, 0, v0, u1, maxv, difColor, speColor, depth, 1); DrawSimple2DTexture(x0, y2, x2, y1, u0, 0, maxu, v1, difColor, speColor, depth, 1); DrawSimple2DTexture(x2, y2, x1, y1, 0, 0, u1, v1, difColor, speColor, depth, 1); } } DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N( (pauseAtNext&&(eventToPause==NEXT_OBJ_BG||eventToPause==NEXT_FLUSH_TRI||eventToPause==NEXT_OBJ_TXT_CMD)), { DebuggerAppendMsg("Pause BG 1CYC: (%.0f,%.0f - %.0f,%.0f), \ntex (%.2f,%.2f), scale (%.2f,%.2f)",x0,y0,x1,y1,s0,t0,scaleX,scaleY); } ); } void CRender::DrawSprite(uObjTxSprite &sprite, bool rectR) //Without Ratation { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); if( status.bHandleN64RenderTexture ) { g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height; if( !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } } SetCombinerAndBlender(); COLOR speColor = PostProcessSpecularColor(); COLOR difColor = PostProcessDiffuseColor(0xffffffff); float objX = sprite.sprite.objX/4.0f; float objY = sprite.sprite.objY/4.0f; float width = sprite.sprite.imageW / 32.0f; float high = sprite.sprite.imageH / 32.0f; float scaleW = sprite.sprite.scaleW/1024.0f; float scaleH = sprite.sprite.scaleH/1024.0f; if( g_curRomInfo.bIncTexRectEdge ) { width++; high++; } float x0, y0, x1, y1; if( rectR ) { // Upper-left coordinate // ( X + objX / BaseScaleX, Y+objY/BaseScaleY ) // Lower-right coordinate // ( X + (objX + imageW / scaleW) / BaseScaleX - 1, Y + (objY + imageH / scaleH) / BaseScaleY - 1 ) x0 = gObjMtxReal.X + objX/gObjMtxReal.BaseScaleX; y0 = gObjMtxReal.Y + objY/gObjMtxReal.BaseScaleY; x1 = gObjMtxReal.X + (objX + width / scaleW) / gObjMtxReal.BaseScaleX; y1 = gObjMtxReal.Y + (objY + high / scaleH) / gObjMtxReal.BaseScaleY; } else { // (objX, objY) - ( objX+imageW/scaleW-1, objY+imageH/scaleH-1) x0 = objX; y0 = objY; x1 = objX + width / scaleW; y1 = objY + high / scaleH; if( (sprite.sprite.imageFlags&1) ) // flipX { float temp = x0; x0 = x1; x1 = temp; } if( (sprite.sprite.imageFlags&0x10) ) // flipY { float temp = y0; y0 = y1; y1 = temp; } } // save the current clamp type GLint iClampS, iClampT; glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &iClampS); OPENGL_CHECK_ERRORS; glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, &iClampT); OPENGL_CHECK_ERRORS; // force clamp type to CLAMP_EDGE (experiments show sometimes this is set to hex 0x2901 - invalid value) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); OPENGL_CHECK_ERRORS; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); OPENGL_CHECK_ERRORS; // draw the 2D sprite as 2 triangles float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0.0f); CTexture *pTexture = g_textures[0].m_pCTexture; DrawSimple2DTexture(x0, y0, x1, y1, 0, 0, 1/pTexture->m_fXScale, 1/pTexture->m_fYScale, difColor, speColor, depth, 1); // return clamp type to original setting glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, iClampS); OPENGL_CHECK_ERRORS; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, iClampT); OPENGL_CHECK_ERRORS; } void CRender::LoadObjBG1CYC(uObjScaleBg &bg) { uint32 imageWidth = bg.imageW/4; uint32 imageHeight = bg.imageH/4; TxtrInfo gti; gti.Format = bg.imageFmt; gti.Size = bg.imageSiz; //uint8* img = (uint8*)(g_pRDRAMu8+RSPSegmentAddr(bg.imagePtr)); uchar *palAddr = (uchar *) &g_wRDPTlut[0]; gti.Address = RSPSegmentAddr(bg.imagePtr); gti.LeftToLoad = 0; gti.TopToLoad = 0; gti.WidthToCreate = imageWidth; gti.HeightToCreate = imageHeight; gti.clampS = gti.clampT = 1; gti.maskS = gti.maskT = 0; gti.Palette = bg.imagePal; gti.PalAddress = palAddr; gti.Pitch = imageWidth << gti.Size >> 1; gti.Pitch = (gti.Pitch>>3)<<3; // Align to 8 bytes if( gti.Address + gti.Pitch*gti.HeightToCreate > g_dwRamSize ) { TRACE0("Skip BG 1CYC loading, memory out of bound"); return; } gti.TLutFmt = TLUT_FMT_RGBA16; //RGBA16 gti.bSwapped = FALSE; gti.HeightToLoad = gti.HeightToCreate; gti.WidthToLoad = gti.WidthToCreate; gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address; gti.tileNo = -1; TxtrCacheEntry *pEntry = gTextureManager.GetTexture(>i, false,true,false); SetCurrentTexture(0,pEntry); DEBUGGER_IF_DUMP((pauseAtNext && (eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI||eventToPause == NEXT_OBJ_BG)), { TRACE0("Load Obj BG 1CYC:\n"); DebuggerAppendMsg("Addr=0x%08X, W=%d, H=%d, Left=%d, Top=%d\n", gti.Address, gti.WidthToCreate, gti.HeightToCreate, gti.LeftToLoad, gti.TopToLoad); DebuggerAppendMsg("Fmt=%s-%db, Pal=%d\n", pszImgFormat[gti.Format], pnImgSize[gti.Size], gti.Palette); } ); } void CRender::LoadObjSprite(uObjTxSprite &sprite, bool useTIAddr) { TxtrInfo gti; gti.Format = sprite.sprite.imageFmt; gti.Size = sprite.sprite.imageSiz; uchar *palAddr = (uchar *) &g_wRDPTlut[0]; gti.Address = RSPSegmentAddr(sprite.txtr.block.image); gti.Address += sprite.sprite.imageAdrs<<3; gti.LeftToLoad = 0; gti.TopToLoad = 0; gti.Palette = sprite.sprite.imagePal; gti.PalAddress = palAddr; if( sprite.txtr.block.type == S2DEX_OBJLT_TXTRBLOCK ) { gti.WidthToCreate = sprite.sprite.imageW/32; if( sprite.sprite.imageW >= 0x8000 ) { gti.WidthToCreate = (0x10000-sprite.sprite.imageW)/32; } gti.HeightToCreate = sprite.sprite.imageH/32; if( sprite.sprite.imageH >= 0x8000 ) { gti.HeightToCreate = (0x10000-sprite.sprite.imageH)/32; } gti.Pitch = (2047/(sprite.txtr.block.tline-1)) << 3; } else if( sprite.txtr.block.type == S2DEX_OBJLT_TXTRTILE ) { //#define GS_PIX2TMEM(pix, siz) ((pix)>>(4-(siz))) //#define GS_TT_TWIDTH(pix,siz) ((GS_PIX2TMEM((pix), (siz))<<2)-1) //#define GS_TT_THEIGHT(pix,siz) (((pix)<<2)-1) gti.WidthToCreate = ((sprite.txtr.tile.twidth+1)>>2)<<(4-gti.Size); gti.HeightToCreate = (sprite.txtr.tile.theight+1)>>2; if( gti.Size == TXT_SIZE_4b ) { gti.Pitch = gti.WidthToCreate >> 1; } else //gti.Pitch = (sprite.txtr.tile.twidth+1) << 3; gti.Pitch = gti.WidthToCreate << (gti.Size-1); } if( gti.Address + gti.Pitch*gti.HeightToCreate > g_dwRamSize ) { TRACE0("Skip Obj sprite loading, memory out of bound"); return; } gti.TLutFmt = TLUT_FMT_RGBA16; //RGBA16 gti.bSwapped = FALSE; gti.HeightToLoad = gti.HeightToCreate; gti.WidthToLoad = gti.WidthToCreate; gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address; gti.tileNo = -1; TxtrCacheEntry *pEntry = gTextureManager.GetTexture(>i, false); SetCurrentTexture(0,pEntry); } mupen64plus-video-rice-src-2.0/src/RenderTexture.cpp0000644000000000000000000000374512165031100020605 0ustar 00000000000000/* Copyright (C) 2005 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "osal_opengl.h" #include "Debugger.h" #include "FrameBuffer.h" #include "OGLTexture.h" // =========================================================================== COGLRenderTexture::COGLRenderTexture(int width, int height, RenderTextureInfo* pInfo, TextureUsage usage) : CRenderTexture(width, height, pInfo, usage), m_pOGLTexture(NULL) { if( usage == AS_BACK_BUFFER_SAVE ) { m_pTexture = m_pOGLTexture = new COGLTexture(width, height, usage); if( !m_pTexture ) { TRACE0("Error to create OGL render_texture"); SAFE_DELETE(m_pTexture); } } m_width = width; m_height = height; m_beingRendered = false; } COGLRenderTexture::~COGLRenderTexture() { if( m_beingRendered ) { g_pFrameBufferManager->CloseRenderTexture(false); SetAsRenderTarget(false); } ShutdownPBuffer(); SAFE_DELETE(m_pTexture); m_pOGLTexture = NULL; m_beingRendered = false; } bool COGLRenderTexture::InitPBuffer( void ) { return true; } void COGLRenderTexture::ShutdownPBuffer(void) { } bool COGLRenderTexture::SetAsRenderTarget(bool enable) { return true; } void COGLRenderTexture::LoadTexture(TxtrCacheEntry* pEntry) { } void COGLRenderTexture::StoreToRDRAM(int infoIdx) { } mupen64plus-video-rice-src-2.0/src/RenderTexture.h0000644000000000000000000000554512165031100020252 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _TEXTURE_BUFFER_H_ #define _TEXTURE_BUFFER_H_ #include "typedefs.h" #include "TextureManager.h" class CRenderTexture; typedef struct { CRenderTexture *pRenderTexture; SetImgInfo CI_Info; uint32 bufferWidth; uint32 bufferHeight; uint32 N64Width; uint32 N64Height; float scaleX; float scaleY; int maxUsedHeight; uint32 updateAtFrame; uint32 updateAtUcodeCount; bool isUsed; uint32 knownHeight; uint32 crcInRDRAM; uint32 crcCheckedAtFrame; TxtrCacheEntry txtEntry; } RenderTextureInfo; class CRenderTexture { public: friend class CGraphicsContext; friend class CDXGraphicsContext; friend class FrameBufferManager; friend class DXFrameBufferManager; friend class OGLFrameBufferManager; CRenderTexture(int width, int height, RenderTextureInfo* pInfo, TextureUsage usage) { m_beingRendered = false; m_width = m_height = 0; m_pTexture = NULL; m_pInfo = pInfo; m_usage = usage; } virtual ~CRenderTexture() {} virtual bool SetAsRenderTarget(bool enable)=0; virtual void LoadTexture(TxtrCacheEntry* pEntry)=0; virtual void StoreToRDRAM(int infoIdx) {}; void GetDimension(int &width, int &height) { width = m_width; height = m_height; } bool IsBeingRendered() { return m_beingRendered; } TextureUsage GetUsage() {return m_usage;} protected: int m_width; int m_height; bool m_beingRendered; TextureUsage m_usage; CTexture* m_pTexture; RenderTextureInfo* m_pInfo; }; class COGLRenderTexture : public CRenderTexture { // Haven't implemented yet public: COGLRenderTexture(int width, int height, RenderTextureInfo* pInfo, TextureUsage usage); ~COGLRenderTexture(); bool SetAsRenderTarget(bool enable); void LoadTexture(TxtrCacheEntry* pEntry); void StoreToRDRAM(int infoIdx); protected: bool InitPBuffer(void); void ShutdownPBuffer(void); int m_widthCreated; int m_heightCreated; COGLTexture *m_pOGLTexture; }; #endif mupen64plus-video-rice-src-2.0/src/Texture.cpp0000644000000000000000000002054312165031100017440 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "TextureManager.h" ////////////////////////////////////////// // Constructors / Deconstructors // Probably shouldn't need more than 4096 * 4096 CTexture::CTexture(uint32 dwWidth, uint32 dwHeight, TextureUsage usage) : m_dwWidth(dwWidth), m_dwHeight(dwHeight), m_dwCreatedTextureWidth(dwWidth), m_dwCreatedTextureHeight(dwHeight), m_fXScale(1.0f), m_fYScale(1.0f), m_bScaledS(false), m_bScaledT(false), m_bClampedS(false), m_bClampedT(false), m_bIsEnhancedTexture(false), m_Usage(usage), m_pTexture(NULL), m_dwTextureFmt(TEXTURE_FMT_A8R8G8B8) { // fix me, do something here } CTexture::~CTexture(void) { } TextureFmt CTexture::GetSurfaceFormat(void) { if (m_pTexture == NULL) return TEXTURE_FMT_UNKNOWN; else return m_dwTextureFmt; } uint32 CTexture::GetPixelSize() { if( m_dwTextureFmt == TEXTURE_FMT_A8R8G8B8 ) return 4; else return 2; } // There are reasons to create this function. D3D and OGL will only create surface of width and height // as 2's pow, for example, N64's 20x14 image, D3D and OGL will create a 32x16 surface. // When we using such a surface as D3D texture, and the U and V address is for the D3D and OGL surface // width and height. It is still OK if the U and V addr value is less than the real image within // the D3D surface. But we will have problems if the U and V addr value is larger than it, or even // large then 1.0. // In such a case, we need to scale the image to the D3D surface dimension, to ease the U/V addr // limition void CTexture::ScaleImageToSurface(bool scaleS, bool scaleT) { uint8 g_ucTempBuffer[1024*1024*4]; if( scaleS==false && scaleT==false) return; // If the image is not scaled, call this function to scale the real image to // the D3D given dimension uint32 width = scaleS ? m_dwWidth : m_dwCreatedTextureWidth; uint32 height = scaleT ? m_dwHeight : m_dwCreatedTextureHeight; uint32 xDst, yDst; uint32 xSrc, ySrc; DrawInfo di; if (!StartUpdate(&di)) { return; } int pixSize = GetPixelSize(); // Copy across from the temp buffer to the surface switch (pixSize) { case 4: { memcpy((uint8*)g_ucTempBuffer, (uint8*)(di.lpSurface), m_dwHeight*m_dwCreatedTextureWidth*4); uint32 * pDst; uint32 * pSrc; for (yDst = 0; yDst < m_dwCreatedTextureHeight; yDst++) { // ySrc ranges from 0..m_dwHeight // I'd rather do this but sometimes very narrow (i.e. 1 pixel) // surfaces are created which results in /0... //ySrc = (yDst * (m_dwHeight-1)) / (d3dTextureHeight-1); ySrc = (uint32)((yDst * height) / m_dwCreatedTextureHeight+0.49f); pSrc = (uint32*)((uint8*)g_ucTempBuffer + (ySrc * m_dwCreatedTextureWidth * 4)); pDst = (uint32*)((uint8*)di.lpSurface + (yDst * di.lPitch)); for (xDst = 0; xDst < m_dwCreatedTextureWidth; xDst++) { xSrc = (uint32)((xDst * width) / m_dwCreatedTextureWidth+0.49f); pDst[xDst] = pSrc[xSrc]; } } } break; case 2: { memcpy((uint8*)g_ucTempBuffer, (uint8*)(di.lpSurface), m_dwHeight*m_dwCreatedTextureWidth*2); uint16 * pDst; uint16 * pSrc; for (yDst = 0; yDst < m_dwCreatedTextureHeight; yDst++) { // ySrc ranges from 0..m_dwHeight ySrc = (yDst * height) / m_dwCreatedTextureHeight; pSrc = (uint16*)((uint8*)g_ucTempBuffer + (ySrc * m_dwCreatedTextureWidth * 2)); pDst = (uint16*)((uint8*)di.lpSurface + (yDst * di.lPitch)); for (xDst = 0; xDst < m_dwCreatedTextureWidth; xDst++) { xSrc = (xDst * width) / m_dwCreatedTextureWidth; pDst[xDst] = pSrc[xSrc]; } } } break; } EndUpdate(&di); if( scaleS ) m_bScaledS = true; if( scaleT ) m_bScaledT = true; } void CTexture::ClampImageToSurfaceS() { if( !m_bClampedS && m_dwWidth < m_dwCreatedTextureWidth ) { DrawInfo di; if( StartUpdate(&di) ) { if( m_dwTextureFmt == TEXTURE_FMT_A8R8G8B8 ) { for( uint32 y = 0; y>16); uint32 dwGreen = (uint8)((dw & 0x0000FF00)>>8 ); uint32 dwBlue = (uint8)((dw & 0x000000FF) ); uint32 dwAlpha = (dwRed+dwGreen+dwBlue)/3; dw &= 0x00FFFFFF; dw |= (dwAlpha<<24); /* uint32 dw = dwSrc[x]; if( (dw&0x00FFFFFF) > 0 ) dw |= 0xFF000000; else dw &= 0x00FFFFFF; */ } } EndUpdate(&di); } else { //TRACE0("Cannot lock texture"); } } mupen64plus-video-rice-src-2.0/src/Texture.h0000644000000000000000000000641012165031100017102 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __SURFACEHANDLER_H__ #define __SURFACEHANDLER_H__ #include "typedefs.h" /////////////// Define a struct to use as /////////////// storage for all the surfaces /////////////// created so far. class CTexture; typedef struct { unsigned short int dwWidth; // Describes the width of the real texture area. Use lPitch to move between successive lines unsigned short int dwHeight; // Describes the height of the real texture area unsigned short int dwCreatedWidth; // Describes the width of the created texture area. Use lPitch to move between successive lines unsigned short int dwCreatedHeight; // Describes the height of the created texture area int lPitch; // Specifies the number of bytes on each row (not necessarily bitdepth*width/8) void *lpSurface; // Pointer to the top left pixel of the image } DrawInfo; enum TextureFmt { TEXTURE_FMT_A8R8G8B8, TEXTURE_FMT_A4R4G4B4, TEXTURE_FMT_UNKNOWN, }; enum TextureUsage { AS_NORMAL, AS_RENDER_TARGET, AS_BACK_BUFFER_SAVE, }; class CTexture { public: virtual ~CTexture(); uint32 m_dwWidth; // The requested Texture w/h uint32 m_dwHeight; unsigned int m_dwCreatedTextureWidth; // What was actually created unsigned int m_dwCreatedTextureHeight; float m_fXScale; // = m_dwCorrectedWidth/m_dwWidth float m_fYScale; // = m_dwCorrectedHeight/m_dwWidth bool m_bScaledS; bool m_bScaledT; bool m_bClampedS; bool m_bClampedT; bool m_bIsEnhancedTexture; TextureUsage m_Usage; virtual void ScaleImageToSurface(bool scaleS=true, bool scaleT=true); virtual void ClampImageToSurfaceS(); virtual void ClampImageToSurfaceT(); virtual LPRICETEXTURE GetTexture() { return m_pTexture; } uint32 GetPixelSize(); TextureFmt GetSurfaceFormat(void); // Surface pixel format... inline void SetOthersVariables(void) { m_bClampedS = m_bScaledS = (m_dwWidth == m_dwCreatedTextureWidth); m_bClampedT = m_bScaledT = (m_dwHeight == m_dwCreatedTextureHeight); } // Provides access to "surface" virtual bool StartUpdate(DrawInfo *di)=0; virtual void EndUpdate(DrawInfo *di)=0; virtual void RestoreAlphaChannel(void); // Restore Alpha channel from RGB channel protected: CTexture(uint32 dwWidth, uint32 dwHeight, TextureUsage usage = AS_NORMAL); LPRICETEXTURE m_pTexture; TextureFmt m_dwTextureFmt; }; #endif mupen64plus-video-rice-src-2.0/src/TextureFilters.cpp0000644000000000000000000023570012165031100020774 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "osal_files.h" #define M64P_PLUGIN_PROTOTYPES 1 #include "m64p_plugin.h" #include "typedefs.h" #include "ConvertImage.h" #include "DeviceBuilder.h" #include "TextureFilters.h" #include "Render.h" #include "Video.h" #include "liblinux/BMGLibPNG.h" #include "liblinux/BMGDLL.h" #include #include #ifdef min #undef min #endif /************************************************************************/ /* 2X filters */ /************************************************************************/ // Basic 2x R8G8B8A8 filter with interpolation void Texture2x_32( DrawInfo &srcInfo, DrawInfo &destInfo) { uint32 *pDst1, *pDst2; uint32 *pSrc, *pSrc2; uint32 nWidth = srcInfo.dwWidth; uint32 nHeight = srcInfo.dwHeight; uint32 b1; uint32 g1; uint32 r1; uint32 a1; uint32 b2 = 0; uint32 g2 = 0; uint32 r2 = 0; uint32 a2 = 0; uint32 b3 = 0; uint32 g3 = 0; uint32 r3 = 0; uint32 a3 = 0; uint32 b4 = 0; uint32 g4 = 0; uint32 r4 = 0; uint32 a4 = 0; for (uint32 ySrc = 0; ySrc < nHeight; ySrc++) { pSrc = (uint32*)(((uint8*)srcInfo.lpSurface)+ySrc*srcInfo.lPitch); pSrc2 = (uint32*)(((uint8*)srcInfo.lpSurface)+(ySrc+1)*srcInfo.lPitch); pDst1 = (uint32*)(((uint8*)destInfo.lpSurface)+(ySrc*2)*destInfo.lPitch); pDst2 = (uint32*)(((uint8*)destInfo.lpSurface)+(ySrc*2+1)*destInfo.lPitch); for (uint32 xSrc = 0; xSrc < nWidth; xSrc++) { b1 = (pSrc[xSrc]>>0)&0xFF; g1 = (pSrc[xSrc]>>8)&0xFF; r1 = (pSrc[xSrc]>>16)&0xFF; a1 = (pSrc[xSrc]>>24)&0xFF; if( xSrc>0)&0xFF; g2 = (pSrc[xSrc+1]>>8)&0xFF; r2 = (pSrc[xSrc+1]>>16)&0xFF; a2 = (pSrc[xSrc+1]>>24)&0xFF; } if( ySrc>0)&0xFF; g3 = (pSrc2[xSrc]>>8)&0xFF; r3 = (pSrc2[xSrc]>>16)&0xFF; a3 = (pSrc2[xSrc]>>24)&0xFF; if( xSrc>0)&0xFF; g4 = (pSrc2[xSrc+1]>>8)&0xFF; r4 = (pSrc2[xSrc+1]>>16)&0xFF; a4 = (pSrc2[xSrc+1]>>24)&0xFF; } } // Pixel 1 pDst1[xSrc*2] = pSrc[xSrc]; // Pixel 2 if( xSrc> 0)&0xF; g1 = (pSrc[xSrc]>> 4)&0xF; r1 = (pSrc[xSrc]>> 8)&0xF; a1 = (pSrc[xSrc]>>12)&0xF; if( xSrc> 0)&0xF; g2 = (pSrc[xSrc+1]>> 4)&0xF; r2 = (pSrc[xSrc+1]>> 8)&0xF; a2 = (pSrc[xSrc+1]>>12)&0xF; } if( ySrc> 0)&0xF; g3 = (pSrc2[xSrc]>> 4)&0xF; r3 = (pSrc2[xSrc]>> 8)&0xF; a3 = (pSrc2[xSrc]>>12)&0xF; if( xSrc> 0)&0xF; g4 = (pSrc2[xSrc+1]>> 4)&0xF; r4 = (pSrc2[xSrc+1]>> 8)&0xF; a4 = (pSrc2[xSrc+1]>>12)&0xF; } } // Pixel 1 pDst1[xSrc*2] = pSrc[xSrc]; // Pixel 2 if( xSrc (t1+t3+t7+t9+t2+t4+t6+t8)*mul1 ) { val[z]= std::min((((t5*mul3) - (t1+t3+t7+t9+t2+t4+t6+t8)*mul1)>>shift4),0xFFU); } } dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24); } } delete [] pcopy; } void SharpenFilter_16(uint16 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter) { //return; // Sharpen does not make sense for 16 bits uint32 len=height*pitch; uint16 *pcopy = new uint16[len]; if( !pcopy ) return; memcpy(pcopy, pdata, len<<1); uint16 mul1, mul2, mul3, shift4; switch( filter ) { case TEXTURE_SHARPEN_MORE_ENHANCEMENT: mul1=1; mul2=8; mul3=12; shift4=2; break; case TEXTURE_SHARPEN_ENHANCEMENT: default: mul1=1; mul2=8; mul3=16; shift4=3; break; } uint32 x,y,z; uint16 *src1, *src2, *src3, *dest; uint16 val[4]; uint16 t1,t2,t3,t4,t5,t6,t7,t8,t9; for( y=1; y>1)))>>shift; t2 = (*((uint8*)(src1+x )+(z>>1)))>>shift; t3 = (*((uint8*)(src1+x+1)+(z>>1)))>>shift; t4 = (*((uint8*)(src2+x-1)+(z>>1)))>>shift; t5 = (*((uint8*)(src2+x )+(z>>1)))>>shift; t6 = (*((uint8*)(src2+x+1)+(z>>1)))>>shift; t7 = (*((uint8*)(src3+x-1)+(z>>1)))>>shift; t8 = (*((uint8*)(src3+x )+(z>>1)))>>shift; t9 = (*((uint8*)(src3+x+1)+(z>>1)))>>shift; val[z]=t5; if( (t5*mul2) > (t1+t3+t7+t9+t2+t4+t6+t8)*mul1 ) { val[z] = (((t5*mul3) - (t1+t3+t7+t9+t2+t4+t6+t8)*mul1)>>shift4); val[z]= std::min(val[z],(unsigned short)0xFU); } } dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12); } } delete [] pcopy; } /************************************************************************/ /* Smooth filters */ /************************************************************************/ void SmoothFilter_32(uint32 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter) { uint32 len=height*pitch; uint32 *pcopy = new uint32[len]; if( !pcopy ) return; memcpy(pcopy, pdata, len<<2); uint32 mul1, mul2, mul3, shift4; switch( filter ) { case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1: mul1=1; mul2=2; mul3=4; shift4=4; break; case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2: mul1=1; mul2=1; mul3=8; shift4=4; break; case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3: mul1=1; mul2=1; mul3=2; shift4=2; break; case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4: default: mul1=1; mul2=1; mul3=6; shift4=3; break; } uint32 x,y,z; uint32 *src1, *src2, *src3, *dest; uint32 val[4]; uint32 t1,t2,t3,t4,t5,t6,t7,t8,t9; if( filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3 || filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4 ) { for( y=1; y>shift4; } dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24); } } } else { for( y=0; y0 ) { src1 = pcopy+(y-1)*pitch; src2 = src1 + pitch; } else { src1 = src2 = pcopy; } src3 = src2; if( y>shift4; } dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24); } } } delete [] pcopy; } void SmoothFilter_16(uint16 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter) { uint32 len=height*pitch; uint16 *pcopy = new uint16[len]; if( !pcopy ) return; memcpy(pcopy, pdata, len<<1); uint16 mul1, mul2, mul3, shift4; switch( filter ) { case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1: mul1=1; mul2=2; mul3=4; shift4=4; break; case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2: mul1=1; mul2=1; mul3=8; shift4=4; break; case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3: mul1=1; mul2=1; mul3=2; shift4=2; break; case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4: default: mul1=1; mul2=1; mul3=6; shift4=3; break; } uint32 x,y,z; uint16 *src1, *src2, *src3, *dest; uint16 val[4]; uint16 t1,t2,t3,t4,t5,t6,t7,t8,t9; if( filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3 || filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4 ) { for( y=1; y>1)))>>shift; t5 = (*((uint8*)(src2+x )+(z>>1)))>>shift; t8 = (*((uint8*)(src3+x )+(z>>1)))>>shift; val[z] = ((t2+t8)*mul2+(t5*mul3))>>shift4; } dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12); } } } else { for( y=0; y0 ) { src1 = pcopy+(y-1)*pitch; src2 = src1 + pitch; } else { src1 = src2 = pcopy; } src3 = src2; if( y>1)))>>shift; t2 = (*((uint8*)(src1+x )+(z>>1)))>>shift; t3 = (*((uint8*)(src1+x+1)+(z>>1)))>>shift; t4 = (*((uint8*)(src2+x-1)+(z>>1)))>>shift; t5 = (*((uint8*)(src2+x )+(z>>1)))>>shift; t6 = (*((uint8*)(src2+x+1)+(z>>1)))>>shift; t7 = (*((uint8*)(src3+x-1)+(z>>1)))>>shift; t8 = (*((uint8*)(src3+x )+(z>>1)))>>shift; t9 = (*((uint8*)(src3+x+1)+(z>>1)))>>shift; val[z] = ((t1+t3+t7+t9)*mul1+((t2+t4+t6+t8)*mul2)+(t5*mul3))>>shift4; } dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12); } } } delete [] pcopy; } void EnhanceTexture(TxtrCacheEntry *pEntry) { if( pEntry->dwEnhancementFlag == options.textureEnhancement ) { // The texture has already been enhanced return; } else if( options.textureEnhancement == TEXTURE_NO_ENHANCEMENT ) { //Texture enhancement has being turned off //Delete any allocated memory for the enhanced texture SAFE_DELETE(pEntry->pEnhancedTexture); //Set the enhancement flag so the texture wont be processed again pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT; return; } if( status.primitiveType != PRIM_TEXTRECT && options.bTexRectOnly ) { return; } DrawInfo srcInfo; //Start the draw update if( pEntry->pTexture->StartUpdate(&srcInfo) == false ) { //If we get here we were unable to start the draw update //Delete any allocated memory for the enhanced texture SAFE_DELETE(pEntry->pEnhancedTexture); return; } uint32 realwidth = srcInfo.dwWidth; uint32 realheight = srcInfo.dwHeight; uint32 nWidth = srcInfo.dwCreatedWidth; uint32 nHeight = srcInfo.dwCreatedHeight; //Sharpen option is enabled, sharpen the texture if( options.textureEnhancement == TEXTURE_SHARPEN_ENHANCEMENT || options.textureEnhancement == TEXTURE_SHARPEN_MORE_ENHANCEMENT ) { if( pEntry->pTexture->GetPixelSize() == 4 ) SharpenFilter_32((uint32*)srcInfo.lpSurface, nWidth, nHeight, nWidth, options.textureEnhancement); else SharpenFilter_16((uint16*)srcInfo.lpSurface, nWidth, nHeight, nWidth, options.textureEnhancement); pEntry->dwEnhancementFlag = options.textureEnhancement; //End the draw update pEntry->pTexture->EndUpdate(&srcInfo); //Delete any allocated memory for the enhanced texture SAFE_DELETE(pEntry->pEnhancedTexture); return; } pEntry->dwEnhancementFlag = options.textureEnhancement; if( options.bSmallTextureOnly ) { if( nWidth + nHeight > 256 ) { //End the draw update pEntry->pTexture->EndUpdate(&srcInfo); //Delete any data allocated for the enhanced texture SAFE_DELETE(pEntry->pEnhancedTexture); //Set the enhancement flag so the texture wont be processed again pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT; return; } } CTexture* pSurfaceHandler = NULL; if( options.textureEnhancement == TEXTURE_HQ4X_ENHANCEMENT ) { if( nWidth + nHeight > 1024/4 ) { // Don't enhance for large textures pEntry->pTexture->EndUpdate(&srcInfo); SAFE_DELETE(pEntry->pEnhancedTexture); pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT; return; } pSurfaceHandler = CDeviceBuilder::GetBuilder()->CreateTexture(nWidth*4, nHeight*4); } else { if( nWidth + nHeight > 1024/2 ) { // Don't enhance for large textures pEntry->pTexture->EndUpdate(&srcInfo); SAFE_DELETE(pEntry->pEnhancedTexture); pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT; return; } pSurfaceHandler = CDeviceBuilder::GetBuilder()->CreateTexture(nWidth*2, nHeight*2); } DrawInfo destInfo; if(pSurfaceHandler) { if(pSurfaceHandler->StartUpdate(&destInfo)) { if( options.textureEnhancement == TEXTURE_2XSAI_ENHANCEMENT ) { if( pEntry->pTexture->GetPixelSize() == 4 ) Super2xSaI_32((uint32*)(srcInfo.lpSurface),(uint32*)(destInfo.lpSurface), nWidth, realheight, nWidth); else Super2xSaI_16((uint16*)(srcInfo.lpSurface),(uint16*)(destInfo.lpSurface), nWidth, realheight, nWidth); } else if( options.textureEnhancement == TEXTURE_HQ2X_ENHANCEMENT ) { if( pEntry->pTexture->GetPixelSize() == 4 ) { hq2x_init(32); hq2x_32((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight); } else { hq2x_init(16); hq2x_16((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight); } } else if( options.textureEnhancement == TEXTURE_LQ2X_ENHANCEMENT ) { if( pEntry->pTexture->GetPixelSize() == 4 ) { hq2x_init(32); lq2x_32((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight); } else { hq2x_init(16); lq2x_16((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight); } } else if( options.textureEnhancement == TEXTURE_HQ4X_ENHANCEMENT ) { if( pEntry->pTexture->GetPixelSize() == 4 ) { hq4x_InitLUTs(); hq4x_32((uint8*)(srcInfo.lpSurface), (uint8*)(destInfo.lpSurface), realwidth, realheight, nWidth, destInfo.lPitch); } else { hq4x_InitLUTs(); hq4x_16((uint8*)(srcInfo.lpSurface), (uint8*)(destInfo.lpSurface), realwidth, realheight, nWidth, destInfo.lPitch); } } else { if( pEntry->pTexture->GetPixelSize() == 4 ) Texture2x_32( srcInfo, destInfo); else Texture2x_16( srcInfo, destInfo); } if( options.textureEnhancementControl >= TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1 ) { if( options.textureEnhancement != TEXTURE_HQ4X_ENHANCEMENT ) { if( pEntry->pTexture->GetPixelSize() == 4 ) SmoothFilter_32((uint32*)destInfo.lpSurface, realwidth<<1, realheight<<1, nWidth<<1, options.textureEnhancementControl); else SmoothFilter_16((uint16*)destInfo.lpSurface, realwidth<<1, realheight<<1, nWidth<<1, options.textureEnhancementControl); } else { if( pEntry->pTexture->GetPixelSize() == 4 ) SmoothFilter_32((uint32*)destInfo.lpSurface, realwidth<<2, realheight<<2, nWidth<<2, options.textureEnhancementControl); else SmoothFilter_16((uint16*)destInfo.lpSurface, realwidth<<2, realheight<<2, nWidth<<2, options.textureEnhancementControl); } } pSurfaceHandler->EndUpdate(&destInfo); } pSurfaceHandler->SetOthersVariables(); pSurfaceHandler->m_bIsEnhancedTexture = true; } pEntry->pTexture->EndUpdate(&srcInfo); pEntry->pEnhancedTexture = pSurfaceHandler; } /************************************************************************/ /* */ /************************************************************************/ void MirrorEmulator_DrawLine(DrawInfo& destInfo, DrawInfo& srcInfo, uint32 *pSource, uint32 *pDest, uint32 nWidth, BOOL bFlipLeftRight) { if(!bFlipLeftRight) { memcpy(pDest, pSource, nWidth * 4); } else { uint32 *pMaxDest = pDest + nWidth; pSource += nWidth - 1; for(; pDest < pMaxDest; pDest++, pSource--) { *pDest = *pSource; } } } void MirrorEmulator_Draw(DrawInfo& destInfo, DrawInfo& srcInfo, uint32 nDestX, uint32 nDestY, BOOL bFlipLeftRight, BOOL bFlipUpDown) { uint8 *pDest = (uint8 *) destInfo.lpSurface + (destInfo.lPitch * nDestY) + (4 * nDestX); uint8 *pMaxDest = pDest + (destInfo.lPitch * srcInfo.dwHeight); uint8 *pSource = (uint8 *)(srcInfo.lpSurface); if(!bFlipUpDown) { for(; pDest < pMaxDest; pDest += destInfo.lPitch, pSource += srcInfo.lPitch) { MirrorEmulator_DrawLine(destInfo, srcInfo, (uint32*)pSource, (uint32*)pDest, srcInfo.dwWidth, bFlipLeftRight); } } else { pSource += (srcInfo.lPitch * (srcInfo.dwHeight - 1)); for(; pDest < pMaxDest; pDest += destInfo.lPitch, pSource -= srcInfo.lPitch) { MirrorEmulator_DrawLine(destInfo, srcInfo, (uint32*)pSource, (uint32*)pDest, srcInfo.dwWidth, bFlipLeftRight); } } } void MirrorTexture(uint32 dwTile, TxtrCacheEntry *pEntry) { if( ((gRDP.tiles[dwTile].bMirrorS) || (gRDP.tiles[dwTile].bMirrorT)) && CGraphicsContext::Get()->m_supportTextureMirror == false ) { if(pEntry->pEnhancedTexture) { return; } else { CTexture* pSurfaceHandler = NULL; // FIXME: Compute the correct values. 2/2 seems to always work correctly in Mario64 uint32 nXTimes = gRDP.tiles[dwTile].bMirrorS ? 2 : 1; uint32 nYTimes = gRDP.tiles[dwTile].bMirrorT ? 2 : 1; // For any texture need to use mirror, we should not need to rescale it // because texture need to be mirrored must with MaskS and MaskT // But again, check me //if( pEntry->pTexture->m_bScaledS == false || pEntry->pTexture->m_bScaledT == false) //{ // pEntry->pTexture->ScaleImageToSurface(); //} DrawInfo srcInfo; if( pEntry->pTexture->StartUpdate(&srcInfo) ) { uint32 nWidth = srcInfo.dwWidth; uint32 nHeight = srcInfo.dwHeight; pSurfaceHandler = CDeviceBuilder::GetBuilder()->CreateTexture(nWidth * nXTimes, nHeight * nYTimes); if( pSurfaceHandler ) { DrawInfo destInfo; if( pSurfaceHandler->StartUpdate(&destInfo) ) { for(uint32 nY = 0; nY < nYTimes; nY++) { for(uint32 nX = 0; nX < nXTimes; nX++) { MirrorEmulator_Draw(destInfo, srcInfo, nWidth * nX, nHeight * nY, nX & 0x1, nY & 0x1); } } pSurfaceHandler->EndUpdate(&destInfo); } // FIXME: There should be a flag to tell that it is a mirrored texture handler // not the original texture handlers, so all texture coordinate should be divided by 2 pSurfaceHandler->SetOthersVariables(); } pEntry->pTexture->EndUpdate(&srcInfo); pEntry->dwEnhancementFlag = TEXTURE_MIRRORED; } pEntry->pEnhancedTexture = pSurfaceHandler; } } } /**** All code bellow, CLEAN ME ****/ enum TextureType { NO_TEXTURE, RGB_PNG, COLOR_INDEXED_BMP, RGB_WITH_ALPHA_TOGETHER_PNG, RGBA_PNG_FOR_CI, RGBA_PNG_FOR_ALL_CI, }; typedef struct { unsigned int width; unsigned int height; int fmt; int siz; int crc32; int pal_crc32; char *foldername; char *filename; char *filename_a; //char name[40]; TextureType type; bool bSeparatedAlpha; } ExtTxtrInfo; CSortedList gTxtrDumpInfos; CSortedList gHiresTxtrInfos; extern char * right(const char * src, int nchars); #define SURFFMT_P8 41 int GetImageInfoFromFile(char* pSrcFile, IMAGE_INFO *pSrcInfo) { unsigned char sig[8]; FILE *f; f = fopen(pSrcFile, "rb"); if (f == NULL) { DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile() error: couldn't open file '%s'", pSrcFile); return 1; } if (fread(sig, 1, 8, f) != 8) { DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile() error: couldn't read first 8 bytes of file '%s'", pSrcFile); fclose(f); return 1; } fclose(f); if(sig[0] == 'B' && sig[1] == 'M') // BMP { struct BMGImageStruct img; memset(&img, 0, sizeof(BMGImageStruct)); BMG_Error code = ReadBMP(pSrcFile, &img); if( code == BMG_OK ) { pSrcInfo->Width = img.width; pSrcInfo->Height = img.height; pSrcInfo->Depth = img.bits_per_pixel; pSrcInfo->MipLevels = 1; if(img.bits_per_pixel == 32) pSrcInfo->Format = SURFFMT_A8R8G8B8; else if(img.bits_per_pixel == 8) pSrcInfo->Format = SURFFMT_P8; // Resource and File Format ignored FreeBMGImage(&img); return 0; } DebugMessage(M64MSG_ERROR, "Couldn't read BMP file '%s'; error = %i", pSrcFile, code); return 1; } else if(sig[0] == 137 && sig[1] == 'P' && sig[2] == 'N' && sig[3] == 'G' && sig[4] == '\r' && sig[5] == '\n' && sig[6] == 26 && sig[7] == '\n') // PNG { struct BMGImageStruct img; memset(&img, 0, sizeof(BMGImageStruct)); BMG_Error code = ReadPNGInfo(pSrcFile, &img); if( code == BMG_OK ) { pSrcInfo->Width = img.width; pSrcInfo->Height = img.height; pSrcInfo->Depth = img.bits_per_pixel; pSrcInfo->MipLevels = 1; if(img.bits_per_pixel == 32) pSrcInfo->Format = SURFFMT_A8R8G8B8; else if(img.bits_per_pixel == 8) pSrcInfo->Format = SURFFMT_P8; // Resource and File Format ignored FreeBMGImage(&img); return 0; } DebugMessage(M64MSG_ERROR, "Couldn't read PNG file '%s'; error = %i", pSrcFile, code); return 1; } DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile : unknown file format (%s)", pSrcFile); return 1; } BOOL PathFileExists(char* pszPath) { FILE *f; f = fopen(pszPath, "rb"); if(f != NULL) { fclose(f); return TRUE; } return FALSE; } /******************************************************************************************************************** * Truncates the current list with information about hires textures and scans the hires folder for hires textures and * creates a list with records of properties of the hires textures. * parameter: * foldername: the folder that should be scaned for valid hires textures. * infos: a pointer that will point to the list containing the records with the infos about the found hires textures. * In case of enabled caching, these records will also contain the actual textures. * extraCheck: ? * bRecursive: flag that indicates if also subfolders should be scanned for hires textures * bCacheTextures: flag that indicates if the identified hires textures should also be cached * bMainFolder: indicates if the folder is the main folder that will be scanned. That way, texture counting does not * start at 1 each time a subfolder is accessed. (microdev: I know that is not important but it really * bugged me ;-)) * return: * infos: the list with the records of the identified hires textures. Be aware that these records also contains the * actual textures if caching is enabled. ********************************************************************************************************************/ void FindAllTexturesFromFolder(char *foldername, CSortedList &infos, bool extraCheck, bool bRecursive) { // check if folder actually exists if (!osal_is_directory(foldername)) return; // the path of the texture char texturefilename[PATH_MAX]; // IMAGE_INFO imgInfo; // IMAGE_INFO imgInfo2; void *dir; dir = osal_search_dir_open(foldername); const char *foundfilename; int crc, palcrc32; unsigned int fmt, siz; char crcstr[16], crcstr2[16]; do { foundfilename = osal_search_dir_read_next(dir); // The array is empty, break the current operation if (foundfilename == NULL) break; // The current file is a hidden one if (foundfilename[0] == '.' ) // These files we don't need continue; // Get the folder name strcpy(texturefilename, foldername); // And append the file name strcat(texturefilename, foundfilename); // Check if the current file is a directory and if recursive scanning is enabled if (osal_is_directory(texturefilename) && bRecursive ) { // Add file-separator strcat(texturefilename, OSAL_DIR_SEPARATOR_STR); // Scan detected folder for hires textures (recursive call) FindAllTexturesFromFolder(texturefilename, infos, extraCheck, bRecursive); continue; } // well, the current file is actually no file (probably a directory & recursive scanning is not enabled) if( strstr(foundfilename,(const char*)g_curRomInfo.szGameName) == 0 ) // go on with the next one continue; TextureType type = NO_TEXTURE; bool bSeparatedAlpha = false; // Detect the texture type by it's extention // microdev: this is not the smartest way. Should be done by header analysis if possible if( strcasecmp(right(foundfilename,7), "_ci.bmp") == 0 ) { // Identify type if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0) { DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename); continue; } if( imgInfo.Format == SURFFMT_P8 ) // and store it to the record type = COLOR_INDEXED_BMP; else // Type is not supported, go on with the next one continue; } // Detect the texture type by its extention else if( strcasecmp(right(foundfilename,13), "_ciByRGBA.png") == 0 ) { // Identify type if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 ) { DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename); continue; } if( imgInfo.Format == SURFFMT_A8R8G8B8 ) // and store it to the record type = RGBA_PNG_FOR_CI; else // Type is not supported, go on with the next one continue; } // Detect the texture type by its extention else if( strcasecmp(right(foundfilename,16), "_allciByRGBA.png") == 0 ) { // Identify type if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 ) { DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename); continue; } if( imgInfo.Format == SURFFMT_A8R8G8B8 ) // and store it to the record type = RGBA_PNG_FOR_ALL_CI; else // Type not supported, go on with next one continue; } // Detect the texture type by its extention else if( strcasecmp(right(foundfilename,8), "_rgb.png") == 0 ) { // Identify type if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 ) { DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename); continue; } // Store type to the record type = RGB_PNG; char filename2[PATH_MAX]; // Assemble the file name for the separate alpha channel file strcpy(filename2,texturefilename); strcpy(filename2+strlen(filename2)-8,"_a.png"); // Check if the file actually exists if( PathFileExists(filename2) ) { // Check if the file with this name is actually a texture (well an alpha channel one) if( GetImageInfoFromFile(filename2, &imgInfo2) != 0 ) { // Nope, it isn't. => Go on with the next file DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", filename2); continue; } // Yes it is a texture file. Check if the size of the alpha channel is the same as the one of the texture if( extraCheck && (imgInfo2.Width != imgInfo.Width || imgInfo2.Height != imgInfo.Height) ) { // Nope, it isn't => go on with next file DebugMessage(M64MSG_WARNING, "RGB and alpha texture size mismatch: %s", filename2); continue; } bSeparatedAlpha = true; } } // Detect the texture type by its extention else if( strcasecmp(right(foundfilename,8), "_all.png") == 0 ) { // Check if texture is of expected type if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 ) { DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename); // Nope, continue with next file continue; } // Indicate file type type = RGB_WITH_ALPHA_TOGETHER_PNG; } // If a known texture format has been detected... if( type != NO_TEXTURE ) { /* Try to read image information here. (CASTLEVANIA2)#(58E2333F)#(2)#(0)#(D7A5C6D9)_ciByRGBA.png (------1-----)#(---2----)#(3)#(4)#(---5----)_ciByRGBA.png 1. Internal ROM name 2. The DRAM CRC 3. The image pixel size (8b=0, 16b=1, 24b=2, 32b=3) 4. The texture format (RGBA=0, YUV=1, CI=2, IA=3, I=4) 5. The palette CRC ##<24bit>##_ciByRGBA.png */ // Get the actual file name strcpy(texturefilename, foundfilename); // Place the pointer before the DRAM-CRC (first occurrence of '#') char *ptr = strchr(texturefilename,'#'); // Terminate the string ('0' means end of string - or in this case begin of string) *ptr++ = 0; if( type == RGBA_PNG_FOR_CI ) { // Extract the information from the file name; information is: // sscanf(ptr,"%8c#%d#%d#%8c", crcstr, &fmt, &siz,crcstr2); // Terminate the ascii represntation of the palette crc crcstr2[8] = 0; // Transform the ascii presentation of the hex value to an unsigned integer palcrc32 = strtoul(crcstr2,NULL,16); } else { // Extract the information from the file name - this file does not have a palette crc; information is: // // o gosh, commenting source code is really boring - but necessary!! Thus do it! (and don't use drugs ;-)) sscanf(ptr,"%8c#%d#%d", crcstr, &fmt, &siz); // Use dummy for palette crc - that way each texture can be handled in a heterogeneous way palcrc32 = 0xFFFFFFFF; } // Terminate the ascii represntation of the texture crc crcstr[8]=0; // Transform the ascii presentation of the hex value to an unsigned integer crc = strtoul(crcstr,NULL,16); // For the detection of an existing item int foundIdx = -1; for( int k=0; k uint64 crc64 = newinfo.crc32; crc64 <<= 32; if (options.bLoadHiResCRCOnly) crc64 |= newinfo.pal_crc32&0xFFFFFFFF; else crc64 |= (newinfo.pal_crc32&0xFFFFFF00)|(newinfo.fmt<<4)|newinfo.siz; // Add the new record to the list infos.add(crc64,newinfo); } } } while(foundfilename != NULL); osal_search_dir_close(dir); } /******************************************************************************************************************** * Checks if a folder is actually existant. If not, it tries to create this folder * parameter: * pathname: the name of the folder that should be checked or created if not existant * return: * return value: flag that indicates true if the folder is existant or could be created. If none was the case, * false will be returned ********************************************************************************************************************/ bool CheckAndCreateFolder(const char* pathname) { // Check if provided folder already exists if( !PathFileExists((char*)pathname) ) { // It didn't. Try creating it. if (osal_mkdirp(pathname, 0700) != 0) { // It didn't work (probably insufficient permissions or read-only media) ==> return false DebugMessage(M64MSG_WARNING, "Can not create new folder: %s", pathname); return false; } } // success return true; } // microdev: THIS HAS TO BE CLEANED UP... // Texture dumping filenaming // GameName_FrameCount_CRC_Fmt_Siz.bmp // File format: BMP // GameName: N64 game internal name // CRC: 32 bit, 8 hex digits // Fmt: 0 - 4 // Siz: 0 - 3 const char *subfolders[] = { "png_all", "png_by_rgb_a", "ci_bmp", "ci_bmp_with_pal_crc", "ci_by_png", }; void FindAllDumpedTextures(void) { char foldername[PATH_MAX + 64]; strncpy(foldername, ConfigGetUserDataPath(), PATH_MAX); foldername[PATH_MAX] = 0; if (foldername[strlen(foldername) - 1] != OSAL_DIR_SEPARATOR_CHAR) strcat(foldername, OSAL_DIR_SEPARATOR_STR); strcat(foldername,"texture_dump" OSAL_DIR_SEPARATOR_STR); CheckAndCreateFolder(foldername); strcat(foldername,(const char*)g_curRomInfo.szGameName); strcat(foldername, OSAL_DIR_SEPARATOR_STR); gTxtrDumpInfos.clear(); if( !PathFileExists(foldername) ) { CheckAndCreateFolder(foldername); char foldername2[PATH_MAX]; for( int i=0; i<5; i++) { strcpy(foldername2,foldername); strcat(foldername2,subfolders[i]); CheckAndCreateFolder(foldername2); } return; } else { gTxtrDumpInfos.clear(); FindAllTexturesFromFolder(foldername,gTxtrDumpInfos, false, true); char foldername2[PATH_MAX]; for( int i=0; i<5; i++) { strcpy(foldername2,foldername); strcat(foldername2,subfolders[i]); CheckAndCreateFolder(foldername2); } } } /******************************************************************************************************************** * Truncates the current list with information about hires textures and scans the hires folder for hires textures and * creates a list with records of properties of the hires textures. * parameter: * none * return: * none ********************************************************************************************************************/ void FindAllHiResTextures(void) { char foldername[PATH_MAX + 64]; strncpy(foldername, ConfigGetUserDataPath(), PATH_MAX); foldername[PATH_MAX] = 0; // Assure that a backslash exists at the end (should be handled by GetPluginDir()) if(foldername[strlen(foldername) - 1] != OSAL_DIR_SEPARATOR_CHAR) strcat(foldername, OSAL_DIR_SEPARATOR_STR); // Add the relative path to the hires folder strcat(foldername,"hires_texture" OSAL_DIR_SEPARATOR_STR); // It does not exist? => Create it CheckAndCreateFolder(foldername); // Add the path to a sub-folder corresponding to the rom name // HOOK IN: PACK SELECT strcat(foldername,(const char*)g_curRomInfo.szGameName); strcat(foldername, OSAL_DIR_SEPARATOR_STR); // Truncate the current list with the hires texture info gHiresTxtrInfos.clear(); if (!osal_is_directory(foldername)) { DebugMessage(M64MSG_WARNING, "Couldn't open hi-res texture directory: %s", foldername); return; } else { // Find all hires textures and also cache them if configured to do so FindAllTexturesFromFolder(foldername,gHiresTxtrInfos, true, true); } } void CloseHiresTextures(void) { for( int i=0; i= entry.ti.HeightToLoad*(1<= entry.ti.WidthToLoad*(1< &infos, TxtrCacheEntry &entry, int &indexa, int &scaleShift, bool bForDump = false) { if ((entry.ti.WidthToLoad != 0 && entry.ti.WidthToCreate / entry.ti.WidthToLoad > 2) || (entry.ti.HeightToLoad != 0 && entry.ti.HeightToCreate / entry.ti.HeightToLoad > 2 )) { //DebugMessage(M64MSG_WARNING, "Hires texture does not support extreme texture replication"); return -1; } // determine if texture is a color-indexed (CI) texture bool bCI = (gRDP.otherMode.text_tlut>=2 || entry.ti.Format == TXT_FMT_CI || entry.ti.Format == TXT_FMT_RGBA) && entry.ti.Size <= TXT_SIZE_8b; // generate two alternative ids uint64 crc64a = entry.dwCRC; crc64a <<= 32; uint64 crc64b = crc64a; if (options.bLoadHiResCRCOnly) { crc64a |= (0xFFFFFFFF); crc64b |= (entry.dwPalCRC&0xFFFFFFFF); } else { crc64a |= (0xFFFFFF00|(entry.ti.Format<<4)|entry.ti.Size); crc64b |= ((entry.dwPalCRC&0xFFFFFF00)|(entry.ti.Format<<4)|entry.ti.Size); } // infos is the list containing the references to the detected external textures // get the number of items contained in this list int infosize = infos.size(); int indexb=-1; // try to identify the external texture that // corresponds to the original texture indexa = infos.find(crc64a); // For CI without pal CRC, and for RGBA_PNG_FOR_ALL_CI if( bCI ) // and also for textures with separate alpha channel indexb = infos.find(crc64b); // For CI or PNG with pal CRC // did not found the ext. text. if( indexa >= infosize ) indexa = -1; // did not found the ext. text. w/ sep. alpha channel if( indexb >= infosize ) indexb = -1; scaleShift = -1; // found texture with sep. alpha channel if( indexb >= 0 ) { // determine the factor for scaling scaleShift = FindScaleFactor(infos[indexb], entry); // ok. the scale factor is supported. A valid replacement has been found if( scaleShift >= 0 ) return indexb; } // if texture is 4bit, should be dumped and there is no match in the list of external textures if( bForDump && bCI && indexb < 0) // than return that there is no replacement & therefore texture can be dumped (microdev: not sure about that...) return -1; // texture has no separate alpha channel, try to find it in the ext. text. list if( indexa >= 0 ) scaleShift = FindScaleFactor(infos[indexa], entry); // ok. the scale factor is supported. A valid replacement has been found // this is a texture without ext. alpha channel if( scaleShift >= 0 ) return indexa; // no luck at all. there is no valid replacement else return -1; } bool SaveCITextureToFile(TxtrCacheEntry &entry, char *filename, bool bShow, bool bWhole); void DumpCachedTexture( TxtrCacheEntry &entry ) { char cSep = '/'; CTexture *pSrcTexture = entry.pTexture; if( pSrcTexture ) { // Check the vector table int ciidx, scaleShift; if( CheckTextureInfos(gTxtrDumpInfos,entry,ciidx,scaleShift,true) >= 0 ) return; // This texture has been dumpped char filename1[PATH_MAX + 64]; char filename2[PATH_MAX + 64]; char filename3[PATH_MAX + 64]; char gamefolder[PATH_MAX + 64]; strncpy(gamefolder, ConfigGetUserDataPath(), PATH_MAX); gamefolder[PATH_MAX] = 0; strcat(gamefolder,"texture_dump" OSAL_DIR_SEPARATOR_STR); strcat(gamefolder,(const char*)g_curRomInfo.szGameName); strcat(gamefolder, OSAL_DIR_SEPARATOR_STR); //sprintf(filename1+strlen(filename1), "%08X#%d#%d", entry.dwCRC, entry.ti.Format, entry.ti.Size); sprintf(filename1, "%s%s#%08X#%d#%d", gamefolder, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size); if( (gRDP.otherMode.text_tlut>=2 || entry.ti.Format == TXT_FMT_CI || entry.ti.Format == TXT_FMT_RGBA) && entry.ti.Size <= TXT_SIZE_8b ) { if( ciidx < 0 ) { sprintf(filename1, "%sci_bmp%c%s#%08X#%d#%d_ci", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size); SaveCITextureToFile(entry, filename1, false, false); } sprintf(filename1, "%sci_bmp_with_pal_crc%c%s#%08X#%d#%d#%08X_ci", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size,entry.dwPalCRC); SaveCITextureToFile(entry, filename1, false, false); sprintf(filename1, "%sci_by_png%c%s#%08X#%d#%d#%08X_ciByRGBA", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size,entry.dwPalCRC); CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename1, TXT_RGBA, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad); } else { sprintf(filename1, "%spng_by_rgb_a%c%s#%08X#%d#%d_rgb", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size); sprintf(filename2, "%spng_by_rgb_a%c%s#%08X#%d#%d_a", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size); sprintf(filename3, "%spng_all%c%s#%08X#%d#%d_all", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size); CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename1, TXT_RGB, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad); CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename3, TXT_RGBA, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad); if( entry.ti.Format != TXT_FMT_I ) { DrawInfo srcInfo; uint32 aFF = 0xFF; if( pSrcTexture->StartUpdate(&srcInfo) ) { // Copy RGB to buffer for( int i=entry.ti.HeightToLoad-1; i>=0; i--) { unsigned char *pSrc = (unsigned char*)srcInfo.lpSurface+srcInfo.lPitch * i; for( uint32 j=0; jEndUpdate(&srcInfo); } if( aFF != 0xFF) CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename2, TXT_ALPHA, false, false); } } ExtTxtrInfo newinfo; newinfo.width = entry.ti.WidthToLoad; newinfo.height = entry.ti.HeightToLoad; //strcpy(newinfo.name,g_curRomInfo.szGameName); newinfo.fmt = entry.ti.Format; newinfo.siz = entry.ti.Size; newinfo.crc32 = entry.dwCRC; newinfo.pal_crc32 = entry.dwPalCRC; newinfo.foldername = NULL; newinfo.filename = NULL; newinfo.filename_a = NULL; newinfo.type = NO_TEXTURE; newinfo.bSeparatedAlpha = false; uint64 crc64 = newinfo.crc32; crc64 <<= 32; if (options.bLoadHiResCRCOnly) crc64 |= newinfo.pal_crc32&0xFFFFFFFF; else crc64 |= (newinfo.pal_crc32&0xFFFFFF00)|(newinfo.fmt<<4)|newinfo.siz; gTxtrDumpInfos.add(crc64,newinfo); } } bool LoadRGBBufferFromPNGFile(char *filename, unsigned char **pbuf, int &width, int &height, int bits_per_pixel = 24 ) { struct BMGImageStruct img; memset(&img, 0, sizeof(BMGImageStruct)); if (!PathFileExists(filename)) { DebugMessage(M64MSG_ERROR, "File at '%s' doesn't exist in LoadRGBBufferFromPNGFile!", filename); return false; } BMG_Error code = ReadPNG( filename, &img ); if( code == BMG_OK ) { *pbuf = NULL; *pbuf = new unsigned char[img.width*img.height*bits_per_pixel/8]; if (*pbuf == NULL) { DebugMessage(M64MSG_ERROR, "new[] returned NULL for image width=%i height=%i bpp=%i", img.width, img.height, bits_per_pixel); return false; } if (img.bits_per_pixel == bits_per_pixel) { memcpy(*pbuf, img.bits, img.width*img.height*bits_per_pixel/8); } else if (img.bits_per_pixel == 24 && bits_per_pixel == 32) { unsigned char *pSrc = img.bits; unsigned char *pDst = *pbuf; for (int i = 0; i < (int)(img.width*img.height); i++) { *pDst++ = *pSrc++; *pDst++ = *pSrc++; *pDst++ = *pSrc++; *pDst++ = 0; } } // loaded image has alpha, needed image has to be without alpha channel else if (img.bits_per_pixel == 32 && bits_per_pixel == 24) { // pointer to source image data unsigned char *pSrc = img.bits; // buffer for destination image unsigned char *pDst = *pbuf; // copy data of the loaded image to the buffer by skipping the alpha byte for (int i = 0; i < (int)(img.width*img.height); i++) { // copy R *pDst++ = *pSrc++; // copy G *pDst++ = *pSrc++; // copy B *pDst++ = *pSrc++; // skip the alpha byte of the loaded image pSrc++; } } else if (img.bits_per_pixel == 8 && (bits_per_pixel == 24 || bits_per_pixel == 32)) { // do palette lookup and convert 8bpp to 24/32bpp int destBytePP = bits_per_pixel / 8; int paletteBytePP = img.bytes_per_palette_entry; unsigned char *pSrc = img.bits; unsigned char *pDst = *pbuf; // clear the destination image data (just to clear alpha if bpp=32) memset(*pbuf, 0, img.width*img.height*destBytePP); for (int i = 0; i < (int)(img.width*img.height); i++) { unsigned char clridx = *pSrc++; unsigned char *palcolor = img.palette + clridx * paletteBytePP; pDst[0] = palcolor[2]; // red pDst[1] = palcolor[1]; // green pDst[2] = palcolor[0]; // blue pDst += destBytePP; } } else { DebugMessage(M64MSG_ERROR, "PNG file '%s' is %i bpp but texture is %i bpp.", filename, img.bits_per_pixel, bits_per_pixel); delete [] *pbuf; *pbuf = NULL; } width = img.width; height = img.height; FreeBMGImage(&img); return true; } else { DebugMessage(M64MSG_ERROR, "ReadPNG() returned error for '%s' in LoadRGBBufferFromPNGFile!", filename); *pbuf = NULL; return false; } } bool LoadRGBABufferFromColorIndexedFile(char *filename, TxtrCacheEntry &entry, unsigned char **pbuf, int &width, int &height) { BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; FILE *f; f = fopen(filename, "rb"); if(f != NULL) { if (fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f) != 1 || fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f) != 1) { DebugMessage(M64MSG_ERROR, "Couldn't read BMP headers in file '%s'", filename); return false; } if( infoHeader.biBitCount != 4 && infoHeader.biBitCount != 8 ) { fclose(f); DebugMessage(M64MSG_ERROR, "Unsupported BMP file format: %s", filename); *pbuf = NULL; return false; } int tablesize = infoHeader.biBitCount == 4 ? 16 : 256; uint32 *pTable = new uint32[tablesize]; if (fread(pTable, tablesize*4, 1, f) != 1) { DebugMessage(M64MSG_ERROR, "Couldn't read BMP palette in file '%s'", filename); delete [] pTable; return false; } // Create the pallette table uint16 * pPal = (uint16 *)entry.ti.PalAddress; if( entry.ti.Size == TXT_SIZE_4b ) { // 4-bit table for( int i=0; i<16; i++ ) { pTable[i] = entry.ti.TLutFmt == TLUT_FMT_RGBA16 ? Convert555ToRGBA(pPal[i^1]) : ConvertIA16ToRGBA(pPal[i^1]); } } else { // 8-bit table for( int i=0; i<256; i++ ) { pTable[i] = entry.ti.TLutFmt == TLUT_FMT_RGBA16 ? Convert555ToRGBA(pPal[i^1]) : ConvertIA16ToRGBA(pPal[i^1]); } } *pbuf = new unsigned char[infoHeader.biWidth*infoHeader.biHeight*4]; if( *pbuf ) { unsigned char *colorIdxBuf = new unsigned char[infoHeader.biSizeImage]; if( colorIdxBuf ) { if (fread(colorIdxBuf, infoHeader.biSizeImage, 1, f) != 1) { DebugMessage(M64MSG_ERROR, "Couldn't read BMP image data in file '%s'", filename); } width = infoHeader.biWidth; height = infoHeader.biHeight; // Converting pallette texture to RGBA texture int idx = 0; uint32 *pbuf2 = (uint32*) *pbuf; for( int i=height-1; i>=0; i--) { for( int j=0; j>1]&0xF]; } else { // 0 *pbuf2++ = pTable[(colorIdxBuf[(idx++)>>1]>>4)&0xF]; } } else { // 8 bits *pbuf2++ = pTable[colorIdxBuf[idx++]]; } } if( entry.ti.Size == TXT_SIZE_4b ) { if( idx%8 ) idx = (idx/8+1)*8; } else { if( idx%4 ) idx = (idx/4+1)*4; } } delete [] colorIdxBuf; } else { TRACE0("Out of memory"); } delete [] pTable; return true; } else { fclose(f); delete [] pTable; return false; } } else { // Do something TRACE1("Fail to open file %s", filename); *pbuf = NULL; return false; } } bool LoadRGBBufferFromBMPFile(char *filename, unsigned char **pbuf, int &width, int &height) { BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; FILE *f; f = fopen(filename, "rb"); if(f != NULL) { if (fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f) != 1 || fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f) != 1) { DebugMessage(M64MSG_ERROR, "Couldn't read BMP headers in file '%s'", filename); return false; } if( infoHeader.biBitCount != 24 ) { fclose(f); DebugMessage(M64MSG_ERROR, "Unsupported BMP file 16 bits format: %s", filename); *pbuf = NULL; return false; } *pbuf = new unsigned char[infoHeader.biWidth*infoHeader.biHeight*3]; if( *pbuf ) { if (fread(*pbuf, infoHeader.biWidth*infoHeader.biHeight*3, 1, f) != 1) DebugMessage(M64MSG_ERROR, "Couldn't read RGB BMP image data in file '%s'", filename); fclose(f); width = infoHeader.biWidth; height = infoHeader.biHeight; return true; } else { fclose(f); return false; } } else { // Do something DebugMessage(M64MSG_WARNING, "Fail to open file %s", filename); *pbuf = NULL; return false; } } /******************************************************* * Loads the hires equivaltent of a texture * parameter: * TxtrCacheEntry: The original texture in the texture cache * return: * none *******************************************************/ void LoadHiresTexture( TxtrCacheEntry &entry ) { // check if the external texture has already been loaded if( entry.bExternalTxtrChecked ) return; // there is already an enhanced texture (e.g. a filtered one) if( entry.pEnhancedTexture ) { // delete it from memory before loading the external one SAFE_DELETE(entry.pEnhancedTexture); } int ciidx, scaleShift; // search the index of the appropriate hires replacement texture // in the list containing the infos of the external textures // ciidx is not needed here (just needed for dumping) int idx = CheckTextureInfos(gHiresTxtrInfos,entry,ciidx,scaleShift,false); if( idx < 0 ) { // there is no hires replacement => indicate that entry.bExternalTxtrChecked = true; return; } // Load the bitmap file char filename_rgb[PATH_MAX]; char filename_a[PATH_MAX]; strcpy(filename_rgb, gHiresTxtrInfos[idx].foldername); strcat(filename_rgb, gHiresTxtrInfos[idx].filename); if (gHiresTxtrInfos[idx].filename_a) { strcpy(filename_a, gHiresTxtrInfos[idx].foldername); strcat(filename_a, gHiresTxtrInfos[idx].filename_a); } else { strcpy(filename_a, ""); } // Load BMP image to buffer_rbg unsigned char *buf_rgba = NULL; unsigned char *buf_a = NULL; int width, height; bool bResRGBA=false, bResA=false; bool bCI = ((gRDP.otherMode.text_tlut>=2 || entry.ti.Format == TXT_FMT_CI || entry.ti.Format == TXT_FMT_RGBA) && entry.ti.Size <= TXT_SIZE_8b ); switch( gHiresTxtrInfos[idx].type ) { case RGB_PNG: if( bCI ) return; else { bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height); if( bResRGBA && gHiresTxtrInfos[idx].bSeparatedAlpha ) bResA = LoadRGBBufferFromPNGFile(filename_a, &buf_a, width, height); } break; case COLOR_INDEXED_BMP: if( bCI ) bResRGBA = LoadRGBABufferFromColorIndexedFile(filename_rgb, entry, &buf_rgba, width, height); else return; break; case RGBA_PNG_FOR_CI: case RGBA_PNG_FOR_ALL_CI: if( bCI ) bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height, 32); else return; break; case RGB_WITH_ALPHA_TOGETHER_PNG: if( bCI ) return; else bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height, 32); break; default: return; } if( !bResRGBA || !buf_rgba ) { DebugMessage(M64MSG_ERROR, "RGBBuffer creation failed for file '%s'.", filename_rgb); return; } // check if the alpha channel has been loaded if the texture has a separate alpha channel else if( gHiresTxtrInfos[idx].bSeparatedAlpha && !bResA ) { DebugMessage(M64MSG_ERROR, "Alpha buffer creation failed for file '%s'.", filename_a); delete [] buf_rgba; return; } // calculate the texture size magnification by comparing the N64 texture size and the hi-res texture size int scale = 1 << scaleShift; int mirrorx = 1; int mirrory = 1; int input_height_shift = height - entry.ti.HeightToLoad * scale; int input_pitch_a = width; int input_pitch_rgb = width; width = entry.ti.WidthToLoad * scale; height = entry.ti.HeightToLoad * scale; if (entry.ti.WidthToCreate/entry.ti.WidthToLoad == 2) mirrorx = 2; if (entry.ti.HeightToCreate/entry.ti.HeightToLoad == 2) mirrory = 2; entry.pEnhancedTexture = CDeviceBuilder::GetBuilder()->CreateTexture(entry.ti.WidthToCreate*scale, entry.ti.HeightToCreate*scale); DrawInfo info; if( entry.pEnhancedTexture && entry.pEnhancedTexture->StartUpdate(&info) ) { if( gHiresTxtrInfos[idx].type == RGB_PNG ) { input_pitch_rgb *= 3; input_pitch_a *= 3; if (info.lPitch < width * 4) DebugMessage(M64MSG_ERROR, "Texture pitch %i less than width %i times 4", info.lPitch, width); if (height > info.dwHeight) DebugMessage(M64MSG_ERROR, "Texture source height %i greater than destination height %i", height, info.dwHeight); // Update the texture by using the buffer for( int i=0; i=0; i--) { uint32 *pRGB = (uint32*)(buf_rgba + (input_height_shift + i) * input_pitch_rgb); uint32 *pdst = (uint32*)((unsigned char*)info.lpSurface + (height - i - 1)*info.lPitch); for( int j=0; jm_dwCreatedTextureWidth, height, T_FLAG, 4 ); } if( entry.ti.WidthToCreate*scale < entry.pEnhancedTexture->m_dwCreatedTextureWidth ) { // Clamp gTextureManager.Clamp(info.lpSurface, width, entry.pEnhancedTexture->m_dwCreatedTextureWidth, entry.pEnhancedTexture->m_dwCreatedTextureWidth, height, S_FLAG, 4 ); } if( entry.ti.HeightToCreate*scale < entry.pEnhancedTexture->m_dwCreatedTextureHeight ) { // Clamp gTextureManager.Clamp(info.lpSurface, height, entry.pEnhancedTexture->m_dwCreatedTextureHeight, entry.pEnhancedTexture->m_dwCreatedTextureWidth, height, T_FLAG, 4 ); } entry.pEnhancedTexture->EndUpdate(&info); entry.pEnhancedTexture->SetOthersVariables(); entry.pEnhancedTexture->m_bIsEnhancedTexture = true; entry.dwEnhancementFlag = TEXTURE_EXTERNAL; DebugMessage(M64MSG_VERBOSE, "Loaded hi-res texture: %s", filename_rgb); } else { DebugMessage(M64MSG_ERROR, "New texture creation failed."); TRACE0("Cannot create a new texture"); } if( buf_rgba ) { delete [] buf_rgba; } if( buf_a ) { delete [] buf_a; } } mupen64plus-video-rice-src-2.0/src/TextureFilters.h0000644000000000000000000000620312165031100020433 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __FILTERS_H__ #define __FILTERS_H__ #include "Config.h" #include "TextureManager.h" #define DWORD_MAKE(r, g, b, a) ((uint32) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))) #define WORD_MAKE(r, g, b, a) ((uint16) (((a) << 12) | ((r) << 8) | ((g) << 4) | (b))) extern void InitExternalTextures(void); extern void CloseExternalTextures(void); void Texture2x_32( DrawInfo &srcInfo, DrawInfo &destInfo); void Texture2x_16( DrawInfo &srcInfo, DrawInfo &destInfo); void Texture2x_Interp_32( DrawInfo &srcInfo, DrawInfo &destInfo); void Texture2x_Interp_16( DrawInfo &srcInfo, DrawInfo &destInfo); void Super2xSaI_32( uint32 *srcPtr, uint32 *destPtr, uint32 width, uint32 height, uint32 pitch); void Super2xSaI_16( uint16 *srcPtr, uint16 *destPtr, uint32 width, uint32 height, uint32 pitch); void hq4x_16( unsigned char * pIn, unsigned char * pOut, int Xres, int Yres, int SrcPPL, int BpL ); void hq4x_32( unsigned char * pIn, unsigned char * pOut, int Xres, int Yres, int SrcPPL, int BpL ); void hq4x_InitLUTs(void); void SmoothFilter_32(uint32 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter=TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1); void SmoothFilter_16(uint16 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter=TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1); void SharpenFilter_32(uint32 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter=TEXTURE_SHARPEN_ENHANCEMENT); void SharpenFilter_16(uint16 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter=TEXTURE_SHARPEN_ENHANCEMENT); void hq2x_init(unsigned bits_per_pixel); void hq2x_16(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height); void hq2x_32(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height); void lq2x_16(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height); void lq2x_32(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height); typedef enum _IMAGE_FILEFORMAT { XIFF_BMP = 0, XIFF_JPG = 1, XIFF_TGA = 2, XIFF_PNG = 3, XIFF_DDS = 4, XIFF_PPM = 5, XIFF_DIB = 6, XIFF_HDR = 7, XIFF_PFM = 8, XIFF_FORCE_DWORD = 0x7fffffff } IMAGE_FILEFORMAT; typedef struct _IMAGE_INFO { unsigned int Width; unsigned int Height; unsigned int Depth; unsigned int MipLevels; int Format; /* SURFFORMAT */ IMAGE_FILEFORMAT ImageFileFormat; } IMAGE_INFO; #endif mupen64plus-video-rice-src-2.0/src/TextureFilters_2xsai.cpp0000644000000000000000000003502412165031100022077 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "TextureFilters.h" /************************************************************************/ /* 2xSAI filters */ /************************************************************************/ static __inline int SAI_GetResult1_32( uint32 A, uint32 B, uint32 C, uint32 D, uint32 E ) { int x = 0; int y = 0; int r = 0; if (A == C) x += 1; else if (B == C) y += 1; if (A == D) x += 1; else if (B == D) y += 1; if (x <= 1) r += 1; if (y <= 1) r -= 1; return r; } static __inline uint16 SAI_GetResult1_16( uint16 A, uint16 B, uint16 C, uint16 D, uint16 E ) { uint16 x = 0; uint16 y = 0; uint16 r = 0; if (A == C) x += 1; else if (B == C) y += 1; if (A == D) x += 1; else if (B == D) y += 1; if (x <= 1) r += 1; if (y <= 1 && r>0) r -= 1; return r; } static __inline int SAI_GetResult2_32( uint32 A, uint32 B, uint32 C, uint32 D, uint32 E) { int x = 0; int y = 0; int r = 0; if (A == C) x += 1; else if (B == C) y += 1; if (A == D) x += 1; else if (B == D) y += 1; if (x <= 1) r -= 1; if (y <= 1) r += 1; return r; } static __inline uint16 SAI_GetResult2_16( uint16 A, uint16 B, uint16 C, uint16 D, uint16 E) { uint16 x = 0; uint16 y = 0; uint16 r = 0; if (A == C) x += 1; else if (B == C) y += 1; if (A == D) x += 1; else if (B == D) y += 1; if (x <= 1 && r>0 ) r -= 1; if (y <= 1) r += 1; return r; } static __inline int SAI_GetResult_32( uint32 A, uint32 B, uint32 C, uint32 D ) { int x = 0; int y = 0; int r = 0; if (A == C) x += 1; else if (B == C) y += 1; if (A == D) x += 1; else if (B == D) y += 1; if (x <= 1) r += 1; if (y <= 1) r -= 1; return r; } static __inline uint16 SAI_GetResult_16( uint16 A, uint16 B, uint16 C, uint16 D ) { uint16 x = 0; uint16 y = 0; uint16 r = 0; if (A == C) x += 1; else if (B == C) y += 1; if (A == D) x += 1; else if (B == D) y += 1; if (x <= 1) r += 1; if (y <= 1 && r>0 ) r -= 1; return r; } static __inline uint32 SAI_INTERPOLATE_32( uint32 A, uint32 B) { if (A != B) return ((A & 0xFEFEFEFE) >> 1) + (((B & 0xFEFEFEFE) >> 1) | (A & B & 0x01010101)); else return A; } static __inline uint16 SAI_INTERPOLATE_16( uint16 A, uint16 B) { if (A != B) return ((A & 0xFEFE) >> 1) + (((B & 0xFEFE) >> 1) | (A & B & 0x0101)); else return A; } static __inline uint32 SAI_Q_INTERPOLATE_32( uint32 A, uint32 B, uint32 C, uint32 D) { uint32 x = ((A & 0xFCFCFCFC) >> 2) + ((B & 0xFCFCFCFC) >> 2) + ((C & 0xFCFCFCFC) >> 2) + ((D & 0xFCFCFCFC) >> 2); uint32 y = (((A & 0x03030303) + (B & 0x03030303) + (C & 0x03030303) + (D & 0x03030303)) >> 2) & 0x03030303; return x | y; } static __inline uint16 SAI_Q_INTERPOLATE_16( uint16 A, uint16 B, uint16 C, uint16 D) { uint16 x = ((A & 0xFCFC) >> 2) + ((B & 0xFCFC) >> 2) + ((C & 0xFCFC) >> 2) + ((D & 0xFCFC) >> 2); uint16 y = (((A & 0x0303) + (B & 0x0303) + (C & 0x0303) + (D & 0x0303)) >> 2) & 0x0303; return x | y; } void Super2xSaI_32( uint32 *srcPtr, uint32 *destPtr, uint32 width, uint32 height, uint32 pitch) { uint32 destWidth = width << 1; //uint32 destHeight = height << 1; uint32 color4, color5, color6; uint32 color1, color2, color3; uint32 colorA0, colorA1, colorA2, colorA3; uint32 colorB0, colorB1, colorB2, colorB3; uint32 colorS1, colorS2; uint32 product1a, product1b, product2a, product2b; int row0, row1, row2, row3; int col0, col1, col2, col3; for (uint16 y = 0; y < height; y++) { if (y > 0) { row0 = width; row0 = -row0; } else row0 = 0; row1 = 0; if (y < height - 1) { row2 = width; if (y < height - 2) row3 = width << 1; else row3 = width; } else { row2 = 0; row3 = 0; } for (uint16 x = 0; x < width; x++) { //--------------------------------------- B0 B1 B2 B3 // 4 5 6 S2 // 1 2 3 S1 // A0 A1 A2 A3 if (x > 0) col0 = -1; else col0 = 0; col1 = 0; if (x < width - 1) { col2 = 1; if (x < width - 2) col3 = 2; else col3 = 1; } else { col2 = 0; col3 = 0; } colorB0 = *(srcPtr + col0 + row0); colorB1 = *(srcPtr + col1 + row0); colorB2 = *(srcPtr + col2 + row0); colorB3 = *(srcPtr + col3 + row0); color4 = *(srcPtr + col0 + row1); color5 = *(srcPtr + col1 + row1); color6 = *(srcPtr + col2 + row1); colorS2 = *(srcPtr + col3 + row1); color1 = *(srcPtr + col0 + row2); color2 = *(srcPtr + col1 + row2); color3 = *(srcPtr + col2 + row2); colorS1 = *(srcPtr + col3 + row2); colorA0 = *(srcPtr + col0 + row3); colorA1 = *(srcPtr + col1 + row3); colorA2 = *(srcPtr + col2 + row3); colorA3 = *(srcPtr + col3 + row3); //-------------------------------------- if (color2 == color6 && color5 != color3) product2b = product1b = color2; else if (color5 == color3 && color2 != color6) product2b = product1b = color5; else if (color5 == color3 && color2 == color6) { int r = 0; r += SAI_GetResult_32 (color6, color5, color1, colorA1); r += SAI_GetResult_32 (color6, color5, color4, colorB1); r += SAI_GetResult_32 (color6, color5, colorA2, colorS1); r += SAI_GetResult_32 (color6, color5, colorB2, colorS2); if (r > 0) product2b = product1b = color6; else if (r < 0) product2b = product1b = color5; else product2b = product1b = SAI_INTERPOLATE_32 (color5, color6); } else { if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0) product2b = SAI_Q_INTERPOLATE_32 (color3, color3, color3, color2); else if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3) product2b = SAI_Q_INTERPOLATE_32 (color2, color2, color2, color3); else product2b = SAI_INTERPOLATE_32 (color2, color3); if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0) product1b = SAI_Q_INTERPOLATE_32 (color6, color6, color6, color5); else if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3) product1b = SAI_Q_INTERPOLATE_32 (color6, color5, color5, color5); else product1b = SAI_INTERPOLATE_32 (color5, color6); } if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2) product2a = SAI_INTERPOLATE_32 (color2, color5); else if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0) product2a = SAI_INTERPOLATE_32(color2, color5); else product2a = color2; if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2) product1a = SAI_INTERPOLATE_32 (color2, color5); else if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0) product1a = SAI_INTERPOLATE_32(color2, color5); else product1a = color5; destPtr[0] = product1a; destPtr[1] = product1b; destPtr[destWidth] = product2a; destPtr[destWidth + 1] = product2b; srcPtr++; destPtr += 2; } srcPtr += (pitch-width); destPtr += (((pitch-width)<<1)+(pitch<<1)); } } void Super2xSaI_16( uint16 *srcPtr, uint16 *destPtr, uint32 width, uint32 height, uint32 pitch) { uint32 destWidth = width << 1; //uint32 destHeight = height << 1; uint16 color4, color5, color6; uint16 color1, color2, color3; uint16 colorA0, colorA1, colorA2, colorA3; uint16 colorB0, colorB1, colorB2, colorB3; uint16 colorS1, colorS2; uint16 product1a, product1b, product2a, product2b; int row0, row1, row2, row3; int col0, col1, col2, col3; for (uint16 y = 0; y < height; y++) { if (y > 0) { row0 = width; row0 = -row0; } else row0 = 0; row1 = 0; if (y < height - 1) { row2 = width; if (y < height - 2) row3 = width << 1; else row3 = width; } else { row2 = 0; row3 = 0; } for (uint16 x = 0; x < width; x++) { //--------------------------------------- B0 B1 B2 B3 // 4 5 6 S2 // 1 2 3 S1 // A0 A1 A2 A3 if (x > 0) col0 = -1; else col0 = 0; col1 = 0; if (x < width - 1) { col2 = 1; if (x < width - 2) col3 = 2; else col3 = 1; } else { col2 = 0; col3 = 0; } colorB0 = *(srcPtr + col0 + row0); colorB1 = *(srcPtr + col1 + row0); colorB2 = *(srcPtr + col2 + row0); colorB3 = *(srcPtr + col3 + row0); color4 = *(srcPtr + col0 + row1); color5 = *(srcPtr + col1 + row1); color6 = *(srcPtr + col2 + row1); colorS2 = *(srcPtr + col3 + row1); color1 = *(srcPtr + col0 + row2); color2 = *(srcPtr + col1 + row2); color3 = *(srcPtr + col2 + row2); colorS1 = *(srcPtr + col3 + row2); colorA0 = *(srcPtr + col0 + row3); colorA1 = *(srcPtr + col1 + row3); colorA2 = *(srcPtr + col2 + row3); colorA3 = *(srcPtr + col3 + row3); //-------------------------------------- if (color2 == color6 && color5 != color3) product2b = product1b = color2; else if (color5 == color3 && color2 != color6) product2b = product1b = color5; else if (color5 == color3 && color2 == color6) { int r = 0; r += SAI_GetResult_16 (color6, color5, color1, colorA1); r += SAI_GetResult_16 (color6, color5, color4, colorB1); r += SAI_GetResult_16 (color6, color5, colorA2, colorS1); r += SAI_GetResult_16 (color6, color5, colorB2, colorS2); if (r > 0) product2b = product1b = color6; else if (r < 0) product2b = product1b = color5; else product2b = product1b = SAI_INTERPOLATE_16 (color5, color6); } else { if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0) product2b = SAI_Q_INTERPOLATE_16 (color3, color3, color3, color2); else if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3) product2b = SAI_Q_INTERPOLATE_16 (color2, color2, color2, color3); else product2b = SAI_INTERPOLATE_16 (color2, color3); if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0) product1b = SAI_Q_INTERPOLATE_16 (color6, color6, color6, color5); else if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3) product1b = SAI_Q_INTERPOLATE_16 (color6, color5, color5, color5); else product1b = SAI_INTERPOLATE_16 (color5, color6); } if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2) product2a = SAI_INTERPOLATE_16 (color2, color5); else if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0) product2a = SAI_INTERPOLATE_16(color2, color5); else product2a = color2; if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2) product1a = SAI_INTERPOLATE_16 (color2, color5); else if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0) product1a = SAI_INTERPOLATE_16(color2, color5); else product1a = color5; destPtr[0] = product1a; destPtr[1] = product1b; destPtr[destWidth] = product2a; destPtr[destWidth + 1] = product2b; srcPtr++; destPtr += 2; } srcPtr += (pitch-width); destPtr += (((pitch-width)<<1)+(pitch<<1)); } } mupen64plus-video-rice-src-2.0/src/TextureFilters_hq2x.cpp0000644000000000000000000006356312165031100021744 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - TextureFilters_hq2x.cpp * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "typedefs.h" /************************************************************************/ /* hq2x filters */ /************************************************************************/ /***************************************************************************/ /* Basic types */ /***************************************************************************/ /* interpolation */ static unsigned interp_bits_per_pixel; #define INTERP_16_MASK_1_3(v) ((v)&0x0F0F) #define INTERP_16_MASK_SHIFT_2_4(v) (((v)&0xF0F0)>>4) #define INTERP_16_MASK_SHIFTBACK_2_4(v) ((INTERP_16_MASK_1_3(v))<<4) static inline uint16 hq2x_interp_16_521(uint16 p1, uint16 p2, uint16 p3) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*5 + INTERP_16_MASK_1_3(p2)*2 + INTERP_16_MASK_1_3(p3)*1) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*5 + INTERP_16_MASK_SHIFT_2_4(p2)*2 + INTERP_16_MASK_SHIFT_2_4(p3)*1) / 8); } static inline uint16 hq2x_interp_16_332(uint16 p1, uint16 p2, uint16 p3) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*3 + INTERP_16_MASK_1_3(p2)*3 + INTERP_16_MASK_1_3(p3)*2) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*3 + INTERP_16_MASK_SHIFT_2_4(p2)*3 + INTERP_16_MASK_SHIFT_2_4(p3)*2) / 8); } static inline uint16 hq2x_interp_16_611(uint16 p1, uint16 p2, uint16 p3) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*6 + INTERP_16_MASK_1_3(p2) + INTERP_16_MASK_1_3(p3)) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*6 + INTERP_16_MASK_SHIFT_2_4(p2) + INTERP_16_MASK_SHIFT_2_4(p3)) / 8); } static inline uint16 hq2x_interp_16_71(uint16 p1, uint16 p2) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*7 + INTERP_16_MASK_1_3(p2)) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*7 + INTERP_16_MASK_SHIFT_2_4(p2)) / 8); } static inline uint16 hq2x_interp_16_211(uint16 p1, uint16 p2, uint16 p3) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*2 + INTERP_16_MASK_1_3(p2) + INTERP_16_MASK_1_3(p3)) / 4) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*2 + INTERP_16_MASK_SHIFT_2_4(p2) + INTERP_16_MASK_SHIFT_2_4(p3)) / 4); } static inline uint16 hq2x_interp_16_772(uint16 p1, uint16 p2, uint16 p3) { return INTERP_16_MASK_1_3(((INTERP_16_MASK_1_3(p1) + INTERP_16_MASK_1_3(p2))*7 + INTERP_16_MASK_1_3(p3)*2) / 16) | INTERP_16_MASK_SHIFTBACK_2_4(((INTERP_16_MASK_SHIFT_2_4(p1) + INTERP_16_MASK_SHIFT_2_4(p2))*7 + INTERP_16_MASK_SHIFT_2_4(p3)*2) / 16); } static inline uint16 hq2x_interp_16_11(uint16 p1, uint16 p2) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1) + INTERP_16_MASK_1_3(p2)) / 2) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1) + INTERP_16_MASK_SHIFT_2_4(p2)) / 2); } static inline uint16 hq2x_interp_16_31(uint16 p1, uint16 p2) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*3 + INTERP_16_MASK_1_3(p2)) / 4) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*3 + INTERP_16_MASK_SHIFT_2_4(p2)) / 4); } static inline uint16 hq2x_interp_16_1411(uint16 p1, uint16 p2, uint16 p3) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*14 + INTERP_16_MASK_1_3(p2) + INTERP_16_MASK_1_3(p3)) / 16) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*14 + INTERP_16_MASK_SHIFT_2_4(p2) + INTERP_16_MASK_SHIFT_2_4(p3)) / 16); } static inline uint16 hq2x_interp_16_431(uint16 p1, uint16 p2, uint16 p3) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*4 + INTERP_16_MASK_1_3(p2)*3 + INTERP_16_MASK_1_3(p3)) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*4 + INTERP_16_MASK_SHIFT_2_4(p2)*3 + INTERP_16_MASK_SHIFT_2_4(p3)) / 8); } static inline uint16 hq2x_interp_16_53(uint16 p1, uint16 p2) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*5 + INTERP_16_MASK_1_3(p2)*3) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*5 + INTERP_16_MASK_SHIFT_2_4(p2)*3) / 8); } static inline uint16 hq2x_interp_16_151(uint16 p1, uint16 p2) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*15 + INTERP_16_MASK_1_3(p2)) / 16) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*15 + INTERP_16_MASK_SHIFT_2_4(p2)) / 16); } static inline uint16 hq2x_interp_16_97(uint16 p1, uint16 p2) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*9 + INTERP_16_MASK_1_3(p2)*7) / 16) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*9 + INTERP_16_MASK_SHIFT_2_4(p2)*7) / 16); } #define INTERP_32_MASK_1_3(v) ((v)&0x00FF00FF) #define INTERP_32_MASK_SHIFT_2_4(v) (((v)&0xFF00FF00)>>8) #define INTERP_32_MASK_SHIFTBACK_2_4(v) (((INTERP_32_MASK_1_3(v))<<8)) static inline uint32 hq2x_interp_32_521(uint32 p1, uint32 p2, uint32 p3) { return INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*5 + INTERP_32_MASK_1_3(p2)*2 + INTERP_32_MASK_1_3(p3)*1) / 8) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*5 + INTERP_32_MASK_SHIFT_2_4(p2)*2 + INTERP_32_MASK_SHIFT_2_4(p3)*1) / 8); } static inline uint32 hq2x_interp_32_332(uint32 p1, uint32 p2, uint32 p3) { return INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*3 + INTERP_32_MASK_1_3(p2)*3 + INTERP_32_MASK_1_3(p3)*2) / 8) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*3 + INTERP_32_MASK_SHIFT_2_4(p2)*3 + INTERP_32_MASK_SHIFT_2_4(p3)*2) / 8); } static inline uint32 hq2x_interp_32_211(uint32 p1, uint32 p2, uint32 p3) { return INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*2 + INTERP_32_MASK_1_3(p2) + INTERP_32_MASK_1_3(p3)) / 4) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*2 + INTERP_32_MASK_SHIFT_2_4(p2) + INTERP_32_MASK_SHIFT_2_4(p3)) / 4); } static inline uint32 hq2x_interp_32_611(uint32 p1, uint32 p2, uint32 p3) { return INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*6 + INTERP_32_MASK_1_3(p2) + INTERP_32_MASK_1_3(p3)) / 8) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*6 + INTERP_32_MASK_SHIFT_2_4(p2) + INTERP_32_MASK_SHIFT_2_4(p3)) / 8); } static inline uint32 hq2x_interp_32_71(uint32 p1, uint32 p2) { return INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*7 + INTERP_32_MASK_1_3(p2)) / 8) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*7 + INTERP_32_MASK_SHIFT_2_4(p2)) / 8); } static inline uint32 hq2x_interp_32_772(uint32 p1, uint32 p2, uint32 p3) { return INTERP_32_MASK_1_3(((INTERP_32_MASK_1_3(p1) + INTERP_32_MASK_1_3(p2))*7 + INTERP_32_MASK_1_3(p3)*2) / 16) | INTERP_32_MASK_SHIFTBACK_2_4(((INTERP_32_MASK_SHIFT_2_4(p1) + INTERP_32_MASK_SHIFT_2_4(p2))*7 + INTERP_32_MASK_SHIFT_2_4(p3)*2) / 16); } static inline uint32 hq2x_interp_32_11(uint32 p1, uint32 p2) { return INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1) + INTERP_32_MASK_1_3(p2)) / 2) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1) + INTERP_32_MASK_SHIFT_2_4(p2)) / 2); } static inline uint32 hq2x_interp_32_31(uint32 p1, uint32 p2) { return INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*3 + INTERP_32_MASK_1_3(p2)) / 4) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*3 + INTERP_32_MASK_SHIFT_2_4(p2)) / 4); } static inline uint32 hq2x_interp_32_1411(uint32 p1, uint32 p2, uint32 p3) { return INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*14 + INTERP_32_MASK_1_3(p2) + INTERP_32_MASK_1_3(p3)) / 16) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*14 + INTERP_32_MASK_SHIFT_2_4(p2) + INTERP_32_MASK_SHIFT_2_4(p3)) / 16); } static inline uint32 hq2x_interp_32_431(uint32 p1, uint32 p2, uint32 p3) { return INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*4 + INTERP_32_MASK_1_3(p2)*3 + INTERP_32_MASK_1_3(p3)) / 8) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*4 + INTERP_32_MASK_SHIFT_2_4(p2)*3 + INTERP_32_MASK_SHIFT_2_4(p3)) / 8); } static inline uint32 hq2x_interp_32_53(uint32 p1, uint32 p2) { return INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*5 + INTERP_32_MASK_1_3(p2)*3) / 8) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*5 + INTERP_32_MASK_SHIFT_2_4(p2)*3) / 8); } static inline uint32 hq2x_interp_32_151(uint32 p1, uint32 p2) { return INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*15 + INTERP_32_MASK_1_3(p2)) / 16) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*15 + INTERP_32_MASK_SHIFT_2_4(p2)) / 16); } static inline uint32 hq2x_interp_32_97(uint32 p1, uint32 p2) { return INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*9 + INTERP_32_MASK_1_3(p2)*7) / 16) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*9 + INTERP_32_MASK_SHIFT_2_4(p2)*7) / 16); } /***************************************************************************/ /* diff */ #define INTERP_Y_LIMIT (0x30*4) #define INTERP_U_LIMIT (0x07*4) #define INTERP_V_LIMIT (0x06*8) static int hq2x_interp_16_diff(uint16 p1, uint16 p2) { int r, g, b; int y, u, v; if (p1 == p2) return 0; b = (int)((p1 & 0x000F) - (p2 & 0x000F)); g = (int)((p1 & 0x00F0) - (p2 & 0x00F0)) >> 4; r = (int)((p1 & 0x0F00) - (p2 & 0x0F00)) >> 8; y = r + g + b; u = r - b; v = -r + 2*g - b; if (y < -INTERP_Y_LIMIT || y > INTERP_Y_LIMIT) return 1; if (u < -INTERP_U_LIMIT || u > INTERP_U_LIMIT) return 1; if (v < -INTERP_V_LIMIT || v > INTERP_V_LIMIT) return 1; return 0; } static int hq2x_interp_32_diff(uint32 p1, uint32 p2) { int r, g, b; int y, u, v; if ((p1 & 0xF8F8F8) == (p2 & 0xF8F8F8)) return 0; b = (int)((p1 & 0xFF) - (p2 & 0xFF)); g = (int)((p1 & 0xFF00) - (p2 & 0xFF00)) >> 8; r = (int)((p1 & 0xFF0000) - (p2 & 0xFF0000)) >> 16; y = r + g + b; u = r - b; v = -r + 2*g - b; if (y < -INTERP_Y_LIMIT || y > INTERP_Y_LIMIT) return 1; if (u < -INTERP_U_LIMIT || u > INTERP_U_LIMIT) return 1; if (v < -INTERP_V_LIMIT || v > INTERP_V_LIMIT) return 1; return 0; } static void interp_set(unsigned bits_per_pixel) { interp_bits_per_pixel = bits_per_pixel; } static void hq2x_16_def(uint16* dst0, uint16* dst1, const uint16* src0, const uint16* src1, const uint16* src2, unsigned count) { unsigned i; for(i=0;i0) { c[0] = src0[-1]; c[3] = src1[-1]; c[6] = src2[-1]; } else { c[0] = c[1]; c[3] = c[4]; c[6] = c[7]; } if (i0) { c[0] = src0[-1]; c[3] = src1[-1]; c[6] = src2[-1]; } else { c[0] = src0[0]; c[3] = src1[0]; c[6] = src2[0]; } if (i0) { c[0] = src0[-1]; c[3] = src1[-1]; c[6] = src2[-1]; } else { c[0] = c[1]; c[3] = c[4]; c[6] = c[7]; } if (i0) { c[0] = src0[-1]; c[3] = src1[-1]; c[6] = src2[-1]; } else { c[0] = c[1]; c[3] = c[4]; c[6] = c[7]; } if (i> 1); uint16 *src0 = (uint16 *)srcPtr; uint16 *src1 = src0 + (srcPitch >> 1); uint16 *src2 = src1 + (srcPitch >> 1); hq2x_16_def(dst0, dst1, src0, src0, src1, width); if( height == 1 ) return; int count = height; count -= 2; while(count>0) { dst0 += dstPitch; dst1 += dstPitch; hq2x_16_def(dst0, dst1, src0, src1, src2, width); src0 = src1; src1 = src2; src2 += srcPitch >> 1; --count; } dst0 += dstPitch; dst1 += dstPitch; hq2x_16_def(dst0, dst1, src0, src1, src1, width); } void hq2x_32(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { uint32 *dst0 = (uint32 *)dstPtr; uint32 *dst1 = dst0 + (dstPitch >> 2); uint32 *src0 = (uint32 *)srcPtr; uint32 *src1 = src0 + (srcPitch >> 2); uint32 *src2 = src1 + (srcPitch >> 2); hq2x_32_def(dst0, dst1, src0, src0, src1, width); if( height == 1 ) return; int count = height; count -= 2; while(count>0) { dst0 += dstPitch >> 1; dst1 += dstPitch >> 1; hq2x_32_def(dst0, dst1, src0, src1, src2, width); src0 = src1; src1 = src2; src2 += srcPitch >> 2; --count; } dst0 += dstPitch >> 1; dst1 += dstPitch >> 1; hq2x_32_def(dst0, dst1, src0, src1, src1, width); } void lq2x_16(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { uint16 *dst0 = (uint16 *)dstPtr; uint16 *dst1 = dst0 + (dstPitch >> 1); uint16 *src0 = (uint16 *)srcPtr; uint16 *src1 = src0 + (srcPitch >> 1); uint16 *src2 = src1 + (srcPitch >> 1); lq2x_16_def(dst0, dst1, src0, src0, src1, width); if( height == 1 ) return; int count = height; count -= 2; while(count>0) { dst0 += dstPitch; dst1 += dstPitch; hq2x_16_def(dst0, dst1, src0, src1, src2, width); src0 = src1; src1 = src2; src2 += srcPitch >> 1; --count; } dst0 += dstPitch; dst1 += dstPitch; lq2x_16_def(dst0, dst1, src0, src1, src1, width); } void lq2x_32(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { uint32 *dst0 = (uint32 *)dstPtr; uint32 *dst1 = dst0 + (dstPitch >> 2); uint32 *src0 = (uint32 *)srcPtr; uint32 *src1 = src0 + (srcPitch >> 2); uint32 *src2 = src1 + (srcPitch >> 2); lq2x_32_def(dst0, dst1, src0, src0, src1, width); if( height == 1 ) return; int count = height; count -= 2; while(count>0) { dst0 += dstPitch >> 1; dst1 += dstPitch >> 1; hq2x_32_def(dst0, dst1, src0, src1, src2, width); src0 = src1; src1 = src2; src2 += srcPitch >> 2; --count; } dst0 += dstPitch >> 1; dst1 += dstPitch >> 1; lq2x_32_def(dst0, dst1, src0, src1, src1, width); } void hq2x_init(unsigned bits_per_pixel) { interp_set(bits_per_pixel); } /************************************************************************/ /* hq3x filters */ /************************************************************************/ /************************************************************************/ /* scale2x filters */ /************************************************************************/ /************************************************************************/ /* scale3x filters */ /************************************************************************/ mupen64plus-video-rice-src-2.0/src/TextureFilters_hq2x.h0000644000000000000000000006455512165031100021413 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - TextureFilters_hq2x.h * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2003 Rice1964 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ case 0 : case 1 : case 4 : case 5 : case 32 : case 33 : case 36 : case 37 : case 128 : case 129 : case 132 : case 133 : case 160 : case 161 : case 164 : case 165 : { P0 = I211(4, 1, 3); P1 = I211(4, 1, 5); P2 = I211(4, 3, 7); P3 = I211(4, 5, 7); } break; case 2 : case 34 : case 130 : case 162 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I211(4, 3, 7); P3 = I211(4, 5, 7); } break; case 3 : case 35 : case 131 : case 163 : { P0 = I31(4, 3); P1 = I31(4, 2); P2 = I211(4, 3, 7); P3 = I211(4, 5, 7); } break; case 6 : case 38 : case 134 : case 166 : { P0 = I31(4, 0); P1 = I31(4, 5); P2 = I211(4, 3, 7); P3 = I211(4, 5, 7); } break; case 7 : case 39 : case 135 : case 167 : { P0 = I31(4, 3); P1 = I31(4, 5); P2 = I211(4, 3, 7); P3 = I211(4, 5, 7); } break; case 8 : case 12 : case 136 : case 140 : { P0 = I31(4, 0); P1 = I211(4, 1, 5); P2 = I31(4, 6); P3 = I211(4, 5, 7); } break; case 9 : case 13 : case 137 : case 141 : { P0 = I31(4, 1); P1 = I211(4, 1, 5); P2 = I31(4, 6); P3 = I211(4, 5, 7); } break; case 10 : case 138 : { P1 = I31(4, 2); P2 = I31(4, 6); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I211(4, 1, 3); } } break; case 11 : case 139 : { P1 = I31(4, 2); P2 = I31(4, 6); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 14 : case 142 : { P2 = I31(4, 6); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = I31(4, 0); P1 = I31(4, 5); } else { P0 = I332(1, 3, 4); P1 = I521(4, 1, 5); } } break; case 15 : case 143 : { P2 = I31(4, 6); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = IC(4); P1 = I31(4, 5); } else { P0 = I332(1, 3, 4); P1 = I521(4, 1, 5); } } break; case 16 : case 17 : case 48 : case 49 : { P0 = I211(4, 1, 3); P1 = I31(4, 2); P2 = I211(4, 3, 7); P3 = I31(4, 8); } break; case 18 : case 50 : { P0 = I31(4, 0); P2 = I211(4, 3, 7); P3 = I31(4, 8); if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I211(4, 1, 5); } } break; case 19 : case 51 : { P2 = I211(4, 3, 7); P3 = I31(4, 8); if (HQ2X_MUR) { P0 = I31(4, 3); P1 = I31(4, 2); } else { P0 = I521(4, 1, 3); P1 = I332(1, 5, 4); } } break; case 20 : case 21 : case 52 : case 53 : { P0 = I211(4, 1, 3); P1 = I31(4, 1); P2 = I211(4, 3, 7); P3 = I31(4, 8); } break; case 22 : case 54 : { P0 = I31(4, 0); P2 = I211(4, 3, 7); P3 = I31(4, 8); if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 23 : case 55 : { P2 = I211(4, 3, 7); P3 = I31(4, 8); if (HQ2X_MUR) { P0 = I31(4, 3); P1 = IC(4); } else { P0 = I521(4, 1, 3); P1 = I332(1, 5, 4); } } break; case 24 : case 66 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 25 : { P0 = I31(4, 1); P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 26 : case 31 : case 95 : { P2 = I31(4, 6); P3 = I31(4, 8); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 27 : case 75 : { P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 8); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 28 : { P0 = I31(4, 0); P1 = I31(4, 1); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 29 : { P0 = I31(4, 1); P1 = I31(4, 1); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 30 : case 86 : { P0 = I31(4, 0); P2 = I31(4, 6); P3 = I31(4, 8); if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 40 : case 44 : case 168 : case 172 : { P0 = I31(4, 0); P1 = I211(4, 1, 5); P2 = I31(4, 7); P3 = I211(4, 5, 7); } break; case 41 : case 45 : case 169 : case 173 : { P0 = I31(4, 1); P1 = I211(4, 1, 5); P2 = I31(4, 7); P3 = I211(4, 5, 7); } break; case 42 : case 170 : { P1 = I31(4, 2); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = I31(4, 0); P2 = I31(4, 7); } else { P0 = I332(1, 3, 4); P2 = I521(4, 3, 7); } } break; case 43 : case 171 : { P1 = I31(4, 2); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = IC(4); P2 = I31(4, 7); } else { P0 = I332(1, 3, 4); P2 = I521(4, 3, 7); } } break; case 46 : case 174 : { P1 = I31(4, 5); P2 = I31(4, 7); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } } break; case 47 : case 175 : { P1 = I31(4, 5); P2 = I31(4, 7); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } } break; case 56 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 7); P3 = I31(4, 8); } break; case 57 : { P0 = I31(4, 1); P1 = I31(4, 2); P2 = I31(4, 7); P3 = I31(4, 8); } break; case 58 : { P2 = I31(4, 7); P3 = I31(4, 8); if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 59 : { P2 = I31(4, 7); P3 = I31(4, 8); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 60 : { P0 = I31(4, 0); P1 = I31(4, 1); P2 = I31(4, 7); P3 = I31(4, 8); } break; case 61 : { P0 = I31(4, 1); P1 = I31(4, 1); P2 = I31(4, 7); P3 = I31(4, 8); } break; case 62 : { P0 = I31(4, 0); P2 = I31(4, 7); P3 = I31(4, 8); if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 63 : { P2 = I31(4, 7); P3 = I31(4, 8); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 64 : case 65 : case 68 : case 69 : { P0 = I211(4, 1, 3); P1 = I211(4, 1, 5); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 67 : { P0 = I31(4, 3); P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 70 : { P0 = I31(4, 0); P1 = I31(4, 5); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 71 : { P0 = I31(4, 3); P1 = I31(4, 5); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 72 : case 76 : { P0 = I31(4, 0); P1 = I211(4, 1, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I211(4, 3, 7); } } break; case 73 : case 77 : { P1 = I211(4, 1, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P0 = I31(4, 1); P2 = I31(4, 6); } else { P0 = I521(4, 3, 1); P2 = I332(3, 7, 4); } } break; case 74 : case 107 : case 123 : { P1 = I31(4, 2); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 78 : { P1 = I31(4, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } } break; case 79 : { P1 = I31(4, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 80 : case 81 : { P0 = I211(4, 1, 3); P1 = I31(4, 2); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I211(4, 5, 7); } } break; case 82 : case 214 : case 222 : { P0 = I31(4, 0); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 83 : { P0 = I31(4, 3); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 84 : case 85 : { P0 = I211(4, 1, 3); P2 = I31(4, 6); if (HQ2X_MDR) { P1 = I31(4, 1); P3 = I31(4, 8); } else { P1 = I521(4, 5, 1); P3 = I332(5, 7, 4); } } break; case 87 : { P0 = I31(4, 3); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 88 : case 248 : case 250 : { P0 = I31(4, 0); P1 = I31(4, 2); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } } break; case 89 : { P0 = I31(4, 1); P1 = I31(4, 2); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } } break; case 90 : { if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 91 : { if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 92 : { P0 = I31(4, 0); P1 = I31(4, 1); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } } break; case 93 : { P0 = I31(4, 1); P1 = I31(4, 1); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } } break; case 94 : { if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 96 : case 97 : case 100 : case 101 : { P0 = I211(4, 1, 3); P1 = I211(4, 1, 5); P2 = I31(4, 3); P3 = I31(4, 8); } break; case 98 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 3); P3 = I31(4, 8); } break; case 99 : { P0 = I31(4, 3); P1 = I31(4, 2); P2 = I31(4, 3); P3 = I31(4, 8); } break; case 102 : { P0 = I31(4, 0); P1 = I31(4, 5); P2 = I31(4, 3); P3 = I31(4, 8); } break; case 103 : { P0 = I31(4, 3); P1 = I31(4, 5); P2 = I31(4, 3); P3 = I31(4, 8); } break; case 104 : case 108 : { P0 = I31(4, 0); P1 = I211(4, 1, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } } break; case 105 : case 109 : { P1 = I211(4, 1, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P0 = I31(4, 1); P2 = IC(4); } else { P0 = I521(4, 3, 1); P2 = I332(3, 7, 4); } } break; case 106 : case 120 : { P0 = I31(4, 0); P1 = I31(4, 2); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } } break; case 110 : { P0 = I31(4, 0); P1 = I31(4, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } } break; case 111 : { P1 = I31(4, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } } break; case 112 : case 113 : { P0 = I211(4, 1, 3); P1 = I31(4, 2); if (HQ2X_MDR) { P2 = I31(4, 3); P3 = I31(4, 8); } else { P2 = I521(4, 7, 3); P3 = I332(5, 7, 4); } } break; case 114 : { P0 = I31(4, 0); P2 = I31(4, 3); if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 115 : { P0 = I31(4, 3); P2 = I31(4, 3); if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 116 : case 117 : { P0 = I211(4, 1, 3); P1 = I31(4, 1); P2 = I31(4, 3); if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } } break; case 118 : { P0 = I31(4, 0); P2 = I31(4, 3); P3 = I31(4, 8); if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 119 : { P2 = I31(4, 3); P3 = I31(4, 8); if (HQ2X_MUR) { P0 = I31(4, 3); P1 = IC(4); } else { P0 = I521(4, 1, 3); P1 = I332(1, 5, 4); } } break; case 121 : { P0 = I31(4, 1); P1 = I31(4, 2); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } } break; case 122 : { if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 124 : { P0 = I31(4, 0); P1 = I31(4, 1); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } } break; case 125 : { P1 = I31(4, 1); P3 = I31(4, 8); if (HQ2X_MDL) { P0 = I31(4, 1); P2 = IC(4); } else { P0 = I521(4, 3, 1); P2 = I332(3, 7, 4); } } break; case 126 : { P0 = I31(4, 0); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 127 : { P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 144 : case 145 : case 176 : case 177 : { P0 = I211(4, 1, 3); P1 = I31(4, 2); P2 = I211(4, 3, 7); P3 = I31(4, 7); } break; case 146 : case 178 : { P0 = I31(4, 0); P2 = I211(4, 3, 7); if (HQ2X_MUR) { P1 = I31(4, 2); P3 = I31(4, 7); } else { P1 = I332(1, 5, 4); P3 = I521(4, 5, 7); } } break; case 147 : case 179 : { P0 = I31(4, 3); P2 = I211(4, 3, 7); P3 = I31(4, 7); if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 148 : case 149 : case 180 : case 181 : { P0 = I211(4, 1, 3); P1 = I31(4, 1); P2 = I211(4, 3, 7); P3 = I31(4, 7); } break; case 150 : case 182 : { P0 = I31(4, 0); P2 = I211(4, 3, 7); if (HQ2X_MUR) { P1 = IC(4); P3 = I31(4, 7); } else { P1 = I332(1, 5, 4); P3 = I521(4, 5, 7); } } break; case 151 : case 183 : { P0 = I31(4, 3); P2 = I211(4, 3, 7); P3 = I31(4, 7); if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 152 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 7); } break; case 153 : { P0 = I31(4, 1); P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 7); } break; case 154 : { P2 = I31(4, 6); P3 = I31(4, 7); if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 155 : { P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 7); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 156 : { P0 = I31(4, 0); P1 = I31(4, 1); P2 = I31(4, 6); P3 = I31(4, 7); } break; case 157 : { P0 = I31(4, 1); P1 = I31(4, 1); P2 = I31(4, 6); P3 = I31(4, 7); } break; case 158 : { P2 = I31(4, 6); P3 = I31(4, 7); if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 159 : { P2 = I31(4, 6); P3 = I31(4, 7); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 184 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 7); P3 = I31(4, 7); } break; case 185 : { P0 = I31(4, 1); P1 = I31(4, 2); P2 = I31(4, 7); P3 = I31(4, 7); } break; case 186 : { P2 = I31(4, 7); P3 = I31(4, 7); if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 187 : { P1 = I31(4, 2); P3 = I31(4, 7); if (HQ2X_MUL) { P0 = IC(4); P2 = I31(4, 7); } else { P0 = I332(1, 3, 4); P2 = I521(4, 3, 7); } } break; case 188 : { P0 = I31(4, 0); P1 = I31(4, 1); P2 = I31(4, 7); P3 = I31(4, 7); } break; case 189 : { P0 = I31(4, 1); P1 = I31(4, 1); P2 = I31(4, 7); P3 = I31(4, 7); } break; case 190 : { P0 = I31(4, 0); P2 = I31(4, 7); if (HQ2X_MUR) { P1 = IC(4); P3 = I31(4, 7); } else { P1 = I332(1, 5, 4); P3 = I521(4, 5, 7); } } break; case 191 : { P2 = I31(4, 7); P3 = I31(4, 7); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 192 : case 193 : case 196 : case 197 : { P0 = I211(4, 1, 3); P1 = I211(4, 1, 5); P2 = I31(4, 6); P3 = I31(4, 5); } break; case 194 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 5); } break; case 195 : { P0 = I31(4, 3); P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 5); } break; case 198 : { P0 = I31(4, 0); P1 = I31(4, 5); P2 = I31(4, 6); P3 = I31(4, 5); } break; case 199 : { P0 = I31(4, 3); P1 = I31(4, 5); P2 = I31(4, 6); P3 = I31(4, 5); } break; case 200 : case 204 : { P0 = I31(4, 0); P1 = I211(4, 1, 5); if (HQ2X_MDL) { P2 = I31(4, 6); P3 = I31(4, 5); } else { P2 = I332(3, 7, 4); P3 = I521(4, 7, 5); } } break; case 201 : case 205 : { P0 = I31(4, 1); P1 = I211(4, 1, 5); P3 = I31(4, 5); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } } break; case 202 : { P1 = I31(4, 2); P3 = I31(4, 5); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } } break; case 203 : { P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 5); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 206 : { P1 = I31(4, 5); P3 = I31(4, 5); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } } break; case 207 : { P2 = I31(4, 6); P3 = I31(4, 5); if (HQ2X_MUL) { P0 = IC(4); P1 = I31(4, 5); } else { P0 = I332(1, 3, 4); P1 = I521(4, 1, 5); } } break; case 208 : case 209 : { P0 = I211(4, 1, 3); P1 = I31(4, 2); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } } break; case 210 : case 216 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } } break; case 211 : { P0 = I31(4, 3); P1 = I31(4, 2); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } } break; case 212 : case 213 : { P0 = I211(4, 1, 3); P2 = I31(4, 6); if (HQ2X_MDR) { P1 = I31(4, 1); P3 = IC(4); } else { P1 = I521(4, 5, 1); P3 = I332(5, 7, 4); } } break; case 215 : { P0 = I31(4, 3); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 217 : { P0 = I31(4, 1); P1 = I31(4, 2); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } } break; case 218 : { if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 219 : { P1 = I31(4, 2); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 220 : { P0 = I31(4, 0); P1 = I31(4, 1); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } } break; case 221 : { P0 = I31(4, 1); P2 = I31(4, 6); if (HQ2X_MDR) { P1 = I31(4, 1); P3 = IC(4); } else { P1 = I521(4, 5, 1); P3 = I332(5, 7, 4); } } break; case 223 : { P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 224 : case 225 : case 228 : case 229 : { P0 = I211(4, 1, 3); P1 = I211(4, 1, 5); P2 = I31(4, 3); P3 = I31(4, 5); } break; case 226 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 3); P3 = I31(4, 5); } break; case 227 : { P0 = I31(4, 3); P1 = I31(4, 2); P2 = I31(4, 3); P3 = I31(4, 5); } break; case 230 : { P0 = I31(4, 0); P1 = I31(4, 5); P2 = I31(4, 3); P3 = I31(4, 5); } break; case 231 : { P0 = I31(4, 3); P1 = I31(4, 5); P2 = I31(4, 3); P3 = I31(4, 5); } break; case 232 : case 236 : { P0 = I31(4, 0); P1 = I211(4, 1, 5); if (HQ2X_MDL) { P2 = IC(4); P3 = I31(4, 5); } else { P2 = I332(3, 7, 4); P3 = I521(4, 7, 5); } } break; case 233 : case 237 : { P0 = I31(4, 1); P1 = I211(4, 1, 5); P3 = I31(4, 5); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } } break; case 234 : { P1 = I31(4, 2); P3 = I31(4, 5); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } } break; case 235 : { P1 = I31(4, 2); P3 = I31(4, 5); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 238 : { P0 = I31(4, 0); P1 = I31(4, 5); if (HQ2X_MDL) { P2 = IC(4); P3 = I31(4, 5); } else { P2 = I332(3, 7, 4); P3 = I521(4, 7, 5); } } break; case 239 : { P1 = I31(4, 5); P3 = I31(4, 5); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } } break; case 240 : case 241 : { P0 = I211(4, 1, 3); P1 = I31(4, 2); if (HQ2X_MDR) { P2 = I31(4, 3); P3 = IC(4); } else { P2 = I521(4, 7, 3); P3 = I332(5, 7, 4); } } break; case 242 : { P0 = I31(4, 0); P2 = I31(4, 3); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 243 : { P0 = I31(4, 3); P1 = I31(4, 2); if (HQ2X_MDR) { P2 = I31(4, 3); P3 = IC(4); } else { P2 = I521(4, 7, 3); P3 = I332(5, 7, 4); } } break; case 244 : case 245 : { P0 = I211(4, 1, 3); P1 = I31(4, 1); P2 = I31(4, 3); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } } break; case 246 : { P0 = I31(4, 0); P2 = I31(4, 3); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 247 : { P0 = I31(4, 3); P2 = I31(4, 3); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 249 : { P0 = I31(4, 1); P1 = I31(4, 2); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } } break; case 251 : { P1 = I31(4, 2); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 252 : { P0 = I31(4, 0); P1 = I31(4, 1); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } } break; case 253 : { P0 = I31(4, 1); P1 = I31(4, 1); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } } break; case 254 : { P0 = I31(4, 0); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 255 : { if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; mupen64plus-video-rice-src-2.0/src/TextureFilters_hq4x.cpp0000644000000000000000000005615412165031100021744 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - TextureFilters_hq4x.cpp * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "typedefs.h" static int RGBtoYUV[4096]; //#define RGB32toYUV(val) (RGBtoYUV[((val&0x00FF0000)>>20)+((val&0x0000FF00)>>12)+((val&0x000000FF)>>4)]) inline int RGB32toYUV(uint32 val) { int a,r,g,b,Y,u,v; //r = (val&0x00FF0000)>>16; //g = (val&0x0000FF00)>>8; //b = (val&0x000000FF); a = (val&0xFF000000); r = (val&0x00FF0000)>>16; g = (val&0x0000FF00)>>8; b = (val&0x000000FF); //r = (val&0x00F80000)>>16; //g = (val&0x0000FC00)>>8; //b = (val&0x000000F8); Y = (r + g + b) >> 2; u = 128 + ((r - b) >> 2); v = 128 + ((-r + 2*g -b)>>3); return a + (Y<<16) + (u<<8) + v; } #define RGB16toYUV(val) (RGBtoYUV[(val&0x0FFF)]) static int YUV1, YUV2; const int Amask = 0xFF000000; const int Ymask = 0x00FF0000; const int Umask = 0x0000FF00; const int Vmask = 0x000000FF; const int trA = 0x20000000; const int trY = 0x00300000; const int trU = 0x00000700; const int trV = 0x00000006; //const int trU = 0x00001800; //const int trV = 0x00000018; #define INTERP_16_MASK_1_3(v) ((v)&0x0F0F) #define INTERP_16_MASK_SHIFT_2_4(v) (((v)&0xF0F0)>>4) #define INTERP_16_MASK_SHIFTBACK_2_4(v) ((INTERP_16_MASK_1_3(v))<<4) inline void hq4x_Interp1_16(unsigned char * pc, uint16 p1, uint16 p2) { *((uint16*)pc) = INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*3 + INTERP_16_MASK_1_3(p2)) / 4) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*3 + INTERP_16_MASK_SHIFT_2_4(p2)) / 4 ); } inline void hq4x_Interp2_16(unsigned char * pc, uint16 p1, uint16 p2, uint16 p3) { *((uint16*)pc) = INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*2 + INTERP_16_MASK_1_3(p2) + INTERP_16_MASK_1_3(p3)) / 4) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*2 + INTERP_16_MASK_SHIFT_2_4(p2) + INTERP_16_MASK_SHIFT_2_4(p3)) / 4); } inline void hq4x_Interp3_16(unsigned char * pc, uint16 p1, uint16 p2) { *((uint16*)pc) = INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*7 + INTERP_16_MASK_1_3(p2)) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*7 + INTERP_16_MASK_SHIFT_2_4(p2)) / 8); } inline void hq4x_Interp5_16(unsigned char * pc, uint16 p1, uint16 p2) { *((uint16*)pc) = INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1) + INTERP_16_MASK_1_3(p2)) / 2) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1) + INTERP_16_MASK_SHIFT_2_4(p2)) / 2); } inline void hq4x_Interp6_16(unsigned char * pc, uint16 p1, uint16 p2, uint16 p3) { *((uint16*)pc) = INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*5 + INTERP_16_MASK_1_3(p2)*2 + INTERP_16_MASK_1_3(p3)*1) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*5 + INTERP_16_MASK_SHIFT_2_4(p2)*2 + INTERP_16_MASK_SHIFT_2_4(p3)*1) / 8); } inline void hq4x_Interp7_16(unsigned char * pc, uint16 p1, uint16 p2, uint16 p3) { *((uint16*)pc) = INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*6 + INTERP_16_MASK_1_3(p2) + INTERP_16_MASK_1_3(p3)) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*6 + INTERP_16_MASK_SHIFT_2_4(p2) + INTERP_16_MASK_SHIFT_2_4(p3)) / 8); } inline void hq4x_Interp8_16(unsigned char * pc, uint16 p1, uint16 p2) { //*((int*)pc) = (c1*5+c2*3)/8; *((uint16*)pc) = INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*5 + INTERP_16_MASK_1_3(p2)*3) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*5 + INTERP_16_MASK_SHIFT_2_4(p2)*3) / 8); } #define INTERP_32_MASK_1_3(v) ((v)&0x00FF00FF) #define INTERP_32_MASK_SHIFT_2_4(v) (((v)&0xFF00FF00)>>8) #define INTERP_32_MASK_SHIFTBACK_2_4(v) (((INTERP_32_MASK_1_3(v))<<8)) inline void hq4x_Interp1_32(unsigned char * pc, uint32 p1, uint32 p2) { *((uint32*)pc) = INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*3 + INTERP_32_MASK_1_3(p2)) / 4) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*3 + INTERP_32_MASK_SHIFT_2_4(p2)) / 4 ); } inline void hq4x_Interp2_32(unsigned char * pc, uint32 p1, uint32 p2, uint32 p3) { *((uint32*)pc) = INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*2 + INTERP_32_MASK_1_3(p2) + INTERP_32_MASK_1_3(p3)) / 4) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*2 + INTERP_32_MASK_SHIFT_2_4(p2) + INTERP_32_MASK_SHIFT_2_4(p3)) / 4); } inline void hq4x_Interp3_32(unsigned char * pc, uint32 p1, uint32 p2) { *((uint32*)pc) = INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*7 + INTERP_32_MASK_1_3(p2)) / 8) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*7 + INTERP_32_MASK_SHIFT_2_4(p2)) / 8); } inline void hq4x_Interp5_32(unsigned char * pc, uint32 p1, uint32 p2) { *((uint32*)pc) = INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1) + INTERP_32_MASK_1_3(p2)) / 2) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1) + INTERP_32_MASK_SHIFT_2_4(p2)) / 2); } inline void hq4x_Interp6_32(unsigned char * pc, uint32 p1, uint32 p2, uint32 p3) { *((uint32*)pc) = INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*5 + INTERP_32_MASK_1_3(p2)*2 + INTERP_32_MASK_1_3(p3)*1) / 8) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*5 + INTERP_32_MASK_SHIFT_2_4(p2)*2 + INTERP_32_MASK_SHIFT_2_4(p3)*1) / 8); } inline void hq4x_Interp7_32(unsigned char * pc, uint32 p1, uint32 p2, uint32 p3) { *((uint32*)pc) = INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*6 + INTERP_32_MASK_1_3(p2) + INTERP_32_MASK_1_3(p3)) / 8) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*6 + INTERP_32_MASK_SHIFT_2_4(p2) + INTERP_32_MASK_SHIFT_2_4(p3)) / 8); } inline void hq4x_Interp8_32(unsigned char * pc, uint32 p1, uint32 p2) { //*((int*)pc) = (c1*5+c2*3)/8; *((uint32*)pc) = INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*5 + INTERP_32_MASK_1_3(p2)*3) / 8) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*5 + INTERP_32_MASK_SHIFT_2_4(p2)*3) / 8); } #define PIXEL00_0 *((int*)(pOut)) = c[5]; #define PIXEL00_11 hq4x_Interp1(pOut, c[5], c[4]); #define PIXEL00_12 hq4x_Interp1(pOut, c[5], c[2]); #define PIXEL00_20 hq4x_Interp2(pOut, c[5], c[2], c[4]); #define PIXEL00_50 hq4x_Interp5(pOut, c[2], c[4]); #define PIXEL00_80 hq4x_Interp8(pOut, c[5], c[1]); #define PIXEL00_81 hq4x_Interp8(pOut, c[5], c[4]); #define PIXEL00_82 hq4x_Interp8(pOut, c[5], c[2]); #define PIXEL01_0 *((int*)(pOut+BPP)) = c[5]; #define PIXEL01_10 hq4x_Interp1(pOut+BPP, c[5], c[1]); #define PIXEL01_12 hq4x_Interp1(pOut+BPP, c[5], c[2]); #define PIXEL01_14 hq4x_Interp1(pOut+BPP, c[2], c[5]); #define PIXEL01_21 hq4x_Interp2(pOut+BPP, c[2], c[5], c[4]); #define PIXEL01_31 hq4x_Interp3(pOut+BPP, c[5], c[4]); #define PIXEL01_50 hq4x_Interp5(pOut+BPP, c[2], c[5]); #define PIXEL01_60 hq4x_Interp6(pOut+BPP, c[5], c[2], c[4]); #define PIXEL01_61 hq4x_Interp6(pOut+BPP, c[5], c[2], c[1]); #define PIXEL01_82 hq4x_Interp8(pOut+BPP, c[5], c[2]); #define PIXEL01_83 hq4x_Interp8(pOut+BPP, c[2], c[4]); #define PIXEL02_0 *((int*)(pOut+BPP2)) = c[5]; #define PIXEL02_10 hq4x_Interp1(pOut+BPP2, c[5], c[3]); #define PIXEL02_11 hq4x_Interp1(pOut+BPP2, c[5], c[2]); #define PIXEL02_13 hq4x_Interp1(pOut+BPP2, c[2], c[5]); #define PIXEL02_21 hq4x_Interp2(pOut+BPP2, c[2], c[5], c[6]); #define PIXEL02_32 hq4x_Interp3(pOut+BPP2, c[5], c[6]); #define PIXEL02_50 hq4x_Interp5(pOut+BPP2, c[2], c[5]); #define PIXEL02_60 hq4x_Interp6(pOut+BPP2, c[5], c[2], c[6]); #define PIXEL02_61 hq4x_Interp6(pOut+BPP2, c[5], c[2], c[3]); #define PIXEL02_81 hq4x_Interp8(pOut+BPP2, c[5], c[2]); #define PIXEL02_83 hq4x_Interp8(pOut+BPP2, c[2], c[6]); #define PIXEL03_0 *((int*)(pOut+BPP3)) = c[5]; #define PIXEL03_11 hq4x_Interp1(pOut+BPP3, c[5], c[2]); #define PIXEL03_12 hq4x_Interp1(pOut+BPP3, c[5], c[6]); #define PIXEL03_20 hq4x_Interp2(pOut+BPP3, c[5], c[2], c[6]); #define PIXEL03_50 hq4x_Interp5(pOut+BPP3, c[2], c[6]); #define PIXEL03_80 hq4x_Interp8(pOut+BPP3, c[5], c[3]); #define PIXEL03_81 hq4x_Interp8(pOut+BPP3, c[5], c[2]); #define PIXEL03_82 hq4x_Interp8(pOut+BPP3, c[5], c[6]); #define PIXEL10_0 *((int*)(pOut+BpL)) = c[5]; #define PIXEL10_10 hq4x_Interp1(pOut+BpL, c[5], c[1]); #define PIXEL10_11 hq4x_Interp1(pOut+BpL, c[5], c[4]); #define PIXEL10_13 hq4x_Interp1(pOut+BpL, c[4], c[5]); #define PIXEL10_21 hq4x_Interp2(pOut+BpL, c[4], c[5], c[2]); #define PIXEL10_32 hq4x_Interp3(pOut+BpL, c[5], c[2]); #define PIXEL10_50 hq4x_Interp5(pOut+BpL, c[4], c[5]); #define PIXEL10_60 hq4x_Interp6(pOut+BpL, c[5], c[4], c[2]); #define PIXEL10_61 hq4x_Interp6(pOut+BpL, c[5], c[4], c[1]); #define PIXEL10_81 hq4x_Interp8(pOut+BpL, c[5], c[4]); #define PIXEL10_83 hq4x_Interp8(pOut+BpL, c[4], c[2]); #define PIXEL11_0 *((int*)(pOut+BpL+BPP)) = c[5]; #define PIXEL11_30 hq4x_Interp3(pOut+BpL+BPP, c[5], c[1]); #define PIXEL11_31 hq4x_Interp3(pOut+BpL+BPP, c[5], c[4]); #define PIXEL11_32 hq4x_Interp3(pOut+BpL+BPP, c[5], c[2]); #define PIXEL11_70 hq4x_Interp7(pOut+BpL+BPP, c[5], c[4], c[2]); #define PIXEL12_0 *((int*)(pOut+BpL+BPP2)) = c[5]; #define PIXEL12_30 hq4x_Interp3(pOut+BpL+BPP2, c[5], c[3]); #define PIXEL12_31 hq4x_Interp3(pOut+BpL+BPP2, c[5], c[2]); #define PIXEL12_32 hq4x_Interp3(pOut+BpL+BPP2, c[5], c[6]); #define PIXEL12_70 hq4x_Interp7(pOut+BpL+BPP2, c[5], c[6], c[2]); #define PIXEL13_0 *((int*)(pOut+BpL+BPP3)) = c[5]; #define PIXEL13_10 hq4x_Interp1(pOut+BpL+BPP3, c[5], c[3]); #define PIXEL13_12 hq4x_Interp1(pOut+BpL+BPP3, c[5], c[6]); #define PIXEL13_14 hq4x_Interp1(pOut+BpL+BPP3, c[6], c[5]); #define PIXEL13_21 hq4x_Interp2(pOut+BpL+BPP3, c[6], c[5], c[2]); #define PIXEL13_31 hq4x_Interp3(pOut+BpL+BPP3, c[5], c[2]); #define PIXEL13_50 hq4x_Interp5(pOut+BpL+BPP3, c[6], c[5]); #define PIXEL13_60 hq4x_Interp6(pOut+BpL+BPP3, c[5], c[6], c[2]); #define PIXEL13_61 hq4x_Interp6(pOut+BpL+BPP3, c[5], c[6], c[3]); #define PIXEL13_82 hq4x_Interp8(pOut+BpL+BPP3, c[5], c[6]); #define PIXEL13_83 hq4x_Interp8(pOut+BpL+BPP3, c[6], c[2]); #define PIXEL20_0 *((int*)(pOut+BpL+BpL)) = c[5]; #define PIXEL20_10 hq4x_Interp1(pOut+BpL+BpL, c[5], c[7]); #define PIXEL20_12 hq4x_Interp1(pOut+BpL+BpL, c[5], c[4]); #define PIXEL20_14 hq4x_Interp1(pOut+BpL+BpL, c[4], c[5]); #define PIXEL20_21 hq4x_Interp2(pOut+BpL+BpL, c[4], c[5], c[8]); #define PIXEL20_31 hq4x_Interp3(pOut+BpL+BpL, c[5], c[8]); #define PIXEL20_50 hq4x_Interp5(pOut+BpL+BpL, c[4], c[5]); #define PIXEL20_60 hq4x_Interp6(pOut+BpL+BpL, c[5], c[4], c[8]); #define PIXEL20_61 hq4x_Interp6(pOut+BpL+BpL, c[5], c[4], c[7]); #define PIXEL20_82 hq4x_Interp8(pOut+BpL+BpL, c[5], c[4]); #define PIXEL20_83 hq4x_Interp8(pOut+BpL+BpL, c[4], c[8]); #define PIXEL21_0 *((int*)(pOut+BpL+BpL+BPP)) = c[5]; #define PIXEL21_30 hq4x_Interp3(pOut+BpL+BpL+BPP, c[5], c[7]); #define PIXEL21_31 hq4x_Interp3(pOut+BpL+BpL+BPP, c[5], c[8]); #define PIXEL21_32 hq4x_Interp3(pOut+BpL+BpL+BPP, c[5], c[4]); #define PIXEL21_70 hq4x_Interp7(pOut+BpL+BpL+BPP, c[5], c[4], c[8]); #define PIXEL22_0 *((int*)(pOut+BpL+BpL+BPP2)) = c[5]; #define PIXEL22_30 hq4x_Interp3(pOut+BpL+BpL+BPP2, c[5], c[9]); #define PIXEL22_31 hq4x_Interp3(pOut+BpL+BpL+BPP2, c[5], c[6]); #define PIXEL22_32 hq4x_Interp3(pOut+BpL+BpL+BPP2, c[5], c[8]); #define PIXEL22_70 hq4x_Interp7(pOut+BpL+BpL+BPP2, c[5], c[6], c[8]); #define PIXEL23_0 *((int*)(pOut+BpL+BpL+BPP3)) = c[5]; #define PIXEL23_10 hq4x_Interp1(pOut+BpL+BpL+BPP3, c[5], c[9]); #define PIXEL23_11 hq4x_Interp1(pOut+BpL+BpL+BPP3, c[5], c[6]); #define PIXEL23_13 hq4x_Interp1(pOut+BpL+BpL+BPP3, c[6], c[5]); #define PIXEL23_21 hq4x_Interp2(pOut+BpL+BpL+BPP3, c[6], c[5], c[8]); #define PIXEL23_32 hq4x_Interp3(pOut+BpL+BpL+BPP3, c[5], c[8]); #define PIXEL23_50 hq4x_Interp5(pOut+BpL+BpL+BPP3, c[6], c[5]); #define PIXEL23_60 hq4x_Interp6(pOut+BpL+BpL+BPP3, c[5], c[6], c[8]); #define PIXEL23_61 hq4x_Interp6(pOut+BpL+BpL+BPP3, c[5], c[6], c[9]); #define PIXEL23_81 hq4x_Interp8(pOut+BpL+BpL+BPP3, c[5], c[6]); #define PIXEL23_83 hq4x_Interp8(pOut+BpL+BpL+BPP3, c[6], c[8]); #define PIXEL30_0 *((int*)(pOut+BpL+BpL+BpL)) = c[5]; #define PIXEL30_11 hq4x_Interp1(pOut+BpL+BpL+BpL, c[5], c[8]); #define PIXEL30_12 hq4x_Interp1(pOut+BpL+BpL+BpL, c[5], c[4]); #define PIXEL30_20 hq4x_Interp2(pOut+BpL+BpL+BpL, c[5], c[8], c[4]); #define PIXEL30_50 hq4x_Interp5(pOut+BpL+BpL+BpL, c[8], c[4]); #define PIXEL30_80 hq4x_Interp8(pOut+BpL+BpL+BpL, c[5], c[7]); #define PIXEL30_81 hq4x_Interp8(pOut+BpL+BpL+BpL, c[5], c[8]); #define PIXEL30_82 hq4x_Interp8(pOut+BpL+BpL+BpL, c[5], c[4]); #define PIXEL31_0 *((int*)(pOut+BpL+BpL+BpL+BPP)) = c[5]; #define PIXEL31_10 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP, c[5], c[7]); #define PIXEL31_11 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP, c[5], c[8]); #define PIXEL31_13 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP, c[8], c[5]); #define PIXEL31_21 hq4x_Interp2(pOut+BpL+BpL+BpL+BPP, c[8], c[5], c[4]); #define PIXEL31_32 hq4x_Interp3(pOut+BpL+BpL+BpL+BPP, c[5], c[4]); #define PIXEL31_50 hq4x_Interp5(pOut+BpL+BpL+BpL+BPP, c[8], c[5]); #define PIXEL31_60 hq4x_Interp6(pOut+BpL+BpL+BpL+BPP, c[5], c[8], c[4]); #define PIXEL31_61 hq4x_Interp6(pOut+BpL+BpL+BpL+BPP, c[5], c[8], c[7]); #define PIXEL31_81 hq4x_Interp8(pOut+BpL+BpL+BpL+BPP, c[5], c[8]); #define PIXEL31_83 hq4x_Interp8(pOut+BpL+BpL+BpL+BPP, c[8], c[4]); #define PIXEL32_0 *((int*)(pOut+BpL+BpL+BpL+BPP2)) = c[5]; #define PIXEL32_10 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP2, c[5], c[9]); #define PIXEL32_12 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP2, c[5], c[8]); #define PIXEL32_14 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP2, c[8], c[5]); #define PIXEL32_21 hq4x_Interp2(pOut+BpL+BpL+BpL+BPP2, c[8], c[5], c[6]); #define PIXEL32_31 hq4x_Interp3(pOut+BpL+BpL+BpL+BPP2, c[5], c[6]); #define PIXEL32_50 hq4x_Interp5(pOut+BpL+BpL+BpL+BPP2, c[8], c[5]); #define PIXEL32_60 hq4x_Interp6(pOut+BpL+BpL+BpL+BPP2, c[5], c[8], c[6]); #define PIXEL32_61 hq4x_Interp6(pOut+BpL+BpL+BpL+BPP2, c[5], c[8], c[9]); #define PIXEL32_82 hq4x_Interp8(pOut+BpL+BpL+BpL+BPP2, c[5], c[8]); #define PIXEL32_83 hq4x_Interp8(pOut+BpL+BpL+BpL+BPP2, c[8], c[6]); #define PIXEL33_0 *((int*)(pOut+BpL+BpL+BpL+BPP3)) = c[5]; #define PIXEL33_11 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP3, c[5], c[6]); #define PIXEL33_12 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP3, c[5], c[8]); #define PIXEL33_20 hq4x_Interp2(pOut+BpL+BpL+BpL+BPP3, c[5], c[8], c[6]); #define PIXEL33_50 hq4x_Interp5(pOut+BpL+BpL+BpL+BPP3, c[8], c[6]); #define PIXEL33_80 hq4x_Interp8(pOut+BpL+BpL+BpL+BPP3, c[5], c[9]); #define PIXEL33_81 hq4x_Interp8(pOut+BpL+BpL+BpL+BPP3, c[5], c[6]); #define PIXEL33_82 hq4x_Interp8(pOut+BpL+BpL+BpL+BPP3, c[5], c[8]); inline bool Diff_16(uint16 w1, uint16 w2) { YUV1 = RGB16toYUV(w1); YUV2 = RGB16toYUV(w2); return ( ( abs((YUV1 & Amask) - (YUV2 & Amask)) > trA ) || ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ); } inline bool Diff_32(uint32 w1, uint32 w2) { YUV1 = RGB32toYUV(w1); YUV2 = RGB32toYUV(w2); return ( ( abs((YUV1 & Amask) - (YUV2 & Amask)) > trA ) || ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ); } void hq4x_16( unsigned char * pIn, unsigned char * pOut, int Xres, int Yres, int SrcPPL, int BpL ) { #define hq4x_Interp1 hq4x_Interp1_16 #define hq4x_Interp2 hq4x_Interp2_16 #define hq4x_Interp3 hq4x_Interp3_16 #define hq4x_Interp4 hq4x_Interp4_16 #define hq4x_Interp5 hq4x_Interp5_16 #define hq4x_Interp6 hq4x_Interp6_16 #define hq4x_Interp7 hq4x_Interp7_16 #define hq4x_Interp8 hq4x_Interp8_16 #define Diff Diff_16 #define BPP 2 #define BPP2 4 #define BPP3 6 int i, j, k; int prevline, nextline; uint16 w[10]; uint16 c[10]; // +----+----+----+ // | | | | // | w1 | w2 | w3 | // +----+----+----+ // | | | | // | w4 | w5 | w6 | // +----+----+----+ // | | | | // | w7 | w8 | w9 | // +----+----+----+ for (j=0; j0) prevline = -SrcPPL*2; else prevline = 0; if (j0) { w[1] = *((uint16*)(pIn + prevline - 2)); w[4] = *((uint16*)(pIn - 2)); w[7] = *((uint16*)(pIn + nextline - 2)); } else { w[1] = w[2]; w[4] = w[5]; w[7] = w[8]; } if (i trA ) || ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ) pattern |= flag; } flag <<= 1; } for (k=1; k<=9; k++) c[k] = w[k]; #include "TextureFilters_hq4x.h" pIn+=2; pOut+=8; } pIn += 2*(SrcPPL-Xres); pOut+= 8*(SrcPPL-Xres); pOut+=BpL; pOut+=BpL; pOut+=BpL; } #undef BPP #undef BPP2 #undef BPP3 #undef Diff #undef hq4x_Interp1 #undef hq4x_Interp2 #undef hq4x_Interp3 #undef hq4x_Interp4 #undef hq4x_Interp5 #undef hq4x_Interp6 #undef hq4x_Interp7 #undef hq4x_Interp8 } void hq4x_32( unsigned char * pIn, unsigned char * pOut, int Xres, int Yres, int SrcPPL, int BpL ) { #define hq4x_Interp1 hq4x_Interp1_32 #define hq4x_Interp2 hq4x_Interp2_32 #define hq4x_Interp3 hq4x_Interp3_32 #define hq4x_Interp4 hq4x_Interp4_32 #define hq4x_Interp5 hq4x_Interp5_32 #define hq4x_Interp6 hq4x_Interp6_32 #define hq4x_Interp7 hq4x_Interp7_32 #define hq4x_Interp8 hq4x_Interp8_32 #define Diff Diff_32 #define BPP 4 #define BPP2 8 #define BPP3 12 int i, j, k; int prevline, nextline; uint32 w[10]; uint32 c[10]; // +----+----+----+ // | | | | // | w1 | w2 | w3 | // +----+----+----+ // | | | | // | w4 | w5 | w6 | // +----+----+----+ // | | | | // | w7 | w8 | w9 | // +----+----+----+ for (j=0; j0) prevline = -SrcPPL*4; else prevline = 0; if (j0) { w[1] = *((uint32*)(pIn + prevline - 4)); w[4] = *((uint32*)(pIn - 4)); w[7] = *((uint32*)(pIn + nextline - 4)); } else { w[1] = w[2]; w[4] = w[5]; w[7] = w[8]; } if (i trA ) || ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ) pattern |= flag; } flag <<= 1; } for (k=1; k<=9; k++) c[k] = w[k]; #include "TextureFilters_hq4x.h" pIn+=4; pOut+=16; } pIn += 4*(SrcPPL-Xres); pOut+= 16*(SrcPPL-Xres); pOut+=BpL; pOut+=BpL; pOut+=BpL; } #undef BPP #undef BPP2 #undef BPP3 #undef Diff #undef hq4x_Interp1 #undef hq4x_Interp2 #undef hq4x_Interp3 #undef hq4x_Interp4 #undef hq4x_Interp5 #undef hq4x_Interp6 #undef hq4x_Interp7 #undef hq4x_Interp8 } void hq4x_InitLUTs(void) { static bool done = false; int i, j, k, r, g, b, Y, u, v; if( !done ) { for (i=0; i<16; i++) { for (j=0; j<16; j++) { for (k=0; k<16; k++) { r = i << 4; g = j << 4; b = k << 4; Y = (r + g + b) >> 2; u = 128 + ((r - b) >> 2); v = 128 + ((-r + 2*g -b)>>3); RGBtoYUV[ (i << 8) + (j << 4) + k ] = (Y<<16) + (u<<8) + v; } } } done = true; } } mupen64plus-video-rice-src-2.0/src/TextureFilters_hq4x.h0000644000000000000000000032131512165031100021403 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - TextureFilters_hq4x.h * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ switch (pattern) { case 0: case 1: case 4: case 32: case 128: case 5: case 132: case 160: case 33: case 129: case 36: case 133: case 164: case 161: case 37: case 165: { PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; } case 2: case 34: case 130: case 162: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; } case 16: case 17: case 48: case 49: { PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; } case 64: case 65: case 68: case 69: { PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 8: case 12: case 136: case 140: { PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; } case 3: case 35: case 131: case 163: { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; } case 6: case 38: case 134: case 166: { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; } case 20: case 21: case 52: case 53: { PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; } case 144: case 145: case 176: case 177: { PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; } case 192: case 193: case 196: case 197: { PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; } case 96: case 97: case 100: case 101: { PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; } case 40: case 44: case 168: case 172: { PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; } case 9: case 13: case 137: case 141: { PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; } case 18: case 50: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_50 PIXEL03_50 PIXEL12_0 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; } case 80: case 81: { PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_61 PIXEL21_30 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 72: case 76: { PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_50 PIXEL21_0 PIXEL30_50 PIXEL31_50 } PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 10: case 138: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 PIXEL11_0 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; } case 66: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 24: { PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; } case 7: case 39: case 135: { PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; } case 148: case 149: case 180: { PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; } case 224: case 228: case 225: { PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; } case 41: case 169: case 45: { PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; } case 22: case 54: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; } case 208: case 209: { PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 104: case 108: { PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 11: case 139: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; } case 19: case 51: { if (Diff(w[2], w[6])) { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL00_12 PIXEL01_14 PIXEL02_83 PIXEL03_50 PIXEL12_70 PIXEL13_21 } PIXEL10_81 PIXEL11_31 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; } case 146: case 178: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 PIXEL23_32 PIXEL33_82 } else { PIXEL02_21 PIXEL03_50 PIXEL12_70 PIXEL13_83 PIXEL23_13 PIXEL33_11 } PIXEL10_61 PIXEL11_30 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 break; } case 84: case 85: { PIXEL00_20 PIXEL01_60 PIXEL02_81 if (Diff(w[6], w[8])) { PIXEL03_81 PIXEL13_31 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL03_12 PIXEL13_14 PIXEL22_70 PIXEL23_83 PIXEL32_21 PIXEL33_50 } PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL20_61 PIXEL21_30 PIXEL30_80 PIXEL31_10 break; } case 112: case 113: { PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_82 PIXEL21_32 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 } else { PIXEL22_70 PIXEL23_21 PIXEL30_11 PIXEL31_13 PIXEL32_83 PIXEL33_50 } break; } case 200: case 204: { PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 } else { PIXEL20_21 PIXEL21_70 PIXEL30_50 PIXEL31_83 PIXEL32_14 PIXEL33_12 } PIXEL22_31 PIXEL23_81 break; } case 73: case 77: { if (Diff(w[8], w[4])) { PIXEL00_82 PIXEL10_32 PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL00_11 PIXEL10_13 PIXEL20_83 PIXEL21_70 PIXEL30_50 PIXEL31_21 } PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 42: case 170: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 PIXEL20_31 PIXEL30_81 } else { PIXEL00_50 PIXEL01_21 PIXEL10_83 PIXEL11_70 PIXEL20_14 PIXEL30_12 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; } case 14: case 142: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_10 PIXEL11_30 } else { PIXEL00_50 PIXEL01_83 PIXEL02_13 PIXEL03_11 PIXEL10_21 PIXEL11_70 } PIXEL12_32 PIXEL13_82 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; } case 67: { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 70: { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 28: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; } case 152: { PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 194: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; } case 98: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; } case 56: { PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 25: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; } case 26: case 31: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL11_0 PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; } case 82: case 214: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 88: case 248: { PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } break; } case 74: case 107: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 27: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; } case 86: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 216: { PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 106: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_61 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 30: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; } case 210: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 120: { PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; } case 75: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 29: { PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; } case 198: { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; } case 184: { PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; } case 99: { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; } case 57: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 71: { PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 156: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 226: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; } case 60: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 195: { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; } case 102: { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; } case 153: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 58: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 83: { PIXEL00_81 PIXEL01_31 if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_81 PIXEL11_31 PIXEL20_61 PIXEL21_30 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_80 PIXEL31_10 break; } case 92: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 202: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_31 PIXEL23_81 PIXEL32_31 PIXEL33_81 break; } case 78: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_32 PIXEL03_82 PIXEL12_32 PIXEL13_82 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 154: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 114: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_61 PIXEL11_30 PIXEL20_82 PIXEL21_32 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_82 PIXEL31_32 break; } case 89: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 90: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 55: case 23: { if (Diff(w[2], w[6])) { PIXEL00_81 PIXEL01_31 PIXEL02_0 PIXEL03_0 PIXEL12_0 PIXEL13_0 } else { PIXEL00_12 PIXEL01_14 PIXEL02_83 PIXEL03_50 PIXEL12_70 PIXEL13_21 } PIXEL10_81 PIXEL11_31 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; } case 182: case 150: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL12_0 PIXEL13_0 PIXEL23_32 PIXEL33_82 } else { PIXEL02_21 PIXEL03_50 PIXEL12_70 PIXEL13_83 PIXEL23_13 PIXEL33_11 } PIXEL10_61 PIXEL11_30 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 break; } case 213: case 212: { PIXEL00_20 PIXEL01_60 PIXEL02_81 if (Diff(w[6], w[8])) { PIXEL03_81 PIXEL13_31 PIXEL22_0 PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL03_12 PIXEL13_14 PIXEL22_70 PIXEL23_83 PIXEL32_21 PIXEL33_50 } PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL20_61 PIXEL21_30 PIXEL30_80 PIXEL31_10 break; } case 241: case 240: { PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_82 PIXEL21_32 if (Diff(w[6], w[8])) { PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 PIXEL33_0 } else { PIXEL22_70 PIXEL23_21 PIXEL30_11 PIXEL31_13 PIXEL32_83 PIXEL33_50 } break; } case 236: case 232: { PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL21_0 PIXEL30_0 PIXEL31_0 PIXEL32_31 PIXEL33_81 } else { PIXEL20_21 PIXEL21_70 PIXEL30_50 PIXEL31_83 PIXEL32_14 PIXEL33_12 } PIXEL22_31 PIXEL23_81 break; } case 109: case 105: { if (Diff(w[8], w[4])) { PIXEL00_82 PIXEL10_32 PIXEL20_0 PIXEL21_0 PIXEL30_0 PIXEL31_0 } else { PIXEL00_11 PIXEL10_13 PIXEL20_83 PIXEL21_70 PIXEL30_50 PIXEL31_21 } PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 171: case 43: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 PIXEL11_0 PIXEL20_31 PIXEL30_81 } else { PIXEL00_50 PIXEL01_21 PIXEL10_83 PIXEL11_70 PIXEL20_14 PIXEL30_12 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; } case 143: case 15: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 } else { PIXEL00_50 PIXEL01_83 PIXEL02_13 PIXEL03_11 PIXEL10_21 PIXEL11_70 } PIXEL12_32 PIXEL13_82 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; } case 124: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; } case 203: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 PIXEL20_10 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; } case 62: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 211: { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_10 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 118: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_10 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; } case 217: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 110: { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_10 PIXEL11_30 PIXEL12_32 PIXEL13_82 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 155: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 188: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; } case 185: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; } case 61: { PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 157: { PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 103: { PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; } case 227: { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; } case 230: { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; } case 199: { PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; } case 220: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } break; } case 158: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 234: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_31 PIXEL23_81 PIXEL32_31 PIXEL33_81 break; } case 242: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_61 PIXEL11_30 PIXEL20_82 PIXEL21_32 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_82 PIXEL31_32 break; } case 59: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL11_0 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 121: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 87: { PIXEL00_81 PIXEL01_31 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_81 PIXEL11_31 PIXEL12_0 PIXEL20_61 PIXEL21_30 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_80 PIXEL31_10 break; } case 79: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_32 PIXEL03_82 PIXEL11_0 PIXEL12_32 PIXEL13_82 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 122: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 94: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL12_0 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 218: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } break; } case 91: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL11_0 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 229: { PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; } case 167: { PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; } case 173: { PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; } case 181: { PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; } case 186: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; } case 115: { PIXEL00_81 PIXEL01_31 if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_81 PIXEL11_31 PIXEL20_82 PIXEL21_32 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_82 PIXEL31_32 break; } case 93: { PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 206: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_32 PIXEL03_82 PIXEL12_32 PIXEL13_82 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_31 PIXEL23_81 PIXEL32_31 PIXEL33_81 break; } case 205: case 201: { PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_31 PIXEL23_81 PIXEL32_31 PIXEL33_81 break; } case 174: case 46: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_32 PIXEL03_82 PIXEL12_32 PIXEL13_82 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; } case 179: case 147: { PIXEL00_81 PIXEL01_31 if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_81 PIXEL11_31 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; } case 117: case 116: { PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_82 PIXEL21_32 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_82 PIXEL31_32 break; } case 189: { PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; } case 231: { PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; } case 126: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; } case 219: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 125: { if (Diff(w[8], w[4])) { PIXEL00_82 PIXEL10_32 PIXEL20_0 PIXEL21_0 PIXEL30_0 PIXEL31_0 } else { PIXEL00_11 PIXEL10_13 PIXEL20_83 PIXEL21_70 PIXEL30_50 PIXEL31_21 } PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; } case 221: { PIXEL00_82 PIXEL01_82 PIXEL02_81 if (Diff(w[6], w[8])) { PIXEL03_81 PIXEL13_31 PIXEL22_0 PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL03_12 PIXEL13_14 PIXEL22_70 PIXEL23_83 PIXEL32_21 PIXEL33_50 } PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 break; } case 207: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 } else { PIXEL00_50 PIXEL01_83 PIXEL02_13 PIXEL03_11 PIXEL10_21 PIXEL11_70 } PIXEL12_32 PIXEL13_82 PIXEL20_10 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; } case 238: { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_10 PIXEL11_30 PIXEL12_32 PIXEL13_82 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL21_0 PIXEL30_0 PIXEL31_0 PIXEL32_31 PIXEL33_81 } else { PIXEL20_21 PIXEL21_70 PIXEL30_50 PIXEL31_83 PIXEL32_14 PIXEL33_12 } PIXEL22_31 PIXEL23_81 break; } case 190: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL12_0 PIXEL13_0 PIXEL23_32 PIXEL33_82 } else { PIXEL02_21 PIXEL03_50 PIXEL12_70 PIXEL13_83 PIXEL23_13 PIXEL33_11 } PIXEL10_10 PIXEL11_30 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 break; } case 187: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 PIXEL11_0 PIXEL20_31 PIXEL30_81 } else { PIXEL00_50 PIXEL01_21 PIXEL10_83 PIXEL11_70 PIXEL20_14 PIXEL30_12 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; } case 243: { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_10 PIXEL20_82 PIXEL21_32 if (Diff(w[6], w[8])) { PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 PIXEL33_0 } else { PIXEL22_70 PIXEL23_21 PIXEL30_11 PIXEL31_13 PIXEL32_83 PIXEL33_50 } break; } case 119: { if (Diff(w[2], w[6])) { PIXEL00_81 PIXEL01_31 PIXEL02_0 PIXEL03_0 PIXEL12_0 PIXEL13_0 } else { PIXEL00_12 PIXEL01_14 PIXEL02_83 PIXEL03_50 PIXEL12_70 PIXEL13_21 } PIXEL10_81 PIXEL11_31 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_10 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; } case 237: case 233: { PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL20_0 PIXEL21_0 PIXEL22_31 PIXEL23_81 if (Diff(w[8], w[4])) { PIXEL30_0 } else { PIXEL30_20 } PIXEL31_0 PIXEL32_31 PIXEL33_81 break; } case 175: case 47: { if (Diff(w[4], w[2])) { PIXEL00_0 } else { PIXEL00_20 } PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 PIXEL12_32 PIXEL13_82 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; } case 183: case 151: { PIXEL00_81 PIXEL01_31 PIXEL02_0 if (Diff(w[2], w[6])) { PIXEL03_0 } else { PIXEL03_20 } PIXEL10_81 PIXEL11_31 PIXEL12_0 PIXEL13_0 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; } case 245: case 244: { PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_82 PIXEL21_32 PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 if (Diff(w[6], w[8])) { PIXEL33_0 } else { PIXEL33_20 } break; } case 250: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } break; } case 123: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; } case 95: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL11_0 PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 222: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 252: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_0 PIXEL23_0 PIXEL32_0 if (Diff(w[6], w[8])) { PIXEL33_0 } else { PIXEL33_20 } break; } case 249: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_0 PIXEL21_0 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } if (Diff(w[8], w[4])) { PIXEL30_0 } else { PIXEL30_20 } PIXEL31_0 break; } case 235: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 PIXEL20_0 PIXEL21_0 PIXEL22_31 PIXEL23_81 if (Diff(w[8], w[4])) { PIXEL30_0 } else { PIXEL30_20 } PIXEL31_0 PIXEL32_31 PIXEL33_81 break; } case 111: { if (Diff(w[4], w[2])) { PIXEL00_0 } else { PIXEL00_20 } PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 PIXEL12_32 PIXEL13_82 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 63: { if (Diff(w[4], w[2])) { PIXEL00_0 } else { PIXEL00_20 } PIXEL01_0 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_0 PIXEL11_0 PIXEL12_0 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 159: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_0 if (Diff(w[2], w[6])) { PIXEL03_0 } else { PIXEL03_20 } PIXEL11_0 PIXEL12_0 PIXEL13_0 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 215: { PIXEL00_81 PIXEL01_31 PIXEL02_0 if (Diff(w[2], w[6])) { PIXEL03_0 } else { PIXEL03_20 } PIXEL10_81 PIXEL11_31 PIXEL12_0 PIXEL13_0 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 246: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_82 PIXEL21_32 PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 if (Diff(w[6], w[8])) { PIXEL33_0 } else { PIXEL33_20 } break; } case 254: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_0 PIXEL23_0 PIXEL32_0 if (Diff(w[6], w[8])) { PIXEL33_0 } else { PIXEL33_20 } break; } case 253: { PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_0 PIXEL21_0 PIXEL22_0 PIXEL23_0 if (Diff(w[8], w[4])) { PIXEL30_0 } else { PIXEL30_20 } PIXEL31_0 PIXEL32_0 if (Diff(w[6], w[8])) { PIXEL33_0 } else { PIXEL33_20 } break; } case 251: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 PIXEL20_0 PIXEL21_0 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } if (Diff(w[8], w[4])) { PIXEL30_0 } else { PIXEL30_20 } PIXEL31_0 break; } case 239: { if (Diff(w[4], w[2])) { PIXEL00_0 } else { PIXEL00_20 } PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 PIXEL12_32 PIXEL13_82 PIXEL20_0 PIXEL21_0 PIXEL22_31 PIXEL23_81 if (Diff(w[8], w[4])) { PIXEL30_0 } else { PIXEL30_20 } PIXEL31_0 PIXEL32_31 PIXEL33_81 break; } case 127: { if (Diff(w[4], w[2])) { PIXEL00_0 } else { PIXEL00_20 } PIXEL01_0 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_0 PIXEL11_0 PIXEL12_0 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; } case 191: { if (Diff(w[4], w[2])) { PIXEL00_0 } else { PIXEL00_20 } PIXEL01_0 PIXEL02_0 if (Diff(w[2], w[6])) { PIXEL03_0 } else { PIXEL03_20 } PIXEL10_0 PIXEL11_0 PIXEL12_0 PIXEL13_0 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; } case 223: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_0 if (Diff(w[2], w[6])) { PIXEL03_0 } else { PIXEL03_20 } PIXEL11_0 PIXEL12_0 PIXEL13_0 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 247: { PIXEL00_81 PIXEL01_31 PIXEL02_0 if (Diff(w[2], w[6])) { PIXEL03_0 } else { PIXEL03_20 } PIXEL10_81 PIXEL11_31 PIXEL12_0 PIXEL13_0 PIXEL20_82 PIXEL21_32 PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 if (Diff(w[6], w[8])) { PIXEL33_0 } else { PIXEL33_20 } break; } case 255: { if (Diff(w[4], w[2])) { PIXEL00_0 } else { PIXEL00_20 } PIXEL01_0 PIXEL02_0 if (Diff(w[2], w[6])) { PIXEL03_0 } else { PIXEL03_20 } PIXEL10_0 PIXEL11_0 PIXEL12_0 PIXEL13_0 PIXEL20_0 PIXEL21_0 PIXEL22_0 PIXEL23_0 if (Diff(w[8], w[4])) { PIXEL30_0 } else { PIXEL30_20 } PIXEL31_0 PIXEL32_0 if (Diff(w[6], w[8])) { PIXEL33_0 } else { PIXEL33_20 } break; } } mupen64plus-video-rice-src-2.0/src/TextureFilters_lq2x.h0000644000000000000000000004326412165031100021411 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - TextureFilters_lq2x.h * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ case 0 : case 2 : case 4 : case 6 : case 8 : case 12 : case 16 : case 20 : case 24 : case 28 : case 32 : case 34 : case 36 : case 38 : case 40 : case 44 : case 48 : case 52 : case 56 : case 60 : case 64 : case 66 : case 68 : case 70 : case 96 : case 98 : case 100 : case 102 : case 128 : case 130 : case 132 : case 134 : case 136 : case 140 : case 144 : case 148 : case 152 : case 156 : case 160 : case 162 : case 164 : case 166 : case 168 : case 172 : case 176 : case 180 : case 184 : case 188 : case 192 : case 194 : case 196 : case 198 : case 224 : case 226 : case 228 : case 230 : { P0 = IC(0); P1 = IC(0); P2 = IC(0); P3 = IC(0); } break; case 1 : case 5 : case 9 : case 13 : case 17 : case 21 : case 25 : case 29 : case 33 : case 37 : case 41 : case 45 : case 49 : case 53 : case 57 : case 61 : case 65 : case 69 : case 97 : case 101 : case 129 : case 133 : case 137 : case 141 : case 145 : case 149 : case 153 : case 157 : case 161 : case 165 : case 169 : case 173 : case 177 : case 181 : case 185 : case 189 : case 193 : case 197 : case 225 : case 229 : { P0 = IC(1); P1 = IC(1); P2 = IC(1); P3 = IC(1); } break; case 3 : case 35 : case 67 : case 99 : case 131 : case 163 : case 195 : case 227 : { P0 = IC(2); P1 = IC(2); P2 = IC(2); P3 = IC(2); } break; case 7 : case 39 : case 71 : case 103 : case 135 : case 167 : case 199 : case 231 : { P0 = IC(3); P1 = IC(3); P2 = IC(3); P3 = IC(3); } break; case 10 : case 138 : { P1 = IC(0); P2 = IC(0); P3 = IC(0); if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I211(0, 1, 3); } } break; case 11 : case 27 : case 75 : case 139 : case 155 : case 203 : { P1 = IC(2); P2 = IC(2); P3 = IC(2); if (HQ2X_MUL) { P0 = IC(2); } else { P0 = I211(2, 1, 3); } } break; case 14 : case 142 : { P2 = IC(0); P3 = IC(0); if (HQ2X_MUL) { P0 = IC(0); P1 = IC(0); } else { P0 = I332(1, 3, 0); P1 = I31(0, 1); } } break; case 15 : case 143 : case 207 : { P2 = IC(4); P3 = IC(4); if (HQ2X_MUL) { P0 = IC(4); P1 = IC(4); } else { P0 = I332(1, 3, 4); P1 = I31(4, 1); } } break; case 18 : case 22 : case 30 : case 50 : case 54 : case 62 : case 86 : case 118 : { P0 = IC(0); P2 = IC(0); P3 = IC(0); if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 19 : case 51 : { P2 = IC(2); P3 = IC(2); if (HQ2X_MUR) { P0 = IC(2); P1 = IC(2); } else { P0 = I31(2, 1); P1 = I332(1, 5, 2); } } break; case 23 : case 55 : case 119 : { P2 = IC(3); P3 = IC(3); if (HQ2X_MUR) { P0 = IC(3); P1 = IC(3); } else { P0 = I31(3, 1); P1 = I332(1, 5, 3); } } break; case 26 : { P2 = IC(0); P3 = IC(0); if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I211(0, 1, 3); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 31 : case 95 : { P2 = IC(4); P3 = IC(4); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 42 : case 170 : { P1 = IC(0); P3 = IC(0); if (HQ2X_MUL) { P0 = IC(0); P2 = IC(0); } else { P0 = I332(1, 3, 0); P2 = I31(0, 3); } } break; case 43 : case 171 : case 187 : { P1 = IC(2); P3 = IC(2); if (HQ2X_MUL) { P0 = IC(2); P2 = IC(2); } else { P0 = I332(1, 3, 2); P2 = I31(2, 3); } } break; case 46 : case 174 : { P1 = IC(0); P2 = IC(0); P3 = IC(0); if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } } break; case 47 : case 175 : { P1 = IC(4); P2 = IC(4); P3 = IC(4); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } } break; case 58 : case 154 : case 186 : { P2 = IC(0); P3 = IC(0); if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I611(0, 1, 5); } } break; case 59 : { P2 = IC(2); P3 = IC(2); if (HQ2X_MUL) { P0 = IC(2); } else { P0 = I211(2, 1, 3); } if (HQ2X_MUR) { P1 = IC(2); } else { P1 = I611(2, 1, 5); } } break; case 63 : { P2 = IC(4); P3 = IC(4); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 72 : case 76 : case 104 : case 106 : case 108 : case 110 : case 120 : case 124 : { P0 = IC(0); P1 = IC(0); P3 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } } break; case 73 : case 77 : case 105 : case 109 : case 125 : { P1 = IC(1); P3 = IC(1); if (HQ2X_MDL) { P0 = IC(1); P2 = IC(1); } else { P0 = I31(1, 3); P2 = I332(3, 7, 1); } } break; case 74 : { P1 = IC(0); P3 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I211(0, 1, 3); } } break; case 78 : case 202 : case 206 : { P1 = IC(0); P3 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I611(0, 3, 7); } if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } } break; case 79 : { P1 = IC(4); P3 = IC(4); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I611(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 80 : case 208 : case 210 : case 216 : { P0 = IC(0); P1 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I211(0, 5, 7); } } break; case 81 : case 209 : case 217 : { P0 = IC(1); P1 = IC(1); P2 = IC(1); if (HQ2X_MDR) { P3 = IC(1); } else { P3 = I211(1, 5, 7); } } break; case 82 : case 214 : case 222 : { P0 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I211(0, 5, 7); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 83 : case 115 : { P0 = IC(2); P2 = IC(2); if (HQ2X_MDR) { P3 = IC(2); } else { P3 = I611(2, 5, 7); } if (HQ2X_MUR) { P1 = IC(2); } else { P1 = I611(2, 1, 5); } } break; case 84 : case 212 : { P0 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P1 = IC(0); P3 = IC(0); } else { P1 = I31(0, 5); P3 = I332(5, 7, 0); } } break; case 85 : case 213 : case 221 : { P0 = IC(1); P2 = IC(1); if (HQ2X_MDR) { P1 = IC(1); P3 = IC(1); } else { P1 = I31(1, 5); P3 = I332(5, 7, 1); } } break; case 87 : { P0 = IC(3); P2 = IC(3); if (HQ2X_MDR) { P3 = IC(3); } else { P3 = I611(3, 5, 7); } if (HQ2X_MUR) { P1 = IC(3); } else { P1 = I211(3, 1, 5); } } break; case 88 : case 248 : case 250 : { P0 = IC(0); P1 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I211(0, 5, 7); } } break; case 89 : case 93 : { P0 = IC(1); P1 = IC(1); if (HQ2X_MDL) { P2 = IC(1); } else { P2 = I611(1, 3, 7); } if (HQ2X_MDR) { P3 = IC(1); } else { P3 = I611(1, 5, 7); } } break; case 90 : { if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I611(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I611(0, 5, 7); } if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I611(0, 1, 5); } } break; case 91 : { if (HQ2X_MDL) { P2 = IC(2); } else { P2 = I611(2, 3, 7); } if (HQ2X_MDR) { P3 = IC(2); } else { P3 = I611(2, 5, 7); } if (HQ2X_MUL) { P0 = IC(2); } else { P0 = I211(2, 1, 3); } if (HQ2X_MUR) { P1 = IC(2); } else { P1 = I611(2, 1, 5); } } break; case 92 : { P0 = IC(0); P1 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I611(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I611(0, 5, 7); } } break; case 94 : { if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I611(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I611(0, 5, 7); } if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 107 : case 123 : { P1 = IC(2); P3 = IC(2); if (HQ2X_MDL) { P2 = IC(2); } else { P2 = I211(2, 3, 7); } if (HQ2X_MUL) { P0 = IC(2); } else { P0 = I211(2, 1, 3); } } break; case 111 : { P1 = IC(4); P3 = IC(4); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } } break; case 112 : case 240 : { P0 = IC(0); P1 = IC(0); if (HQ2X_MDR) { P2 = IC(0); P3 = IC(0); } else { P2 = I31(0, 7); P3 = I332(5, 7, 0); } } break; case 113 : case 241 : { P0 = IC(1); P1 = IC(1); if (HQ2X_MDR) { P2 = IC(1); P3 = IC(1); } else { P2 = I31(1, 7); P3 = I332(5, 7, 1); } } break; case 114 : { P0 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I611(0, 5, 7); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I611(0, 1, 5); } } break; case 116 : { P0 = IC(0); P1 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I611(0, 5, 7); } } break; case 117 : { P0 = IC(1); P1 = IC(1); P2 = IC(1); if (HQ2X_MDR) { P3 = IC(1); } else { P3 = I611(1, 5, 7); } } break; case 121 : { P0 = IC(1); P1 = IC(1); if (HQ2X_MDL) { P2 = IC(1); } else { P2 = I211(1, 3, 7); } if (HQ2X_MDR) { P3 = IC(1); } else { P3 = I611(1, 5, 7); } } break; case 122 : { if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I611(0, 5, 7); } if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I611(0, 1, 5); } } break; case 126 : { P0 = IC(0); P3 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 127 : { P3 = IC(4); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 146 : case 150 : case 178 : case 182 : case 190 : { P0 = IC(0); P2 = IC(0); if (HQ2X_MUR) { P1 = IC(0); P3 = IC(0); } else { P1 = I332(1, 5, 0); P3 = I31(0, 5); } } break; case 147 : case 179 : { P0 = IC(2); P2 = IC(2); P3 = IC(2); if (HQ2X_MUR) { P1 = IC(2); } else { P1 = I611(2, 1, 5); } } break; case 151 : case 183 : { P0 = IC(3); P2 = IC(3); P3 = IC(3); if (HQ2X_MUR) { P1 = IC(3); } else { P1 = I1411(3, 1, 5); } } break; case 158 : { P2 = IC(0); P3 = IC(0); if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 159 : { P2 = IC(4); P3 = IC(4); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 191 : { P2 = IC(4); P3 = IC(4); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 200 : case 204 : case 232 : case 236 : case 238 : { P0 = IC(0); P1 = IC(0); if (HQ2X_MDL) { P2 = IC(0); P3 = IC(0); } else { P2 = I332(3, 7, 0); P3 = I31(0, 7); } } break; case 201 : case 205 : { P0 = IC(1); P1 = IC(1); P3 = IC(1); if (HQ2X_MDL) { P2 = IC(1); } else { P2 = I611(1, 3, 7); } } break; case 211 : { P0 = IC(2); P1 = IC(2); P2 = IC(2); if (HQ2X_MDR) { P3 = IC(2); } else { P3 = I211(2, 5, 7); } } break; case 215 : { P0 = IC(3); P2 = IC(3); if (HQ2X_MDR) { P3 = IC(3); } else { P3 = I211(3, 5, 7); } if (HQ2X_MUR) { P1 = IC(3); } else { P1 = I1411(3, 1, 5); } } break; case 218 : { if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I611(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I211(0, 5, 7); } if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I611(0, 1, 5); } } break; case 219 : { P1 = IC(2); P2 = IC(2); if (HQ2X_MDR) { P3 = IC(2); } else { P3 = I211(2, 5, 7); } if (HQ2X_MUL) { P0 = IC(2); } else { P0 = I211(2, 1, 3); } } break; case 220 : { P0 = IC(0); P1 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I611(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I211(0, 5, 7); } } break; case 223 : { P2 = IC(4); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 233 : case 237 : { P0 = IC(1); P1 = IC(1); P3 = IC(1); if (HQ2X_MDL) { P2 = IC(1); } else { P2 = I1411(1, 3, 7); } } break; case 234 : { P1 = IC(0); P3 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } } break; case 235 : { P1 = IC(2); P3 = IC(2); if (HQ2X_MDL) { P2 = IC(2); } else { P2 = I1411(2, 3, 7); } if (HQ2X_MUL) { P0 = IC(2); } else { P0 = I211(2, 1, 3); } } break; case 239 : { P1 = IC(4); P3 = IC(4); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } } break; case 242 : { P0 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I211(0, 5, 7); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I611(0, 1, 5); } } break; case 243 : { P0 = IC(2); P1 = IC(2); if (HQ2X_MDR) { P2 = IC(2); P3 = IC(2); } else { P2 = I31(2, 7); P3 = I332(5, 7, 2); } } break; case 244 : { P0 = IC(0); P1 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I1411(0, 5, 7); } } break; case 245 : { P0 = IC(1); P1 = IC(1); P2 = IC(1); if (HQ2X_MDR) { P3 = IC(1); } else { P3 = I1411(1, 5, 7); } } break; case 246 : { P0 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I1411(0, 5, 7); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 247 : { P0 = IC(3); P2 = IC(3); if (HQ2X_MDR) { P3 = IC(3); } else { P3 = I1411(3, 5, 7); } if (HQ2X_MUR) { P1 = IC(3); } else { P1 = I1411(3, 1, 5); } } break; case 249 : { P0 = IC(1); P1 = IC(1); if (HQ2X_MDL) { P2 = IC(1); } else { P2 = I1411(1, 3, 7); } if (HQ2X_MDR) { P3 = IC(1); } else { P3 = I211(1, 5, 7); } } break; case 251 : { P1 = IC(2); if (HQ2X_MDL) { P2 = IC(2); } else { P2 = I1411(2, 3, 7); } if (HQ2X_MDR) { P3 = IC(2); } else { P3 = I211(2, 5, 7); } if (HQ2X_MUL) { P0 = IC(2); } else { P0 = I211(2, 1, 3); } } break; case 252 : { P0 = IC(0); P1 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I1411(0, 5, 7); } } break; case 253 : { P0 = IC(1); P1 = IC(1); if (HQ2X_MDL) { P2 = IC(1); } else { P2 = I1411(1, 3, 7); } if (HQ2X_MDR) { P3 = IC(1); } else { P3 = I1411(1, 5, 7); } } break; case 254 : { P0 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I1411(0, 5, 7); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 255 : { if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; mupen64plus-video-rice-src-2.0/src/TextureManager.cpp0000644000000000000000000013203112165031100020727 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "ConvertImage.h" #include "DeviceBuilder.h" #include "FrameBuffer.h" #include "RenderBase.h" #include "TextureManager.h" CTextureManager gTextureManager; unsigned int g_maxTextureMemUsage = (5*1024*1024); unsigned int g_amountToFree = (512*1024); bool g_bUseSetTextureMem = false; // Returns the first prime greater than or equal to nFirst inline int GetNextPrime(int nFirst) { int nCurrent; nCurrent = nFirst; // Just make sure it's odd if ((nCurrent % 2) == 0) nCurrent++; for (;;) { int nSqrtCurrent; BOOL bIsComposite; // nSqrtCurrent = nCurrent^0.5 + 1 (round up) nSqrtCurrent = (int)sqrt((double)nCurrent) + 1; bIsComposite = FALSE; // Test all odd numbers from 3..nSqrtCurrent for (int i = 3; i <= nSqrtCurrent; i+=2) { if ((nCurrent % i) == 0) { bIsComposite = TRUE; break; } } if (!bIsComposite) { return nCurrent; } // Select next odd candidate... nCurrent += 2; } } /////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////// CTextureManager::CTextureManager() : m_pHead(NULL), m_pCacheTxtrList(NULL), m_numOfCachedTxtrList(809) { m_numOfCachedTxtrList = GetNextPrime(800); m_currentTextureMemUsage = 0; m_pYoungestTexture = NULL; m_pOldestTexture = NULL; m_pCacheTxtrList = new TxtrCacheEntry *[m_numOfCachedTxtrList]; SAFE_CHECK(m_pCacheTxtrList); for (uint32 i = 0; i < m_numOfCachedTxtrList; i++) m_pCacheTxtrList[i] = NULL; memset(&m_blackTextureEntry, 0, sizeof(TxtrCacheEntry)); memset(&m_PrimColorTextureEntry, 0, sizeof(TxtrCacheEntry)); memset(&m_EnvColorTextureEntry, 0, sizeof(TxtrCacheEntry)); memset(&m_LODFracTextureEntry, 0, sizeof(TxtrCacheEntry)); memset(&m_PrimLODFracTextureEntry, 0, sizeof(TxtrCacheEntry)); } CTextureManager::~CTextureManager() { CleanUp(); delete []m_pCacheTxtrList; m_pCacheTxtrList = NULL; } // // Delete all textures. // bool CTextureManager::CleanUp() { RecycleAllTextures(); if (!g_bUseSetTextureMem) { while (m_pHead) { TxtrCacheEntry * pVictim = m_pHead; m_pHead = pVictim->pNext; delete pVictim; } } if( m_blackTextureEntry.pTexture ) delete m_blackTextureEntry.pTexture; if( m_PrimColorTextureEntry.pTexture ) delete m_PrimColorTextureEntry.pTexture; if( m_EnvColorTextureEntry.pTexture ) delete m_EnvColorTextureEntry.pTexture; if( m_LODFracTextureEntry.pTexture ) delete m_LODFracTextureEntry.pTexture; if( m_PrimLODFracTextureEntry.pTexture ) delete m_PrimLODFracTextureEntry.pTexture; memset(&m_blackTextureEntry, 0, sizeof(TxtrCacheEntry)); memset(&m_PrimColorTextureEntry, 0, sizeof(TxtrCacheEntry)); memset(&m_EnvColorTextureEntry, 0, sizeof(TxtrCacheEntry)); memset(&m_LODFracTextureEntry, 0, sizeof(TxtrCacheEntry)); memset(&m_PrimLODFracTextureEntry, 0, sizeof(TxtrCacheEntry)); return true; } bool CTextureManager::TCacheEntryIsLoaded(TxtrCacheEntry *pEntry) { for (int i = 0; i < MAX_TEXTURES; i++) { if (g_textures[i].pTextureEntry == pEntry) return true; } return false; } // Purge any textures whos last usage was over 5 seconds ago void CTextureManager::PurgeOldTextures() { if (m_pCacheTxtrList == NULL) return; if (g_bUseSetTextureMem) return; static const uint32 dwFramesToKill = 5*30; // 5 secs at 30 fps static const uint32 dwFramesToDelete = 30*30; // 30 secs at 30 fps for ( uint32 i = 0; i < m_numOfCachedTxtrList; i++ ) { TxtrCacheEntry * pEntry; TxtrCacheEntry * pNext; pEntry = m_pCacheTxtrList[i]; while (pEntry) { pNext = pEntry->pNext; if ( status.gDlistCount - pEntry->FrameLastUsed > dwFramesToKill && !TCacheEntryIsLoaded(pEntry)) { RemoveTexture(pEntry); } pEntry = pNext; } } // Remove any old textures that haven't been recycled in 1 minute or so // Normally these would be reused TxtrCacheEntry * pPrev; TxtrCacheEntry * pCurr; TxtrCacheEntry * pNext; pPrev = NULL; pCurr = m_pHead; while (pCurr) { pNext = pCurr->pNext; if ( status.gDlistCount - pCurr->FrameLastUsed > dwFramesToDelete && !TCacheEntryIsLoaded(pCurr) ) { if (pPrev != NULL) pPrev->pNext = pCurr->pNext; else m_pHead = pCurr->pNext; delete pCurr; pCurr = pNext; } else { pPrev = pCurr; pCurr = pNext; } } } void CTextureManager::RecycleAllTextures() { if (m_pCacheTxtrList == NULL) return; uint32 dwCount = 0; uint32 dwTotalUses = 0; m_pYoungestTexture = NULL; m_pOldestTexture = NULL; for (uint32 i = 0; i < m_numOfCachedTxtrList; i++) { while (m_pCacheTxtrList[i]) { TxtrCacheEntry *pTVictim = m_pCacheTxtrList[i]; m_pCacheTxtrList[i] = pTVictim->pNext; dwTotalUses += pTVictim->dwUses; dwCount++; if (g_bUseSetTextureMem) delete pTVictim; else RecycleTexture(pTVictim); } } } void CTextureManager::RecheckHiresForAllTextures() { if (m_pCacheTxtrList == NULL) return; for (uint32 i = 0; i < m_numOfCachedTxtrList; i++) { while (m_pCacheTxtrList[i]) { TxtrCacheEntry *pTVictim = m_pCacheTxtrList[i]; m_pCacheTxtrList[i] = pTVictim->pNext; pTVictim->bExternalTxtrChecked = false; } } } // Add to the recycle list void CTextureManager::RecycleTexture(TxtrCacheEntry *pEntry) { if (g_bUseSetTextureMem) return; if( CDeviceBuilder::GetGeneralDeviceType() == OGL_DEVICE ) { // Fix me, why I can not reuse the texture in OpenGL, // how can I unload texture from video card memory for OpenGL delete pEntry; return; } if (pEntry->pTexture == NULL) { // No point in saving! delete pEntry; } else { // Add to the list pEntry->pNext = m_pHead; SAFE_DELETE(pEntry->pEnhancedTexture); m_pHead = pEntry; } } // Search for a texture of the specified dimensions to recycle TxtrCacheEntry * CTextureManager::ReviveTexture( uint32 width, uint32 height ) { if (g_bUseSetTextureMem) return NULL; TxtrCacheEntry * pPrev; TxtrCacheEntry * pCurr; pPrev = NULL; pCurr = m_pHead; while (pCurr) { if (pCurr->ti.WidthToCreate == width && pCurr->ti.HeightToCreate == height) { // Remove from list if (pPrev != NULL) pPrev->pNext = pCurr->pNext; else m_pHead = pCurr->pNext; return pCurr; } pPrev = pCurr; pCurr = pCurr->pNext; } return NULL; } uint32 CTextureManager::Hash(uint32 dwValue) { // Divide by four, because most textures will be on a 4 byte boundry, so bottom four // bits are null return (dwValue>>2) % m_numOfCachedTxtrList; } void CTextureManager::MakeTextureYoungest(TxtrCacheEntry *pEntry) { if (!g_bUseSetTextureMem) return; if (pEntry == m_pYoungestTexture) return; // if its the oldest, then change the oldest pointer if (pEntry == m_pOldestTexture) { m_pOldestTexture = pEntry->pNextYoungest; } // if its a not a new texture, close the gap in the age list // where pEntry use to reside if (pEntry->pNextYoungest != NULL || pEntry->pLastYoungest != NULL) { if (pEntry->pNextYoungest != NULL) { pEntry->pNextYoungest->pLastYoungest = pEntry->pLastYoungest; } if (pEntry->pLastYoungest != NULL) { pEntry->pLastYoungest->pNextYoungest = pEntry->pNextYoungest; } } // this texture is now the youngest, so place it on the end of the list if (m_pYoungestTexture != NULL) { m_pYoungestTexture->pNextYoungest = pEntry; } pEntry->pNextYoungest = NULL; pEntry->pLastYoungest = m_pYoungestTexture; m_pYoungestTexture = pEntry; // if this is the first texture in memory then its also the oldest if (m_pOldestTexture == NULL) { m_pOldestTexture = pEntry; } } void CTextureManager::AddTexture(TxtrCacheEntry *pEntry) { uint32 dwKey = Hash(pEntry->ti.Address); if (m_pCacheTxtrList == NULL) return; //TxtrCacheEntry **p = &m_pCacheTxtrList[dwKey]; // Add to head (not tail, for speed - new textures are more likely to be accessed next) pEntry->pNext = m_pCacheTxtrList[dwKey]; m_pCacheTxtrList[dwKey] = pEntry; // Move the texture to the top of the age list MakeTextureYoungest(pEntry); } TxtrCacheEntry * CTextureManager::GetTxtrCacheEntry(TxtrInfo * pti) { TxtrCacheEntry *pEntry; if (m_pCacheTxtrList == NULL) return NULL; // See if it is already in the hash table uint32 dwKey = Hash(pti->Address); for (pEntry = m_pCacheTxtrList[dwKey]; pEntry; pEntry = pEntry->pNext) { if ( pEntry->ti == *pti ) { MakeTextureYoungest(pEntry); return pEntry; } } return NULL; } void CTextureManager::RemoveTexture(TxtrCacheEntry * pEntry) { TxtrCacheEntry * pPrev; TxtrCacheEntry * pCurr; if (m_pCacheTxtrList == NULL) return; // See if it is already in the hash table uint32 dwKey = Hash(pEntry->ti.Address); pPrev = NULL; pCurr = m_pCacheTxtrList[dwKey]; while (pCurr) { // Check that the attributes match if ( pCurr->ti == pEntry->ti ) { if (pPrev != NULL) pPrev->pNext = pCurr->pNext; else m_pCacheTxtrList[dwKey] = pCurr->pNext; if (g_bUseSetTextureMem) { // remove the texture from the age list if (pEntry->pNextYoungest != NULL) { pEntry->pNextYoungest->pLastYoungest = pEntry->pLastYoungest; } if (pEntry->pLastYoungest != NULL) { pEntry->pLastYoungest->pNextYoungest = pEntry->pNextYoungest; } // decrease the mem usage counter m_currentTextureMemUsage -= (pEntry->pTexture->m_dwWidth * pEntry->pTexture->m_dwHeight * 4); delete pEntry; } else { RecycleTexture(pEntry); } break; } pPrev = pCurr; pCurr = pCurr->pNext; } } TxtrCacheEntry * CTextureManager::CreateNewCacheEntry(uint32 dwAddr, uint32 dwWidth, uint32 dwHeight) { TxtrCacheEntry * pEntry = NULL; if (g_bUseSetTextureMem) { uint32 widthToCreate = dwWidth; uint32 heightToCreate = dwHeight; unsigned int freeUpSize = (widthToCreate * heightToCreate * 4) + g_amountToFree; // make sure there is enough room for the new texture by deleting old textures while ((m_currentTextureMemUsage + freeUpSize) > g_maxTextureMemUsage && m_pOldestTexture != NULL) { TxtrCacheEntry *nextYoungest = m_pOldestTexture->pNextYoungest; RemoveTexture(m_pOldestTexture); m_pOldestTexture = nextYoungest; //printf("Freeing Texture\n"); } m_currentTextureMemUsage += widthToCreate * heightToCreate * 4; } else { // Find a used texture pEntry = ReviveTexture(dwWidth, dwHeight); } if (pEntry == NULL || g_bUseSetTextureMem) { // Couldn't find on - recreate! pEntry = new TxtrCacheEntry; if (pEntry == NULL) { _VIDEO_DisplayTemporaryMessage("Error to create an texture entry"); return NULL; } pEntry->pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(dwWidth, dwHeight); if (pEntry->pTexture == NULL || pEntry->pTexture->GetTexture() == NULL) { _VIDEO_DisplayTemporaryMessage("Error to create an texture"); TRACE2("Warning, unable to create %d x %d texture!", dwWidth, dwHeight); } else { pEntry->pTexture->m_bScaledS = false; pEntry->pTexture->m_bScaledT = false; } } // Initialize pEntry->ti.Address = dwAddr; pEntry->pNext = NULL; pEntry->pNextYoungest = NULL; pEntry->pLastYoungest = NULL; pEntry->dwUses = 0; pEntry->dwTimeLastUsed = status.gRDPTime; pEntry->dwCRC = 0; pEntry->FrameLastUsed = status.gDlistCount; pEntry->FrameLastUpdated = 0; pEntry->lastEntry = NULL; pEntry->bExternalTxtrChecked = false; pEntry->maxCI = -1; // Add to the hash table AddTexture(pEntry); return pEntry; } // If already in table, return // Otherwise, create surfaces, and load texture into memory uint32 dwAsmHeight; uint32 dwAsmPitch; uint32 dwAsmdwBytesPerLine; uint32 dwAsmCRC; uint32 dwAsmCRC2; uint8* pAsmStart; TxtrCacheEntry *g_lastTextureEntry=NULL; bool lastEntryModified = false; TxtrCacheEntry * CTextureManager::GetTexture(TxtrInfo * pgti, bool fromTMEM, bool doCRCCheck, bool AutoExtendTexture) { TxtrCacheEntry *pEntry; if( g_curRomInfo.bDisableTextureCRC ) doCRCCheck = false; gRDP.texturesAreReloaded = true; dwAsmCRC = 0; uint32 dwPalCRC = 0; pEntry = GetTxtrCacheEntry(pgti); bool loadFromTextureBuffer=false; int txtBufIdxToLoadFrom = -1; if( (frameBufferOptions.bCheckRenderTextures&&!frameBufferOptions.bWriteBackBufToRDRAM) || (frameBufferOptions.bCheckBackBufs&&!frameBufferOptions.bWriteBackBufToRDRAM) ) { txtBufIdxToLoadFrom = g_pFrameBufferManager->CheckAddrInRenderTextures(pgti->Address); if( txtBufIdxToLoadFrom >= 0 ) { loadFromTextureBuffer = true; // Check if it is the same size, RenderTextureInfo &info = gRenderTextureInfos[txtBufIdxToLoadFrom]; //if( info.pRenderTexture && info.CI_Info.dwAddr == pgti->Address && info.CI_Info.dwFormat == pgti->Format if( info.pRenderTexture && info.CI_Info.dwFormat == pgti->Format && info.CI_Info.dwSize == pgti->Size ) { info.txtEntry.ti = *pgti; return &info.txtEntry; } } } if( frameBufferOptions.bCheckBackBufs && g_pFrameBufferManager->CheckAddrInBackBuffers(pgti->Address, pgti->HeightToLoad*pgti->Pitch) >= 0 ) { if( !frameBufferOptions.bWriteBackBufToRDRAM ) { // Load the texture from recent back buffer txtBufIdxToLoadFrom = g_pFrameBufferManager->CheckAddrInRenderTextures(pgti->Address); if( txtBufIdxToLoadFrom >= 0 ) { loadFromTextureBuffer = true; // Check if it is the same size, RenderTextureInfo &info = gRenderTextureInfos[txtBufIdxToLoadFrom]; //if( info.pRenderTexture && info.CI_Info.dwAddr == pgti->Address && info.CI_Info.dwFormat == pgti->Format if( info.pRenderTexture && info.CI_Info.dwFormat == pgti->Format && info.CI_Info.dwSize == pgti->Size ) { info.txtEntry.ti = *pgti; return &info.txtEntry; } } } } if (pEntry && pEntry->dwTimeLastUsed == status.gRDPTime && status.gDlistCount != 0 && !status.bN64FrameBufferIsUsed ) // This is not good, Palatte may changes { // We've already calculated a CRC this frame! dwAsmCRC = pEntry->dwCRC; } else { if ( doCRCCheck ) { if( loadFromTextureBuffer ) dwAsmCRC = gRenderTextureInfos[txtBufIdxToLoadFrom].crcInRDRAM; else CalculateRDRAMCRC(pgti->pPhysicalAddress, pgti->LeftToLoad, pgti->TopToLoad, pgti->WidthToLoad, pgti->HeightToLoad, pgti->Size, pgti->Pitch); } } int maxCI = 0; if ( doCRCCheck && (pgti->Format == TXT_FMT_CI || (pgti->Format == TXT_FMT_RGBA && pgti->Size <= TXT_SIZE_8b ))) { //maxCI = pgti->Size == TXT_SIZE_8b ? 255 : 15; extern unsigned char CalculateMaxCI(void *pPhysicalAddress, uint32 left, uint32 top, uint32 width, uint32 height, uint32 size, uint32 pitchInBytes ); if( !pEntry || pEntry->dwCRC != dwAsmCRC || pEntry->maxCI < 0 ) { maxCI = CalculateMaxCI(pgti->pPhysicalAddress, pgti->LeftToLoad, pgti->TopToLoad, pgti->WidthToLoad, pgti->HeightToLoad, pgti->Size, pgti->Pitch); } else { maxCI = pEntry->maxCI; } //Check PAL CRC uint8 * pStart; uint32 dwPalSize = 16; uint32 dwOffset; if( pgti->Size == TXT_SIZE_8b ) { dwPalSize = 256; dwOffset = 0; } else { dwOffset = pgti->Palette << 4; } pStart = (uint8*)pgti->PalAddress+dwOffset*2; //uint32 y; //for (y = 0; y < dwPalSize*2; y+=4) //{ // dwPalCRC = (dwPalCRC + *(uint32*)&pStart[y]); //} uint32 dwAsmCRCSave = dwAsmCRC; //dwPalCRC = CalculateRDRAMCRC(pStart, 0, 0, dwPalSize, 1, TXT_SIZE_16b, dwPalSize*2); dwPalCRC = CalculateRDRAMCRC(pStart, 0, 0, maxCI+1, 1, TXT_SIZE_16b, dwPalSize*2); dwAsmCRC = dwAsmCRCSave; } if (pEntry && doCRCCheck ) { if(pEntry->dwCRC == dwAsmCRC && pEntry->dwPalCRC == dwPalCRC && (!loadFromTextureBuffer || gRenderTextureInfos[txtBufIdxToLoadFrom].updateAtFrame < pEntry->FrameLastUsed ) ) { // Tile is ok, return pEntry->dwUses++; pEntry->dwTimeLastUsed = status.gRDPTime; pEntry->FrameLastUsed = status.gDlistCount; LOG_TEXTURE(TRACE0(" Use current texture:\n")); pEntry->lastEntry = g_lastTextureEntry; g_lastTextureEntry = pEntry; lastEntryModified = false; DEBUGGER_IF_DUMP((pauseAtNext && loadFromTextureBuffer) , {DebuggerAppendMsg("Load cached texture from render_texture");} ); return pEntry; } else { //Do something } } if (pEntry == NULL) { // We need to create a new entry, and add it // to the hash table. pEntry = CreateNewCacheEntry(pgti->Address, pgti->WidthToCreate, pgti->HeightToCreate); if (pEntry == NULL) { g_lastTextureEntry = pEntry; _VIDEO_DisplayTemporaryMessage("Fail to create new texture entry"); return NULL; } } pEntry->ti = *pgti; pEntry->dwCRC = dwAsmCRC; pEntry->dwPalCRC = dwPalCRC; pEntry->bExternalTxtrChecked = false; pEntry->maxCI = maxCI; try { if (pEntry->pTexture != NULL) { if( pEntry->pTexture->m_dwCreatedTextureWidth < pgti->WidthToCreate ) { pEntry->ti.WidthToLoad = pEntry->pTexture->m_dwCreatedTextureWidth; pEntry->pTexture->m_bScaledS = false; pEntry->pTexture->m_bScaledT = false; } if( pEntry->pTexture->m_dwCreatedTextureHeight < pgti->HeightToCreate ) { pEntry->ti.HeightToLoad = pEntry->pTexture->m_dwCreatedTextureHeight; pEntry->pTexture->m_bScaledT = false; pEntry->pTexture->m_bScaledS = false; } TextureFmt dwType = pEntry->pTexture->GetSurfaceFormat(); SAFE_DELETE(pEntry->pEnhancedTexture); pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT; if (dwType != TEXTURE_FMT_UNKNOWN) { if( loadFromTextureBuffer ) { g_pFrameBufferManager->LoadTextureFromRenderTexture(pEntry, txtBufIdxToLoadFrom); DEBUGGER_IF_DUMP((pauseAtNext && loadFromTextureBuffer) , {DebuggerAppendMsg("Load texture from render_texture %d", txtBufIdxToLoadFrom);} ); extern void ConvertTextureRGBAtoI(TxtrCacheEntry* pEntry, bool alpha); if( g_pRenderTextureInfo->CI_Info.dwFormat == TXT_FMT_I ) { // Convert texture from RGBA to I ConvertTextureRGBAtoI(pEntry,false); } else if( g_pRenderTextureInfo->CI_Info.dwFormat == TXT_FMT_IA ) { // Convert texture from RGBA to IA ConvertTextureRGBAtoI(pEntry,true); } } else { LOG_TEXTURE(TRACE0(" Load new texture from RDRAM:\n")); if (dwType == TEXTURE_FMT_A8R8G8B8) { ConvertTexture(pEntry, fromTMEM); } else ConvertTexture_16(pEntry, fromTMEM); pEntry->FrameLastUpdated = status.gDlistCount; SAFE_DELETE(pEntry->pEnhancedTexture); pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT; } } pEntry->ti.WidthToLoad = pgti->WidthToLoad; pEntry->ti.HeightToLoad = pgti->HeightToLoad; if( AutoExtendTexture ) { ExpandTextureS(pEntry); ExpandTextureT(pEntry); } if( options.bDumpTexturesToFiles && !loadFromTextureBuffer ) { DumpCachedTexture(*pEntry); } #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_NEW_TEXTURE ) { CRender::g_pRender->SetCurrentTexture( 0, pEntry->pTexture, pEntry->ti.WidthToCreate, pEntry->ti.HeightToCreate, pEntry); CRender::g_pRender->DrawTexture(0); debuggerPause = true; TRACE0("Pause after loading a new texture"); if( pEntry->ti.Format == TXT_FMT_YUV ) { TRACE0("This is YUV texture"); } DebuggerAppendMsg("W:%d, H:%d, RealW:%d, RealH:%d, D3DW:%d, D3DH: %d", pEntry->ti.WidthToCreate, pEntry->ti.HeightToCreate, pEntry->ti.WidthToLoad, pEntry->ti.HeightToLoad, pEntry->pTexture->m_dwCreatedTextureWidth, pEntry->pTexture->m_dwCreatedTextureHeight); DebuggerAppendMsg("ScaledS:%s, ScaledT:%s, CRC=%08X", pEntry->pTexture->m_bScaledS?"T":"F", pEntry->pTexture->m_bScaledT?"T":"F", pEntry->dwCRC); DebuggerPause(); CRender::g_pRender->SetCurrentTexture( 0, NULL, 64, 64, NULL); } #endif } } catch (...) { TRACE0("Exception in texture decompression"); g_lastTextureEntry = NULL; return NULL; } pEntry->lastEntry = g_lastTextureEntry; g_lastTextureEntry = pEntry; lastEntryModified = true; return pEntry; } const char *pszImgFormat[8] = {"RGBA", "YUV", "CI", "IA", "I", "?1", "?2", "?3"}; uint8 pnImgSize[4] = {4, 8, 16, 32}; const char *textlutname[4] = {"RGB16", "I16?", "RGBA16", "IA16"}; extern uint16 g_wRDPTlut[]; extern ConvertFunction gConvertFunctions_FullTMEM[ 8 ][ 4 ]; extern ConvertFunction gConvertFunctions[ 8 ][ 4 ]; extern ConvertFunction gConvertTlutFunctions[ 8 ][ 4 ]; extern ConvertFunction gConvertFunctions_16[ 8 ][ 4 ]; extern ConvertFunction gConvertFunctions_16_FullTMEM[ 8 ][ 4 ]; extern ConvertFunction gConvertTlutFunctions_16[ 8 ][ 4 ]; void CTextureManager::ConvertTexture(TxtrCacheEntry * pEntry, bool fromTMEM) { static uint32 dwCount = 0; ConvertFunction pF; if( options.bUseFullTMEM && fromTMEM && status.bAllowLoadFromTMEM ) { pF = gConvertFunctions_FullTMEM[ pEntry->ti.Format ][ pEntry->ti.Size ]; } else { if( gRDP.tiles[7].dwFormat == TXT_FMT_YUV ) { if( gRDP.otherMode.text_tlut>=2 ) pF = gConvertTlutFunctions[ TXT_FMT_YUV ][ pEntry->ti.Size ]; else pF = gConvertFunctions[ TXT_FMT_YUV ][ pEntry->ti.Size ]; } else { if( gRDP.otherMode.text_tlut>=2 ) pF = gConvertTlutFunctions[ pEntry->ti.Format ][ pEntry->ti.Size ]; else pF = gConvertFunctions[ pEntry->ti.Format ][ pEntry->ti.Size ]; } } if( pF ) { pF( pEntry->pTexture, pEntry->ti ); LOG_TEXTURE( { DebuggerAppendMsg("Decompress 32bit Texture:\n\tFormat: %s\n\tImage Size:%d\n", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]); DebuggerAppendMsg("Palette Format: %s (%d)\n", textlutname[pEntry->ti.TLutFmt>>RSP_SETOTHERMODE_SHIFT_TEXTLUT], pEntry->ti.TLutFmt>>RSP_SETOTHERMODE_SHIFT_TEXTLUT); }); } else { TRACE2("ConvertTexture: Unable to decompress %s/%dbpp", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]); } dwCount++; } void CTextureManager::ConvertTexture_16(TxtrCacheEntry * pEntry, bool fromTMEM) { static uint32 dwCount = 0; ConvertFunction pF; if( options.bUseFullTMEM && fromTMEM && status.bAllowLoadFromTMEM ) { pF = gConvertFunctions_16_FullTMEM[ pEntry->ti.Format ][ pEntry->ti.Size ]; } else { if( gRDP.otherMode.text_tlut>=2 ) pF = gConvertTlutFunctions_16[ pEntry->ti.Format ][ pEntry->ti.Size ]; else pF = gConvertFunctions_16[ pEntry->ti.Format ][ pEntry->ti.Size ]; } if( pF ) { pF( pEntry->pTexture, pEntry->ti ); LOG_TEXTURE(TRACE2("Decompress 16bit Texture:\n\tFormat: %s\n\tImage Size:%d\n", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size])); } else { TRACE2("ConvertTexture: Unable to decompress %s/%dbpp", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]); } dwCount++; } void CTextureManager::ExpandTexture(TxtrCacheEntry * pEntry, uint32 sizeToLoad, uint32 sizeToCreate, uint32 sizeCreated, int arrayWidth, int flag, int mask, int mirror, int clamp, uint32 otherSize) { if( sizeToLoad >= sizeCreated ) return; uint32 maskWidth = (1<pTexture->GetPixelSize(); #ifdef DEBUGGER // Some checks if( sizeToLoad > sizeToCreate || sizeToCreate > sizeCreated ) TRACE0("Something is wrong, check me here in ExpandTextureS"); #endif // Doing Mirror And/Or Wrap in S direction // Image has been loaded with width=WidthToLoad, we need to enlarge the image // to width = pEntry->ti.WidthToCreate by doing mirroring or wrapping DrawInfo di; if( !(pEntry->pTexture->StartUpdate(&di)) ) { TRACE0("Cann't update the texture"); return; } if( mask == 0 ) { // Clamp Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, flag, size); pEntry->pTexture->EndUpdate(&di); return; } #ifdef DEBUGGER if( sizeToLoad > maskWidth ) { TRACE0("Something is wrong, check me here in ExpandTextureS"); pEntry->pTexture->EndUpdate(&di); return; } if( sizeToLoad == maskWidth && maskWidth == sizeToCreate && sizeToCreate != sizeCreated ) { TRACE0("Something is wrong, check me here in ExpandTextureS"); pEntry->pTexture->EndUpdate(&di); return; } #endif if( sizeToLoad == maskWidth ) { uint32 tempwidth = clamp ? sizeToCreate : sizeCreated; if( mirror ) { Mirror(di.lpSurface, sizeToLoad, mask, tempwidth, arrayWidth, otherSize, flag, size ); } else { Wrap(di.lpSurface, sizeToLoad, mask, tempwidth, arrayWidth, otherSize, flag, size ); } if( tempwidth < sizeCreated ) { Clamp(di.lpSurface, tempwidth, sizeCreated, arrayWidth, otherSize, flag, size ); } pEntry->pTexture->EndUpdate(&di); return; } if( sizeToLoad < sizeToCreate && sizeToCreate == maskWidth && maskWidth == sizeCreated ) { // widthToLoad < widthToCreate = maskWidth Wrap(di.lpSurface, sizeToLoad, mask, sizeCreated, arrayWidth, otherSize, flag, size ); pEntry->pTexture->EndUpdate(&di); return; } if( sizeToLoad == sizeToCreate && sizeToCreate < maskWidth ) { #ifdef DEBUGGER if( maskWidth < sizeToCreate ) TRACE0("Incorrect condition, check me"); #endif Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, flag, size ); pEntry->pTexture->EndUpdate(&di); return; } if( sizeToLoad < sizeToCreate && sizeToCreate < maskWidth ) { #ifdef DEBUGGER if( clamp ) TRACE0("Incorrect condition, check me"); if( maskWidth < sizeCreated ) TRACE0("Incorrect condition, check me"); #endif Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, flag, size ); pEntry->pTexture->EndUpdate(&di); return; } TRACE0("Check me, should not get here"); pEntry->pTexture->EndUpdate(&di); } void CTextureManager::ExpandTextureS(TxtrCacheEntry * pEntry) { TxtrInfo &ti = pEntry->ti; uint32 textureWidth = pEntry->pTexture->m_dwCreatedTextureWidth; ExpandTexture(pEntry, ti.WidthToLoad, ti.WidthToCreate, textureWidth, textureWidth, S_FLAG, ti.maskS, ti.mirrorS, ti.clampS, ti.HeightToLoad); } void CTextureManager::ExpandTextureT(TxtrCacheEntry * pEntry) { TxtrInfo &ti = pEntry->ti; uint32 textureHeight = pEntry->pTexture->m_dwCreatedTextureHeight; uint32 textureWidth = pEntry->pTexture->m_dwCreatedTextureWidth; ExpandTexture(pEntry, ti.HeightToLoad, ti.HeightToCreate, textureHeight, textureWidth, T_FLAG, ti.maskT, ti.mirrorT, ti.clampT, ti.WidthToLoad); } void CTextureManager::ClampS32(uint32 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows) { if ((int) width <= 0 || (int) towidth < 0) return; for( uint32 y = 0; ymaskval?y&maskval:y-height); uint32* linedst = array+arrayWidth*y;; for( uint32 x=0; xmaskval?y&maskval:y-height); uint16* linedst = array+arrayWidth*y;; for( uint32 x=0; xpNext) { if( size == tex ) return pEntry; else size++; } } } return NULL; } uint32 CTextureManager::GetNumOfCachedTexture() { uint32 size = 0; for( uint32 i=0; ipNext) { size++; } } } TRACE1("Totally %d texture cached", size); return size; } #endif TxtrCacheEntry * CTextureManager::GetBlackTexture(void) { if( m_blackTextureEntry.pTexture == NULL ) { m_blackTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4); m_blackTextureEntry.ti.WidthToCreate = 4; m_blackTextureEntry.ti.HeightToCreate = 4; updateColorTexture(m_blackTextureEntry.pTexture,0x00000000); } return &m_blackTextureEntry; } TxtrCacheEntry * CTextureManager::GetPrimColorTexture(uint32 color) { static uint32 mcolor = 0; if( m_PrimColorTextureEntry.pTexture == NULL ) { m_PrimColorTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4); m_PrimColorTextureEntry.ti.WidthToCreate = 4; m_PrimColorTextureEntry.ti.HeightToCreate = 4; updateColorTexture(m_PrimColorTextureEntry.pTexture,color); gRDP.texturesAreReloaded = true; } else if( mcolor != color ) { updateColorTexture(m_PrimColorTextureEntry.pTexture,color); gRDP.texturesAreReloaded = true; } mcolor = color; return &m_PrimColorTextureEntry; } TxtrCacheEntry * CTextureManager::GetEnvColorTexture(uint32 color) { static uint32 mcolor = 0; if( m_EnvColorTextureEntry.pTexture == NULL ) { m_EnvColorTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4); m_EnvColorTextureEntry.ti.WidthToCreate = 4; m_EnvColorTextureEntry.ti.HeightToCreate = 4; gRDP.texturesAreReloaded = true; updateColorTexture(m_EnvColorTextureEntry.pTexture,color); } else if( mcolor != color ) { updateColorTexture(m_EnvColorTextureEntry.pTexture,color); gRDP.texturesAreReloaded = true; } mcolor = color; return &m_EnvColorTextureEntry; } TxtrCacheEntry * CTextureManager::GetLODFracTexture(uint8 fac) { static uint8 mfac = 0; if( m_LODFracTextureEntry.pTexture == NULL ) { m_LODFracTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4); m_LODFracTextureEntry.ti.WidthToCreate = 4; m_LODFracTextureEntry.ti.HeightToCreate = 4; uint32 factor = fac; uint32 color = fac; color |= factor << 8; color |= color << 16; updateColorTexture(m_LODFracTextureEntry.pTexture,color); gRDP.texturesAreReloaded = true; } else if( mfac != fac ) { uint32 factor = fac; uint32 color = fac; color |= factor << 8; color |= color << 16; updateColorTexture(m_LODFracTextureEntry.pTexture,color); gRDP.texturesAreReloaded = true; } mfac = fac; return &m_LODFracTextureEntry; } TxtrCacheEntry * CTextureManager::GetPrimLODFracTexture(uint8 fac) { static uint8 mfac = 0; if( m_PrimLODFracTextureEntry.pTexture == NULL ) { m_PrimLODFracTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4); m_PrimLODFracTextureEntry.ti.WidthToCreate = 4; m_PrimLODFracTextureEntry.ti.HeightToCreate = 4; uint32 factor = fac; uint32 color = fac; color |= factor << 8; color |= color << 16; updateColorTexture(m_PrimLODFracTextureEntry.pTexture,color); gRDP.texturesAreReloaded = true; } else if( mfac != fac ) { uint32 factor = fac; uint32 color = fac; color |= factor << 8; color |= color << 16; updateColorTexture(m_PrimLODFracTextureEntry.pTexture,color); gRDP.texturesAreReloaded = true; } mfac = fac; return &m_PrimLODFracTextureEntry; } TxtrCacheEntry * CTextureManager::GetConstantColorTexture(uint32 constant) { switch( constant ) { case MUX_PRIM: return GetPrimColorTexture(gRDP.primitiveColor); break; case MUX_ENV: return GetEnvColorTexture(gRDP.envColor); break; case MUX_LODFRAC: return GetLODFracTexture((uint8)gRDP.LODFrac); break; default: // MUX_PRIMLODFRAC return GetPrimLODFracTexture((uint8)gRDP.primLODFrac); break; } } void CTextureManager::updateColorTexture(CTexture *ptexture, uint32 color) { DrawInfo di; if( !(ptexture->StartUpdate(&di)) ) { TRACE0("Cann't update the texture"); return; } int size = ptexture->GetPixelSize(); switch( size ) { case 2: // 16 bits { uint16 *buf = (uint16*)di.lpSurface; uint16 color16= (uint16)((color>>4)&0xF); color16 |= ((color>>12)&0xF)<<4; color16 |= ((color>>20)&0xF)<<8; color16 |= ((color>>28)&0xF)<<12; for( int i=0; i<16; i++ ) { buf[i] = color16; } } break; case 4: // 32 bits { uint32 *buf = (uint32*)di.lpSurface; for( int i=0; i<16; i++ ) { buf[i] = color; } } break; } ptexture->EndUpdate(&di); } void ConvertTextureRGBAtoI(TxtrCacheEntry* pEntry, bool alpha) { DrawInfo srcInfo; if( pEntry->pTexture->StartUpdate(&srcInfo) ) { uint32 *buf; uint32 val; uint32 r,g,b,a,i; for(int nY = 0; nY < srcInfo.dwCreatedHeight; nY++) { buf = (uint32*)((uint8*)srcInfo.lpSurface+nY*srcInfo.lPitch); for(int nX = 0; nX < srcInfo.dwCreatedWidth; nX++) { val = buf[nX]; b = (val>>0)&0xFF; g = (val>>8)&0xFF; r = (val>>16)&0xFF; i = (r+g+b)/3; a = alpha?(val&0xFF000000):(i<<24); buf[nX] = (a|(i<<16)|(i<<8)|i); } } pEntry->pTexture->EndUpdate(&srcInfo); } } mupen64plus-video-rice-src-2.0/src/TextureManager.h0000644000000000000000000002014212165031100020373 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __TEXTUREHANDLER_H__ #define __TEXTUREHANDLER_H__ #ifndef SAFE_DELETE #define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } #endif #ifndef SAFE_CHECK # define SAFE_CHECK(a) if( (a) == NULL ) {DebugMessage(M64MSG_ERROR, "Creater out of memory"); throw new std::exception();} #endif #include #include "typedefs.h" #include "Texture.h" #define absi(x) ((x)>=0?(x):(-x)) #define S_FLAG 0 #define T_FLAG 1 class TxtrInfo { public: uint32 WidthToCreate; uint32 HeightToCreate; uint32 Address; void *pPhysicalAddress; uint32 Format; uint32 Size; int LeftToLoad; int TopToLoad; uint32 WidthToLoad; uint32 HeightToLoad; uint32 Pitch; uchar *PalAddress; uint32 TLutFmt; uint32 Palette; BOOL bSwapped; uint32 maskS; uint32 maskT; BOOL clampS; BOOL clampT; BOOL mirrorS; BOOL mirrorT; int tileNo; inline TxtrInfo& operator = (const TxtrInfo& src) { memcpy(this, &src, sizeof( TxtrInfo )); return *this; } inline TxtrInfo& operator = (const Tile& tile) { Format = tile.dwFormat; Size = tile.dwSize; Palette = tile.dwPalette; maskS = tile.dwMaskS; maskT = tile.dwMaskT; mirrorS = tile.bMirrorS; mirrorT = tile.bMirrorT; clampS = tile.bClampS; clampT = tile.bClampT; return *this; } inline bool operator == ( const TxtrInfo& sec) { return ( Address == sec.Address && WidthToLoad == sec.WidthToLoad && HeightToLoad == sec.HeightToLoad && WidthToCreate == sec.WidthToCreate && HeightToCreate == sec.HeightToCreate && maskS == sec.maskS && maskT == sec.maskT && TLutFmt == sec.TLutFmt && PalAddress == sec.PalAddress && Palette == sec.Palette && LeftToLoad == sec.LeftToLoad && TopToLoad == sec.TopToLoad && Format == sec.Format && Size == sec.Size && Pitch == sec.Pitch && bSwapped == sec.bSwapped && mirrorS == sec.mirrorS && mirrorT == sec.mirrorT && clampS == sec.clampS && clampT == sec.clampT ); } inline bool isEqual(const TxtrInfo& sec) { return (*this == sec); } } ; typedef struct TxtrCacheEntry { TxtrCacheEntry(): pTexture(NULL),pEnhancedTexture(NULL),txtrBufIdx(0) {} ~TxtrCacheEntry() { SAFE_DELETE(pTexture); SAFE_DELETE(pEnhancedTexture); } struct TxtrCacheEntry *pNext; // Must be first element! struct TxtrCacheEntry *pNextYoungest; struct TxtrCacheEntry *pLastYoungest; TxtrInfo ti; uint32 dwCRC; uint32 dwPalCRC; int maxCI; uint32 dwUses; // Total times used (for stats) uint32 dwTimeLastUsed; // timeGetTime of time of last usage uint32 FrameLastUsed; // Frame # that this was last used uint32 FrameLastUpdated; CTexture *pTexture; CTexture *pEnhancedTexture; uint32 dwEnhancementFlag; int txtrBufIdx; bool bExternalTxtrChecked; TxtrCacheEntry *lastEntry; } TxtrCacheEntry; //***************************************************************************** // Texture cache implementation //***************************************************************************** class CTextureManager { protected: TxtrCacheEntry * CreateNewCacheEntry(uint32 dwAddr, uint32 dwWidth, uint32 dwHeight); void AddTexture(TxtrCacheEntry *pEntry); void RemoveTexture(TxtrCacheEntry * pEntry); void RecycleTexture(TxtrCacheEntry *pEntry); TxtrCacheEntry * ReviveTexture( uint32 width, uint32 height ); TxtrCacheEntry * GetTxtrCacheEntry(TxtrInfo * pti); void ConvertTexture(TxtrCacheEntry * pEntry, bool fromTMEM); void ConvertTexture_16(TxtrCacheEntry * pEntry, bool fromTMEM); void ClampS32(uint32 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows); void ClampS16(uint16 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows); void ClampT32(uint32 *array, uint32 height, uint32 toheight, uint32 arrayWidth, uint32 cols); void ClampT16(uint16 *array, uint32 height, uint32 toheight, uint32 arrayWidth, uint32 cols); void MirrorS32(uint32 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows); void MirrorS16(uint16 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows); void MirrorT32(uint32 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols); void MirrorT16(uint16 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols); void WrapS32(uint32 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows); void WrapS16(uint16 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows); void WrapT32(uint32 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols); void WrapT16(uint16 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols); void ExpandTextureS(TxtrCacheEntry * pEntry); void ExpandTextureT(TxtrCacheEntry * pEntry); void ExpandTexture(TxtrCacheEntry * pEntry, uint32 sizeOfLoad, uint32 sizeToCreate, uint32 sizeCreated, int arrayWidth, int flag, int mask, int mirror, int clamp, uint32 otherSize); uint32 Hash(uint32 dwValue); bool TCacheEntryIsLoaded(TxtrCacheEntry *pEntry); void updateColorTexture(CTexture *ptexture, uint32 color); public: void Wrap(void *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size ); void Clamp(void *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size ); void Mirror(void *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size ); protected: TxtrCacheEntry * m_pHead; TxtrCacheEntry ** m_pCacheTxtrList; uint32 m_numOfCachedTxtrList; TxtrCacheEntry m_blackTextureEntry; TxtrCacheEntry m_PrimColorTextureEntry; TxtrCacheEntry m_EnvColorTextureEntry; TxtrCacheEntry m_LODFracTextureEntry; TxtrCacheEntry m_PrimLODFracTextureEntry; TxtrCacheEntry * GetPrimColorTexture(uint32 color); TxtrCacheEntry * GetEnvColorTexture(uint32 color); TxtrCacheEntry * GetLODFracTexture(uint8 fac); TxtrCacheEntry * GetPrimLODFracTexture(uint8 fac); void MakeTextureYoungest(TxtrCacheEntry *pEntry); unsigned int m_currentTextureMemUsage; TxtrCacheEntry *m_pYoungestTexture; TxtrCacheEntry *m_pOldestTexture; public: CTextureManager(); ~CTextureManager(); TxtrCacheEntry * GetBlackTexture(void); TxtrCacheEntry * GetConstantColorTexture(uint32 constant); TxtrCacheEntry * GetTexture(TxtrInfo * pgti, bool fromTMEM, bool doCRCCheck=true, bool AutoExtendTexture = false); void PurgeOldTextures(); void RecycleAllTextures(); void RecheckHiresForAllTextures(); bool CleanUp(); #ifdef DEBUGGER TxtrCacheEntry * GetCachedTexture(uint32 tex); uint32 GetNumOfCachedTexture(); #endif }; extern CTextureManager gTextureManager; // The global instance of CTextureManager class extern void DumpCachedTexture(TxtrCacheEntry &entry); #endif mupen64plus-video-rice-src-2.0/src/Timing.h0000644000000000000000000001114312165031100016670 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _RSP_RDP_TIMING_H_ #define _RSP_RDP_TIMING_H_ enum { Timing_SP_Minimal = 10, Timing_SP_Minimal2 = 20, Timing_SP_Minimal4 = 40, Timing_SP_Minimal8 = 80, Timing_SP_Each_Triangle = 80, Timing_SP_Each_2_Triangle2 = 160, Timing_RSP_GBI1_SpNoop = Timing_SP_Minimal, Timing_RSP_GBI0_Mtx = Timing_SP_Minimal8, Timing_RSP_GBI1_Reserved = Timing_SP_Minimal2, Timing_RSP_GBI1_MoveMem = Timing_SP_Minimal2, // Fix me Timing_RSP_GBI1_Vtx = Timing_SP_Minimal4, // for each vertex Timing_RSP_GBI0_Vtx = Timing_SP_Minimal4, // for each vertex Timing_RSP_GBI0_DL = Timing_SP_Minimal*2, Timing_RSP_GBI1_Sprite2DBase = Timing_SP_Minimal8, Timing_RSP_GBI1_LoadUCode = 800, Timing_RSP_GBI1_BranchZ = Timing_SP_Minimal2, Timing_RSP_GBI1_Tri2 = Timing_SP_Each_2_Triangle2, Timing_RSP_GBI1_ModifyVtx = Timing_SP_Minimal4, Timing_RSP_GBI1_RDPHalf_2 = Timing_SP_Minimal, Timing_RSP_GBI1_RDPHalf_1 = Timing_SP_Minimal, Timing_RSP_GBI1_RDPHalf_Cont = Timing_SP_Minimal, Timing_RSP_GBI1_Line3D = Timing_SP_Each_Triangle, Timing_RSP_GBI1_ClearGeometryMode = Timing_SP_Minimal, Timing_RSP_GBI1_SetGeometryMode = Timing_SP_Minimal, Timing_RSP_GBI2_GeometryMode = Timing_SP_Minimal, Timing_RSP_GBI1_EndDL = Timing_SP_Minimal, Timing_RSP_GBI1_SetOtherModeL = Timing_SP_Minimal, Timing_RSP_GBI1_SetOtherModeH = Timing_SP_Minimal, Timing_RSP_GBI1_Texture = Timing_SP_Minimal2, Timing_RSP_GBI1_MoveWord = Timing_SP_Minimal2, Timing_RSP_GBI2_SubModule = Timing_SP_Minimal2, Timing_RSP_GBI1_PopMtx = Timing_SP_Minimal8, Timing_RSP_GBI1_CullDL = Timing_SP_Minimal2, Timing_RSP_GBI1_Tri1 = Timing_SP_Each_Triangle, Timing_RSP_GBI1_Noop = Timing_SP_Minimal, Timing_RSP_S2DEX_SPObjLoadTxtr_Ucode1 = Timing_SP_Minimal8, Timing_DP_Minimal = 10, Timing_DP_Minimal2 = 20, Timing_DP_Minimal4 = 40, Timing_DP_Minimal8 = 80, Timing_DP_Minimal16 = 160, Timing_DP_Each_Point = 1, Timing_RDP_TriFill = Timing_DP_Minimal8, Timing_RDP_TriFillZ = Timing_DP_Minimal8, Timing_RDP_TriTxtr = Timing_DP_Minimal8, Timing_RDP_TriTxtrZ = Timing_DP_Minimal8, Timing_RDP_TriShade = Timing_DP_Minimal8, Timing_RDP_TriShadeZ = Timing_DP_Minimal8, Timing_RDP_TriShadeTxtr = Timing_DP_Minimal8, Timing_RDP_TriShadeTxtrZ = Timing_DP_Minimal8, Timing_DLParser_TexRect = Timing_DP_Minimal8, Timing_DLParser_TexRectFlip = Timing_DP_Minimal8, Timing_DLParser_RDPLoadSync = Timing_DP_Minimal, Timing_DLParser_RDPPipeSync = Timing_DP_Minimal, Timing_DLParser_RDPTileSync = Timing_DP_Minimal, Timing_DLParser_RDPFullSync = Timing_DP_Minimal8, Timing_DLParser_SetKeyGB = Timing_DP_Minimal, Timing_DLParser_SetKeyR = Timing_DP_Minimal, Timing_DLParser_SetConvert = Timing_DP_Minimal2, Timing_DLParser_SetScissor = Timing_DP_Minimal2, Timing_DLParser_SetPrimDepth = Timing_DP_Minimal2, Timing_DLParser_RDPSetOtherMode = Timing_DP_Minimal, Timing_DLParser_LoadTLut = Timing_DP_Minimal16, Timing_RSP_RDP_Nothing = Timing_DP_Minimal, Timing_DLParser_SetTileSize = Timing_DP_Minimal4, Timing_DLParser_LoadBlock = Timing_DP_Minimal16, Timing_DLParser_LoadTile = Timing_DP_Minimal16, Timing_DLParser_SetTile = Timing_DP_Minimal8, Timing_DLParser_FillRect = Timing_DP_Minimal16, Timing_DLParser_SetFillColor = Timing_DP_Minimal, Timing_DLParser_SetFogColor = Timing_DP_Minimal, Timing_DLParser_SetBlendColor = Timing_DP_Minimal, Timing_DLParser_SetPrimColor = Timing_DP_Minimal, Timing_DLParser_SetEnvColor = Timing_DP_Minimal, Timing_DLParser_SetCombine = Timing_DP_Minimal, Timing_DLParser_SetTImg = Timing_DP_Minimal, Timing_DLParser_SetZImg = Timing_DP_Minimal, Timing_DLParser_SetCImg = Timing_DP_Minimal, }; #define DP_Timing(t) {status.DPCycleCount+=Timing_##t;} #define SP_Timing(t) {status.SPCycleCount+=Timing_##t;} #endif mupen64plus-video-rice-src-2.0/src/UcodeDefs.h0000644000000000000000000001665712165031100017321 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _UCODE_DEFS_H_ #define _UCODE_DEFS_H_ typedef struct { union { unsigned int w0; struct { unsigned int arg0:24; unsigned int cmd:8; }; }; unsigned int w1; } Gwords; typedef struct { unsigned int w0; unsigned int v2:8; unsigned int v1:8; unsigned int v0:8; unsigned int flag:8; } GGBI0_Tri1; typedef struct { unsigned int v0:8; unsigned int v1:8; unsigned int v2:8; unsigned int cmd:8; unsigned int pad:24; unsigned int flag:8; } GGBI2_Tri1; typedef struct { unsigned int :1; unsigned int v3:7; unsigned int :1; unsigned int v4:7; unsigned int :1; unsigned int v5:7; unsigned int cmd:8; unsigned int :1; unsigned int v0:7; unsigned int :1; unsigned int v1:7; unsigned int :1; unsigned int v2:7; unsigned int flag:8; } GGBI2_Tri2; typedef struct { unsigned int w0; unsigned int v2:8; unsigned int v1:8; unsigned int v0:8; unsigned int v3:8; } GGBI0_Ln3DTri2; typedef struct { unsigned int v5:8; unsigned int v4:8; unsigned int v3:8; unsigned int cmd:8; unsigned int v2:8; unsigned int v1:8; unsigned int v0:8; unsigned int flag:8; } GGBI1_Tri2; typedef struct { unsigned int v3:8; unsigned int v4:8; unsigned int v5:8; unsigned int cmd:8; unsigned int v0:8; unsigned int v1:8; unsigned int v2:8; unsigned int flag:8; } GGBI2_Line3D; typedef struct { unsigned int len:16; unsigned int v0:4; unsigned int n:4; unsigned int cmd:8; unsigned int addr; } GGBI0_Vtx; typedef struct { unsigned int len:10; unsigned int n:6; unsigned int :1; unsigned int v0:7; unsigned int cmd:8; unsigned int addr; } GGBI1_Vtx; typedef struct { unsigned int vend:8; unsigned int :4; unsigned int n:8; unsigned int :4; unsigned int cmd:8; unsigned int addr; } GGBI2_Vtx; typedef struct { unsigned int width:12; unsigned int :7; unsigned int siz:2; unsigned int fmt:3; unsigned int cmd:8; unsigned int addr; } GSetImg; typedef struct { unsigned int prim_level:8; unsigned int prim_min_level:8; unsigned int pad:8; unsigned int cmd:8; union { unsigned int color; struct { unsigned int fillcolor:16; unsigned int fillcolor2:16; }; struct { unsigned int a:8; unsigned int b:8; unsigned int g:8; unsigned int r:8; }; }; } GSetColor; typedef struct { unsigned int :16; unsigned int param:8; unsigned int cmd:8; unsigned int addr; } GGBI0_Dlist; typedef struct { unsigned int len:16; unsigned int projection:1; unsigned int load:1; unsigned int push:1; unsigned int :5; unsigned int cmd:8; unsigned int addr; } GGBI0_Matrix; typedef struct { unsigned int :24; unsigned int cmd:8; unsigned int projection:1; unsigned int :31; } GGBI0_PopMatrix; typedef struct { union { struct { unsigned int param:8; unsigned int len:16; unsigned int cmd:8; }; struct { unsigned int nopush:1; unsigned int load:1; unsigned int projection:1; unsigned int :5; unsigned int len2:16; unsigned int cmd2:8; }; }; unsigned int addr; } GGBI2_Matrix; typedef struct { unsigned int type:8; unsigned int offset:16; unsigned int cmd:8; unsigned int value; } GGBI0_MoveWord; typedef struct { unsigned int offset:16; unsigned int type:8; unsigned int cmd:8; unsigned int value; } GGBI2_MoveWord; typedef struct { unsigned int enable_gbi0:1; unsigned int enable_gbi2:1; unsigned int :6; unsigned int tile:3; unsigned int level:3; unsigned int :10; unsigned int cmd:8; unsigned int scaleT:16; unsigned int scaleS:16; } GTexture; typedef struct { unsigned int tl:12; unsigned int sl:12; unsigned int cmd:8; unsigned int th:12; unsigned int sh:12; unsigned int tile:3; unsigned int pad:5; } Gloadtile; typedef struct { unsigned int tmem:9; unsigned int line:9; unsigned int pad0:1; unsigned int siz:2; unsigned int fmt:3; unsigned int cmd:8; unsigned int shifts:4; unsigned int masks:4; unsigned int ms:1; unsigned int cs:1; unsigned int shiftt:4; unsigned int maskt:4; unsigned int mt:1; unsigned int ct:1; unsigned int palette:4; unsigned int tile:3; unsigned int pad1:5; } Gsettile; typedef union { Gwords words; GGBI0_Tri1 tri1; GGBI0_Ln3DTri2 ln3dtri2; GGBI1_Tri2 gbi1tri2; GGBI2_Tri1 gbi2tri1; GGBI2_Tri2 gbi2tri2; GGBI2_Line3D gbi2line3d; GGBI0_Vtx gbi0vtx; GGBI1_Vtx gbi1vtx; GGBI2_Vtx gbi2vtx; GSetImg setimg; GSetColor setcolor; GGBI0_Dlist gbi0dlist; GGBI0_Matrix gbi0matrix; GGBI0_PopMatrix gbi0popmatrix; GGBI2_Matrix gbi2matrix; GGBI0_MoveWord gbi0moveword; GGBI2_MoveWord gbi2moveword; GTexture texture; Gloadtile loadtile; Gsettile settile; /* Gdma dma; Gsegment segment; GsetothermodeH setothermodeH; GsetothermodeL setothermodeL; Gtexture texture; Gperspnorm perspnorm; Gsetcombine setcombine; Gfillrect fillrect; Gsettile settile; Gloadtile loadtile; Gsettilesize settilesize; Gloadtlut loadtlut; */ long long int force_structure_alignment; } Gfx; typedef union { struct { unsigned int w0; unsigned int w1; unsigned int w2; unsigned int w3; }; struct { unsigned int yl:12; /* Y coordinate of upper left */ unsigned int xl:12; /* X coordinate of upper left */ unsigned int cmd:8; /* command */ unsigned int yh:12; /* Y coordinate of lower right */ unsigned int xh:12; /* X coordinate of lower right */ unsigned int tile:3; /* Tile descriptor index */ unsigned int pad1:5; /* Padding */ unsigned int t:16; /* T texture coord at top left */ unsigned int s:16; /* S texture coord at top left */ unsigned int dtdy:16;/* Change in T per change in Y */ unsigned int dsdx:16;/* Change in S per change in X */ }; } Gtexrect; #endif mupen64plus-video-rice-src-2.0/src/VectorMath.cpp0000644000000000000000000001710412165031100020053 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - VectorMath.cpp * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2002 Rice1964 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "VectorMath.h" //---------- XMATRIX XMATRIX::XMATRIX() { } XMATRIX::XMATRIX( const float *pIn ) { memcpy(m, pIn, 16*4); } XMATRIX::XMATRIX( const MATRIX &pIn ) { memcpy(m, pIn.m, 16*4); } XMATRIX::XMATRIX( float _11, float _12, float _13, float _14, float _21, float _22, float _23, float _24, float _31, float _32, float _33, float _34, float _41, float _42, float _43, float _44 ) { this->_11 = _11; this->_12 = _12; this->_13 = _13; this->_14 = _14; this->_21 = _21; this->_22 = _22; this->_23 = _23; this->_24 = _24; this->_31 = _31; this->_32 = _32; this->_33 = _33; this->_34 = _34; this->_41 = _41; this->_42 = _42; this->_43 = _43; this->_44 = _44; } float& XMATRIX::operator () ( unsigned int Row, unsigned int Col ) { return m[Row][Col]; } float XMATRIX::operator () ( unsigned int Row, unsigned int Col ) const { return m[Row][Col]; } XMATRIX::operator float* () { return (float*)m; } XMATRIX::operator const float* () const { return (float*)m; } XMATRIX& XMATRIX::operator *= ( const XMATRIX &pIn ) { XMATRIX mTemp(*this); *this = mTemp*pIn; return *this; } XMATRIX& XMATRIX::operator += ( const XMATRIX &pIn ) { XMATRIX mTemp(*this); *this = mTemp+pIn; return *this; } XMATRIX& XMATRIX::operator -= ( const XMATRIX &pIn ) { XMATRIX mTemp(*this); *this = mTemp-pIn; return *this; } XMATRIX& XMATRIX::operator *= ( float f) { for (int i=0; i<16; i++) { ((float*)m)[i] *= f; } return *this; } XMATRIX& XMATRIX::operator /= ( float f) { for (int i=0; i<16; i++) { ((float*)m)[i] /= f; } return *this; } XMATRIX XMATRIX::operator + () const { return *this; } XMATRIX XMATRIX::operator - () const { XMATRIX mTemp; for (int i=0; i<16; i++) { ((float*)mTemp.m)[i] = -((float*)m)[i]; } return mTemp; } XMATRIX XMATRIX::operator * ( const XMATRIX &pIn ) const { XMATRIX mTemp; for (int i=0; i<4; i++) { for (int j=0; j<4; j++) { mTemp.m[i][j] = m[i][0]*pIn.m[0][j] + m[i][1]*pIn.m[1][j] + m[i][2]*pIn.m[2][j] + m[i][3]*pIn.m[3][j]; } } return mTemp; } XMATRIX XMATRIX::operator + ( const XMATRIX &pIn ) const { XMATRIX mTemp; for (int i=0; i<16; i++) { ((float*)mTemp.m)[i] = ((float*)m)[i] + ((float*)pIn.m)[i]; } return mTemp; } XMATRIX XMATRIX::operator - ( const XMATRIX &pIn ) const { XMATRIX mTemp; for (int i=0; i<16; i++) { ((float*)mTemp.m)[i] = ((float*)m)[i] - ((float*)pIn.m)[i]; } return mTemp; } /* XMATRIX operator * ( float ) const; XMATRIX operator / ( float ) const; friend XMATRIX operator * ( float, const XMATRIX & ); bool operator == ( const XMATRIX & ) const; bool operator != ( const XMATRIX & ) const; */ //---------- VECTOR3 XVECTOR3::XVECTOR3() { } XVECTOR3::XVECTOR3( const float *f ) { x = f[0]; y = f[1]; z = f[2]; } XVECTOR3::XVECTOR3( const VECTOR3 &v ) { x = v.x; y = v.y; z = v.z; } XVECTOR3::XVECTOR3( float _x, float _y, float _z ) { x = _x; y = _y; z = _z; } /* // casting inline operator float* (); inline operator const float* () const; // assignment operators inline XVECTOR3& operator += ( const XVECTOR3 &op ); inline XVECTOR3& operator -= ( const XVECTOR3 &op ); inline XVECTOR3& operator *= ( float op ); inline XVECTOR3& operator /= ( float op ); // unary operators inline XVECTOR3 operator + () const; inline XVECTOR3 operator - () const; // binary operators inline XVECTOR3 operator + ( const XVECTOR3 &op ) const; inline XVECTOR3 operator - ( const XVECTOR3 &op ) const; inline XVECTOR3 operator * ( float op ) const; inline XVECTOR3 operator / ( float op ) const; friend XVECTOR3 operator * ( float, const XVECTOR3& ); inline bool operator == ( const XVECTOR3 &op ) const; inline bool operator != ( const XVECTOR3 &op ) const; */ //---------- XVECTOR4 XVECTOR4::XVECTOR4() { } /* XVECTOR4( const float *f ); XVECTOR4( const VECTOR4 &v ); XVECTOR4( float _x, float _y, float _z, float _w ); // casting inline operator float* (); inline operator const float* () const; // assignment operators inline XVECTOR4& operator += ( const XVECTOR4 &op ); inline XVECTOR4& operator -= ( const XVECTOR4 &op ); inline XVECTOR4& operator *= ( float op ); inline XVECTOR4& operator /= ( float op ); // unary operators inline XVECTOR4 operator + () const; inline XVECTOR4 operator - () const; // binary operators inline XVECTOR4 operator + ( const XVECTOR4 &op ) const; inline XVECTOR4 operator - ( const XVECTOR4 &op ) const; inline XVECTOR4 operator * ( float op ) const; inline XVECTOR4 operator / ( float op ) const; friend XVECTOR4 operator * ( float, const XVECTOR4& ); inline bool operator == ( const XVECTOR4 &op ) const; inline bool operator != ( const XVECTOR4 &op ) const; */ //---------- OTHER XMATRIX* MatrixTranspose( XMATRIX* pOut, const XMATRIX* pM ) { pOut->_11 = pM->_11; pOut->_12 = pM->_21; pOut->_13 = pM->_31; pOut->_14 = pM->_41; pOut->_21 = pM->_12; pOut->_22 = pM->_22; pOut->_23 = pM->_32; pOut->_24 = pM->_42; pOut->_31 = pM->_13; pOut->_32 = pM->_23; pOut->_33 = pM->_33; pOut->_34 = pM->_43; pOut->_41 = pM->_14; pOut->_42 = pM->_24; pOut->_43 = pM->_34; pOut->_44 = pM->_44; return pOut; } XVECTOR4 Vec3Transform( XVECTOR4 *pOut, const XVECTOR3 *pV, const XMATRIX *pM ) { pOut->x = pV->x*pM->_11 + pV->y*pM->_21 + pV->z*pM->_31 + pM->_41; pOut->y = pV->x*pM->_12 + pV->y*pM->_22 + pV->z*pM->_32 + pM->_42; pOut->z = pV->x*pM->_13 + pV->y*pM->_23 + pV->z*pM->_33 + pM->_43; pOut->w = pV->x*pM->_14 + pV->y*pM->_24 + pV->z*pM->_34 + pM->_44; return *pOut; } mupen64plus-video-rice-src-2.0/src/VectorMath.h0000644000000000000000000001373112165031100017522 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - VectorMath.h * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2002 Rice1964 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef VECTORMATH_H #define VECTORMATH_H /****************************************************************************** * 4x4 matrix ******************************************************************************/ typedef struct _MATRIX { union { struct { float _11, _12, _13, _14; float _21, _22, _23, _24; float _31, _32, _33, _34; float _41, _42, _43, _44; }; float m[4][4]; }; } MATRIX; typedef struct XMATRIX : public MATRIX { public: XMATRIX(); XMATRIX( const float * ); XMATRIX( const MATRIX & ); XMATRIX( float _11, float _12, float _13, float _14, float _21, float _22, float _23, float _24, float _31, float _32, float _33, float _34, float _41, float _42, float _43, float _44 ); float& operator () ( unsigned int Row, unsigned int Col ); float operator () ( unsigned int Row, unsigned int Col ) const; operator float* (); operator const float* () const; // assignment operators XMATRIX& operator *= ( const XMATRIX & ); XMATRIX& operator += ( const XMATRIX & ); XMATRIX& operator -= ( const XMATRIX & ); XMATRIX& operator *= ( float ); XMATRIX& operator /= ( float ); // unary operators XMATRIX operator + () const; XMATRIX operator - () const; // binary operators XMATRIX operator * ( const XMATRIX & ) const; XMATRIX operator + ( const XMATRIX & ) const; XMATRIX operator - ( const XMATRIX & ) const; XMATRIX operator * ( float ) const; XMATRIX operator / ( float ) const; friend XMATRIX operator * ( float, const XMATRIX & ); bool operator == ( const XMATRIX & ) const; bool operator != ( const XMATRIX & ) const; } XMATRIX, *LPXMATRIX; /****************************************************************************** * 3d vector ******************************************************************************/ typedef struct _VECTOR3 { float x; float y; float z; } VECTOR3; class XVECTOR3 : public VECTOR3 { public: XVECTOR3(); XVECTOR3( const float *f ); XVECTOR3( const VECTOR3 &v ); XVECTOR3( float _x, float _y, float _z ); // casting inline operator float* (); inline operator const float* () const; // assignment operators inline XVECTOR3& operator += ( const XVECTOR3 &op ); inline XVECTOR3& operator -= ( const XVECTOR3 &op ); inline XVECTOR3& operator *= ( float op ); inline XVECTOR3& operator /= ( float op ); // unary operators inline XVECTOR3 operator + () const; inline XVECTOR3 operator - () const; // binary operators inline XVECTOR3 operator + ( const XVECTOR3 &op ) const; inline XVECTOR3 operator - ( const XVECTOR3 &op ) const; inline XVECTOR3 operator * ( float op ) const; inline XVECTOR3 operator / ( float op ) const; friend XVECTOR3 operator * ( float, const XVECTOR3& ); inline bool operator == ( const XVECTOR3 &op ) const; inline bool operator != ( const XVECTOR3 &op ) const; }; /****************************************************************************** * 4d vector ******************************************************************************/ typedef struct _VECTOR4 { float x; float y; float z; float w; } VECTOR4; class XVECTOR4 : public VECTOR4 { public: XVECTOR4(); XVECTOR4( const float *f ); XVECTOR4( const VECTOR4 &v ); XVECTOR4( float _x, float _y, float _z, float _w ); // casting inline operator float* (); inline operator const float* () const; // assignment operators inline XVECTOR4& operator += ( const XVECTOR4 &op ); inline XVECTOR4& operator -= ( const XVECTOR4 &op ); inline XVECTOR4& operator *= ( float op ); inline XVECTOR4& operator /= ( float op ); // unary operators inline XVECTOR4 operator + () const; inline XVECTOR4 operator - () const; // binary operators inline XVECTOR4 operator + ( const XVECTOR4 &op ) const; inline XVECTOR4 operator - ( const XVECTOR4 &op ) const; inline XVECTOR4 operator * ( float op ) const; inline XVECTOR4 operator / ( float op ) const; friend XVECTOR4 operator * ( float, const XVECTOR4& ); inline bool operator == ( const XVECTOR4 &op ) const; inline bool operator != ( const XVECTOR4 &op ) const; }; XVECTOR4 Vec3Transform(XVECTOR4 *pOut, const XVECTOR3 *pV, const XMATRIX *pM); XMATRIX* MatrixTranspose(XMATRIX* pOut, const XMATRIX* pM); #endif mupen64plus-video-rice-src-2.0/src/VertexShaderConstantDef.h0000644000000000000000000000602012165031100022174 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - VertexShaderConstantDef.h * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2003 Rice1964 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define iPos v0 #define iNormal v1 #define iColor v2 #define iT0 v3 #define R_NORMAL r1 #define R_DIFFUSE r2 #define R_TEMP1 r3 #define R_TEMP2 r4 #define R_TEMP3 r5 #define R_SPECULAR r6 #define R_POS r7 #define CV_ZERO 0 #define CV_ONE 1 #define CV_HALF 2 #define CV_TENTH 3 #define CV_NINE_TENTH 4 #define CV_200 5 #define CV_WORLDVIEWPROJ_0 10 #define CV_WORLDVIEWPROJ_1 11 #define CV_WORLDVIEWPROJ_2 12 #define CV_WORLDVIEWPROJ_3 13 #define CV_WORLDVIEW_0 14 #define CV_WORLDVIEW_1 15 #define CV_WORLDVIEW_2 16 #define CV_WORLDVIEW_3 17 #define CV_LIGHT1_DIRECTION 30 #define CV_LIGHT2_DIRECTION 31 #define CV_LIGHT3_DIRECTION 32 #define CV_LIGHT4_DIRECTION 33 #define CV_LIGHT5_DIRECTION 34 #define CV_LIGHT6_DIRECTION 35 #define CV_LIGHT7_DIRECTION 36 #define CV_LIGHT0_AMBIENT 20 #define CV_LIGHT1_DIFFUSE 21 #define CV_LIGHT2_DIFFUSE 22 #define CV_LIGHT3_DIFFUSE 23 #define CV_LIGHT4_DIFFUSE 24 #define CV_LIGHT5_DIFFUSE 25 #define CV_LIGHT6_DIFFUSE 26 #define CV_LIGHT7_DIFFUSE 27 #define USE_PRIMARY_DEPTH 40 #define PRIMARY_DEPTH 41 #define FOG_IS_ENABLED 42 #define USE_PRIMARY_COLOR 43 #define PRIMARY_COLOR 44 #define LIGHTING_ENABLED 45 #define FORCE_VTX_ALPHA 46 #define VTX_ALPHA 47 #define Z_HACK_ENABLE 49 #define T0_SCALE_X_Y 50 #define T1_SCALE_X_Y 51 #define T0_OFFSET_X_Y 52 #define T1_OFFSET_X_Y 53 #define FOG_MUL 60 #define FOG_ADD 61 mupen64plus-video-rice-src-2.0/src/Video.cpp0000644000000000000000000010607012165031100017046 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 Copyright (C) 2009-2011 Richard Goedeken This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "osal_opengl.h" #define M64P_PLUGIN_PROTOTYPES 1 #include "m64p_types.h" #include "m64p_common.h" #include "m64p_plugin.h" #include "osal_dynamiclib.h" #include "Config.h" #include "Debugger.h" #include "DeviceBuilder.h" #include "FrameBuffer.h" #include "GraphicsContext.h" #include "Render.h" #include "RSP_Parser.h" #include "TextureFilters.h" #include "TextureManager.h" #include "Video.h" #include "version.h" //======================================================= // local variables static void (*l_DebugCallback)(void *, int, const char *) = NULL; static void *l_DebugCallContext = NULL; static int l_PluginInit = 0; //======================================================= // global variables PluginStatus status; GFX_INFO g_GraphicsInfo; CCritSect g_CritialSection; unsigned int g_dwRamSize = 0x400000; unsigned int *g_pRDRAMu32 = NULL; signed char *g_pRDRAMs8 = NULL; unsigned char *g_pRDRAMu8 = NULL; RECT frameWriteByCPURect; std::vector frameWriteByCPURects; RECT frameWriteByCPURectArray[20][20]; bool frameWriteByCPURectFlag[20][20]; std::vector frameWriteRecord; void (*renderCallback)(int) = NULL; /* definitions of pointers to Core config functions */ ptr_ConfigOpenSection ConfigOpenSection = NULL; ptr_ConfigSetParameter ConfigSetParameter = NULL; ptr_ConfigGetParameter ConfigGetParameter = NULL; ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL; ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL; ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat = NULL; ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL; ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL; ptr_ConfigGetParamInt ConfigGetParamInt = NULL; ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL; ptr_ConfigGetParamBool ConfigGetParamBool = NULL; ptr_ConfigGetParamString ConfigGetParamString = NULL; ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL; ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath = NULL; ptr_ConfigGetUserDataPath ConfigGetUserDataPath = NULL; ptr_ConfigGetUserCachePath ConfigGetUserCachePath = NULL; /* definitions of pointers to Core video extension functions */ ptr_VidExt_Init CoreVideo_Init = NULL; ptr_VidExt_Quit CoreVideo_Quit = NULL; ptr_VidExt_ListFullscreenModes CoreVideo_ListFullscreenModes = NULL; ptr_VidExt_SetVideoMode CoreVideo_SetVideoMode = NULL; ptr_VidExt_SetCaption CoreVideo_SetCaption = NULL; ptr_VidExt_ToggleFullScreen CoreVideo_ToggleFullScreen = NULL; ptr_VidExt_ResizeWindow CoreVideo_ResizeWindow = NULL; ptr_VidExt_GL_GetProcAddress CoreVideo_GL_GetProcAddress = NULL; ptr_VidExt_GL_SetAttribute CoreVideo_GL_SetAttribute = NULL; ptr_VidExt_GL_GetAttribute CoreVideo_GL_GetAttribute = NULL; ptr_VidExt_GL_SwapBuffers CoreVideo_GL_SwapBuffers = NULL; //--------------------------------------------------------------------------------------- // Forward function declarations extern "C" EXPORT void CALL RomClosed(void); //--------------------------------------------------------------------------------------- // Static (local) functions static void ChangeWindowStep2() { status.bDisableFPS = true; windowSetting.bDisplayFullscreen = !windowSetting.bDisplayFullscreen; g_CritialSection.Lock(); windowSetting.bDisplayFullscreen = CGraphicsContext::Get()->ToggleFullscreen(); CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); CGraphicsContext::Get()->UpdateFrame(); CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); CGraphicsContext::Get()->UpdateFrame(); CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); CGraphicsContext::Get()->UpdateFrame(); g_CritialSection.Unlock(); status.bDisableFPS = false; status.ToToggleFullScreen = FALSE; } static void ResizeStep2(void) { g_CritialSection.Lock(); // Delete all OpenGL textures gTextureManager.CleanUp(); RDP_Cleanup(); // delete our opengl renderer CDeviceBuilder::GetBuilder()->DeleteRender(); // call video extension function with updated width, height (this creates a new OpenGL context) windowSetting.uDisplayWidth = status.gNewResizeWidth; windowSetting.uDisplayHeight = status.gNewResizeHeight; CoreVideo_ResizeWindow(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); // re-initialize our OpenGL graphics context state bool res = CGraphicsContext::Get()->ResizeInitialize(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, !windowSetting.bDisplayFullscreen); if (res) { // re-create the OpenGL renderer CDeviceBuilder::GetBuilder()->CreateRender(); CRender::GetRender()->Initialize(); DLParser_Init(); } g_CritialSection.Unlock(); status.ToResize = false; } static void UpdateScreenStep2 (void) { status.bVIOriginIsUpdated = false; if( status.ToToggleFullScreen && status.gDlistCount > 0 ) { ChangeWindowStep2(); return; } if (status.ToResize && status.gDlistCount > 0) { ResizeStep2(); return; } g_CritialSection.Lock(); if( status.bHandleN64RenderTexture ) g_pFrameBufferManager->CloseRenderTexture(true); g_pFrameBufferManager->SetAddrBeDisplayed(*g_GraphicsInfo.VI_ORIGIN_REG); if( status.gDlistCount == 0 ) { // CPU frame buffer update uint32 width = *g_GraphicsInfo.VI_WIDTH_REG; if( (*g_GraphicsInfo.VI_ORIGIN_REG & (g_dwRamSize-1) ) > width*2 && *g_GraphicsInfo.VI_H_START_REG != 0 && width != 0 ) { SetVIScales(); CRender::GetRender()->DrawFrameBuffer(true); CGraphicsContext::Get()->UpdateFrame(); } g_CritialSection.Unlock(); return; } TXTRBUF_DETAIL_DUMP(TRACE1("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG)); if( currentRomOptions.screenUpdateSetting == SCREEN_UPDATE_AT_VI_UPDATE ) { CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); g_CritialSection.Unlock(); return; } TXTRBUF_DETAIL_DUMP(TRACE1("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG)); if( currentRomOptions.screenUpdateSetting == SCREEN_UPDATE_AT_VI_UPDATE_AND_DRAWN ) { if( status.bScreenIsDrawn ) { CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); } else { DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Skip Screen Update: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); } DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); g_CritialSection.Unlock(); return; } if( currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_VI_CHANGE ) { if( *g_GraphicsInfo.VI_ORIGIN_REG != status.curVIOriginReg ) { if( *g_GraphicsInfo.VI_ORIGIN_REG < status.curDisplayBuffer || *g_GraphicsInfo.VI_ORIGIN_REG > status.curDisplayBuffer+0x2000 ) { status.curDisplayBuffer = *g_GraphicsInfo.VI_ORIGIN_REG; status.curVIOriginReg = status.curDisplayBuffer; //status.curRenderBuffer = NULL; CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); } else { status.curDisplayBuffer = *g_GraphicsInfo.VI_ORIGIN_REG; status.curVIOriginReg = status.curDisplayBuffer; DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("Skip Screen Update, closed to the display buffer, VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG);}); } } else { DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("Skip Screen Update, the same VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG);}); } g_CritialSection.Unlock(); return; } if( currentRomOptions.screenUpdateSetting >= SCREEN_UPDATE_AT_1ST_CI_CHANGE ) { status.bVIOriginIsUpdated=true; DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG);}); g_CritialSection.Unlock(); return; } DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("VI is updated, No screen update: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); g_CritialSection.Unlock(); } static void ProcessDListStep2(void) { g_CritialSection.Lock(); if( status.toShowCFB ) { CRender::GetRender()->DrawFrameBuffer(true); status.toShowCFB = false; } try { DLParser_Process((OSTask *)(g_GraphicsInfo.DMEM + 0x0FC0)); } catch (...) { TRACE0("Unknown Error in ProcessDList"); TriggerDPInterrupt(); TriggerSPInterrupt(); } g_CritialSection.Unlock(); } static bool StartVideo(void) { windowSetting.dps = windowSetting.fps = -1; windowSetting.lastSecDlistCount = windowSetting.lastSecFrameCount = 0xFFFFFFFF; g_CritialSection.Lock(); memcpy(&g_curRomInfo.romheader, g_GraphicsInfo.HEADER, sizeof(ROMHeader)); unsigned char *puc = (unsigned char *) &g_curRomInfo.romheader; unsigned int i; unsigned char temp; for (i = 0; i < sizeof(ROMHeader); i += 4) /* byte-swap the ROM header */ { temp = puc[i]; puc[i] = puc[i+3]; puc[i+3] = temp; temp = puc[i+1]; puc[i+1] = puc[i+2]; puc[i+2] = temp; } ROM_GetRomNameFromHeader(g_curRomInfo.szGameName, &g_curRomInfo.romheader); Ini_GetRomOptions(&g_curRomInfo); char *p = (char *) g_curRomInfo.szGameName + (strlen((char *) g_curRomInfo.szGameName) -1); // -1 to skip null while (p >= (char *) g_curRomInfo.szGameName) { if( *p == ':' || *p == '\\' || *p == '/' ) *p = '-'; p--; } GenerateCurrentRomOptions(); status.dwTvSystem = CountryCodeToTVSystem(g_curRomInfo.romheader.nCountryID); if( status.dwTvSystem == TV_SYSTEM_NTSC ) status.fRatio = 0.75f; else status.fRatio = 9/11.0f;; InitExternalTextures(); try { CDeviceBuilder::GetBuilder()->CreateGraphicsContext(); CGraphicsContext::InitWindowInfo(); bool res = CGraphicsContext::Get()->Initialize(640, 480, !windowSetting.bDisplayFullscreen); if (!res) { g_CritialSection.Unlock(); return false; } CDeviceBuilder::GetBuilder()->CreateRender(); CRender::GetRender()->Initialize(); DLParser_Init(); status.bGameIsRunning = true; } catch(...) { DebugMessage(M64MSG_ERROR, "Exception caught while starting video renderer"); throw 0; } g_CritialSection.Unlock(); return true; } static void StopVideo() { g_CritialSection.Lock(); status.bGameIsRunning = false; try { CloseExternalTextures(); // Kill all textures? gTextureManager.RecycleAllTextures(); gTextureManager.CleanUp(); RDP_Cleanup(); CDeviceBuilder::GetBuilder()->DeleteRender(); CGraphicsContext::Get()->CleanUp(); CDeviceBuilder::GetBuilder()->DeleteGraphicsContext(); } catch(...) { TRACE0("Some exceptions during RomClosed"); } g_CritialSection.Unlock(); windowSetting.dps = windowSetting.fps = -1; windowSetting.lastSecDlistCount = windowSetting.lastSecFrameCount = 0xFFFFFFFF; status.gDlistCount = status.gFrameCount = 0; } //--------------------------------------------------------------------------------------- // Global functions, for use by other source files in this plugin void SetVIScales() { if( g_curRomInfo.VIHeight>0 && g_curRomInfo.VIWidth>0 ) { windowSetting.fViWidth = windowSetting.uViWidth = g_curRomInfo.VIWidth; windowSetting.fViHeight = windowSetting.uViHeight = g_curRomInfo.VIHeight; } else if( g_curRomInfo.UseCIWidthAndRatio && g_CI.dwWidth ) { windowSetting.fViWidth = windowSetting.uViWidth = g_CI.dwWidth; windowSetting.fViHeight = windowSetting.uViHeight = g_curRomInfo.UseCIWidthAndRatio == USE_CI_WIDTH_AND_RATIO_FOR_NTSC ? g_CI.dwWidth/4*3 : g_CI.dwWidth/11*9; } else { float xscale, yscale; uint32 val = *g_GraphicsInfo.VI_X_SCALE_REG & 0xFFF; xscale = (float)val / (1<<10); uint32 start = *g_GraphicsInfo.VI_H_START_REG >> 16; uint32 end = *g_GraphicsInfo.VI_H_START_REG&0xFFFF; uint32 width = *g_GraphicsInfo.VI_WIDTH_REG; windowSetting.fViWidth = (end-start)*xscale; if( abs((int)(windowSetting.fViWidth - width) ) < 8 ) { windowSetting.fViWidth = (float)width; } else { DebuggerAppendMsg("fViWidth = %f, Width Reg=%d", windowSetting.fViWidth, width); } val = (*g_GraphicsInfo.VI_Y_SCALE_REG & 0xFFF);// - ((*g_GraphicsInfo.VI_Y_SCALE_REG>>16) & 0xFFF); if( val == 0x3FF ) val = 0x400; yscale = (float)val / (1<<10); start = *g_GraphicsInfo.VI_V_START_REG >> 16; end = *g_GraphicsInfo.VI_V_START_REG&0xFFFF; windowSetting.fViHeight = (end-start)/2*yscale; if( yscale == 0 ) { windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio; } else { if( *g_GraphicsInfo.VI_WIDTH_REG > 0x300 ) windowSetting.fViHeight *= 2; if( windowSetting.fViWidth*status.fRatio > windowSetting.fViHeight && (*g_GraphicsInfo.VI_X_SCALE_REG & 0xFF) != 0 ) { if( abs(int(windowSetting.fViWidth*status.fRatio - windowSetting.fViHeight)) < 8 ) { windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio; } /* else { if( abs(windowSetting.fViWidth*status.fRatio-windowSetting.fViHeight) > windowSetting.fViWidth*0.1f ) { if( status.fRatio > 0.8 ) windowSetting.fViHeight = windowSetting.fViWidth*3/4; //windowSetting.fViHeight = (*g_GraphicsInfo.VI_V_SYNC_REG - 0x2C)/2; } } */ } if( windowSetting.fViHeight<100 || windowSetting.fViWidth<100 ) { //At sometime, value in VI_H_START_REG or VI_V_START_REG are 0 windowSetting.fViWidth = (float)*g_GraphicsInfo.VI_WIDTH_REG; windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio; } } windowSetting.uViWidth = (unsigned short)(windowSetting.fViWidth/4); windowSetting.fViWidth = windowSetting.uViWidth *= 4; windowSetting.uViHeight = (unsigned short)(windowSetting.fViHeight/4); windowSetting.fViHeight = windowSetting.uViHeight *= 4; uint16 optimizeHeight = (uint16)(windowSetting.uViWidth*status.fRatio); optimizeHeight &= ~3; uint16 optimizeHeight2 = (uint16)(windowSetting.uViWidth*3/4); optimizeHeight2 &= ~3; if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 ) { if( abs(windowSetting.uViHeight-optimizeHeight) <= 8 ) windowSetting.fViHeight = windowSetting.uViHeight = optimizeHeight; else if( abs(windowSetting.uViHeight-optimizeHeight2) <= 8 ) windowSetting.fViHeight = windowSetting.uViHeight = optimizeHeight2; } if( gRDP.scissor.left == 0 && gRDP.scissor.top == 0 && gRDP.scissor.right != 0 ) { if( (*g_GraphicsInfo.VI_X_SCALE_REG & 0xFF) != 0x0 && gRDP.scissor.right == windowSetting.uViWidth ) { // Mario Tennis if( abs(int( windowSetting.fViHeight - gRDP.scissor.bottom )) < 8 ) { windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom; } else if( windowSetting.fViHeight < gRDP.scissor.bottom ) { windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom; } windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom; } else if( gRDP.scissor.right == windowSetting.uViWidth - 1 && gRDP.scissor.bottom != 0 ) { if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 ) { if( status.fRatio != 0.75 && windowSetting.fViHeight > optimizeHeight/2 ) { windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom + gRDP.scissor.top + 1; } } } else if( gRDP.scissor.right == windowSetting.uViWidth && gRDP.scissor.bottom != 0 && status.fRatio != 0.75 ) { if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 ) { if( status.fRatio != 0.75 && windowSetting.fViHeight > optimizeHeight/2 ) { windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom + gRDP.scissor.top + 1; } } } } } SetScreenMult(windowSetting.uDisplayWidth/windowSetting.fViWidth, windowSetting.uDisplayHeight/windowSetting.fViHeight); } void TriggerDPInterrupt(void) { *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_DP; g_GraphicsInfo.CheckInterrupts(); } void TriggerSPInterrupt(void) { *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_SP; g_GraphicsInfo.CheckInterrupts(); } void _VIDEO_DisplayTemporaryMessage(const char *Message) { } void DebugMessage(int level, const char *message, ...) { char msgbuf[1024]; va_list args; if (l_DebugCallback == NULL) return; va_start(args, message); vsprintf(msgbuf, message, args); (*l_DebugCallback)(l_DebugCallContext, level, msgbuf); va_end(args); } //--------------------------------------------------------------------------------------- // Global functions, exported for use by the core library // since these functions are exported, they need to have C-style names #ifdef __cplusplus extern "C" { #endif /* Mupen64Plus plugin functions */ EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context, void (*DebugCallback)(void *, int, const char *)) { if (l_PluginInit) return M64ERR_ALREADY_INIT; /* first thing is to set the callback function for debug info */ l_DebugCallback = DebugCallback; l_DebugCallContext = Context; /* attach and call the CoreGetAPIVersions function, check Config and Video Extension API versions for compatibility */ ptr_CoreGetAPIVersions CoreAPIVersionFunc; CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions"); if (CoreAPIVersionFunc == NULL) { DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found."); return M64ERR_INCOMPATIBLE; } int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion; (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL); if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000)) { DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)", VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION)); return M64ERR_INCOMPATIBLE; } if ((VidextAPIVersion & 0xffff0000) != (VIDEXT_API_VERSION & 0xffff0000)) { DebugMessage(M64MSG_ERROR, "Emulator core Video Extension API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)", VERSION_PRINTF_SPLIT(VidextAPIVersion), VERSION_PRINTF_SPLIT(VIDEXT_API_VERSION)); return M64ERR_INCOMPATIBLE; } /* Get the core config function pointers from the library handle */ ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection"); ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter"); ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter"); ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt"); ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat"); ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool"); ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString"); ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt"); ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat"); ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool"); ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString"); ConfigGetSharedDataFilepath = (ptr_ConfigGetSharedDataFilepath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetSharedDataFilepath"); ConfigGetUserConfigPath = (ptr_ConfigGetUserConfigPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserConfigPath"); ConfigGetUserDataPath = (ptr_ConfigGetUserDataPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserDataPath"); ConfigGetUserCachePath = (ptr_ConfigGetUserCachePath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserCachePath"); if (!ConfigOpenSection || !ConfigSetParameter || !ConfigGetParameter || !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString || !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString || !ConfigGetSharedDataFilepath || !ConfigGetUserConfigPath || !ConfigGetUserDataPath || !ConfigGetUserCachePath) { DebugMessage(M64MSG_ERROR, "Couldn't connect to Core configuration functions"); return M64ERR_INCOMPATIBLE; } /* Get the core Video Extension function pointers from the library handle */ CoreVideo_Init = (ptr_VidExt_Init) osal_dynlib_getproc(CoreLibHandle, "VidExt_Init"); CoreVideo_Quit = (ptr_VidExt_Quit) osal_dynlib_getproc(CoreLibHandle, "VidExt_Quit"); CoreVideo_ListFullscreenModes = (ptr_VidExt_ListFullscreenModes) osal_dynlib_getproc(CoreLibHandle, "VidExt_ListFullscreenModes"); CoreVideo_SetVideoMode = (ptr_VidExt_SetVideoMode) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetVideoMode"); CoreVideo_SetCaption = (ptr_VidExt_SetCaption) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetCaption"); CoreVideo_ToggleFullScreen = (ptr_VidExt_ToggleFullScreen) osal_dynlib_getproc(CoreLibHandle, "VidExt_ToggleFullScreen"); CoreVideo_ResizeWindow = (ptr_VidExt_ResizeWindow) osal_dynlib_getproc(CoreLibHandle, "VidExt_ResizeWindow"); CoreVideo_GL_GetProcAddress = (ptr_VidExt_GL_GetProcAddress) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_GetProcAddress"); CoreVideo_GL_SetAttribute = (ptr_VidExt_GL_SetAttribute) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SetAttribute"); CoreVideo_GL_GetAttribute = (ptr_VidExt_GL_GetAttribute) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_GetAttribute"); CoreVideo_GL_SwapBuffers = (ptr_VidExt_GL_SwapBuffers) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SwapBuffers"); if (!CoreVideo_Init || !CoreVideo_Quit || !CoreVideo_ListFullscreenModes || !CoreVideo_SetVideoMode || !CoreVideo_ResizeWindow || !CoreVideo_SetCaption || !CoreVideo_ToggleFullScreen || !CoreVideo_GL_GetProcAddress || !CoreVideo_GL_SetAttribute || !CoreVideo_GL_GetAttribute || !CoreVideo_GL_SwapBuffers) { DebugMessage(M64MSG_ERROR, "Couldn't connect to Core video extension functions"); return M64ERR_INCOMPATIBLE; } /* open config section handles and set parameter default values */ if (!InitConfiguration()) return M64ERR_INTERNAL; l_PluginInit = 1; return M64ERR_SUCCESS; } EXPORT m64p_error CALL PluginShutdown(void) { if (!l_PluginInit) return M64ERR_NOT_INIT; if( status.bGameIsRunning ) { RomClosed(); } if (bIniIsChanged) { WriteIniFile(); TRACE0("Write back INI file"); } /* reset some local variables */ l_DebugCallback = NULL; l_DebugCallContext = NULL; l_PluginInit = 0; return M64ERR_SUCCESS; } EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities) { /* set version info */ if (PluginType != NULL) *PluginType = M64PLUGIN_GFX; if (PluginVersion != NULL) *PluginVersion = PLUGIN_VERSION; if (APIVersion != NULL) *APIVersion = VIDEO_PLUGIN_API_VERSION; if (PluginNamePtr != NULL) *PluginNamePtr = PLUGIN_NAME; if (Capabilities != NULL) { *Capabilities = 0; } return M64ERR_SUCCESS; } //------------------------------------------------------------------------------------- EXPORT void CALL ChangeWindow (void) { if( status.ToToggleFullScreen ) status.ToToggleFullScreen = FALSE; else status.ToToggleFullScreen = TRUE; } //--------------------------------------------------------------------------------------- EXPORT void CALL MoveScreen (int xpos, int ypos) { } //--------------------------------------------------------------------------------------- EXPORT void CALL RomClosed(void) { TRACE0("To stop video"); Ini_StoreRomOptions(&g_curRomInfo); StopVideo(); TRACE0("Video is stopped"); } EXPORT int CALL RomOpen(void) { /* Read RiceVideoLinux.ini file, set up internal variables by reading values from core configuration API */ LoadConfiguration(); if( g_CritialSection.IsLocked() ) { g_CritialSection.Unlock(); TRACE0("g_CritialSection is locked when game is starting, unlock it now."); } status.bDisableFPS=false; g_dwRamSize = 0x800000; #ifdef DEBUGGER if( debuggerPause ) { debuggerPause = FALSE; usleep(100 * 1000); } #endif if (!StartVideo()) return 0; return 1; } //--------------------------------------------------------------------------------------- EXPORT void CALL UpdateScreen(void) { if(options.bShowFPS) { static unsigned int lastTick=0; static int frames=0; unsigned int nowTick = SDL_GetTicks(); frames++; if(lastTick + 5000 <= nowTick) { char caption[200]; sprintf(caption, "%s v%i.%i.%i - %.3f VI/S", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION), frames/5.0); CoreVideo_SetCaption(caption); frames = 0; lastTick = nowTick; } } UpdateScreenStep2(); } //--------------------------------------------------------------------------------------- EXPORT void CALL ViStatusChanged(void) { g_CritialSection.Lock(); SetVIScales(); CRender::g_pRender->UpdateClipRectangle(); g_CritialSection.Unlock(); } //--------------------------------------------------------------------------------------- EXPORT void CALL ViWidthChanged(void) { g_CritialSection.Lock(); SetVIScales(); CRender::g_pRender->UpdateClipRectangle(); g_CritialSection.Unlock(); } EXPORT int CALL InitiateGFX(GFX_INFO Gfx_Info) { memset(&status, 0, sizeof(status)); memcpy(&g_GraphicsInfo, &Gfx_Info, sizeof(GFX_INFO)); g_pRDRAMu8 = Gfx_Info.RDRAM; g_pRDRAMu32 = (uint32*)Gfx_Info.RDRAM; g_pRDRAMs8 = (signed char *)Gfx_Info.RDRAM; windowSetting.fViWidth = 320; windowSetting.fViHeight = 240; status.ToToggleFullScreen = FALSE; status.ToResize = false; status.bDisableFPS=false; if (!InitConfiguration()) { DebugMessage(M64MSG_ERROR, "Failed to read configuration data"); return FALSE; } CGraphicsContext::InitWindowInfo(); CGraphicsContext::InitDeviceParameters(); return(TRUE); } EXPORT void CALL ResizeVideoOutput(int width, int height) { // save the new window resolution. actual resizing operation is asynchronous (it happens later) status.gNewResizeWidth = width; status.gNewResizeHeight = height; status.ToResize = true; } //--------------------------------------------------------------------------------------- EXPORT void CALL ProcessRDPList(void) { try { RDP_DLParser_Process(); } catch (...) { TRACE0("Unknown Error in ProcessRDPList"); TriggerDPInterrupt(); TriggerSPInterrupt(); } } EXPORT void CALL ProcessDList(void) { ProcessDListStep2(); } //--------------------------------------------------------------------------------------- /****************************************************************** Function: FrameBufferRead Purpose: This function is called to notify the dll that the frame buffer memory is beening read at the given address. DLL should copy content from its render buffer to the frame buffer in N64 RDRAM DLL is responsible to maintain its own frame buffer memory addr list DLL should copy 4KB block content back to RDRAM frame buffer. Emulator should not call this function again if other memory is read within the same 4KB range Since depth buffer is also being watched, the reported addr may belong to depth buffer input: addr rdram address val val size 1 = uint8, 2 = uint16, 4 = uint32 output: none *******************************************************************/ EXPORT void CALL FBRead(uint32 addr) { g_pFrameBufferManager->FrameBufferReadByCPU(addr); } /****************************************************************** Function: FrameBufferWrite Purpose: This function is called to notify the dll that the frame buffer has been modified by CPU at the given address. Since depth buffer is also being watched, the reported addr may belong to depth buffer input: addr rdram address val val size 1 = uint8, 2 = uint16, 4 = uint32 output: none *******************************************************************/ EXPORT void CALL FBWrite(uint32 addr, uint32 size) { g_pFrameBufferManager->FrameBufferWriteByCPU(addr, size); } /************************************************************************ Function: FBGetFrameBufferInfo Purpose: This function is called by the emulator core to retrieve frame buffer information from the video plugin in order to be able to notify the video plugin about CPU frame buffer read/write operations size: = 1 byte = 2 word (16 bit) <-- this is N64 default depth buffer format = 4 dword (32 bit) when frame buffer information is not available yet, set all values in the FrameBufferInfo structure to 0 input: FrameBufferInfo pinfo[6] pinfo is pointed to a FrameBufferInfo structure which to be filled in by this function output: Values are return in the FrameBufferInfo structure Plugin can return up to 6 frame buffer info ************************************************************************/ EXPORT void CALL FBGetFrameBufferInfo(void *p) { FrameBufferInfo * pinfo = (FrameBufferInfo *)p; memset(pinfo,0,sizeof(FrameBufferInfo)*6); //if( g_ZI.dwAddr == 0 ) //{ // memset(pinfo,0,sizeof(FrameBufferInfo)*6); //} //else { for (int i=0; i<5; i++ ) { if( status.gDlistCount-g_RecentCIInfo[i].lastUsedFrame > 30 || g_RecentCIInfo[i].lastUsedFrame == 0 ) { //memset(&pinfo[i],0,sizeof(FrameBufferInfo)); } else { pinfo[i].addr = g_RecentCIInfo[i].dwAddr; pinfo[i].size = 2; pinfo[i].width = g_RecentCIInfo[i].dwWidth; pinfo[i].height = g_RecentCIInfo[i].dwHeight; TXTRBUF_DETAIL_DUMP(TRACE3("Protect 0x%08X (%d,%d)", g_RecentCIInfo[i].dwAddr, g_RecentCIInfo[i].dwWidth, g_RecentCIInfo[i].dwHeight)); pinfo[5].width = g_RecentCIInfo[i].dwWidth; pinfo[5].height = g_RecentCIInfo[i].dwHeight; } } pinfo[5].addr = g_ZI.dwAddr; //pinfo->size = g_RecentCIInfo[5].dwSize; pinfo[5].size = 2; TXTRBUF_DETAIL_DUMP(TRACE3("Protect 0x%08X (%d,%d)", pinfo[5].addr, pinfo[5].width, pinfo[5].height)); } } // Plugin spec 1.3 functions EXPORT void CALL ShowCFB(void) { status.toShowCFB = true; } //void ReadScreen2( void *dest, int *width, int *height, int bFront ) EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int bFront) { if (width == NULL || height == NULL) return; *width = windowSetting.uDisplayWidth; *height = windowSetting.uDisplayHeight; if (dest == NULL) return; #if SDL_VIDEO_OPENGL GLint oldMode; glGetIntegerv( GL_READ_BUFFER, &oldMode ); if (bFront) glReadBuffer( GL_FRONT ); else glReadBuffer( GL_BACK ); glReadPixels( 0, 0, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, GL_RGB, GL_UNSIGNED_BYTE, dest ); glReadBuffer( oldMode ); #endif } EXPORT void CALL SetRenderingCallback(void (*callback)(int)) { renderCallback = callback; } #ifdef __cplusplus } #endif mupen64plus-video-rice-src-2.0/src/Video.h0000644000000000000000000001615512165031100016517 0ustar 00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _DLLINTERFACE_H_ #define _DLLINTERFACE_H_ #define M64P_PLUGIN_PROTOTYPES 1 #include "typedefs.h" #include "m64p_config.h" #include "m64p_plugin.h" #include "m64p_vidext.h" typedef struct { float fViWidth, fViHeight; unsigned short uViWidth, uViHeight; unsigned short uDisplayWidth, uDisplayHeight; BOOL bDisplayFullscreen; BOOL bVerticalSync; float fMultX, fMultY; int vpLeftW, vpTopW, vpRightW, vpBottomW, vpWidthW, vpHeightW; int statusBarHeight, statusBarHeightToUse, toolbarHeight, toolbarHeightToUse; BOOL screenSaverStatus; struct { uint32 left; uint32 top; uint32 right; uint32 bottom; uint32 width; uint32 height; bool needToClip; } clipping; int timer; float fps; // frame per second float dps; // dlist per second uint32 lastSecFrameCount; uint32 lastSecDlistCount; }WindowSettingStruct; typedef enum { PRIM_TRI1, PRIM_TRI2, PRIM_TRI3, PRIM_DMA_TRI, PRIM_LINE3D, PRIM_TEXTRECT, PRIM_TEXTRECTFLIP, PRIM_FILLRECT, } PrimitiveType; typedef enum { RSP_SCISSOR, RDP_SCISSOR, UNKNOWN_SCISSOR, } CurScissorType; typedef struct { bool bGameIsRunning; uint32 dwTvSystem; float fRatio; BOOL frameReadByCPU; BOOL frameWriteByCPU; uint32 SPCycleCount; // Count how many CPU cycles SP used in this DLIST uint32 DPCycleCount; // Count how many CPU cycles DP used in this DLIST uint32 dwNumTrisRendered; uint32 dwNumDListsCulled; uint32 dwNumTrisClipped; uint32 dwNumVertices; uint32 dwBiggestVertexIndex; uint32 gDlistCount; uint32 gFrameCount; uint32 gUcodeCount; uint32 gRDPTime; BOOL ToToggleFullScreen; bool ToResize; uint32 gNewResizeWidth, gNewResizeHeight; bool bDisableFPS; bool bUseModifiedUcodeMap; bool ucodeHasBeenSet; bool bUcodeIsKnown; uint32 curRenderBuffer; uint32 curDisplayBuffer; uint32 curVIOriginReg; CurScissorType curScissor; PrimitiveType primitiveType; uint32 lastPurgeTimeTime; // Time textures were last purged bool UseLargerTile[2]; // This is a speed up for large tile loading, uint32 LargerTileRealLeft[2]; // works only for TexRect, LoadTile, large width, large pitch bool bVIOriginIsUpdated; bool bCIBufferIsRendered; int leftRendered,topRendered,rightRendered,bottomRendered; bool isMMXSupported; bool isSSESupported; bool isVertexShaderSupported; bool isMMXEnabled; bool isSSEEnabled; bool isVertexShaderEnabled; bool bUseHW_T_L; // Use hardware T&L, for debug purpose only bool toShowCFB; bool bAllowLoadFromTMEM; // Frame buffer simulation related status variables bool bN64FrameBufferIsUsed; // Frame buffer is used in the frame bool bN64IsDrawingTextureBuffer; // The current N64 game is rendering into render_texture, to create self-rendering texture bool bHandleN64RenderTexture; // Do we need to handle of the N64 render_texture stuff? bool bDirectWriteIntoRDRAM; // When drawing into render_texture, this value = // = true don't render, but write real N64 graphic value into RDRAM // = false rendering into render_texture of DX or OGL, the render_texture // will be copied into RDRAM at the end bool bFrameBufferIsDrawn; // flag to mark if the frame buffer is ever drawn bool bFrameBufferDrawnByTriangles; // flag to tell if the buffer is even drawn by Triangle cmds bool bScreenIsDrawn; } PluginStatus; #define MI_INTR_DP 0x00000020 #define MI_INTR_SP 0x00000001 extern PluginStatus status; extern GFX_INFO g_GraphicsInfo; extern WindowSettingStruct windowSetting; extern unsigned int g_dwRamSize; extern unsigned int *g_pRDRAMu32; extern signed char *g_pRDRAMs8; extern unsigned char *g_pRDRAMu8; /* declarations of pointers to Core config functions */ extern ptr_ConfigListSections ConfigListSections; extern ptr_ConfigOpenSection ConfigOpenSection; extern ptr_ConfigListParameters ConfigListParameters; extern ptr_ConfigSaveFile ConfigSaveFile; extern ptr_ConfigSetParameter ConfigSetParameter; extern ptr_ConfigGetParameter ConfigGetParameter; extern ptr_ConfigGetParameterHelp ConfigGetParameterHelp; extern ptr_ConfigSetDefaultInt ConfigSetDefaultInt; extern ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat; extern ptr_ConfigSetDefaultBool ConfigSetDefaultBool; extern ptr_ConfigSetDefaultString ConfigSetDefaultString; extern ptr_ConfigGetParamInt ConfigGetParamInt; extern ptr_ConfigGetParamFloat ConfigGetParamFloat; extern ptr_ConfigGetParamBool ConfigGetParamBool; extern ptr_ConfigGetParamString ConfigGetParamString; extern ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath; extern ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath; extern ptr_ConfigGetUserDataPath ConfigGetUserDataPath; extern ptr_ConfigGetUserCachePath ConfigGetUserCachePath; /* declarations of pointers to Core video extension functions */ extern ptr_VidExt_Init CoreVideo_Init; extern ptr_VidExt_Quit CoreVideo_Quit; extern ptr_VidExt_ListFullscreenModes CoreVideo_ListFullscreenModes; extern ptr_VidExt_SetVideoMode CoreVideo_SetVideoMode; extern ptr_VidExt_SetCaption CoreVideo_SetCaption; extern ptr_VidExt_ToggleFullScreen CoreVideo_ToggleFullScreen; extern ptr_VidExt_ResizeWindow CoreVideo_ResizeWindow; extern ptr_VidExt_GL_GetProcAddress CoreVideo_GL_GetProcAddress; extern ptr_VidExt_GL_SetAttribute CoreVideo_GL_SetAttribute; extern ptr_VidExt_GL_GetAttribute CoreVideo_GL_GetAttribute; extern ptr_VidExt_GL_SwapBuffers CoreVideo_GL_SwapBuffers; /* global functions provided by Video.cpp */ extern char generalText[]; extern void (*renderCallback)(int); void DebugMessage(int level, const char *message, ...); void SetVIScales(); extern void _VIDEO_DisplayTemporaryMessage2(const char *msg, ...); extern void _VIDEO_DisplayTemporaryMessage(const char *msg); extern void XBOX_Debugger_Log(const char *Message, ...); #endif mupen64plus-video-rice-src-2.0/src/liblinux/BMGDLL.h0000644000000000000000000001370412165031100020235 0ustar 00000000000000#ifndef _BMG_LIB_ #define _BMG_LIB_ /* // header file for the BMGLib DLL // This DLL encapsulates the libTIFF library, libJPEG library, // libPNG library, and the GeoTIFF library. // // Copyright 2000, 2001 M. Scott Heiman // All Rights Reserved // libTIFF is Copyright Sam Leffler and SGI // libJPEG is Copyright (C) 1991-1998, Thomas G. Lane and is part of the // Independent JPEG Group's software. // libPNG is Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. // (libpng versions 0.5, May 1995, through 0.89c, May 1996) // Copyright (c) 1996, 1997 Andreas Dilger // (libpng versions 0.90, December 1996, through 0.96, May 1997) // Copyright (c) 1998, 1999 Glenn Randers-Pehrson // (libpng versions 0.97, January 1998, through 1.0.5, October 15, 1999) // zLib Copyright (C) 1995-1998 Jean-loup Gailly. // GeoTIFF is Copyright (c) 1999, Frank Warmerdam // libPROJ (used by GeoTIFF) is Copytight (c) 2000, Frank Warmerdam // libUnGif is Copyright (c) 1997, Eric S. Raymond // // You may use the software for any purpose you see fit. You may modify // it, incorporate it in a commercial application, use it for school, // even turn it in as homework. You must keep the Copyright in the // header and source files. This software is not in the "Public Domain". // You may use this software at your own risk. I have made a reasonable // effort to verify that this software works in the manner I expect it to; // however,... // // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "BMGImage.h" #include "tiffrw.h" #include "pngrw.h" #include "jpegrw.h" #if defined(__cplusplus) extern "C" { #endif /* returns a BITMAPINFO structure with the given height, width, bit count, and compression scheme. This structure DOES NOT contain any palette information (bmiColors = NULL) */ extern BITMAPINFO CreateBMI( unsigned int dwWidth, /* width in pixels */ unsigned int dwHeight, /* height in pixels */ unsigned short wBitCount, /* 1, 4, 8, 16, 24, & 32 */ int compression ); /* biCompression value */ /* returns an array of RGBA or BGRA values for all supported graphics file formats. The RGBA pixel format is supported by all versions of OpenGL. The BGRA format is an extension supported by may OpenGL vendors. */ extern BMGError GetUnpackedArray( const char *filename, unsigned int *width, unsigned int *height, unsigned char **bits, int bgra ); /* Saves an array of RGB, RGBA, BGR, and BGRA values to a file. The RGB and RGBA pixel formats are supported by OpenGL. The BGR and BGRA extensions are supported by many OpenGL vendors */ extern BMGError SaveUnpackedArray( const char *filename, unsigned char bytes_per_pixel, unsigned int width, unsigned int height, unsigned char *bits, int bgra ); /* saves the contents of an HBITMAP to a file. The extension of the file name // determines the file type. returns 1 if successfull, 0 otherwise */ extern BMGError SaveBitmapToFile( HBITMAP hBitmap, /* bitmap to be saved */ const char *filename, /* name of output file */ void *parameters ); /* Creates an HBITMAP to an image file. The extension of the file name // determines the file type. returns an HBITMAP if successfull, NULL // otherwise */ extern HBITMAP CreateBitmapFromFile( const char *filename, void *parameters, int blend ); /* extracts a BMGImageStruct from any one of the supported image files */ extern BMGError GetDataFromFile( const char *filename, struct BMGImageStruct *img, void *parameters ); /* the following functions will read/write image files using raw data */ extern BMGError ReadRGB( const char *filename, struct BMGImageStruct *img ); extern BMGError WriteRGB( const char *filename, struct BMGImageStruct img ); extern BMGError ReadTGA( const char *filename, struct BMGImageStruct *img ); extern BMGError WriteTGA( const char *filename, struct BMGImageStruct img ); extern BMGError ReadBMP( const char *filename, struct BMGImageStruct *img ); extern BMGError WriteBMP( const char *filename, struct BMGImageStruct img ); extern BMGError ReadCEL( const char *filename, struct BMGImageStruct *img ); extern BMGError ReadGIF( const char *filename, struct BMGImageStruct *img ); extern BMGError ReadPSD( const char *filename, struct BMGImageStruct *img ); extern BMGError ReadIFF( const char *filename, struct BMGImageStruct *img ); extern BMGError ReadPCX( const char *filename, struct BMGImageStruct *img ); #if defined(__cplusplus) } #endif #endif mupen64plus-video-rice-src-2.0/src/liblinux/BMGImage.c0000644000000000000000000010375512165031100020645 0ustar 00000000000000/* // source code for the BMGImage functions // // Copyright (C) 2001 Michael S. Heiman // // You may use the software for any purpose you see fit. You may modify // it, incorporate it in a commercial application, use it for school, // even turn it in as homework. You must keep the Copyright in the // header and source files. This software is not in the "Public Domain". // You may use this software at your own risk. I have made a reasonable // effort to verify that this software works in the manner I expect it to; // however,... // // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "BMGUtils.h" /* initializes a BMGImage to default values */ void InitBMGImage( struct BMGImageStruct *img ) { img->width = img->height = 0; img->bits_per_pixel = 0; img->palette_size = 0; img->bytes_per_palette_entry = 0; img->bits = NULL; img->palette = NULL; img->opt_for_bmp = 0; img->scan_width = 0; img->transparency_index = -1; } /* frees memory allocated to a BMGImage */ void FreeBMGImage( struct BMGImageStruct *img ) { if ( img->bits != NULL ) { free( img->bits ); img->bits = NULL; } if ( img->palette != NULL ) { free( img->palette ); img->palette = NULL; } img->bits_per_pixel = 0; img->palette_size = 0; img->bytes_per_palette_entry = 0; img->width = img->height = 0; img->opt_for_bmp = 0; img->scan_width = 0; img->transparency_index = -1; } /* allocates memory for the bits & palette. Assigned values to scan_line & bits_per_palette_entry as well. Assumes opt_for_bmp has been set before this function is called. Assumes that all images with bits_per_pixel <= 8 require a palette. */ BMGError AllocateBMGImage( struct BMGImageStruct *img ) { unsigned int mempal; SetLastBMGError( BMG_OK ); /* make sure that all REQUIRED parameters are valid */ if ( img->width * img->height <= 0 ) { SetLastBMGError(errInvalidSize); return errInvalidSize; } switch( img->bits_per_pixel ) { case 1: case 4: case 8: case 16: case 24: case 32: break; default: SetLastBMGError( errInvalidPixelFormat ); return errInvalidPixelFormat; } /* delete old memory */ if ( img->bits != NULL ) { free( img->bits ); img->bits = NULL; } if ( img->palette != NULL ) { free( img->palette ); img->palette = NULL; } /* allocate memory for the palette */ if ( img->bits_per_pixel <= 8 ) { if ( img->opt_for_bmp > 0 ) img->bytes_per_palette_entry = 4U; else { /* we only support 3-byte and 4-byte palettes */ if ( img->bytes_per_palette_entry <= 3U ) img->bytes_per_palette_entry = 3U; else img->bytes_per_palette_entry = 4U; } /* use bits_per_pixel to determine palette_size if none was specified */ if ( img->palette_size == 0 ) img->palette_size = (unsigned short)(1 << img->bits_per_pixel); mempal = img->bytes_per_palette_entry * img->palette_size; img->palette = (unsigned char *)calloc( mempal, sizeof(unsigned char) ); if ( img->palette == NULL ) { SetLastBMGError(errMemoryAllocation); return errMemoryAllocation; } } else { img->bytes_per_palette_entry = 0; img->palette_size = 0; } /* set the scan width. Bitmaps optimized for windows have scan widths that are evenly divisible by 4. */ img->scan_width = ( img->bits_per_pixel * img->width + 7 ) / 8; if ( img->opt_for_bmp && img->scan_width % 4 ) img->scan_width += 4 - img->scan_width % 4; /* allocate memory for the bits */ mempal = img->scan_width * img->height; if ( mempal > 0 ) { img->bits = (unsigned char *)calloc( mempal, sizeof( unsigned char) ); if ( img->bits == NULL ) { if ( img->palette != NULL ) { free( img->palette ); img->palette = NULL; } SetLastBMGError(errMemoryAllocation); return errMemoryAllocation; } } else { SetLastBMGError(errInvalidSize); return errInvalidSize; } return BMG_OK; } /******************************************************************************* A utility function for compressing paletted images. Will automatically convert 8-bit paletted images to 1-bit or 4-bit paletted images based upon palette_size. Assumes that indices in img->bits are valid. That is, 0 <= img->bits[i] <= 1 for all i if 1-bit compression is desired, and 0 <= img->bits[i] <= 15 for all i if 4-bit compression is desired Returns BMG_OK if successful, or an error code otherwise. *******************************************************************************/ BMGError CompressBMGImage( struct BMGImageStruct *img ) { unsigned char new_bits_per_pixel; unsigned int new_scan_width; unsigned char *new_bits = NULL; unsigned int new_bit_size; unsigned char *new_row, *old_row, *p, *q; unsigned char *end; unsigned short scale; SetLastBMGError( BMG_OK ); /* if we cannot compress it then do no harm and return "true" */ if ( img->palette == NULL || img->palette_size > 16 || img->bits_per_pixel != 8 ) { return BMG_OK; } /* calculate new dimensions */ new_bits_per_pixel = img->palette_size <= 2 ? 1U : 4U; new_scan_width = ( new_bits_per_pixel * img->width + 7 ) / 8; if ( img->opt_for_bmp > 0 && new_scan_width % 4 ) new_scan_width += 4 - new_scan_width % 4; new_bit_size = new_scan_width * img->height; /* allocate & test memory */ new_bits = (unsigned char *)calloc( new_bit_size, sizeof(unsigned char) ); if ( new_bits == NULL ) { SetLastBMGError( errMemoryAllocation ); return errMemoryAllocation; } old_row = img->bits; for ( new_row = new_bits; new_row < new_bits + new_bit_size; new_row += new_scan_width, old_row += img->scan_width ) { scale = 8 / new_bits_per_pixel; end = new_row + img->width / scale; p = old_row; if ( new_bits_per_pixel == 1 ) { for ( q = new_row; q < end; q++, p += scale ) { *q = (unsigned char)( (p[0] << 7) | (p[1] << 6) | (p[2] << 5) | (p[3] << 4) | (p[4] << 3) | (p[5] << 2) | (p[6] << 1) | p[7] ); } scale = img->width % scale; if ( scale-- > 0 ) { *q = (unsigned char)(p[0] << 7); if ( scale-- ) { *q |= (unsigned char)(p[1] << 6); if ( scale-- ) { *q |= (unsigned char)(p[2] << 5); if ( scale-- ) { *q |= (unsigned char)(p[3] << 4); if ( scale-- ) { *q |= (unsigned char)(p[4] << 3); if ( scale-- ) { *q |= (unsigned char)(p[5] << 2); if ( scale-- ) *q |= (unsigned char)(p[6] << 1); } } } } } } } else /* new_bits_per_pixel == 4 */ { for ( q = new_row; q < end; q++, p += scale ) { *q = (unsigned char)( (p[0] << 4) | (p[1] & 0x0F) ); } if ( img->width % scale ) *q = (unsigned char)(p[0] << 4); } } /* replace old values with new values */ free( img->bits ); img->bits = new_bits; img->scan_width = new_scan_width; img->bits_per_pixel = new_bits_per_pixel; return BMG_OK; } /* this function simply frees memory that was allocated by any function in the BMGLib. This was required because acces violations occurred when I tried to delete memory created by CreateRGBAArray in the demo applications */ void FreeBMGMemory( unsigned char *mem ) { if ( mem != NULL ) free( mem ); } /* converts a BGR to a gray scale // color[0] = blue, color[1] = green, color[2] = red */ static unsigned char CreateGrayScale( unsigned char *color ) { return (unsigned char)( 0.299f * color[2] + 0.587f * color[1] + 0.114f * color[0] + 0.5f ); } /* // converts a color image to a gray scale image. If img is a 16 or // 24-BPP image then it is converted to a 256 color grayscale bitmap. // If img is a 1, 4, or 8 BPP image, then it will have the same number // of grayscales as it has palette entries. If it is a 32-BPP bitmap then // it will remain a 32-BPP bitmap to preserve the alpha channel. // // This function returns BMG_OK if successfull, or an error state // otherwise. */ BMGError ConvertToGrayScale( struct BMGImageStruct *img ) { unsigned char *p, *q, *r, *end, gray; SetLastBMGError( BMG_OK ); /* if this is a paletted image then we simply need to convert the // palette entries */ switch ( img->bits_per_pixel ) { default: end = img->palette + img->palette_size * img->bytes_per_palette_entry; for ( p = img->palette; p < end; p += img->bytes_per_palette_entry ) { gray = CreateGrayScale( p ); memset( (void *)p, gray, 3 ); } break; /* 16 BPP image are converted to 24 BPP images */ case 16: { BMGError tmp = Convert16to24( img ); if ( tmp != BMG_OK ) { SetLastBMGError( tmp ); return tmp; } } case 24: { unsigned char *new_bits; unsigned char *s, *s_end; unsigned short i; /* calculate the new scan width */ unsigned int new_scan_width = img->width; if ( new_scan_width % 4 && img->opt_for_bmp ) new_scan_width += 4 - new_scan_width % 4; /* allocate memory for the new pixel values */ new_bits = (unsigned char *)calloc( new_scan_width * img->height, sizeof(unsigned char) ); if ( new_bits == NULL ) { SetLastBMGError( errMemoryAllocation ); return errMemoryAllocation; } /* allocate memory for a 256 gray scale palette */ img->bytes_per_palette_entry = img->opt_for_bmp == 1 ? 4 : 3; img->palette_size = 256; img->palette = (unsigned char *)calloc(img->bytes_per_palette_entry * img->palette_size, sizeof(unsigned char) ); if ( img->palette == NULL ) { free( new_bits ); img->bytes_per_palette_entry = 0; img->palette_size = 0; SetLastBMGError( errMemoryAllocation ); return errMemoryAllocation; } /* assign values to the gray scale palette */ for ( i = 0; i < 256; i++ ) { p = img->palette + i * img->bytes_per_palette_entry; memset( (void *)p, i, 3 ); if ( img->bytes_per_palette_entry == 4 ) p[3] = 0; } /* cycle through the pixels and convert them to gray scale values */ q = new_bits; end = img->bits + img->scan_width * img->height; for ( p = img->bits; p < end; p += img->scan_width, q += new_scan_width ) { s_end = p + 3 * img->width; r = q; for ( s = p; s < s_end; s += 3, r++ ) *r = CreateGrayScale( s ); } free( img->bits ); img->bits = new_bits; img->scan_width = new_scan_width; img->bits_per_pixel = 8; break; } case 32: end = img->bits + img->scan_width * img->height; for ( p = img->bits; p < end; p += img->scan_width ) { r = p + img->scan_width; for ( q = p; q < r; q += 4 ) { gray = CreateGrayScale( q ); memset( (void *)q, gray, 3 ); } } break; } return BMG_OK; } /* // converts a color image to a pseudo-gray scale image. This is a implementation // is based upon the code published by Rich Franzen // . I have "simplified" the 2 functions // he published into a single function. This implementation creates 1786 gray // scales from a 24-bit image. 16-BPP images are converted to 24-BPP images. 24 // and 32-BPP images will keep the same bitdepth. Paletted images and 16-BPP images // are not supported. // // This function returns BMK_OK if successfull, // errInvalidPixelFormat otherwise */ BMGError ConvertToPseudoGrayScale( struct BMGImageStruct *img ) { unsigned char *p, *p_end; unsigned char *q, *q_end; unsigned char gray; unsigned int bytes_per_pixel; SetLastBMGError( errMemoryAllocation ); if ( img->bits_per_pixel <= 16 ) { SetLastBMGError( errInvalidPixelFormat ); return errInvalidPixelFormat; } bytes_per_pixel = img->bits_per_pixel / 8; p_end = img->bits + img->scan_width * img->height; for ( p = img->bits; p < p_end; p += img->scan_width ) { q_end = p + bytes_per_pixel * img->width; for ( q = p; q < q_end; q += bytes_per_pixel ) { /* Rich's code has 1 function that converts an RGB triplet to a float // bounded by 0 and 1. He has a second function that converts a // float to a pseudo gray value. Pseudo gray values are RGB triplets // whose red, green and blue values differ by no more than 1. I have // combined these two functions into a single function that simply // looks for pseudo gray RGB triplets. If an RGB triplet meets this // criteria, I leave it unchanged; otherwise, I use the common intensity // conversion to create a grayscale value */ unsigned char cmin, cmax; cmin = q[0]; if ( q[1] < cmin ) cmin = q[1]; if ( q[2] < cmin ) cmin = q[2]; cmax = q[0]; if ( q[1] > cmax ) cmax = q[1]; if ( q[2] > cmax ) cmax = q[2]; if ( cmax - cmin > 2 ) { gray = CreateGrayScale( q ); memset( (void *)q, gray, 3 ); } } } return BMG_OK; } #ifdef _WIN32 /******************************************************************************* // extracts the dimensional information, pixel array, and color table from an // HBITMAP. // hBitmap can be a handle to a DIB or a DDB. This function assumes that DDBs // will not have a palette. If you create a DDB on a 256-color graphics card, // then the DDB will have a palette and this function will fail. // // returns BMK_OK if successfull, and error state otherwise. ********************************************************************************/ BMGError GetDataFromBitmap( HBITMAP hBitmap, struct BMGImageStruct *img, int remove_alpha ) { unsigned int DIBScanWidth; DIBSECTION DS; HWND hWnd = GetForegroundWindow(); HDC hDC = NULL; HDC hMemDC = NULL; unsigned char red, green, blue; int FreelpBits = 0; unsigned int numBytes; size_t soDIBSECTION = sizeof(DIBSECTION); size_t soBITMAP = sizeof(BITMAP); unsigned char *p, *q, *lpBits, alpha; jmp_buf err_jmp; int error; BMGError bmgerr; /* error handler */ error = setjmp( err_jmp ); if ( error != 0 ) { if ( hMemDC != NULL ) DeleteDC( hMemDC ); if ( hDC != NULL ) ReleaseDC( hWnd, hDC ); if ( FreelpBits ) free( lpBits ); FreeBMGImage( img ); SetLastBMGError( (BMGError)error ); return (BMGError)error; } SetLastBMGError( BMG_OK ); /* check for valid bitmap*/ if ( !hBitmap ) longjmp( err_jmp, (int)errInvalidBitmapHandle ); /* Extract DIBSECTION info from the HBITMAP. numBytes will equal // soDIBSECTION (84) if hBitmap is a handle to a DIBSECTION (DIB). // numBytes will equal soBITMAP (24) if hBitmap is a handle to a // BITMAP (DDB). */ numBytes = GetObject( hBitmap, sizeof(DIBSECTION), &DS ); if ( numBytes == 0 ) longjmp( err_jmp, (int)errWindowsAPI ); img->opt_for_bmp = 1; if ( numBytes == soDIBSECTION ) { img->width = DS.dsBmih.biWidth; img->height = DS.dsBmih.biHeight; img->bits_per_pixel = (unsigned char)DS.dsBmih.biBitCount; if ( img->bits_per_pixel <= 8 && DS.dsBmih.biClrUsed > 0 ) img->palette_size = (unsigned short)DS.dsBmih.biClrUsed; lpBits = (unsigned char *)DS.dsBm.bmBits; } /* this may be a DDB which must be handled differently */ else if ( numBytes == soBITMAP ) { BITMAP bm; BITMAPINFO bmi; if ( GetObject( hBitmap, sizeof(BITMAP), &bm ) == 0 ) longjmp( err_jmp, (int)errWindowsAPI ); /* DDB with a palette */ if ( bm.bmBitsPixel <= 8 ) longjmp( err_jmp, (int)errInvalidPixelFormat ); img->width = bm.bmWidth; img->height = bm.bmHeight; img->bits_per_pixel = (unsigned char)bm.bmBitsPixel; bmi = InternalCreateBMI( bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, BI_RGB ); lpBits = (unsigned char *)calloc( bm.bmHeight * bm.bmWidthBytes, sizeof(unsigned char) ); if ( lpBits == 0 ) longjmp( err_jmp, (int)errMemoryAllocation ); FreelpBits = 1; hDC = GetDC( hWnd ); if ( GetDIBits(hDC, hBitmap, 0, bm.bmHeight, (void *)lpBits, &bmi, DIB_RGB_COLORS ) == 0 ) longjmp( err_jmp, (int)errWindowsAPI ); ReleaseDC( hWnd, hDC ); hDC = NULL; } else /* I have no idea what this is */ longjmp( err_jmp, (int)errInvalidBitmapHandle ); /* allocate memory */ bmgerr = AllocateBMGImage( img ); if ( bmgerr != BMG_OK ) longjmp( err_jmp, (int)bmgerr ); /* dimensions */ DIBScanWidth = ( img->width * img->bits_per_pixel + 7 )/8; if ( DIBScanWidth % 4 ) DIBScanWidth += 4 - DIBScanWidth % 4; p = img->bits; for ( q = lpBits; q < lpBits + DIBScanWidth * img->height; p += img->scan_width, q += DIBScanWidth ) { memcpy( (void *)p, (void *)q, DIBScanWidth ); } /* "un-blend" the image if requested. NOTE: unblending only works with // bland backgrounds */ if ( remove_alpha > 0 && img->bits_per_pixel == 32 && numBytes == soDIBSECTION ) { unsigned char *color = GetBackgroundColor(); red = color[2]; green = color[1]; blue = color[0]; for ( p = img->bits; p < img->bits + img->scan_width * img->height; p += 4 ) { alpha = p[3]; p[2] = InverseAlphaComp( p[2], alpha, blue); p[1] = InverseAlphaComp( p[1], alpha, green); p[0] = InverseAlphaComp( p[0], alpha, red); } } /* 32-bit DDBs must have the alpha channel set to 0xFF before they are // saved to a file. This may not be true for all devices that generate // 32-bit DDBs. I have only created 32-bit DDBs using an Intense3D Wildcat // 4110 card. The alpha channel was always 0. */ if (img->bits_per_pixel == 32 && numBytes == soBITMAP ) { for ( p = img->bits + 3; p < img->bits + img->scan_width * img->height; p += 4 ) { *p = 0xFF; } } /* create palette if necessary */ if ( img->bits_per_pixel <= 8 ) { hDC = GetDC( hWnd ); hMemDC = CreateCompatibleDC( hDC ); SelectObject( hMemDC, hBitmap ); if ( !GetDIBColorTable( hMemDC, 0, img->palette_size, (RGBQUAD *)img->palette ) ) { longjmp( err_jmp, (int)errWindowsAPI ); } DeleteDC( hMemDC ); ReleaseDC( hWnd, hDC ); } if ( FreelpBits ) free( lpBits ); return BMG_OK; } /******************************************************************************* // this function creates a bitmap from raw data. Returns an HBITMAP if it // succeeds, otherwise NULL */ HBITMAP CreateBitmapFromData( struct BMGImageStruct img, int alpha_blend ) { HBITMAP hBitmap = NULL; HDC hMemDC = NULL; HWND hWnd = GetForegroundWindow(); HDC hDC = NULL; RGBQUAD *pColor = NULL; BITMAPINFO bmi; unsigned char *rbits; unsigned char *bits; unsigned char *lpBits; unsigned char alpha; unsigned int DIBScanWidth; int i; jmp_buf err_jmp; int error; /* error handler */ error = setjmp( err_jmp ); if ( error != 0 ) { if ( hMemDC != NULL ) DeleteDC( hMemDC ); if ( hDC != NULL ) ReleaseDC( hWnd, hDC ); if ( pColor != NULL && img.bytes_per_palette_entry == 3U ) free( pColor ); SetLastBMGError( (BMGError)error ); return 0; } SetLastBMGError( BMG_OK ); /* create the DIB section that will hold this bitmap */ bmi = InternalCreateBMI( (unsigned int)img.width, (unsigned int)img.height, (unsigned short)img.bits_per_pixel, BI_RGB ); bmi.bmiHeader.biClrUsed = bmi.bmiHeader.biClrImportant = img.palette_size; hDC = GetDC( hWnd ); hBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS, (void **)&lpBits, NULL, 0 ); if ( !hBitmap || !lpBits ) longjmp( err_jmp, (int)errWindowsAPI ); /* create a palette if needed */ if ( img.palette != NULL ) { /* copy pixel data to pColor */ if ( img.bytes_per_palette_entry == 4U ) pColor = (RGBQUAD *)img.palette; else /* bytes_per_palette_entry === 3 */ { pColor = (RGBQUAD *)calloc(img.palette_size, sizeof(RGBQUAD) ); if ( pColor == NULL ) longjmp( err_jmp, (int)errMemoryAllocation ); bits = img.palette; for ( i = 0; i < (int)bmi.bmiHeader.biClrUsed; i++, bits += 3 ) { pColor[i].rgbRed = bits[0]; pColor[i].rgbGreen = bits[1]; pColor[i].rgbBlue = bits[2]; } } if ( img.transparency_index > -1 ) { unsigned char *color = GetBackgroundColor(); rbits = img.palette + img.bytes_per_palette_entry * img.transparency_index; rbits[0] = color[2]; rbits[1] = color[1]; rbits[2] = color[0]; } /* save color table in bitmap */ hMemDC = CreateCompatibleDC( hDC ); SelectObject( hMemDC, hBitmap ); if ( !SetDIBColorTable( hMemDC, 0, img.palette_size, pColor ) ) longjmp( err_jmp, (int)errWindowsAPI ); DeleteDC( hMemDC ); hMemDC = NULL; if ( img.bytes_per_palette_entry == 3U ) free( pColor ); pColor = NULL; } /* calculate the scan line width */ DIBScanWidth = img.scan_width; if ( DIBScanWidth % 4 ) DIBScanWidth += 4 - DIBScanWidth % 4; if ( img.opt_for_bmp == 0 ) { /* store bits into hBitmap */ rbits = img.bits; for ( bits = lpBits; bits < lpBits + img.height * DIBScanWidth; bits += DIBScanWidth, rbits += img.scan_width ) { memcpy( (void *)bits, (void *)rbits, img.scan_width ); } } else memcpy( (void *)lpBits, (void *)img.bits, img.scan_width * img.height ); /* blend the image with the window background if alpha pixels // are present */ if ( img.bits_per_pixel == 32 ) { /* blend with a bland background */ if ( alpha_blend == 1 ) { unsigned char *color = GetBackgroundColor(); unsigned char red = color[2]; unsigned char green = color[1]; unsigned char blue = color[0]; for ( rbits = lpBits; rbits < lpBits + img.height*DIBScanWidth; rbits += DIBScanWidth ) { for ( bits = rbits; bits < rbits + DIBScanWidth; bits += 4 ) { alpha = bits[3]; bits[2] = AlphaComp( bits[2], alpha, blue ); bits[1] = AlphaComp( bits[1], alpha, green ); bits[0] = AlphaComp( bits[0], alpha, red ); } } } /* blend with a background image */ else if ( alpha_blend == 2 ) { unsigned char *bg_bits; unsigned char *bg_bits_2; unsigned int bg_bytes_per_pixel; struct BMGImageStruct *bg = GetBackgroundImage(); /* make sure we can blend with a background image // I assume that the background image is invalid if it does not // have a valid width */ if ( bg->width <= 0 || bg->height <= 0 ) longjmp( err_jmp, (int)errUndefinedBGImage ); /* I cannot blend a foreground image with a background image that // is smaller than it */ if ( bg->width < img.width || bg->height < img.height ) longjmp( err_jmp, (int)errBGImageTooSmall ); /* the background image was forced to be a 24 or 32-BPP image; // therefore, we can safely divide by 8 to determined the // bytes per pixel*/ bg_bytes_per_pixel = bg->bits_per_pixel / 8; /* I will assume that the upper left corner of the input image // must be aligned with the upper left corner of the background // image. This allows me to have background images that are bigger // than the input image. */ bg_bits = bg->bits; for ( rbits = lpBits; rbits < lpBits + img.height*DIBScanWidth; rbits += DIBScanWidth, bg_bits += bg->scan_width ) { bg_bits_2 = bg_bits; for ( bits = rbits; bits < rbits + DIBScanWidth; bits += 4, bg_bits_2 += bg_bytes_per_pixel ) { alpha = bits[3]; bits[2] = AlphaComp( bits[2], alpha, bg_bits_2[2] ); bits[1] = AlphaComp( bits[1], alpha, bg_bits_2[1] ); bits[0] = AlphaComp( bits[0], alpha, bg_bits_2[0] ); } } } } ReleaseDC( hWnd, hDC ); return hBitmap; } #endif // _WIN32 /****************************************************************************** // ConvertPaletteToRGB converts paletted and 16-BPP images that do not have // transparent pixels to 24-BPP images. Paletted images with transparent pixels // are converted to 32-BPP images. 24-BPP and 32-BPP images are simply copied // to the output structure // // INPUTS: // img_in // OUTPUTS: // img_out // // returns BMG_OK if no errors occur, an error code otherwise ******************************************************************************/ BMGError ConvertPaletteToRGB( struct BMGImageStruct img_in, struct BMGImageStruct *img_out ) { jmp_buf err_jmp; int error; /* error handler */ error = setjmp( err_jmp ); if ( error != 0 ) { FreeBMGImage( img_out ); SetLastBMGError( (BMGError)error ); return (BMGError)error; } SetLastBMGError( BMG_OK ); if ( img_in.height == 0 || img_in.width == 0 ) longjmp( err_jmp, (int)errInvalidSize ); InitBMGImage( img_out ); // copy 16, 24, and 32-BPP images into the output image if ( img_in.bits_per_pixel > 8 ) { BMGError out; img_out->bits_per_pixel = img_in.bits_per_pixel; out = CopyBMGImage( img_in, img_out ); if ( out != BMG_OK ) longjmp( err_jmp, (int)out ); // 16-BPP are converted to 24-BPP images if ( img_out->bits_per_pixel == 16 ) { out = Convert16to24( img_out ); if ( out != BMG_OK ) longjmp( err_jmp, (int)out ); } } else // convert paletted images to 24-BPP BGR or 32-BPP BGRA images { BMGError out; unsigned char *buf; unsigned int scan_width; int dealloc; unsigned char *q0, *q1, *p0, *p1; unsigned int bpp; // allocate memory for the 24-BPP output image img_out->width = img_in.width; img_out->height = img_in.height; img_out->opt_for_bmp = img_in.opt_for_bmp; img_out->bits_per_pixel = img_in.transparency_index > -1 ? 32 : 24; out = AllocateBMGImage( img_out ); if ( out != BMG_OK ) longjmp( err_jmp, (int)out ); // 1-BPP and 4-BPP images are packed, so we need to unpack them if ( img_in.bits_per_pixel < 8 ) { dealloc = 1; scan_width = img_in.width; buf = (unsigned char *)malloc(scan_width * img_in.height); if ( buf == NULL ) longjmp( err_jmp, (int)errMemoryAllocation ); if ( img_in.bits_per_pixel == 1 ) Convert1to8( img_in, buf ); else Convert4to8( img_in, buf ); } else // simply point to the bits array if we have a 8-BPP image { dealloc = 0; buf = img_in.bits; scan_width = img_in.scan_width; } // convert palette indices to BGR pixels bpp = img_out->bits_per_pixel / 8; q0 = img_out->bits; for ( p0 = buf; p0 < buf + scan_width * img_in.height; p0 += scan_width, q0 += img_out->scan_width ) { q1 = q0; for ( p1 = p0; p1 < p0 + img_in.width; p1++, q1 += bpp ) { memcpy( (void *)q1, (void *)(img_in.palette + *p1 * img_in.bytes_per_palette_entry), 3 ); if ( bpp == 4 ) { q1[3] = *p1 == img_in.transparency_index ? 0 : 0xFF; } } } if ( dealloc == 1 ) free( buf ); } return BMG_OK; } /****************************************************************************** // CopyBMG copies the contents of img_in into img_out. // // CopyBMG returns BMG_OK if successful, otherwise, it returns an error code ******************************************************************************/ BMGError CopyBMGImage( struct BMGImageStruct img_in, struct BMGImageStruct *img_out ) { BMGError out = BMG_OK; SetLastBMGError( out ); FreeBMGImage( img_out ); img_out->height = img_in.height; img_out->width = img_in.width; img_out->bits_per_pixel = img_in.bits_per_pixel; img_out->palette_size = img_in.palette_size; img_out->opt_for_bmp = img_in.opt_for_bmp; if ( img_in.width > 0 && img_in.height > 0 ) { out = AllocateBMGImage( img_out ); if ( out == BMG_OK ) { memcpy( (void *)img_out->bits, (void *)img_in.bits, img_in.scan_width * img_in.height ); if ( img_in.palette_size > 0 ) memcpy( (void *)img_out->palette, (void *)img_in.palette, img_in.palette_size * img_in.bytes_per_palette_entry ); } } return out; } /* sets the background color for alpha blending color points to an array of 4 unsigned chars color[0] = blue, color[1] = green, color[2] = red, color[3] = unused */ void SetBMGBackgroundColor( unsigned char *color ) { memcpy( (void *)GetBackgroundColor(), (void *)color, 4*sizeof(unsigned char) ); } #ifdef _WIN32 /* defines the background bitmap that is used for alpha blending & transparent pixels */ BMGError SetBMGBackgroundBitmap( HBITMAP hBitmap ) { BMGError out; struct BMGImageStruct tmp; InitBMGImage( &tmp ); /* first we extract the data from the HBITMAP */ out = GetDataFromBitmap( hBitmap, &tmp, 0 ); if ( out == BMG_OK ) { /* clean up the old background image */ FreeBMGImage( GetBackgroundImage() ); /* next, we convert paletted & 16-BPP images to 24 or 32-BPP images. // this will simplify the alpha blending. */ out = ConvertPaletteToRGB( tmp, GetBackgroundImage() ); } return out; } #endif // _WIN32 /* defines the background image that is used for alpha blending & transparent pixels */ BMGError SetBMGBackgroundImage( struct BMGImageStruct img ) { /* clean up the old background image */ FreeBMGImage( GetBackgroundImage() ); /* convert paletted and 16-BPP images to 24-BPP or 32-BPP images. This // will simplify the alpha blending logic*/ return ConvertPaletteToRGB( img, GetBackgroundImage() ); } mupen64plus-video-rice-src-2.0/src/liblinux/BMGImage.h0000644000000000000000000001222212165031100020636 0ustar 00000000000000#ifndef _BMG_IMAGE_H_ #define _BMG_IMAGE_H_ /* // header file for the BMGImage functions // // Copyright 2000, 2001 M. Scott Heiman // // You may use the software for any purpose you see fit. You may modify // it, incorporate it in a commercial application, use it for school, // even turn it in as homework. You must keep the Copyright in the // header and source files. This software is not in the "Public Domain". // You may use this software at your own risk. I have made a reasonable // effort to verify that this software works in the manner I expect it to; // however,... // // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "../osal_preproc.h" #if !defined(WIN32) typedef struct tagRGBQUAD { unsigned char rgbBlue; unsigned char rgbGreen; unsigned char rgbRed; unsigned char rgbReserved; } RGBQUAD; #endif enum BMG_Error { BMG_OK = 0, errLib = 1, errInvalidPixelFormat = 2, errMemoryAllocation = 3, errInvalidSize = 4, errInvalidBitmapHandle = 5, errWindowsAPI = 6, errFileOpen = 7, errUnsupportedFileFormat = 8, errInvalidBMGImage = 9, errInvalidFileExtension = 10, errFileRead = 11, errFileWrite = 12, errInvalidGeoTIFFPointer = 13, errUndefinedBGImage = 14, errBGImageTooSmall = 15, errCorruptFile = 16 }; typedef enum BMG_Error BMGError; #pragma pack(push,1) struct BMGImageStruct { unsigned int width; unsigned int height; unsigned char bits_per_pixel; unsigned char *bits; unsigned short palette_size; unsigned char bytes_per_palette_entry; unsigned char *palette; unsigned int scan_width; int opt_for_bmp; /*= 1 if memory has been sized for HBITMAP, 0 otherwise*/ short transparency_index; }; #pragma pack(pop) #if defined(__cplusplus) extern "C" { #endif /* initializes a BMGImage to default values */ extern void InitBMGImage(struct BMGImageStruct *img ); /* frees memory allocated to a BMGImage */ extern void FreeBMGImage( struct BMGImageStruct *img ); /* allocates memory (bits & palette) for a BMGImage. returns 1 if successfull, 0 otherwise. width, height, bits_per_pixel, palette_size, & opt_for_bmp must have valid values before this function is called. Assumes that all images with bits_per_pixel <= 8 requires a palette. will set bits_per_palette_entry, scan_width, bits, & palette */ extern BMGError AllocateBMGImage( struct BMGImageStruct *img ); /* compresses 8 BPP paletted images to 1 BPP or 4 BPP paletted images if possible */ extern BMGError CompressBMGImage( struct BMGImageStruct *img ); /* a utility function for freeing memory created in BMGLib */ extern void FreeBMGMemory( unsigned char *mem ); /* converts a color image to a gray scale image */ extern BMGError ConvertToGrayScale( struct BMGImageStruct *img ); /* converts a color image to a pseudo-gray scale image */ extern BMGError ConvertToPseudoGrayScale( struct BMGImageStruct *img ); /* stores the contents of a bitmap into a BMGImageStruct */ extern BMGError GetDataFromBitmap( HBITMAP hBitmap, struct BMGImageStruct *img, int remove_alpha ); /* creates an HBITMAP from a BMGImageStruct */ extern HBITMAP CreateBitmapFromData( struct BMGImageStruct img, int alpha_blend ); /* sets the background color for alpha blending color points to an array of 4 unsigned chars color[0] = blue, color[1] = green, color[2] = red, color[3] = unused */ extern void SetBMGBackgroundColor( unsigned char *color ); /* defines the background bitmap that is used for alpha blending & transparent pixels */ extern BMGError SetBMGBackgroundBitmap( HBITMAP hBitmap ); /* defines the background image that is used for alpha blending & transparent pixels */ extern BMGError SetBMGBackgroundImage( struct BMGImageStruct img ); /* Converts paletted images and 16-BPP images to 24-BPP images */ extern BMGError ConvertPaletteToRGB( struct BMGImageStruct img_in, struct BMGImageStruct *img_out ); /* copies the contents of the input image into the output image */ extern BMGError CopyBMGImage( struct BMGImageStruct img_in, struct BMGImageStruct *img_out ); /* returns the last error state */ extern BMGError GetLastBMGError(); /* gets the error message */ extern void GetLastBMGErrorMessage( const char **msg ); #if defined(__cplusplus) } #endif #endif mupen64plus-video-rice-src-2.0/src/liblinux/BMGLibPNG.h0000644000000000000000000000474112165031100020676 0ustar 00000000000000#ifndef _BMG_LIBPNG_H_ #define _BMG_LIBPNG_H_ /* // header file for the BMGLibPNG functions // // Copyright 2000, 2001 M. Scott Heiman // All Rights Reserved // libPNG is Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. // (libpng versions 0.5, May 1995, through 0.89c, May 1996) // Copyright (c) 1996, 1997 Andreas Dilger // (libpng versions 0.90, December 1996, through 0.96, May 1997) // Copyright (c) 1998, 1999 Glenn Randers-Pehrson // (libpng versions 0.97, January 1998, through 1.0.5, October 15, 1999) // // You may use the software for any purpose you see fit. You may modify // it, incorporate it in a commercial application, use it for school, // even turn it in as homework. You must keep the Copyright in the // header and source files. This software is not in the "Public Domain". // You may use this software at your own risk. I have made a reasonable // effort to verify that this software works in the manner I expect it to; // however,... // // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "pngrw.h" #if defined(__cplusplus) extern "C" { #endif //#pragma message ("Exporting BMGLibPNG functions") /* saves the contents of an HBITMAP to a file. The extension of the file name // determines the file type. returns 1 if successfull, 0 otherwise */ extern BMGError SaveBitmapToPNGFile( HBITMAP hBitmap, /* bitmap to be saved */ const char *filename); /* name of output file */ /* Creates an HBITMAP to an image file. The extension of the file name // determines the file type. returns an HBITMAP if successfull, NULL // otherwise */ extern HBITMAP CreateBitmapFromPNGFile( const char *filename, int blend ); #if defined(__cplusplus) } #endif #endif mupen64plus-video-rice-src-2.0/src/liblinux/BMGUtils.c0000644000000000000000000002606612165031100020722 0ustar 00000000000000/* // source code for the BMGLib Utility functions // // Copyright (C) 2001 M. Scott Heiman // All Rights Reserved // // You may use the software for any purpose you see fit. You may modify // it, incorporate it in a commercial application, use it for school, // even turn it in as homework. You must keep the Copyright in the // header and source files. This software is not in the "Public Domain". // You may use this software at your own risk. I have made a reasonable // effort to verify that this software works in the manner I expect it to; // however,... // // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include "BMGUtils.h" #ifndef _WIN32 #include #endif // _WIN32 /* error strings for all BMG errors */ static char BMGErrorStrings[17][128] = { "No Error", "Corrupted file or invalid file format", "Invalid bits per pixel for this file format", "Memory allocation error", "Invalid requested image size", "Invalid bitmap handle", "Windows API Error", /* this will be overwritten */ "Unable to open file", "Unsupported file format option", "Invalid pointer to a BMG image", "Unsupported file extension", "Error reading file", "Error writing to the output file", "Invalid pointer to a GeoTIFF structure", "The background image is undefined", "The background image is too small", "Corrupt File" }; /* stores last BMG error */ static BMGError LastBMGError; /* sets the last BMG error */ void SetLastBMGError( BMGError err ) { LastBMGError = err; } /* returns the last error state */ BMGError GetLastBMGError(void) { return LastBMGError; } /* gets the error message */ void GetLastBMGErrorMessage( const char **msg ) { if ( LastBMGError == errWindowsAPI ) { char* lpMsgBuf = "Erreur BMG\n"; /* copy the string. */ strcpy( BMGErrorStrings[(int)LastBMGError], (char *)lpMsgBuf ); } *msg = BMGErrorStrings[(int)LastBMGError]; } /* Global background color variables */ static unsigned char BackgroundColor[4]; static struct BMGImageStruct BackgroundImage; /* this function simply initializes the background info. It is called from the DllEntryPoint function */ void InitBackground(void) { memset( (void *)BackgroundColor, 0xFF, 3 ); /* white */ BackgroundColor[3] = 0; /* ignored */ InitBMGImage( &BackgroundImage ); } unsigned char *GetBackgroundColor(void) { return &BackgroundColor[0]; } struct BMGImageStruct *GetBackgroundImage(void) { return &BackgroundImage; } /* converts an array of 1-bit scanlines to 8-bit scanlines */ void Convert1to8( struct BMGImageStruct img, unsigned char *out ) { unsigned char *p, *q, *r, *s, *end; int i; q = out; for ( s = img.bits; s < img.bits + img.scan_width * img.height; s += img.scan_width, q += img.width ) { i = img.width % 8; end = q + img.width - i; p = s; for ( r = q; r < end; p++ ) { *r++ = (unsigned char)((*p & 0x80) ? 1 : 0); *r++ = (unsigned char)((*p & 0x40) ? 1 : 0); *r++ = (unsigned char)((*p & 0x20) ? 1 : 0); *r++ = (unsigned char)((*p & 0x10) ? 1 : 0); *r++ = (unsigned char)((*p & 0x08) ? 1 : 0); *r++ = (unsigned char)((*p & 0x04) ? 1 : 0); *r++ = (unsigned char)((*p & 0x02) ? 1 : 0); *r++ = (unsigned char)(*p & 0x01); } if ( i-- ) { *r++ = (unsigned char)((*p & 0x80) ? 1 : 0); if ( i-- ) { *r++ = (unsigned char)((*p & 0x40) ? 1 : 0); if ( i-- ) { *r++ = (unsigned char)((*p & 0x20) ? 1 : 0); if ( i-- ) { *r++ = (unsigned char)((*p & 0x10) ? 1 : 0); if ( i-- ) { *r++ = (unsigned char)((*p & 0x08) ? 1 : 0); if ( i-- ) { *r++ = (unsigned char)((*p & 0x04) ? 1 : 0); if ( i ) *r = (unsigned char)((*p & 0x02) ? 1:0); } } } } } } } } /* converts an array of 4-bit scanlines to 8-bit scanlines */ void Convert4to8( struct BMGImageStruct img, unsigned char *out ) { unsigned char *p, *q, *r, *s, *end; int i; q = out; for ( s = img.bits; s < img.bits + img.scan_width * img.height; s += img.scan_width, q += img.width ) { i = img.width % 2; end = q + img.width - i; p = s; for ( r = q; r < end; p++ ) { *r++ = (unsigned char)((*p >> 4) & 0x0F); *r++ = (unsigned char)(*p & 0x0F); } if ( i ) *r = (unsigned char)((*p >> 4) & 0x0F); } } /****************************************************************************/ /* this function performs alpha blending. It is a variation of a function that I found in the PNG example code */ unsigned char AlphaComp( unsigned char fg, unsigned char alpha, unsigned char bg ) { unsigned char out; unsigned short temp; switch ( alpha ) { case 0: out = bg; break; case 255: out = fg; break; default: temp = ((unsigned short)(fg)*(unsigned short)(alpha) + (unsigned short)(bg)*(unsigned short)(255 - (unsigned short)(alpha)) + (unsigned short)128); out = (unsigned char)((temp + (temp >> 8)) >> 8); break; } return out; } /**************************************************************************** // Converts a 16 BPP image to a 24 BPP image // returns 1 if successfull, 0 otherwise */ BMGError Convert16to24( struct BMGImageStruct *img ) { unsigned int i; unsigned int new_scan_width; unsigned char *new_bits; /* this function will only work with 16 BBP images */ if ( img->bits_per_pixel != 16 ) return errInvalidPixelFormat; /* calculate the new scan width */ new_scan_width = 3 * img->width; if ( new_scan_width % 4 && img->opt_for_bmp ) new_scan_width += 4 - new_scan_width % 4; /* allocate memory for the new pixel values */ new_bits = (unsigned char *)calloc( new_scan_width * img->height, sizeof(unsigned char) ); if ( new_bits == NULL ) return errMemoryAllocation; /* convert the 16 BPP pixel values to the equivalent 24 BPP values */ for ( i = 0; i < img->height; i++ ) { unsigned char *p24; unsigned short *p16 = (unsigned short *)(img->bits + i * img->scan_width); unsigned char *start = new_bits + i * new_scan_width; unsigned char *end = start + new_scan_width; for ( p24 = start; p24 < end; p24 += 3, p16++ ) { p24[0] = (unsigned char)( (*p16 & 0x001F) << 3 ); p24[1] = (unsigned char)( (*p16 & 0x03E0) >> 2 ); p24[2] = (unsigned char)( (*p16 & 0x7C00) >> 7 ); } } free( img->bits ); img->bits = new_bits; img->scan_width = new_scan_width; img->bits_per_pixel = 24; return BMG_OK; } /****************************************************************************/ /* this function undoes alpha blending - kind-a-sort-of ;-) */ unsigned char InverseAlphaComp( unsigned char fg, unsigned char alpha, unsigned char bg ) { unsigned char out; short temp; switch ( alpha ) { case 0: out = bg; break; case 255: out = fg; break; default: temp = (255*fg - bg*(255-alpha))/alpha; if ( temp < 0 ) temp = 0; out = (unsigned char)temp; break; } return out; } /****************************************************************************/ /* // Creates a BITMAPINFOHEADER for the given width, height, bit count, and // compression. Compression must = BI_RGB, BI_BITFIELDS, BI_RLE4, or BI_RLE8. */ BITMAPINFO InternalCreateBMI( unsigned int dwWidth, /* width */ unsigned int dwHeight, /* height */ unsigned short wBitCount, /* bit count */ int compression ) /* compression type */ { BITMAPINFO bi; /* bitmap header */ unsigned int dwBytesPerLine; /* Number of bytes per scanline */ /* clear the bitmapinfo structure */ memset(&bi, 0, sizeof(BITMAPINFO)); /* Make sure bits per pixel is valid */ if (wBitCount <= 1) wBitCount = 1; else if (wBitCount <= 4) wBitCount = 4; else if (wBitCount <= 8) wBitCount = 8; else if (wBitCount <= 16) wBitCount = 16; else if (wBitCount <= 24) wBitCount = 24; else if (wBitCount <= 32) wBitCount = 32; else wBitCount = 8; /* set default value to 8 if parameter is bogus */ dwBytesPerLine = (((wBitCount * dwWidth) + 31) / 32 * 4); /* initialize BITMAPINFO */ bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth = dwWidth; bi.bmiHeader.biHeight = dwHeight; bi.bmiHeader.biPlanes = 1; /* must be 1 */ bi.bmiHeader.biBitCount = wBitCount; bi.bmiHeader.biCompression = compression; bi.bmiHeader.biSizeImage = dwBytesPerLine*dwHeight; bi.bmiHeader.biXPelsPerMeter = 0; bi.bmiHeader.biYPelsPerMeter = 0; bi.bmiHeader.biClrUsed = wBitCount <= 8 ? 1U << wBitCount : 0; bi.bmiHeader.biClrImportant = bi.bmiHeader.biClrUsed; return bi; } short SwapShort( short in ) { char sin[2]; char sout[2]; memcpy( (char *)sin, (char *)&in, 2 ); sout[0] = sin[1]; sout[1] = sin[0]; return *((short *)sout); } unsigned short SwapUShort( unsigned short in ) { char sin[2]; char sout[2]; memcpy( (char *)sin, (char *)&in, 2 ); sout[0] = sin[1]; sout[1] = sin[0]; return *((unsigned short *)sout); } int SwapLong( int in ) { char sin[4]; char sout[4]; memcpy( (char *)sin, (char *)&in, 4 ); sout[0] = sin[3]; sout[1] = sin[2]; sout[2] = sin[1]; sout[3] = sin[0]; return *((int *)sout); } unsigned int SwapULong( unsigned int in ) { char sin[4]; char sout[4]; memcpy( (char *)sin, (char *)&in, 4 ); sout[0] = sin[3]; sout[1] = sin[2]; sout[2] = sin[1]; sout[3] = sin[0]; return *((unsigned int *)sout); } mupen64plus-video-rice-src-2.0/src/liblinux/BMGUtils.h0000644000000000000000000000324412165031100020720 0ustar 00000000000000#ifndef _BMG_UTILS_H_ #define _BMG_UTILS_H_ /* some handy utilities used in several units Copyright 2001 M. Scott Heiman All Rights Reserved */ #include "BMGImage.h" #include "../osal_preproc.h" /* the following 3 functions are used to access the background color // and the background image */ void InitBackground(void); unsigned char *GetBackgroundColor(void); struct BMGImageStruct *GetBackgroundImage(void); /* creates a 24 bpp image from a 16 bpp image */ BMGError Convert16to24( struct BMGImageStruct *img ); /* converts an array of 1-bit scanlines to 8-bit scanlines */ void Convert1to8( struct BMGImageStruct img, unsigned char *out ); /* converts an array of 4-bit scanlines to 8-bit scanlines */ void Convert4to8( struct BMGImageStruct img, unsigned char *out ); unsigned char AlphaComp( unsigned char fg, unsigned char alpha, unsigned char bg ); unsigned char InverseAlphaComp( unsigned char fg, unsigned char alpha, unsigned char bg ); BITMAPINFO InternalCreateBMI( unsigned int dwWidth, /* width */ unsigned int dwHeight, /* height */ unsigned short wBitCount, /* bit count */ int compression ); /* compression type */ void SetLastBMGError( BMGError err ); /* the following 4 functions are for dealing with file formats that store data in big endian format */ short SwapShort( short in ); unsigned short SwapUShort( unsigned short in ); int SwapLong( int in ); unsigned int SwapULong( unsigned int in ); #endif mupen64plus-video-rice-src-2.0/src/liblinux/bmp.c0000644000000000000000000004100112165031100020034 0ustar 00000000000000/* // source code for the ImageLib BMP functions // // Copyright (C) 2001 M. Scott Heiman // All Rights Reserved // // You may use the software for any purpose you see fit. You may modify // it, incorporate it in a commercial application, use it for school, // even turn it in as homework. You must keep the Copyright in the // header and source files. This software is not in the "Public Domain". // You may use this software at your own risk. I have made a reasonable // effort to verify that this software works in the manner I expect it to; // however,... // // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "BMGDLL.h" #include "BMGUtils.h" #include #include #include #ifndef _WIN32 #include #endif // _WIN32 static const unsigned short BMP_ID = 0x4D42; /* ReadBMP - reads the image data from a BMP files and stores it in a BMGImageStruct. Inputs: filename - the name of the file to be opened Outputs: img - the BMGImageStruct containing the image data Returns: BMGError - if the file could not be read or a resource error occurred BMG_OK - if the file was read and the data was stored in img Limitations: will not read BMP files using BI_RLE8, BI_RLE4, or BI_BITFIELDS */ BMGError ReadBMP( const char *filename, struct BMGImageStruct *img ) { FILE *file = NULL; int error; BMGError tmp; unsigned char *p, *q; /*, *q_end; */ /* unsigned int cnt; */ int i; /* int EOBMP; */ BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmih; /* unsigned int mask[3]; */ unsigned int DIBScanWidth; unsigned int bit_size, rawbit_size; unsigned char *rawbits = NULL; SetLastBMGError( BMG_OK ); if ( img == NULL ) { error = (int) errInvalidBMGImage; goto err_jmp; } file = fopen( filename, "rb" ); if ( file == NULL ) { error = (int) errFileOpen; goto err_jmp; } /* read the file header */ if ( fread( (void *)&bmfh, sizeof(BITMAPFILEHEADER), 1, file ) != 1 ) { error = (int) errFileRead; goto err_jmp; } /* confirm that this is a BMP file */ if ( bmfh.bfType != BMP_ID ) { error = (int) errUnsupportedFileFormat; goto err_jmp; } /* read the bitmap info header */ if ( fread( (void *)&bmih, sizeof(BITMAPINFOHEADER), 1, file ) != 1 ) { error = (int) errFileRead; goto err_jmp; } /* abort if this is an unsupported format */ if ( bmih.biCompression != BI_RGB ) { printf("planes: %i bits: %i type: %i ", bmih.biPlanes, bmih.biBitCount, bmih.biCompression); error = (int) errUnsupportedFileFormat; goto err_jmp; } img->bits_per_pixel = (unsigned char)bmih.biBitCount; img->width = bmih.biWidth; img->height = bmih.biHeight; if ( img->bits_per_pixel <= 8 ) { img->palette_size = (unsigned short)bmih.biClrUsed; img->bytes_per_palette_entry = 4U; } tmp = AllocateBMGImage( img ); if ( tmp != BMG_OK ) { error = (int) tmp; goto err_jmp; } /* read palette if necessary */ if ( img->bits_per_pixel <= 8 ) { if ( fread( (void *)img->palette, sizeof(RGBQUAD), img->palette_size, file ) != (unsigned int)img->palette_size ) { error = (int) errFileRead; goto err_jmp; } } /* dimensions */ DIBScanWidth = ( img->bits_per_pixel * img->width + 7 ) / 8; if ( DIBScanWidth %4 ) DIBScanWidth += 4 - DIBScanWidth % 4; bit_size = img->scan_width * img->height; /* allocate memory for the raw bits */ if ( bmih.biCompression != BI_RGB ) rawbit_size = bmfh.bfSize - bmfh.bfOffBits; else rawbit_size = DIBScanWidth * img->height; rawbits = (unsigned char *)calloc( rawbit_size, 1 ); if ( rawbits == NULL ) { error = (int) errMemoryAllocation; goto err_jmp; } if ( fread( (void *)rawbits, sizeof(unsigned char), rawbit_size, file ) != rawbit_size ) { error = (int) errFileRead; goto err_jmp; } if ( bmih.biCompression == BI_RGB ) { p = rawbits; for ( q = img->bits; q < img->bits + bit_size; q += img->scan_width, p += DIBScanWidth ) { memcpy( (void *)q, (void *)p, img->scan_width ); } } /* swap rows if necessary */ if ( bmih.biHeight < 0 ) { for ( i = 0; i < (int)(img->height) / 2; i++ ) { p = img->bits + i * img->scan_width; q = img->bits + ((img->height) - i - 1 ) * img->scan_width; memcpy( (void *)rawbits, (void *)p, img->scan_width ); memcpy( (void *)p, (void *)q, img->scan_width ); memcpy( (void *)q, (void *)rawbits, img->scan_width ); } } fclose( file ); free( rawbits ); return BMG_OK; /* error handler */ err_jmp: if ( file != NULL ) fclose( file ); if ( rawbits != NULL ) free( rawbits ); FreeBMGImage( img ); SetLastBMGError( (BMGError)error ); return (BMGError)error; } /* WriteBMP - writes the contents of an BMGImageStruct to a bmp file. Inputs: filename - the name of the file to be opened img - the BMGImageStruct containing the image data Returns: BMGError - if a write error or a resource error occurred BMG_OK - if the data was successfilly stored in filename Limitations: will not write BMP files using BI_RLE8, BI_RLE4, or BI_BITFIELDS */ BMGError WriteBMP( const char *filename, struct BMGImageStruct img ) { FILE * volatile file = NULL; jmp_buf err_jmp; int error; unsigned char * volatile bits = NULL; unsigned int DIBScanWidth; unsigned int BitsPerPixel; unsigned int bit_size; /*, new_bit_size; */ /* unsigned int rawbit_size; */ unsigned char *p, *q, *r, *t; /* unsigned int cnt; */ unsigned char * volatile pColor = NULL; BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmih; SetLastBMGError( BMG_OK ); /* error handler */ error = setjmp(err_jmp); if (error != 0) { if (file != NULL) fclose(file); if (bits != NULL) free(bits); if (pColor != NULL) free(pColor); SetLastBMGError((BMGError)error); return (BMGError) error; } if ( img.bits == NULL ) longjmp( err_jmp, (int)errInvalidBMGImage ); file = fopen( filename, "wb" ); if ( file == NULL ) longjmp( err_jmp, (int)errFileOpen ); /* abort if we do not support the data */ if ( img.palette != NULL && img.bytes_per_palette_entry < 3 ) longjmp( err_jmp, (int)errInvalidBMGImage ); /* calculate dimensions */ BitsPerPixel = img.bits_per_pixel < 32 ? img.bits_per_pixel : 24U; DIBScanWidth = ( BitsPerPixel * img.width + 7 ) / 8; if ( DIBScanWidth % 4 ) DIBScanWidth += 4 - DIBScanWidth % 4; bit_size = DIBScanWidth * img.height; /* rawbit_size = BITScanWidth * img.height; */ /* allocate memory for bit array - assume that compression will // actually compress the bitmap */ bits = (unsigned char *)calloc( bit_size, 1 ); if ( bits == NULL ) longjmp( err_jmp, (int)errMemoryAllocation ); /* some initialization */ memset( (void *)&bmih, 0, sizeof(BITMAPINFOHEADER) ); bmih.biSize = sizeof(BITMAPINFOHEADER); bmih.biWidth = img.width; bmih.biHeight = img.height; bmih.biPlanes = 1; /* 32-bit images will be stored as 24-bit images to save space. The BMP format does not use the high word and I do not want to store alpha components in an image format that does not recognize it */ bmih.biBitCount = BitsPerPixel; bmih.biCompression = BI_RGB; // assumed bmih.biSizeImage = bit_size; // assumed bmih.biClrUsed = img.palette == NULL ? 0 : img.palette_size; bmih.biClrImportant = img.palette == NULL ? 0 : img.palette_size; /* if we are not compressed then copy the raw bits to bits */ if ( bmih.biCompression == BI_RGB ) { p = img.bits; /* simple memcpy's for images containing < 32-bits per pixel */ if ( img.bits_per_pixel < 32 ) { for ( q = bits; q < bits + bit_size; q += DIBScanWidth, p += img.scan_width ) { memcpy( (void *)q, (void *)p, img.scan_width ); } } /* store 32-bit images as 24-bit images to save space. alpha terms are lost */ else { DIBScanWidth = 3 * img.width; if ( DIBScanWidth % 4 ) DIBScanWidth += 4 - DIBScanWidth % 4; for ( q = bits; q < bits + bit_size; q += DIBScanWidth, p += img.scan_width ) { t = p; for ( r = q; r < q + DIBScanWidth; r += 3, t += 4 ) memcpy( (void *)r, (void *)t, 3 ); } } } /* create the palette if necessary */ if ( img.palette != NULL ) { pColor = (unsigned char *)calloc( img.palette_size, sizeof(RGBQUAD) ); if ( pColor == NULL ) longjmp( err_jmp, (int)errMemoryAllocation ); if ( img.bytes_per_palette_entry == 3 ) { p = img.palette; for ( q = pColor + 1; q < pColor +img.palette_size*sizeof(RGBQUAD); q += sizeof(RGBQUAD), p += 3 ) { memcpy( (void *)pColor, (void *)p, 3 ); } } else /* img.bytes_per_palette_entry == 4 */ { memcpy( (void *)pColor, (void *)img.palette, img.palette_size * sizeof(RGBQUAD) ); } } /* now that we know how big everything is let's write the file */ memset( (void *)&bmfh, 0, sizeof(BITMAPFILEHEADER) ); bmfh.bfType = BMP_ID; bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + img.palette_size * sizeof(RGBQUAD); bmfh.bfSize = bmfh.bfOffBits + bit_size; if ( fwrite( (void *)&bmfh, sizeof(BITMAPFILEHEADER), 1, file ) != 1 ) longjmp( err_jmp, (int)errFileWrite ); if ( fwrite( (void *)&bmih, sizeof(BITMAPINFOHEADER), 1, file ) != 1 ) longjmp( err_jmp, (int)errFileWrite ); if ( pColor != NULL ) { if ( fwrite( (void *)pColor, sizeof(RGBQUAD), img.palette_size, file ) != (unsigned int)img.palette_size ) { longjmp( err_jmp, (int)errFileWrite ); } } if ( fwrite( (void *)bits, sizeof(unsigned char), bit_size, file ) != bit_size ) { longjmp( err_jmp, (int)errFileWrite ); } fclose( file ); free( bits ); if ( pColor != NULL ) free( pColor ); return BMG_OK; } #ifdef _NEVER_DEFINE_THIS_DEF_ /* following code is not tested. I keep it here in case I ever find a BMP file that is compressed and I want to test it */ else if ( bmih.biCompression == BI_RLE8 ) { bmih.biCompression = BI_RGB; bmih.biSizeImage = DIBScanWidth * img.height; p = rawbits; q = img.bits; EOBMP = 1; while ( q < img.bits + bit_size && p < rawbits + rawbit_size && EOBMP ) { cnt = (unsigned int)*p; p++; /* encoded mode */ if ( cnt == 0 ) { cnt = (unsigned int)*p; if ( cnt < 3U ) { p++; /* EOL */ if ( *p == 0 ) p++; /* end of bitmap */ else if ( *p == 1 ) EOBMP = 0; /* delta */ else if ( *p == 2 ) { p++; q += *p; /* columns */ p++; q += (*p)*BITScanWidth; /* rows */ p++; } } /* copy *p duplicates of *(p++) into the bit array */ else { cnt = (unsigned int)*p; p++; q_end = q + cnt; while ( q < q_end ) *q++ = *p; p++; } } /* absolute mode */ else { q_end = q + cnt; while ( q < q_end ) *q++ = *p++; } } } /* if compression is desired && possible then attempt compression. The // following logic will try to compress the data. If the compressed data // requires more space than the uncompressed data then the bits will be // stored in an uncompressed format */ if ( try_compression != 0 && img.bits_per_pixel == 8 ) { p = rawbits; r = bits; new_bit_size = 0; cnt = 0; while ( p < rawbits + rawbit_size && new_bit_size < bit_size ) { q = p; while ( q < p + BITScanWidth ) { t = q; while ( t < q + 255 && t < p + BITScanWidth ) { /* look for non-repeats - absolute mode */ if ( *t != *(t+1) ) { while ( *t != *(t+1) && cnt < 255 && t < p + BITScanWidth ) { t++; cnt++; } cnt++; *r++ = (unsigned char)cnt; memcpy( (void *)r, (void *)q, cnt ); r += cnt; q += cnt; new_bit_size += 1 + cnt; cnt = 0; } /* else look for repeats */ else { while ( *t == *(t+1) && cnt < 255 && t < p + BITScanWidth ) { t++; cnt++; } cnt++; if ( cnt > 2 ) { *r++ = 0; *r++ = (unsigned char)cnt; *r++ = *(t-1); new_bit_size += 3; q = t; cnt = 0; } /* use absolute mode if we have reached the EOL && // cnt <= 2 */ else if ( t >= p + BITScanWidth ) { *r++ = (unsigned char)cnt; memcpy( (void *)r, (void *)q, cnt ); r += cnt; q += cnt; new_bit_size += 1 + cnt; cnt = 0; } } } /* put an EOL marker here */ *r++ = 0; *r++ = 0; new_bit_size += 2; cnt = 0; } p += BITScanWidth; } /* put the EOB marker here */ if ( new_bit_size < bit_size - 2 ) { *r++ = 0; *r = 1; new_bit_size += 2; } else new_bit_size = bit_size + 1; /* if the compressed image will take less space then use it */ if ( new_bit_size < bit_size ) { bmih.biCompression = BI_RLE8; bmih.biSizeImage = bit_size = new_bit_size; } } #endif mupen64plus-video-rice-src-2.0/src/liblinux/jpegrw.h0000644000000000000000000000210212165031100020560 0ustar 00000000000000#ifndef _JPEG_RW_H_ #define _JPEG_RW_H_ /* // header file for the BMGLib JPEG functions // // Copyright 2000, 2001 M. Scott Heiman // All Rights Reserved // libJPEG is Copyright (C) 1991-1998, Thomas G. Lane and is part of the // Independent JPEG Group's software. // // We are releasing this software for both noncommercial and commercial use. // Companies are welcome to use it as the basis for JPEG-related products. // We do not ask a royalty, although we do ask for an acknowledgement in // product literature (see the README file in the distribution for details). // We hope to make this software industrial-quality --- although, as with // anything that's free, we offer no warranty and accept no liability. */ #include "BMGImage.h" #if defined(__cplusplus) extern "C" { #endif extern BMGError ReadJPEG( const char *filename, struct BMGImageStruct *img ); extern BMGError WriteJPEG( const char *filename, struct BMGImageStruct img, int quality ); #if defined(__cplusplus) } #endif #endif mupen64plus-video-rice-src-2.0/src/liblinux/pngrw.c0000644000000000000000000005211512165031100020423 0ustar 00000000000000/* // source code for the ImageLib PNG functions // // Copyright (C) 2001 M. Scott Heiman // All Rights Reserved // // You may use the software for any purpose you see fit. You may modify // it, incorporate it in a commercial application, use it for school, // even turn it in as homework. You must keep the Copyright in the // header and source files. This software is not in the "Public Domain". // You may use this software at your own risk. I have made a reasonable // effort to verify that this software works in the manner I expect it to; // however,... // // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "BMGUtils.h" #include #include #include #ifdef _BMG_LIBPNG_STANDALONE #include "BMGLibPNG.h" #else #include "pngrw.h" #endif #include #ifndef png_jmpbuf # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) #endif /* this stuff is necessary because the normal png_init_io() method crashes in Win32 */ static void user_read_data(png_structp png_read, png_bytep data, png_size_t length) { FILE *fPtr = (FILE *) png_get_io_ptr(png_read); if (fread(data, 1, length, fPtr) != length) fprintf(stderr, "Failed to read %i bytes from PNG file.\n", (int) length); } static void user_write_data(png_structp png_write, png_bytep data, png_size_t length) { FILE *fPtr = (FILE *) png_get_io_ptr(png_write); if (fwrite(data, 1, length, fPtr) != length) fprintf(stderr, "Failed to write %i bytes to PNG file.\n", (int) length); } static void user_flush_data(png_structp png_read) { FILE *fPtr = (FILE *) png_get_io_ptr(png_read); fflush(fPtr); } /* ReadPNG - Reads the contents of a PNG file and stores the contents into BMGImageStruct Inputs: filename - the name of the file to be opened Outputs: img - the BMGImageStruct containing the image data Returns: BMGError - if the file could not be read or a resource error occurred BMG_OK - if the file was read and the data was stored in img Limitations: None. Comments: 2-bit images are converted to 4-bit images. 16-bit images are converted to 8-bit images. gray scale images with alpha components are converted to 32-bit images */ BMGError ReadPNG( const char *filename, struct BMGImageStruct * volatile img ) { jmp_buf err_jmp; int error; FILE * volatile file = NULL; int BitDepth; int ColorType; int InterlaceType; unsigned char signature[8]; png_structp volatile png_ptr = NULL; png_infop volatile info_ptr = NULL; png_infop volatile end_info = NULL; png_color_16 *ImageBackground = NULL; png_bytep trns = NULL; int NumTrans = 0; int i, k; png_color_16p TransColors = NULL; png_uint_32 Width, Height; unsigned char *bits; unsigned char** volatile rows = NULL; BMGError tmp; /* error handler */ error = setjmp( err_jmp ); if (error != 0) { if (end_info != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); else if (info_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL); else if (png_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL); if (rows) { if (rows[0]) free(rows[0]); free(rows); } if (img) FreeBMGImage(img); if (file) fclose(file); SetLastBMGError((BMGError) error); return (BMGError) error; } if ( img == NULL ) longjmp ( err_jmp, (int)errInvalidBMGImage ); file = fopen( filename, "rb" ); if ( !file || fread( signature, 1, 8, file ) != 8) longjmp ( err_jmp, (int)errFileOpen ); /* check the signature */ if ( png_sig_cmp( signature, 0, 8 ) != 0 ) longjmp( err_jmp, (int)errUnsupportedFileFormat ); /* create a pointer to the png read structure */ png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if ( !png_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png info structure */ info_ptr = png_create_info_struct( png_ptr ); if ( !info_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png end-info structure */ end_info = png_create_info_struct(png_ptr); if (!end_info) longjmp( err_jmp, (int)errMemoryAllocation ); /* bamboozle the PNG longjmp buffer */ /*generic PNG error handler*/ /* error will always == 1 which == errLib */ // error = png_setjmp(png_ptr); error = setjmp( png_jmpbuf( png_ptr ) ); if ( error > 0 ) longjmp( err_jmp, error ); /* set function pointers in the PNG library, for read callbacks */ png_set_read_fn(png_ptr, (png_voidp) file, user_read_data); /*let the read functions know that we have already read the 1st 8 bytes */ png_set_sig_bytes( png_ptr, 8 ); /* read all PNG data up to the image data */ png_read_info( png_ptr, info_ptr ); /* extract the data we need to form the HBITMAP from the PNG header */ png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType, &InterlaceType, NULL, NULL); img->width = (unsigned int) Width; img->height = (unsigned int) Height; img->bits_per_pixel = (unsigned char)32; img->scan_width = Width * 4; /* convert 16-bit images to 8-bit images */ if (BitDepth == 16) png_set_strip_16(png_ptr); /* These are not really required per Rice format spec, * but is done just in case someone uses them. */ /* convert palette color to rgb color */ if (ColorType == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); ColorType = PNG_COLOR_TYPE_RGB; } /* expand 1,2,4 bit gray scale to 8 bit gray scale */ if (ColorType == PNG_COLOR_TYPE_GRAY && BitDepth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); /* convert gray scale or gray scale + alpha to rgb color */ if (ColorType == PNG_COLOR_TYPE_GRAY || ColorType == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); ColorType = PNG_COLOR_TYPE_RGB; } /* add alpha channel if any */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); ColorType = PNG_COLOR_TYPE_RGB_ALPHA; } /* convert rgb to rgba */ if (ColorType == PNG_COLOR_TYPE_RGB) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); ColorType = PNG_COLOR_TYPE_RGB_ALPHA; } png_set_bgr(png_ptr); /* set the background color if one is found */ if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD) ) png_get_bKGD(png_ptr, info_ptr, &ImageBackground); /* get the transparent color if one is there */ if ( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) ) png_get_tRNS( png_ptr, info_ptr, &trns, &NumTrans, &TransColors ); img->palette_size = (unsigned short)0; img->bytes_per_palette_entry = 4U; tmp = AllocateBMGImage( img ); if ( tmp != BMG_OK ) longjmp( err_jmp, (int)tmp ); png_read_update_info( png_ptr, info_ptr ); /* create buffer to read data to */ rows = (unsigned char **)malloc(Height*sizeof(unsigned char *)); if ( !rows ) longjmp( err_jmp, (int)errMemoryAllocation ); k = png_get_rowbytes( png_ptr, info_ptr ); rows[0] = (unsigned char *)malloc( Height*k*sizeof(char)); if ( !rows[0] ) longjmp( err_jmp, (int)errMemoryAllocation ); for ( i = 1; i < (int)Height; i++ ) rows[i] = rows[i-1] + k; /* read the entire image into rows */ png_read_image( png_ptr, rows ); bits = img->bits + (Height - 1) * img->scan_width; for ( i = 0; i < (int)Height; i++ ) { memcpy(bits, rows[i], 4*Width); bits -= img->scan_width; } free( rows[0] ); free( rows ); png_read_end( png_ptr, info_ptr ); png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); fclose( file ); return BMG_OK; } BMGError ReadPNGInfo( const char *filename, struct BMGImageStruct * volatile img ) { jmp_buf err_jmp; int error; FILE * volatile file = NULL; int BitDepth; int ColorType; int InterlaceType; unsigned char signature[8]; png_structp volatile png_ptr = NULL; png_infop volatile info_ptr = NULL; png_infop volatile end_info = NULL; png_uint_32 Width, Height; /* error handler */ error = setjmp( err_jmp ); if (error != 0) { if (end_info != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); else if (info_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL); else if (png_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL); if (img) FreeBMGImage(img); if (file) fclose(file); SetLastBMGError((BMGError) error); return (BMGError) error; } if ( img == NULL ) longjmp ( err_jmp, (int)errInvalidBMGImage ); file = fopen( filename, "rb" ); if ( !file || fread( signature, 1, 8, file ) != 8) longjmp ( err_jmp, (int)errFileOpen ); /* check the signature */ if ( png_sig_cmp( signature, 0, 8 ) != 0 ) longjmp( err_jmp, (int)errUnsupportedFileFormat ); /* create a pointer to the png read structure */ png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if ( !png_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png info structure */ info_ptr = png_create_info_struct( png_ptr ); if ( !info_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png end-info structure */ end_info = png_create_info_struct(png_ptr); if (!end_info) longjmp( err_jmp, (int)errMemoryAllocation ); /* bamboozle the PNG longjmp buffer */ /*generic PNG error handler*/ /* error will always == 1 which == errLib */ // error = png_setjmp(png_ptr); error = setjmp( png_jmpbuf( png_ptr ) ); if ( error > 0 ) longjmp( err_jmp, error ); /* set function pointers in the PNG library, for read callbacks */ png_set_read_fn(png_ptr, (png_voidp) file, user_read_data); /*let the read functions know that we have already read the 1st 8 bytes */ png_set_sig_bytes( png_ptr, 8 ); /* read all PNG data up to the image data */ png_read_info( png_ptr, info_ptr ); /* extract the data we need to form the HBITMAP from the PNG header */ png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType, &InterlaceType, NULL, NULL); img->width = (unsigned int) Width; img->height = (unsigned int) Height; img->bits_per_pixel = (unsigned char)32; img->scan_width = Width * 4; img->palette_size = (unsigned short)0; img->bytes_per_palette_entry = 4U; img->bits = NULL; png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); fclose( file ); return BMG_OK; } /* WritePNG - writes the contents of a BMGImageStruct to a PNG file. Inputs: filename - the name of the file to be opened img - the BMGImageStruct containing the image data Returns: 0 - if the file could not be written or a resource error occurred 1 - if the file was written Comments: 16-BPP BMG Images are converted to 24-BPP images Limitations: Color Type is limited to PNG_COLOR_TYPE_GRAY, PNG_COLOR_TYPE_RGB_ALPHA, PNG_COLOR_TYPE_RGB, & PNG_COLOR_TYPE_PALETTE; */ BMGError WritePNG( const char *filename, struct BMGImageStruct img ) { jmp_buf err_jmp; int error = 0; int BitDepth = 0; int ColorType = 0; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_colorp PNGPalette = NULL; unsigned char *bits, *p, *q; unsigned char **rows = NULL; volatile int GrayScale, NumColors; // mark as volatile so GCC won't throw warning with -Wclobbered int DIBScanWidth; FILE *outfile = NULL; int i; BMGError tmp; /* error handler */ error = setjmp( err_jmp ); fprintf(stderr,"Writing PNG file %s.\n", filename); if ( error != 0 ) { if ( png_ptr != NULL ) png_destroy_write_struct( &png_ptr, NULL ); if ( rows ) { if ( rows[0] ) { free( rows[0] ); } free( rows ); } if ( PNGPalette ) free( PNGPalette ); if (outfile) { fclose( outfile ); } SetLastBMGError( (BMGError)error ); return (BMGError)error; } SetLastBMGError( BMG_OK ); /* open the file */ if ((outfile = fopen(filename, "wb")) == NULL) { fprintf(stderr, "Error opening %s for reading.\n", filename); longjmp( err_jmp, (int)errFileOpen ); } /* 16 BPP DIBS do not have palettes. libPNG expects 16 BPP images to have a palette. To correct this situation we must convert 16 BPP images to 24 BPP images before saving the data to the file */ if ( img.bits_per_pixel == 16 ) { tmp = Convert16to24( &img ); if ( tmp != BMG_OK ) longjmp( err_jmp, (int)tmp ); } GrayScale = 0; NumColors = 0; if (img.bits_per_pixel <= 8) // has palette { NumColors = img.palette_size; /* if this is a grayscale image then set the flag and delete the palette*/ i = 0; bits = img.palette; while ( i < NumColors && bits[0] == bits[1] && bits[0] == bits[2] ) { i++; bits += img.bytes_per_palette_entry; } GrayScale = (i == NumColors); } /* dimensions */ DIBScanWidth = ( img.width * img.bits_per_pixel + 7 ) / 8; /* create the png pointer */ png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if ( !png_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create the info pointer */ info_ptr = png_create_info_struct( png_ptr ); if ( !info_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* bamboozle the png error handler */ /* error will always == 1 which equals errLib */ // error = png_setjmp(png_ptr); error = setjmp( png_jmpbuf( png_ptr ) ); if ( error > 0 ) longjmp( err_jmp, error ); /* set function pointers in the PNG library, for write callbacks */ png_set_write_fn(png_ptr, (png_voidp) outfile, user_write_data, user_flush_data); /* prepare variables needed to create PNG header */ BitDepth = img.bits_per_pixel < 8 ? img.bits_per_pixel : 8; /* determine color type */ if ( GrayScale ) ColorType = PNG_COLOR_TYPE_GRAY; else if ( img.bits_per_pixel == 32 ) ColorType = PNG_COLOR_TYPE_RGB_ALPHA; else if ( img.bits_per_pixel == 24 ) ColorType = PNG_COLOR_TYPE_RGB; else ColorType = PNG_COLOR_TYPE_PALETTE; /* create the PNG header */ png_set_IHDR( png_ptr, info_ptr, img.width, img.height, BitDepth, ColorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE ); /* store the palette information if there is any */ if ( img.palette != NULL && !GrayScale ) { PNGPalette = (png_colorp)png_malloc( png_ptr, NumColors*sizeof(png_color)); if ( PNGPalette ) { bits = img.palette; for ( i = 0; i < NumColors; i++, bits += img.bytes_per_palette_entry ) { PNGPalette[i].red = bits[2]; PNGPalette[i].green = bits[1]; PNGPalette[i].blue = bits[0]; } png_set_PLTE( png_ptr, info_ptr, PNGPalette, NumColors ); } else longjmp( err_jmp, (int)errMemoryAllocation ); } /* write the file header information */ png_write_info( png_ptr, info_ptr ); /* create array to store data in */ rows = (unsigned char **)malloc(sizeof(unsigned char*)); if ( !rows ) longjmp( err_jmp, (int)errMemoryAllocation ); rows[0] = (unsigned char *)malloc( DIBScanWidth * sizeof(unsigned char)); if ( !rows[0] ) longjmp( err_jmp, (int)errMemoryAllocation ); /* point to the bottom row of the DIB data. DIBs are stored bottom-to-top, PNGs are stored top-to-bottom. */ bits = img.bits + (img.height - 1) * img.scan_width; /* store bits */ for ( i = 0; i < (int)img.height; i++ ) { switch ( img.bits_per_pixel ) { case 1: case 4: case 8: memcpy( (void *)rows[0], (void *)bits, DIBScanWidth ); break; case 24: q = bits; for ( p = rows[0]; p < rows[0] + DIBScanWidth; p += 3, q += 3 ) { p[0] = q[2]; p[1] = q[1]; p[2] = q[0]; } break; case 32: q = bits; for ( p = rows[0]; p < rows[0] + DIBScanWidth; p += 4, q += 4 ) { p[3] = q[3]; p[0] = q[2]; p[1] = q[1]; p[2] = q[0]; } break; } png_write_rows( png_ptr, rows, 1 ); bits -= img.scan_width; } /* finish writing the rest of the file */ png_write_end( png_ptr, info_ptr ); /* clean up and exit */ if ( PNGPalette ) free( PNGPalette ); free( rows[0] ); free( rows ); png_destroy_write_struct( &png_ptr, NULL ); fclose( outfile ); return BMG_OK; } #ifdef _BMG_LIBPNG_STANDALONE #pragma message ("Creating BMGLibPNG functions") #ifdef _WIN32 /* saves the contents of an HBITMAP to a file. returns 1 if successfull, // 0 otherwise */ BMGError SaveBitmapToPNGFile( HBITMAP hBitmap, /* bitmap to be saved */ const char *filename) /* name of output file */ { struct BMGImageStruct img; char msg[256], ext[4], *period; BMGError out = BMG_OK; InitBMGImage( &img ); /* determine the file type by using the extension */ strcpy( msg, filename ); period = strrchr( msg, '.' ); if ( period != NULL ) { period++; strcpy( ext, period ); ext[0] = toupper( ext[0] ); ext[1] = toupper( ext[1] ); ext[2] = toupper( ext[2] ); ext[3] = 0; } else { strcat( msg, ".PNG" ); strcpy( ext, "PNG" ); } if ( strcmp( ext, "PNG" ) == 0 ) { /* extract data from the bitmap. We assume that 32 bit images have been // blended with the background (unless this is a DDB - see GetDataFromBitmap // for more details) */ out = GetDataFromBitmap( hBitmap, &img, 1 ); if ( out == BMG_OK ) { out = WritePNG( msg, img ); } FreeBMGImage( &img ); } else { out = errInvalidFileExtension; } SetLastBMGError( out ); return out; } #endif // _WIN32 /* Creates an HBITMAP to an image file. returns an HBITMAP if successfull, // NULL otherwise */ HBITMAP CreateBitmapFromPNGFile( const char *filename, int blend ) { char ext[4], msg[256]; char *period; BMGError out = BMG_OK; struct BMGImageStruct img; HBITMAP hBitmap = NULL; InitBMGImage( &img ); img.opt_for_bmp = 1; strcpy( msg, filename ); period = strrchr( msg, '.' ); if ( period != NULL ) { period++; strncpy( ext, period, 3 ); ext[0] = toupper( ext[0] ); ext[1] = toupper( ext[1] ); ext[2] = toupper( ext[2] ); ext[3] = 0; } else { strcat( msg, ".PNG" ); strcpy( ext, "PNG" ); } if ( strcmp( ext, "PNG" ) == 0 ) { out = ReadPNG( msg, &img ); if ( out == BMG_OK ) { hBitmap = CreateBitmapFromData( img, blend ); } FreeBMGImage( &img ); } else { out = errInvalidFileExtension; } SetLastBMGError( out ); return hBitmap; } #endif mupen64plus-video-rice-src-2.0/src/liblinux/pngrw.h0000644000000000000000000000415512165031100020431 0ustar 00000000000000#ifndef _PNG_RW_H_ #define _PNG_RW_H_ /* // header file for the BMGLib PNG functions // // Copyright 2000, 2001 M. Scott Heiman // All Rights Reserved // libPNG is Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. // (libpng versions 0.5, May 1995, through 0.89c, May 1996) // Copyright (c) 1996, 1997 Andreas Dilger // (libpng versions 0.90, December 1996, through 0.96, May 1997) // Copyright (c) 1998, 1999 Glenn Randers-Pehrson // (libpng versions 0.97, January 1998, through 1.0.5, October 15, 1999) // // You may use the software for any purpose you see fit. You may modify // it, incorporate it in a commercial application, use it for school, // even turn it in as homework. You must keep the Copyright in the // header and source files. This software is not in the "Public Domain". // You may use this software at your own risk. I have made a reasonable // effort to verify that this software works in the manner I expect it to; // however,... // // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "BMGImage.h" #if defined(__cplusplus) extern "C" { #endif extern BMGError ReadPNG( const char *filename, struct BMGImageStruct * volatile img ); extern BMGError ReadPNGInfo( const char *filename, struct BMGImageStruct * volatile img ); extern BMGError WritePNG( const char *filename, struct BMGImageStruct img ); #if defined(__cplusplus) } #endif #endif mupen64plus-video-rice-src-2.0/src/liblinux/tiffrw.h0000644000000000000000000000505412165031100020574 0ustar 00000000000000#ifndef _TIFF_RW_H_ #define _TIFF_RW_H_ /* // header file defining BMGLib libTIFF structures and functions // // Copyright 2000, 2001 Scott Heiman // libTIFF is Copyright Sam Leffler and SGI // zLib Copyright (C) 1995-1998 Jean-loup Gailly. // // Permission to use, copy, modify, distribute, and sell this software and // its documentation for any purpose is hereby granted without fee, provided // that (i) the above copyright notices and this permission notice appear in // all copies of the software and related documentation, and (ii) the names of // Sam Leffler and Silicon Graphics may not be used in any advertising or // publicity relating to the software without the specific, prior written // permission of Sam Leffler and Silicon Graphics. // // THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, // EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY // WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. // // IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR // ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, // OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, // WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF // LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE // OF THIS SOFTWARE. */ #include "BMGImage.h" /* enumeration types that support libTIFF */ enum TiffCompressionEnum { NONE, CCITTRLE, CCITTFAX3, CCITTFAX4, LZW, JPEG6, JPEG_DCT, NeXT, CCITTRLEW, MACINTOSH, THUNDERSCAN, PIXARFILM, PIXARLOG, ZIP, KODAK, JBIG }; enum TiffPhotometricEnum { MINISWHITE, MINISBLACK, RGB, PALETTE, MASK, SEPARATED, YCBCR, CIELAB, CIE_LOGL, CIE_LOGLUV }; enum TiffOrientationEnum { TOPLEFT, BOTTOMLEFT }; typedef enum TiffCompressionEnum TiffCompression; typedef enum TiffPhotometricEnum TiffPhotometric; typedef enum TiffOrientationEnum TiffOrientation; #pragma pack(push,1) struct TIFFInfoStruct { TiffCompression compression; TiffPhotometric photometric; TiffOrientation orientation; unsigned short predictor; }; #pragma pack(pop) #if defined(__cplusplus) extern "C" { #endif extern BMGError ReadTIFF( const char *filename, struct BMGImageStruct *img, struct TIFFInfoStruct *info ); extern BMGError WriteTIFF( const char *filename, struct BMGImageStruct img, struct TIFFInfoStruct *info ); #if defined(__cplusplus) } #endif #endif mupen64plus-video-rice-src-2.0/src/osal_dynamiclib.h0000644000000000000000000000344412165031100020577 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal/dynamiclib.h * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if !defined(OSAL_DYNAMICLIB_H) #define OSAL_DYNAMICLIB_H #ifdef __cplusplus extern "C" { #endif #include "m64p_types.h" void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName); #ifdef __cplusplus } #endif #endif /* #define OSAL_DYNAMICLIB_H */ mupen64plus-video-rice-src-2.0/src/osal_dynamiclib_unix.c0000644000000000000000000000347312165031100021637 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal/dynamiclib_unix.c * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include "m64p_types.h" #include "osal_dynamiclib.h" void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName) { if (pccProcedureName == NULL) return NULL; return dlsym(LibHandle, pccProcedureName); } mupen64plus-video-rice-src-2.0/src/osal_dynamiclib_win32.c0000644000000000000000000000616712165031100021621 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-ui-console - osal_dynamiclib_win32.c * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include "m64p_types.h" #include "osal_dynamiclib.h" m64p_error osal_dynlib_open(m64p_dynlib_handle *pLibHandle, const char *pccLibraryPath) { if (pLibHandle == NULL || pccLibraryPath == NULL) return M64ERR_INPUT_ASSERT; *pLibHandle = LoadLibrary(pccLibraryPath); if (*pLibHandle == NULL) { char *pchErrMsg; DWORD dwErr = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL); fprintf(stderr, "LoadLibrary('%s') error: %s\n", pccLibraryPath, pchErrMsg); LocalFree(pchErrMsg); return M64ERR_INPUT_NOT_FOUND; } return M64ERR_SUCCESS; } void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName) { if (pccProcedureName == NULL) return NULL; return GetProcAddress(LibHandle, pccProcedureName); } m64p_error osal_dynlib_close(m64p_dynlib_handle LibHandle) { int rval = FreeLibrary(LibHandle); if (rval == 0) { char *pchErrMsg; DWORD dwErr = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL); fprintf(stderr, "FreeLibrary() error: %s\n", pchErrMsg); LocalFree(pchErrMsg); return M64ERR_INTERNAL; } return M64ERR_SUCCESS; } mupen64plus-video-rice-src-2.0/src/osal_files.h0000644000000000000000000000464312165031100017570 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-ui-console - osal_files.h * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This header file is for all kinds of system-dependent file handling * */ #if !defined(OSAL_FILES_H) #define OSAL_FILES_H #ifdef __cplusplus extern "C" { #endif #include "m64p_types.h" #if defined(WIN32) #define PATH_MAX _MAX_PATH #define OSAL_DIR_SEPARATOR_STR "\\" #define OSAL_DIR_SEPARATOR_CHAR '\\' #define strdup _strdup #else /* Not WIN32 */ #include // for PATH_MAX #define OSAL_DIR_SEPARATOR_STR "/" #define OSAL_DIR_SEPARATOR_CHAR '/' /* PATH_MAX only may be defined by limits.h */ #ifndef PATH_MAX #define PATH_MAX 4096 #endif #endif int osal_is_directory(const char* name); int osal_mkdirp(const char *dirpath, int mode); void * osal_search_dir_open(const char *pathname); const char *osal_search_dir_read_next(void * dir_handle); void osal_search_dir_close(void * dir_handle); #ifdef __cplusplus } #endif #endif /* #define OSAL_FILES_H */ mupen64plus-video-rice-src-2.0/src/osal_files_unix.c0000644000000000000000000000707112165031100020624 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal_files_unix.c * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the definitions for the unix-specific file handling * functions */ #include #include #include #include #include #include #include #include "osal_files.h" /* global functions */ int osal_is_directory(const char* name) { DIR* dir; dir = opendir(name); if(dir != NULL) { closedir(dir); return 1; } return 0; } int osal_mkdirp(const char *dirpath, int mode) { struct stat fileinfo; int dirpathlen = strlen(dirpath); char *currpath = strdup(dirpath); /* first, break the path into pieces by replacing all of the slashes wil NULL chars */ while (strlen(currpath) > 1) { char *lastslash = strrchr(currpath, '/'); if (lastslash == NULL) break; *lastslash = 0; } /* then re-assemble the path from left to right until we get to a directory that doesn't exist */ while (strlen(currpath) < dirpathlen) { if (strlen(currpath) > 0 && stat(currpath, &fileinfo) != 0) break; currpath[strlen(currpath)] = '/'; } /* then walk up the path chain, creating directories along the way */ do { if (stat(currpath, &fileinfo) != 0) { if (mkdir(currpath, mode) != 0) { free(currpath); return 1; /* mkdir failed */ } } if (strlen(currpath) == dirpathlen) break; else currpath[strlen(currpath)] = '/'; } while (1); free(currpath); return 0; } void * osal_search_dir_open(const char *pathname) { DIR *dir; dir = opendir(pathname); return dir; } const char *osal_search_dir_read_next(void * dir_handle) { DIR *dir = (DIR *) dir_handle; struct dirent *entry; entry = readdir(dir); if (entry == NULL) return NULL; return entry->d_name; } void osal_search_dir_close(void * dir_handle) { closedir((DIR *) dir_handle); } mupen64plus-video-rice-src-2.0/src/osal_files_win32.c0000644000000000000000000001156012165031100020601 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal_files_win32.c * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the definitions for the unix-specific file handling * functions */ #include #include #include #include #include #include #include #include "osal_files.h" /* global functions */ int osal_is_directory(const char* name) { char DirName[MAX_PATH + 1]; int namelen = 0; /* we must remove any trailing backslash on the end of the pathname, or this will fail */ strncpy(DirName, name, MAX_PATH); DirName[MAX_PATH] = 0; namelen = strlen(DirName); if (namelen > 0 && DirName[namelen-1] == '\\') DirName[namelen-1] = 0; return (GetFileAttributes(DirName) & FILE_ATTRIBUTE_DIRECTORY); } int osal_mkdirp(const char *dirpath, int mode) { struct _stat fileinfo; size_t dirpathlen = strlen(dirpath); char *currpath = _strdup(dirpath); /* first, remove sub-dirs on the end (by replacing slashes with NULL chars) until we find an existing directory */ while (strlen(currpath) > 1 && _stat(currpath, &fileinfo) != 0) { char *lastslash = strrchr(currpath, '\\'); if (lastslash == NULL) { free(currpath); return 1; /* error: we never found an existing directory, this path is bad */ } *lastslash = 0; } /* then walk up the path chain, creating directories along the way */ do { if (currpath[strlen(currpath)-1] != '\\' && _stat(currpath, &fileinfo) != 0) { if (_mkdir(currpath) != 0) { free(currpath); return 2; /* mkdir failed */ } } if (strlen(currpath) == dirpathlen) break; else currpath[strlen(currpath)] = '\\'; } while (1); free(currpath); return 0; } typedef struct { HANDLE hFind; WIN32_FIND_DATA find_data; } dir_search_info; void * osal_search_dir_open(const char *pathname) { char SearchString[MAX_PATH + 1]; dir_search_info *pInfo = malloc(sizeof(dir_search_info)); if (pInfo == NULL) return NULL; pInfo->hFind = INVALID_HANDLE_VALUE; pInfo->find_data.cFileName[0] = 0; if (pathname[strlen(pathname)-1] == '\\') _snprintf(SearchString, MAX_PATH, "%s*", pathname); else _snprintf(SearchString, MAX_PATH, "%s\\*", pathname); SearchString[MAX_PATH] = 0; pInfo->hFind = FindFirstFile(SearchString, &pInfo->find_data); return (void *) pInfo; } const char *osal_search_dir_read_next(void * search_info) { static char last_filename[_MAX_PATH]; dir_search_info *pInfo = (dir_search_info *) search_info; if (pInfo == NULL || pInfo->hFind == INVALID_HANDLE_VALUE || pInfo->find_data.cFileName[0] == 0) return NULL; strcpy(last_filename, pInfo->find_data.cFileName); if (FindNextFile(pInfo->hFind, &pInfo->find_data) == 0) { pInfo->find_data.cFileName[0] = 0; } return last_filename; } void osal_search_dir_close(void * search_info) { dir_search_info *pInfo = (dir_search_info *) search_info; if (pInfo != NULL) { if (pInfo->hFind != INVALID_HANDLE_VALUE) FindClose(pInfo->hFind); free(pInfo); } } mupen64plus-video-rice-src-2.0/src/osal_opengl.h0000644000000000000000000000716012165031100017747 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - osal_opengl.h * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2013 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if !defined(OSAL_OPENGL_H) #define OSAL_OPENGL_H #include #if SDL_VIDEO_OPENGL #include #define GLSL_VERSION "120" // Extension names #define OSAL_GL_ARB_MULTITEXTURE "GL_ARB_multitexture" #define OSAL_GL_ARB_TEXTURE_ENV_ADD "GL_ARB_texture_env_add" #elif SDL_VIDEO_OPENGL_ES2 #include #define GLSL_VERSION "100" // Extension names #define OSAL_GL_ARB_MULTITEXTURE "GL_multitexture" #define OSAL_GL_ARB_TEXTURE_ENV_ADD "GL_texture_env_add" // Vertex shader params #define VS_POSITION 0 #define VS_COLOR 1 #define VS_TEXCOORD0 2 #define VS_TEXCOORD1 3 // Constant substitutions #define GL_CLAMP GL_CLAMP_TO_EDGE #define GL_MAX_TEXTURE_UNITS_ARB GL_MAX_TEXTURE_IMAGE_UNITS #define GL_MIRRORED_REPEAT_ARB GL_MIRRORED_REPEAT #define GL_TEXTURE0_ARB GL_TEXTURE0 #define GL_TEXTURE1_ARB GL_TEXTURE1 #define GL_TEXTURE2_ARB GL_TEXTURE2 #define GL_TEXTURE3_ARB GL_TEXTURE3 #define GL_TEXTURE4_ARB GL_TEXTURE4 #define GL_TEXTURE5_ARB GL_TEXTURE5 #define GL_TEXTURE6_ARB GL_TEXTURE6 #define GL_TEXTURE7_ARB GL_TEXTURE7 #define GL_ADD 0x0104 #define GL_MODULATE 0x2100 #define GL_INTERPOLATE_ARB 0x8575 #define GL_CONSTANT_ARB 0x8576 #define GL_PREVIOUS_ARB 0x8578 // Function substitutions #define glClearDepth glClearDepthf #define pglActiveTexture glActiveTexture #define pglActiveTextureARB glActiveTexture // No-op substitutions (unavailable in GLES2) #define glLoadIdentity() #define glMatrixMode(x) #define glOrtho(a,b,c,d,e,f) #define glReadBuffer(x) #define glTexEnvi(x,y,z) #define glTexEnvfv(x,y,z) #define glTexCoord2f(u,v) #endif // SDL_VIDEO_OPENGL* #endif // OSAL_OPENGL_H mupen64plus-video-rice-src-2.0/src/osal_preproc.h0000644000000000000000000000603212165031100020132 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - osal_preproc.h * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2009 Richard Goedeken * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* this header file is for system-dependent #defines, #includes, and typedefs */ #if !defined(OSAL_PREPROC_H) #define OSAL_PREPROC_H #if defined(WIN32) #include #if defined(__MINGW32__) #define ALIGN(BYTES,DATA) DATA __attribute__((aligned(BYTES))); #else #define ALIGN(BYTES,DATA) __declspec(align(BYTES)) DATA; #define strncasecmp _strnicmp #define strcasecmp _stricmp #endif #else #define ALIGN(BYTES,DATA) DATA __attribute__((aligned(BYTES))); typedef unsigned int BOOL; typedef void* HBITMAP; typedef struct { int top; int bottom; int right; int left; } RECT; #define __cdecl #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif typedef struct tagBITMAPINFOHEADER { unsigned int biSize; int biWidth; int biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned int biCompression; unsigned int biSizeImage; int biXPelsPerMeter; int biYPelsPerMeter; unsigned int biClrUsed; unsigned int biClrImportant; } __attribute__ ((packed)) BITMAPINFOHEADER; typedef struct tagBITMAPINFO { BITMAPINFOHEADER bmiHeader; unsigned int unused; } BITMAPINFO; typedef struct tagBITMAPFILEHEADER { unsigned short bfType; unsigned int bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned int bfOffBits; } __attribute__ ((packed)) BITMAPFILEHEADER; #define BI_RGB 0 #endif // WIN32 #endif // OSAL_PREPROC_H mupen64plus-video-rice-src-2.0/src/typedefs.h0000644000000000000000000002062112165031100017265 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _TYPEDEFS_H_ #define _TYPEDEFS_H_ #include "osal_preproc.h" #include "VectorMath.h" #define uchar unsigned char #define uint16 unsigned short #define uint32 unsigned int #define uint64 unsigned long long typedef unsigned char uint8; typedef signed char s8; typedef int s32; typedef unsigned int u32; typedef unsigned char u8; typedef unsigned int COLOR; typedef struct _COORDRECT { int x1,y1; int x2,y2; } COORDRECT; #define COLOR_RGBA(r,g,b,a) (((r&0xFF)<<16) | ((g&0xFF)<<8) | ((b&0xFF)<<0) | ((a&0xFF)<<24)) #define SURFFMT_A8R8G8B8 21 #define RGBA_GETALPHA(rgb) ((rgb) >> 24) #define RGBA_GETRED(rgb) (((rgb) >> 16) & 0xff) #define RGBA_GETGREEN(rgb) (((rgb) >> 8) & 0xff) #define RGBA_GETBLUE(rgb) ((rgb) & 0xff) typedef XMATRIX Matrix; typedef void* LPRICETEXTURE ; typedef struct { uint32 dwRGBA, dwRGBACopy; char x,y,z; // Direction uint8 pad; } N64Light; typedef struct { unsigned int dwFormat:3; unsigned int dwSize:2; unsigned int dwWidth:10; uint32 dwAddr; uint32 bpl; } SetImgInfo; typedef struct { // Set by RDP_SetTile unsigned int dwFormat :3; // e.g. RGBA, YUV etc unsigned int dwSize :2; // e.g 4/8/16/32bpp unsigned int dwLine :9; // Ummm... unsigned int dwPalette :4; // 0..15 - a palette index? uint32 dwTMem; // Texture memory location unsigned int bClampS :1; unsigned int bClampT :1; unsigned int bMirrorS :1; unsigned int bMirrorT :1; unsigned int dwMaskS :4; unsigned int dwMaskT :4; unsigned int dwShiftS :4; unsigned int dwShiftT :4; // Set by RDP_SetTileSize int sl; // Upper left S - 8:3 int tl; // Upper Left T - 8:3 int sh; // Lower Right S int th; // Lower Right T int hilite_sl; int hilite_tl; int hilite_sh; int hilite_th; float fsl; // Upper left S - 8:3 float ftl; // Upper Left T - 8:3 float fsh; // Lower Right S float fth; // Lower Right T float fhilite_sl; float fhilite_tl; float fhilite_sh; float fhilite_th; uint32 dwDXT; uint32 dwPitch; uint32 dwWidth; uint32 dwHeight; float fShiftScaleS; float fShiftScaleT; uint32 lastTileCmd; bool bSizeIsValid; bool bForceWrapS; bool bForceWrapT; bool bForceClampS; bool bForceClampT; } Tile; typedef struct { float u; float v; } TexCord; typedef struct VECTOR2 { float x; float y; VECTOR2( float newx, float newy ) {x=newx; y=newy;} VECTOR2() {x=0; y=0;} } VECTOR2; typedef struct { short x; short y; } IVector2; typedef struct { short x; short y; short z; } IVector3; typedef struct { float x,y,z; float rhw; union { COLOR dcDiffuse; struct { uint8 b; uint8 g; uint8 r; uint8 a; }; }; COLOR dcSpecular; TexCord tcord[2]; } TLITVERTEX, *LPTLITVERTEX; typedef struct { float x,y,z; union { COLOR dcDiffuse; struct { uint8 b; uint8 g; uint8 r; uint8 a; }; }; COLOR dcSpecular; TexCord tcord[2]; } UTLITVERTEX, *LPUTLITVERTEX; typedef struct { float x,y,z; float rhw; union { COLOR dcDiffuse; struct { uint8 b; uint8 g; uint8 r; uint8 a; }; }; COLOR dcSpecular; } LITVERTEX, *LPLITVERTEX; typedef struct { float x,y,z; float rhw; COLOR dcDiffuse; } FILLRECTVERTEX, *LPFILLRECTVERTEX; #include "COLOR.h" #include "IColor.h" typedef struct { float x,y,z; float nx,ny,nz; union { COLOR dcDiffuse; struct { uint8 b; uint8 g; uint8 r; uint8 a; }; }; float u,v; }EXTERNAL_VERTEX, *LPSHADERVERTEX; typedef struct { union { struct { float x; float y; float z; float range; // Range == 0 for directional light // Range != 0 for point light, Zelda MM }; }; union { struct { uint8 r; uint8 g; uint8 b; uint8 a; }; uint32 col; }; union { struct { float fr; float fg; float fb; float fa; }; float fcolors[4]; }; union { struct { float tx; float ty; float tz; float tdummy; }; }; union { struct { float ox; float oy; float oz; float odummy; }; }; } Light; typedef struct { char na; char nz; // b char ny; //g char nx; //r }NormalStruct; typedef struct { short y; short x; short flag; short z; short tv; short tu; union { struct { uint8 a; uint8 b; uint8 g; uint8 r; } rgba; NormalStruct norma; }; } FiddledVtx; typedef struct { short y; short x; uint8 a; uint8 b; short z; uint8 g; uint8 r; } FiddledVtxDKR; typedef struct { short y; short x; uint16 cidx; short z; short t; short s; } N64VtxPD; class CTexture; class COGLTexture; class CDirectXTexture; struct TxtrCacheEntry; typedef struct { LPRICETEXTURE m_lpsTexturePtr; union { CTexture * m_pCTexture; CDirectXTexture * m_pCDirectXTexture; COGLTexture * m_pCOGLTexture; }; uint32 m_dwTileWidth; uint32 m_dwTileHeight; float m_fTexWidth; float m_fTexHeight; // Float to avoid converts when processing verts TxtrCacheEntry *pTextureEntry; } RenderTexture; typedef struct { unsigned int dwFormat; unsigned int dwSize; unsigned int dwWidth; unsigned int dwAddr; unsigned int dwLastWidth; unsigned int dwLastHeight; unsigned int dwHeight; unsigned int dwMemSize; bool bCopied; unsigned int dwCopiedAtFrame; unsigned int dwCRC; unsigned int lastUsedFrame; unsigned int bUsedByVIAtFrame; unsigned int lastSetAtUcode; } RecentCIInfo; typedef struct { uint32 addr; uint32 FrameCount; } RecentViOriginInfo; typedef enum { SHADE_DISABLED, SHADE_FLAT, SHADE_SMOOTH, } RenderShadeMode; typedef enum { TEXTURE_UV_FLAG_WRAP, TEXTURE_UV_FLAG_MIRROR, TEXTURE_UV_FLAG_CLAMP, } TextureUVFlag; typedef struct { TextureUVFlag N64flag; uint32 realFlag; } UVFlagMap; typedef enum { FILTER_POINT, FILTER_LINEAR, } TextureFilter; typedef struct { TextureFilter N64filter; uint32 realFilter; } TextureFilterMap; typedef struct { const char* description; int number; uint32 setting; } BufferSettingInfo; typedef struct { const char* description; uint32 setting; } SettingInfo; typedef union { uint8 g_Tmem8bit[0x1000]; short g_Tmem16bit[0x800]; uint32 g_Tmem32bit[0x300]; uint64 g_Tmem64bit[0x200]; } TmemType; typedef struct { uint32 dwFormat; uint32 dwSize; BOOL bSetBy; uint32 dwLoadAddress; uint32 dwTotalWords; uint32 dxt; BOOL bSwapped; uint32 dwWidth; uint32 dwLine; int sl; int sh; int tl; int th; uint32 dwTmem; } TMEMLoadMapInfo; #endif mupen64plus-video-rice-src-2.0/src/ucode.h0000644000000000000000000011040012165031100016534 0ustar 00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "UcodeDefs.h" #ifndef _UCODE_H_ #define _UCODE_H_ //typedef void (*RDPInstruction)(Gfx *gfx); typedef void (*RDPInstruction)(Gfx*); extern RDPInstruction *currentUcodeMap; typedef RDPInstruction UcodeMap[256] ; //#define UcodeFunc(name) void name(uint32, uint32) #define UcodeFunc(name) void name(Gfx*) UcodeFunc(RSP_RDP_Nothing); UcodeFunc(RSP_GBI0_Mtx); UcodeFunc(RSP_Mtx_DKR); UcodeFunc(RSP_GBI0_DL); UcodeFunc(RSP_DL_In_MEM_DKR); UcodeFunc(RSP_GBI0_Vtx); UcodeFunc(RSP_Vtx_DKR); UcodeFunc(RSP_Vtx_WRUS); UcodeFunc(RSP_Vtx_ShadowOfEmpire); UcodeFunc(RSP_GBI0_Tri4); UcodeFunc(RSP_DMA_Tri_DKR); UcodeFunc(DLParser_Set_Addr_Ucode6); UcodeFunc(RSP_MoveWord_DKR); UcodeFunc(RSP_Vtx_PD); UcodeFunc(RSP_Set_Vtx_CI_PD); UcodeFunc(RSP_Tri4_PD); UcodeFunc(RSP_GBI0_Sprite2DBase); UcodeFunc(RSP_GBI0_Sprite2DDraw); UcodeFunc(RSP_GBI1_Sprite2DBase); UcodeFunc(RSP_GBI1_Sprite2DScaleFlip); UcodeFunc(RSP_GBI1_Sprite2DDraw); UcodeFunc(RSP_GBI_Sprite2DBase); UcodeFunc(RSP_GBI_Sprite2D_PuzzleMaster64); UcodeFunc(RSP_GBI1_SpNoop); UcodeFunc(RSP_GBI1_Reserved); UcodeFunc(RSP_GBI1_Vtx); UcodeFunc(RSP_GBI1_MoveMem); UcodeFunc(RSP_GBI1_RDPHalf_Cont); UcodeFunc(RSP_GBI1_RDPHalf_2); UcodeFunc(RSP_GBI1_RDPHalf_1); UcodeFunc(RSP_GBI1_Line3D); UcodeFunc(RSP_GBI1_ClearGeometryMode); UcodeFunc(RSP_GBI1_SetGeometryMode); UcodeFunc(RSP_GBI1_EndDL); UcodeFunc(RSP_GBI1_SetOtherModeL); UcodeFunc(RSP_GBI1_SetOtherModeH); UcodeFunc(RSP_GBI1_Texture); UcodeFunc(RSP_GBI1_MoveWord); UcodeFunc(RSP_GBI1_PopMtx); UcodeFunc(RSP_GBI1_CullDL); UcodeFunc(RSP_GBI1_Tri1); UcodeFunc(RSP_GBI1_Tri2); UcodeFunc(RSP_GBI1_Noop); UcodeFunc(RSP_GBI1_ModifyVtx); UcodeFunc(RSP_GBI1_BranchZ); UcodeFunc(RSP_GBI1_LoadUCode); UcodeFunc(DLParser_TexRect); UcodeFunc(DLParser_TexRectFlip); UcodeFunc(DLParser_RDPLoadSync); UcodeFunc(DLParser_RDPPipeSync); UcodeFunc(DLParser_RDPTileSync); UcodeFunc(DLParser_RDPFullSync); UcodeFunc(DLParser_SetKeyGB); UcodeFunc(DLParser_SetKeyR); UcodeFunc(DLParser_SetConvert); UcodeFunc(DLParser_SetScissor); UcodeFunc(DLParser_SetPrimDepth); UcodeFunc(DLParser_RDPSetOtherMode); UcodeFunc(DLParser_LoadTLut); UcodeFunc(DLParser_SetTileSize); UcodeFunc(DLParser_LoadBlock); UcodeFunc(DLParser_LoadTile); UcodeFunc(DLParser_SetTile); UcodeFunc(DLParser_FillRect); UcodeFunc(DLParser_SetFillColor); UcodeFunc(DLParser_SetFogColor); UcodeFunc(DLParser_SetBlendColor); UcodeFunc(DLParser_SetPrimColor); UcodeFunc(DLParser_SetEnvColor); UcodeFunc(DLParser_SetCombine); UcodeFunc(DLParser_SetTImg); UcodeFunc(DLParser_SetZImg); UcodeFunc(DLParser_SetCImg); UcodeFunc(RSP_GBI2_DL); UcodeFunc(RSP_GBI2_CullDL); UcodeFunc(RSP_GBI2_EndDL); UcodeFunc(RSP_GBI2_MoveWord); UcodeFunc(RSP_GBI2_Texture); UcodeFunc(RSP_GBI2_GeometryMode); UcodeFunc(RSP_GBI2_SetOtherModeL); UcodeFunc(RSP_GBI2_SetOtherModeH); UcodeFunc(RSP_GBI2_MoveMem); UcodeFunc(RSP_GBI2_Mtx); UcodeFunc(RSP_GBI2_PopMtx); UcodeFunc(RSP_GBI2_Vtx); UcodeFunc(RSP_GBI2_Tri1); UcodeFunc(RSP_GBI2_Tri2); UcodeFunc(RSP_GBI2_Line3D); UcodeFunc(RSP_GBI2_DL_Count); UcodeFunc(RSP_GBI2_SubModule); UcodeFunc(RSP_GBI2_0x8); UcodeFunc(DLParser_Bomberman2TextRect); UcodeFunc(RSP_S2DEX_BG_1CYC_2); UcodeFunc(RSP_S2DEX_OBJ_RENDERMODE_2); UcodeFunc(RSP_S2DEX_SPObjLoadTxtr_Ucode1); UcodeFunc( RSP_S2DEX_BG_1CYC); UcodeFunc( RSP_S2DEX_BG_COPY); UcodeFunc( RSP_S2DEX_OBJ_RECTANGLE); UcodeFunc( RSP_S2DEX_OBJ_SPRITE); UcodeFunc( RSP_S2DEX_OBJ_MOVEMEM); UcodeFunc( RSP_S2DEX_SELECT_DL); UcodeFunc( RSP_S2DEX_OBJ_RENDERMODE); UcodeFunc( RSP_S2DEX_OBJ_RECTANGLE_R); UcodeFunc( RSP_S2DEX_SPObjLoadTxtr); UcodeFunc( RSP_S2DEX_SPObjLoadTxSprite); UcodeFunc( RSP_S2DEX_SPObjLoadTxRect); UcodeFunc( RSP_S2DEX_SPObjLoadTxRectR); UcodeFunc( RSP_S2DEX_RDPHALF_0); UcodeFunc( RSP_S2DEX_Yoshi_Unknown); UcodeFunc( RSP_RDP_InsertMatrix ); UcodeFunc( RSP_S2DEX_SPObjLoadTxtr ); UcodeFunc(RDP_TriFill); UcodeFunc(RDP_TriFillZ); UcodeFunc(RDP_TriTxtr); UcodeFunc(RDP_TriTxtrZ); UcodeFunc(RDP_TriShade); UcodeFunc(RDP_TriShadeZ); UcodeFunc(RDP_TriShadeTxtr); UcodeFunc(RDP_TriShadeTxtrZ); #ifdef DEBUGGER const char* ucodeNames_GBI1[256] = { "RSP_SPNOOP", "RSP_MTX", "Reserved0", "RSP_MOVEMEM", "RSP_VTX", "Reserved1", "RSP_DL", "Reserved2", "RSP_RESERVED3", "RSP_SPRITE2D", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //10 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //20 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //30 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //40 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //50 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //60 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //70 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //80 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //90 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //A0 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "RSP_LOAD_UCODE", //B0 "RSP_BRANCH_Z", "RSP_TRI2", "G_MODIFY_VERTEX", "RSP_RDPHALF_2", "RSP_RDPHALF_1", "RSP_LINE3D", "RSP_CLEARGEOMETRYMODE", "RSP_SETGEOMETRYMODE", "RSP_ENDDL", "RSP_SETOTHERMODE_L", "RSP_SETOTHERMODE_H", "RSP_TEXTURE", "RSP_MOVEWORD", "RSP_POPMTX", "RSP_CULLDL", "RSP_TRI1", //C0 "RDP_NOOP", "G_NOTHING", "G_YS_UNK1", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "RDP_TriFill", "RDP_TriFillZ", "RDP_TriTxtr", "RDP_TriTxtrZ", "RDP_TriShade", "RDP_TriShadeZ", "RDP_TriShadeTxtr", "RDP_TriShadeTxtrZ", //D0 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //E0 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "RDP_TEXRECT", "RDP_TEXRECT_FLIP", "RDP_LOADSYNC", "RDP_PIPESYNC", "RDP_TILESYNC", "RDP_FULLSYNC", "RDP_SETKEYGB", "RDP_SETKEYR", "RDP_SETCONVERT", "RDP_SETSCISSOR", "RDP_SETPRIMDEPTH", "RDP_RDPSETOTHERMODE", //F0 "RDP_LOADTLUT", "G_NOTHING", "RDP_SETTILESIZE", "RDP_LOADBLOCK", "RDP_LOADTILE", "RDP_SETTILE", "RDP_FILLRECT", "RDP_SETFILLCOLOR", "RDP_SETFOGCOLOR", "RDP_SETBLENDCOLOR", "RDP_SETPRIMCOLOR", "RDP_SETENVCOLOR", "RDP_SETCOMBINE", "RDP_SETTIMG", "RDP_SETZIMG", "RDP_SETCIMG" }; const char* ucodeNames_GBI2[256] = { "NOOP", "GBI2_Vtx", "ModifyVtx", "GBI2_CullDL", "BranchZ", "GBI2_Tri1", "GBI2_Tri2","GBI2_Line3D", "Nothing", "ObjBG1CYC", "ObjBGCopy", "OBJ_RenderMode", "Nothing", "Nothing", "Nothing", "Nothing", //10 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //20 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //30 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //40 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //50 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //60 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //70 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //80 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //90 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //a0 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Load_Ucode", //b0 "BranchZ", "Tri2_Goldeneye", "ModifyVtx", "RDPHalf_2", "RDPHalf_1", "Line3D", "ClearGeometryMode", "SetGeometryMode", "EndDL", "SetOtherMode_L", "SetOtherMode_H", "Texture", "MoveWord", "PopMtx", "CullDL", "Tri1", //c0 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "RDP_TriFill", "RDP_TriFillZ", "RDP_TriTxtr", "RDP_TriTxtrZ", "RDP_TriShade", "RDP_TriShadeZ", "RDP_TriShadeTxtr", "RDP_TriShadeTxtrZ", //d0 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "GBI2_DL_N", "GBI2_SubModule", "GBI2_Texture", "GBI2_PopMtx", "GBI2_SetGeometryMode", "GBI2_Mtx", "GBI2_MoveWord", "GBI2_MoveMem", "Load_Ucode", "GBI2_DL", "GBI2_EndDL", //e0 "SPNOOP", "RDPHalf_1", "GBI2_SetOtherMode_L", "GBI2_SetOtherMode_H", "TexRect", "TexRectFlip", "RDPLoadSync", "RDPPipeSync", "RDPTileSync", "RDPFullSync", "SetKeyGB", "SetKeyR", "SetConvert", "SetScissor", "SetPrimDepth", "RDPSetOtherMode", //f0 "LoadTLut", "Nothing", "SetTileSize", "LoadBlock", "LoadTile", "SetTile", "FillRect", "SetFillColor", "SetFogColor", "SetBlendColor", "SetPrimColor", "SetEnvColor", "SetCombine", "SetTImg", "SetZImg", "SetCImg", }; #endif typedef RDPInstruction UcodeMap[256] ; // Ucode: F3DEX, for most games UcodeMap ucodeMap1 = { RSP_GBI1_SpNoop, RSP_GBI0_Mtx, RSP_GBI1_Reserved, RSP_GBI1_MoveMem, RSP_GBI1_Vtx, RSP_GBI1_Reserved, RSP_GBI0_DL, RSP_GBI1_Reserved, RSP_GBI1_Reserved, RSP_GBI1_Sprite2DBase, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //10 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //20 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //30 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //40 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //50 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //60 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //70 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //80 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //90 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //a0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_GBI1_LoadUCode, //b0 RSP_GBI1_BranchZ, RSP_GBI1_Tri2, RSP_GBI1_ModifyVtx, RSP_GBI1_RDPHalf_2, RSP_GBI1_RDPHalf_1, RSP_GBI1_Line3D, RSP_GBI1_ClearGeometryMode, RSP_GBI1_SetGeometryMode, RSP_GBI1_EndDL, RSP_GBI1_SetOtherModeL, RSP_GBI1_SetOtherModeH, RSP_GBI1_Texture, RSP_GBI1_MoveWord, RSP_GBI1_PopMtx, RSP_GBI1_CullDL, RSP_GBI1_Tri1, //c0 RSP_GBI1_Noop, RSP_S2DEX_SPObjLoadTxtr_Ucode1, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RDP_TriFill, RDP_TriFillZ, RDP_TriTxtr, RDP_TriTxtrZ, RDP_TriShade, RDP_TriShadeZ, RDP_TriShadeTxtr, RDP_TriShadeTxtrZ, //d0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //e0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, DLParser_TexRect, DLParser_TexRectFlip, DLParser_RDPLoadSync, DLParser_RDPPipeSync, DLParser_RDPTileSync, DLParser_RDPFullSync, DLParser_SetKeyGB, DLParser_SetKeyR, DLParser_SetConvert, DLParser_SetScissor, DLParser_SetPrimDepth, DLParser_RDPSetOtherMode, //f0 DLParser_LoadTLut, RSP_RDP_Nothing, DLParser_SetTileSize, DLParser_LoadBlock, DLParser_LoadTile, DLParser_SetTile, DLParser_FillRect, DLParser_SetFillColor, DLParser_SetFogColor, DLParser_SetBlendColor, DLParser_SetPrimColor, DLParser_SetEnvColor, DLParser_SetCombine, DLParser_SetTImg, DLParser_SetZImg, DLParser_SetCImg }; UcodeMap ucodeMap0= { RSP_GBI1_SpNoop, RSP_GBI0_Mtx, RSP_GBI1_Reserved, RSP_GBI1_MoveMem, RSP_GBI0_Vtx, RSP_GBI1_Reserved, RSP_GBI0_DL, RSP_GBI1_Reserved, RSP_GBI1_Reserved, RSP_GBI0_Sprite2DBase, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //10 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //20 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //30 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //40 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //50 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //60 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //70 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //80 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //90 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //a0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //b0 RSP_RDP_Nothing, RSP_GBI0_Tri4, RSP_GBI1_RDPHalf_Cont, RSP_GBI1_RDPHalf_2, RSP_GBI1_RDPHalf_1, RSP_GBI1_Line3D, RSP_GBI1_ClearGeometryMode, RSP_GBI1_SetGeometryMode, RSP_GBI1_EndDL, RSP_GBI1_SetOtherModeL, RSP_GBI1_SetOtherModeH, RSP_GBI1_Texture, RSP_GBI1_MoveWord, RSP_GBI1_PopMtx, RSP_GBI1_CullDL, RSP_GBI1_Tri1, //c0 RSP_GBI1_Noop, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RDP_TriFill, RDP_TriFillZ, RDP_TriTxtr, RDP_TriTxtrZ, RDP_TriShade, RDP_TriShadeZ, RDP_TriShadeTxtr, RDP_TriShadeTxtrZ, //d0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //e0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, DLParser_TexRect, DLParser_TexRectFlip, DLParser_RDPLoadSync, DLParser_RDPPipeSync, DLParser_RDPTileSync, DLParser_RDPFullSync, DLParser_SetKeyGB, DLParser_SetKeyR, DLParser_SetConvert, DLParser_SetScissor, DLParser_SetPrimDepth, DLParser_RDPSetOtherMode, //f0 DLParser_LoadTLut, RSP_RDP_Nothing, DLParser_SetTileSize, DLParser_LoadBlock, DLParser_LoadTile, DLParser_SetTile, DLParser_FillRect, DLParser_SetFillColor, DLParser_SetFogColor, DLParser_SetBlendColor, DLParser_SetPrimColor, DLParser_SetEnvColor, DLParser_SetCombine, DLParser_SetTImg, DLParser_SetZImg, DLParser_SetCImg }; // Zelda and new games, F3DEX_GBI_2 UcodeMap ucodeMap5= { RSP_GBI1_Noop, RSP_GBI2_Vtx, RSP_GBI1_ModifyVtx, RSP_GBI2_CullDL, RSP_GBI1_BranchZ, RSP_GBI2_Tri1, RSP_GBI2_Tri2, RSP_GBI2_Line3D, RSP_GBI2_0x8, RSP_S2DEX_BG_1CYC, RSP_S2DEX_BG_COPY, RSP_S2DEX_OBJ_RENDERMODE, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //10 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //20 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //30 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //40 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //50 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //60 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //70 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //80 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //90 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //a0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_GBI1_LoadUCode, //b0 RSP_GBI1_BranchZ, RSP_GBI0_Tri4, RSP_GBI1_ModifyVtx, RSP_GBI1_RDPHalf_2, RSP_GBI1_RDPHalf_1, RSP_GBI1_Line3D, RSP_GBI1_ClearGeometryMode, RSP_GBI1_SetGeometryMode, RSP_GBI1_EndDL, RSP_GBI1_SetOtherModeL, RSP_GBI1_SetOtherModeH, RSP_GBI1_Texture, RSP_GBI1_MoveWord, RSP_GBI1_PopMtx, RSP_GBI1_CullDL, RSP_GBI1_Tri1, //c0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RDP_TriFill, RDP_TriFillZ, RDP_TriTxtr, RDP_TriTxtrZ, RDP_TriShade, RDP_TriShadeZ, RDP_TriShadeTxtr, RDP_TriShadeTxtrZ, //d0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_GBI2_DL_Count, RSP_GBI2_SubModule, RSP_GBI2_Texture, RSP_GBI2_PopMtx, RSP_GBI2_GeometryMode, RSP_GBI2_Mtx, RSP_GBI2_MoveWord, RSP_GBI2_MoveMem, RSP_GBI1_LoadUCode, RSP_GBI2_DL, RSP_GBI2_EndDL, //e0 RSP_GBI1_SpNoop, RSP_GBI1_RDPHalf_1, RSP_GBI2_SetOtherModeL, RSP_GBI2_SetOtherModeH, DLParser_TexRect, DLParser_TexRectFlip, DLParser_RDPLoadSync, DLParser_RDPPipeSync, DLParser_RDPTileSync, DLParser_RDPFullSync, DLParser_SetKeyGB, DLParser_SetKeyR, DLParser_SetConvert, DLParser_SetScissor, DLParser_SetPrimDepth, DLParser_RDPSetOtherMode, //f0 DLParser_LoadTLut, RSP_RDP_Nothing, DLParser_SetTileSize, DLParser_LoadBlock, DLParser_LoadTile, DLParser_SetTile, DLParser_FillRect, DLParser_SetFillColor, DLParser_SetFogColor, DLParser_SetBlendColor, DLParser_SetPrimColor, DLParser_SetEnvColor, DLParser_SetCombine, DLParser_SetTImg, DLParser_SetZImg, DLParser_SetCImg }; // S2DEX 1.-- UcodeMap ucodeMap7= { RSP_GBI1_SpNoop, RSP_S2DEX_BG_1CYC_2, RSP_S2DEX_BG_COPY, RSP_S2DEX_OBJ_RECTANGLE, RSP_S2DEX_OBJ_SPRITE, RSP_S2DEX_OBJ_MOVEMEM, RSP_GBI0_DL, RSP_GBI1_Reserved, RSP_GBI1_Reserved, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //10 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //20 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //30 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //40 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //50 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //60 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //70 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //80 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //90 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //a0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_GBI1_LoadUCode, //b0 RSP_S2DEX_SELECT_DL, RSP_S2DEX_OBJ_RENDERMODE_2, RSP_S2DEX_OBJ_RECTANGLE_R, RSP_GBI1_RDPHalf_2, RSP_GBI1_RDPHalf_1, RSP_GBI1_Line3D, RSP_GBI1_ClearGeometryMode, RSP_GBI1_SetGeometryMode, RSP_GBI1_EndDL, RSP_GBI1_SetOtherModeL, RSP_GBI1_SetOtherModeH, RSP_GBI1_Texture, RSP_GBI1_MoveWord, RSP_GBI1_PopMtx, RSP_GBI1_CullDL, RSP_GBI1_Tri1, //c0 RSP_GBI1_Noop, RSP_S2DEX_SPObjLoadTxtr, RSP_S2DEX_SPObjLoadTxSprite, RSP_S2DEX_SPObjLoadTxRect, RSP_S2DEX_SPObjLoadTxRectR, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RDP_TriFill, RDP_TriFillZ, RDP_TriTxtr, RDP_TriTxtrZ, RDP_TriShade, RDP_TriShadeZ, RDP_TriShadeTxtr, RDP_TriShadeTxtrZ, //d0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //e0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_S2DEX_RDPHALF_0, DLParser_TexRectFlip, DLParser_RDPLoadSync, DLParser_RDPPipeSync, DLParser_RDPTileSync, DLParser_RDPFullSync, DLParser_SetKeyGB, DLParser_SetKeyR, DLParser_SetConvert, DLParser_SetScissor, DLParser_SetPrimDepth, DLParser_RDPSetOtherMode, //f0 DLParser_LoadTLut, RSP_RDP_Nothing, DLParser_SetTileSize, DLParser_LoadBlock, DLParser_LoadTile, DLParser_SetTile, DLParser_FillRect, DLParser_SetFillColor, DLParser_SetFogColor, DLParser_SetBlendColor, DLParser_SetPrimColor, DLParser_SetEnvColor, DLParser_SetCombine, DLParser_SetTImg, DLParser_SetZImg, DLParser_SetCImg }; // Ucode 3 - S2DEX GBI2 UcodeMap ucodeMap3= { RSP_GBI1_Noop, RSP_S2DEX_OBJ_RECTANGLE, RSP_S2DEX_OBJ_SPRITE, RSP_GBI2_CullDL, RSP_S2DEX_SELECT_DL, RSP_S2DEX_SPObjLoadTxtr, RSP_S2DEX_SPObjLoadTxSprite, RSP_S2DEX_SPObjLoadTxRect, RSP_S2DEX_SPObjLoadTxRectR, RSP_S2DEX_BG_1CYC, RSP_S2DEX_BG_COPY, RSP_S2DEX_OBJ_RENDERMODE, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //10 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //20 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //30 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //40 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //50 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //60 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //70 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //80 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //90 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //a0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_GBI1_LoadUCode, //b0 RSP_GBI1_BranchZ, RSP_GBI0_Tri4, RSP_GBI1_ModifyVtx, RSP_GBI1_RDPHalf_2, RSP_GBI1_RDPHalf_1, RSP_GBI1_Line3D, RSP_GBI1_ClearGeometryMode, RSP_GBI1_SetGeometryMode, RSP_GBI1_EndDL, RSP_GBI1_SetOtherModeL, RSP_GBI1_SetOtherModeH, RSP_GBI1_Texture, RSP_GBI1_MoveWord, RSP_GBI1_PopMtx, RSP_GBI1_CullDL, RSP_GBI1_Tri1, //c0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RDP_TriFill, RDP_TriFillZ, RDP_TriTxtr, RDP_TriTxtrZ, RDP_TriShade, RDP_TriShadeZ, RDP_TriShadeTxtr, RDP_TriShadeTxtrZ, //d0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_GBI2_DL_Count, RSP_GBI2_SubModule, RSP_GBI2_Texture, RSP_GBI2_PopMtx, RSP_GBI2_GeometryMode, RSP_GBI2_Mtx, RSP_GBI2_MoveWord, RSP_GBI2_MoveMem, RSP_GBI1_LoadUCode, RSP_GBI2_DL, RSP_GBI2_EndDL, //e0 RSP_GBI1_SpNoop, RSP_GBI1_RDPHalf_1, RSP_GBI2_SetOtherModeL, RSP_GBI2_SetOtherModeH, DLParser_TexRect, DLParser_TexRectFlip, DLParser_RDPLoadSync, DLParser_RDPPipeSync, DLParser_RDPTileSync, DLParser_RDPFullSync, DLParser_SetKeyGB, DLParser_SetKeyR, DLParser_SetConvert, DLParser_SetScissor, DLParser_SetPrimDepth, DLParser_RDPSetOtherMode, //f0 DLParser_LoadTLut, RSP_RDP_Nothing, DLParser_SetTileSize, DLParser_LoadBlock, DLParser_LoadTile, DLParser_SetTile, DLParser_FillRect, DLParser_SetFillColor, DLParser_SetFogColor, DLParser_SetBlendColor, DLParser_SetPrimColor, DLParser_SetEnvColor, DLParser_SetCombine, DLParser_SetTImg, DLParser_SetZImg, DLParser_SetCImg }; RDPInstruction *currentUcodeMap = ucodeMap1; #endif mupen64plus-video-rice-src-2.0/src/version.h0000644000000000000000000000372012165031100017130 0ustar 00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-video-rice - version.h * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2009-2011 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This header file is for versioning information * */ #if !defined(VERSION_H) #define VERSION_H #define PLUGIN_NAME "Mupen64Plus OpenGL Video Plugin by Rice" #define PLUGIN_VERSION 0x020000 #define VIDEO_PLUGIN_API_VERSION 0x020200 #define CONFIG_API_VERSION 0x020000 #define VIDEXT_API_VERSION 0x030000 #define VERSION_PRINTF_SPLIT(x) (((x) >> 16) & 0xffff), (((x) >> 8) & 0xff), ((x) & 0xff) #endif /* #define VERSION_H */ mupen64plus-video-rice-src-2.0/src/video_api_export.ver0000644000000000000000000000046612165031100021354 0ustar 00000000000000{ global: PluginStartup; PluginShutdown; PluginGetVersion; ChangeWindow; InitiateGFX; MoveScreen; ProcessDList; ProcessRDPList; RomClosed; RomOpen; ShowCFB; UpdateScreen; ViStatusChanged; ViWidthChanged; ReadScreen2; SetRenderingCallback; ResizeVideoOutput; FBRead; FBWrite; FBGetFrameBufferInfo; local: *; };