Rice GLES2 (from mupen64plus-ae) plugin. Compile but doesn't works well on the OpenPa...
authorptitSeb <sebastien.chev@gmail.com>
Tue, 24 Sep 2013 19:44:14 +0000 (21:44 +0200)
committerptitSeb <sebastien.chev@gmail.com>
Tue, 24 Sep 2013 19:44:14 +0000 (21:44 +0200)
128 files changed:
source/gles2rice/.hgignore [new file with mode: 0644]
source/gles2rice/INSTALL [new file with mode: 0644]
source/gles2rice/LICENSES [new file with mode: 0644]
source/gles2rice/README [new file with mode: 0644]
source/gles2rice/RELEASE [new file with mode: 0644]
source/gles2rice/data/RiceVideoLinux.ini [new file with mode: 0644]
source/gles2rice/projects/android/Android.mk [new file with mode: 0644]
source/gles2rice/projects/msvc11/mupen64plus-video-rice.vcxproj [new file with mode: 0644]
source/gles2rice/projects/msvc8/mupen64plus-video-rice.vcproj [new file with mode: 0644]
source/gles2rice/projects/unix/Makefile [new file with mode: 0755]
source/gles2rice/src/Blender.cpp [new file with mode: 0644]
source/gles2rice/src/Blender.h [new file with mode: 0644]
source/gles2rice/src/CNvTNTCombiner.cpp [new file with mode: 0644]
source/gles2rice/src/CNvTNTCombiner.h [new file with mode: 0644]
source/gles2rice/src/COLOR.h [new file with mode: 0644]
source/gles2rice/src/CSortedList.h [new file with mode: 0644]
source/gles2rice/src/Combiner.cpp [new file with mode: 0644]
source/gles2rice/src/Combiner.h [new file with mode: 0644]
source/gles2rice/src/CombinerDefs.h [new file with mode: 0644]
source/gles2rice/src/CombinerTable.cpp [new file with mode: 0644]
source/gles2rice/src/Config.cpp [new file with mode: 0644]
source/gles2rice/src/Config.h [new file with mode: 0644]
source/gles2rice/src/ConvertImage.cpp [new file with mode: 0644]
source/gles2rice/src/ConvertImage.h [new file with mode: 0644]
source/gles2rice/src/ConvertImage16.cpp [new file with mode: 0644]
source/gles2rice/src/CritSect.h [new file with mode: 0644]
source/gles2rice/src/Debugger.cpp [new file with mode: 0644]
source/gles2rice/src/Debugger.h [new file with mode: 0644]
source/gles2rice/src/DecodedMux.cpp [new file with mode: 0644]
source/gles2rice/src/DecodedMux.h [new file with mode: 0644]
source/gles2rice/src/DeviceBuilder.cpp [new file with mode: 0644]
source/gles2rice/src/DeviceBuilder.h [new file with mode: 0644]
source/gles2rice/src/DirectXDecodedMux.cpp [new file with mode: 0644]
source/gles2rice/src/DirectXDecodedMux.h [new file with mode: 0644]
source/gles2rice/src/ExtendedRender.h [new file with mode: 0644]
source/gles2rice/src/FrameBuffer.cpp [new file with mode: 0644]
source/gles2rice/src/FrameBuffer.h [new file with mode: 0644]
source/gles2rice/src/GeneralCombiner.cpp [new file with mode: 0644]
source/gles2rice/src/GeneralCombiner.h [new file with mode: 0644]
source/gles2rice/src/GraphicsContext.cpp [new file with mode: 0644]
source/gles2rice/src/GraphicsContext.h [new file with mode: 0644]
source/gles2rice/src/IColor.h [new file with mode: 0644]
source/gles2rice/src/OGLCombiner.cpp [new file with mode: 0644]
source/gles2rice/src/OGLCombiner.h [new file with mode: 0644]
source/gles2rice/src/OGLCombinerNV.cpp [new file with mode: 0644]
source/gles2rice/src/OGLCombinerNV.h [new file with mode: 0644]
source/gles2rice/src/OGLCombinerTNT2.cpp [new file with mode: 0644]
source/gles2rice/src/OGLCombinerTNT2.h [new file with mode: 0644]
source/gles2rice/src/OGLDebug.h [new file with mode: 0644]
source/gles2rice/src/OGLDecodedMux.cpp [new file with mode: 0644]
source/gles2rice/src/OGLDecodedMux.h [new file with mode: 0644]
source/gles2rice/src/OGLES2FragmentShaders.cpp [new file with mode: 0644]
source/gles2rice/src/OGLES2FragmentShaders.h [new file with mode: 0644]
source/gles2rice/src/OGLExtCombiner.cpp [new file with mode: 0644]
source/gles2rice/src/OGLExtCombiner.h [new file with mode: 0644]
source/gles2rice/src/OGLExtRender.cpp [new file with mode: 0644]
source/gles2rice/src/OGLExtRender.h [new file with mode: 0644]
source/gles2rice/src/OGLExtensions.cpp [new file with mode: 0644]
source/gles2rice/src/OGLExtensions.h [new file with mode: 0644]
source/gles2rice/src/OGLFragmentShaders.cpp [new file with mode: 0644]
source/gles2rice/src/OGLFragmentShaders.h [new file with mode: 0644]
source/gles2rice/src/OGLGraphicsContext.cpp [new file with mode: 0644]
source/gles2rice/src/OGLGraphicsContext.h [new file with mode: 0644]
source/gles2rice/src/OGLRender.cpp [new file with mode: 0755]
source/gles2rice/src/OGLRender.h [new file with mode: 0644]
source/gles2rice/src/OGLRenderExt.cpp [new file with mode: 0644]
source/gles2rice/src/OGLTexture.cpp [new file with mode: 0644]
source/gles2rice/src/OGLTexture.h [new file with mode: 0644]
source/gles2rice/src/RDP_Texture.h [new file with mode: 0644]
source/gles2rice/src/RSP_GBI0.h [new file with mode: 0644]
source/gles2rice/src/RSP_GBI1.h [new file with mode: 0644]
source/gles2rice/src/RSP_GBI2.h [new file with mode: 0644]
source/gles2rice/src/RSP_GBI2_ext.h [new file with mode: 0644]
source/gles2rice/src/RSP_GBI_Others.h [new file with mode: 0644]
source/gles2rice/src/RSP_GBI_Sprite2D.h [new file with mode: 0644]
source/gles2rice/src/RSP_Parser.cpp [new file with mode: 0644]
source/gles2rice/src/RSP_Parser.h [new file with mode: 0644]
source/gles2rice/src/RSP_S2DEX.cpp [new file with mode: 0644]
source/gles2rice/src/RSP_S2DEX.h [new file with mode: 0644]
source/gles2rice/src/Render.cpp [new file with mode: 0644]
source/gles2rice/src/Render.h [new file with mode: 0644]
source/gles2rice/src/RenderBase.cpp [new file with mode: 0644]
source/gles2rice/src/RenderBase.h [new file with mode: 0644]
source/gles2rice/src/RenderExt.cpp [new file with mode: 0644]
source/gles2rice/src/RenderTexture.cpp [new file with mode: 0644]
source/gles2rice/src/RenderTexture.h [new file with mode: 0644]
source/gles2rice/src/Texture.cpp [new file with mode: 0644]
source/gles2rice/src/Texture.h [new file with mode: 0644]
source/gles2rice/src/TextureFilters.cpp [new file with mode: 0644]
source/gles2rice/src/TextureFilters.h [new file with mode: 0644]
source/gles2rice/src/TextureFilters_2xsai.cpp [new file with mode: 0644]
source/gles2rice/src/TextureFilters_hq2x.cpp [new file with mode: 0644]
source/gles2rice/src/TextureFilters_hq2x.h [new file with mode: 0644]
source/gles2rice/src/TextureFilters_hq4x.cpp [new file with mode: 0644]
source/gles2rice/src/TextureFilters_hq4x.h [new file with mode: 0644]
source/gles2rice/src/TextureFilters_lq2x.h [new file with mode: 0644]
source/gles2rice/src/TextureManager.cpp [new file with mode: 0644]
source/gles2rice/src/TextureManager.h [new file with mode: 0644]
source/gles2rice/src/Timing.h [new file with mode: 0644]
source/gles2rice/src/UcodeDefs.h [new file with mode: 0644]
source/gles2rice/src/VectorMath.cpp [new file with mode: 0644]
source/gles2rice/src/VectorMath.h [new file with mode: 0644]
source/gles2rice/src/VertexShaderConstantDef.h [new file with mode: 0644]
source/gles2rice/src/Video.cpp [new file with mode: 0644]
source/gles2rice/src/Video.h [new file with mode: 0644]
source/gles2rice/src/liblinux/BMGDLL.h [new file with mode: 0644]
source/gles2rice/src/liblinux/BMGImage.c [new file with mode: 0644]
source/gles2rice/src/liblinux/BMGImage.h [new file with mode: 0644]
source/gles2rice/src/liblinux/BMGLibPNG.h [new file with mode: 0644]
source/gles2rice/src/liblinux/BMGUtils.c [new file with mode: 0644]
source/gles2rice/src/liblinux/BMGUtils.h [new file with mode: 0644]
source/gles2rice/src/liblinux/bmp.c [new file with mode: 0644]
source/gles2rice/src/liblinux/jpegrw.h [new file with mode: 0644]
source/gles2rice/src/liblinux/pngrw.c [new file with mode: 0644]
source/gles2rice/src/liblinux/pngrw.h [new file with mode: 0644]
source/gles2rice/src/liblinux/tiffrw.h [new file with mode: 0644]
source/gles2rice/src/osal_dynamiclib.h [new file with mode: 0644]
source/gles2rice/src/osal_dynamiclib_unix.c [new file with mode: 0644]
source/gles2rice/src/osal_dynamiclib_win32.c [new file with mode: 0644]
source/gles2rice/src/osal_files.h [new file with mode: 0644]
source/gles2rice/src/osal_files_unix.c [new file with mode: 0644]
source/gles2rice/src/osal_files_win32.c [new file with mode: 0644]
source/gles2rice/src/osal_opengl.h [new file with mode: 0755]
source/gles2rice/src/osal_preproc.h [new file with mode: 0644]
source/gles2rice/src/typedefs.h [new file with mode: 0644]
source/gles2rice/src/ucode.h [new file with mode: 0644]
source/gles2rice/src/version.h [new file with mode: 0644]
source/gles2rice/src/video_api_export.ver [new file with mode: 0644]

diff --git a/source/gles2rice/.hgignore b/source/gles2rice/.hgignore
new file mode 100644 (file)
index 0000000..8778d6d
--- /dev/null
@@ -0,0 +1,4 @@
+syntax: regexp
+
+^projects/unix/_obj/
+^projects/unix/mupen64plus-video-rice.so$
diff --git a/source/gles2rice/INSTALL b/source/gles2rice/INSTALL
new file mode 100644 (file)
index 0000000..e0bd5c3
--- /dev/null
@@ -0,0 +1,26 @@
+Mupen64Plus-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
+<my-folder> with your desired local installation path):
+
+$ cd projects/unix
+$ make all
+$ make install LIBDIR=<my-folder> SHAREDIR=<my-folder>
+
+
diff --git a/source/gles2rice/LICENSES b/source/gles2rice/LICENSES
new file mode 100644 (file)
index 0000000..30595b6
--- /dev/null
@@ -0,0 +1,369 @@
+Mupen64Plus-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.  
+  
+    <one line to give the program's name and a brief idea of what it does.>  
+    Copyright (C) 19yy  <name of author>  
+  
+    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.  
+  
+  <signature of Ty Coon>, 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.
+
diff --git a/source/gles2rice/README b/source/gles2rice/README
new file mode 100644 (file)
index 0000000..35bc893
--- /dev/null
@@ -0,0 +1,67 @@
+===============================================================================
+-------------------------------------------------------------------------------
+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\
+<username>\Application Data\Mupen64Plus\", while on Windows Vista and newer
+this is "C:\Users\<username>\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/<username>/.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\<username>\Application Data\Mupen64Plus\hires_texture", while on
+Windows Vista and newer this is "C:\Users\<username>\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
+
+
diff --git a/source/gles2rice/RELEASE b/source/gles2rice/RELEASE
new file mode 100644 (file)
index 0000000..8499e3f
--- /dev/null
@@ -0,0 +1,82 @@
+Mupen64Plus-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
+
diff --git a/source/gles2rice/data/RiceVideoLinux.ini b/source/gles2rice/data/RiceVideoLinux.ini
new file mode 100644 (file)
index 0000000..adc671f
--- /dev/null
@@ -0,0 +1,1552 @@
+{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
+
diff --git a/source/gles2rice/projects/android/Android.mk b/source/gles2rice/projects/android/Android.mk
new file mode 100644 (file)
index 0000000..40d8829
--- /dev/null
@@ -0,0 +1,97 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+SRCDIR := ../../src
+
+LOCAL_MODULE := gles2rice
+LOCAL_SHARED_LIBRARIES := ae-imports SDL2 core
+LOCAL_STATIC_LIBRARIES := png
+LOCAL_ARM_MODE := arm
+
+LOCAL_C_INCLUDES :=                     \
+    $(SRCDIR)/liblinux                  \
+    $(M64P_API_INCLUDES)                \
+    $(PNG_INCLUDES)                     \
+    $(SDL_INCLUDES)                     \
+    $(AE_BRIDGE_INCLUDES)               \
+
+LOCAL_SRC_FILES :=                      \
+    $(SRCDIR)/Blender.cpp               \
+    $(SRCDIR)/Combiner.cpp              \
+    $(SRCDIR)/CombinerTable.cpp         \
+    $(SRCDIR)/Config.cpp                \
+    $(SRCDIR)/ConvertImage.cpp          \
+    $(SRCDIR)/ConvertImage16.cpp        \
+    $(SRCDIR)/Debugger.cpp              \
+    $(SRCDIR)/DecodedMux.cpp            \
+    $(SRCDIR)/DeviceBuilder.cpp         \
+    $(SRCDIR)/DirectXDecodedMux.cpp     \
+    $(SRCDIR)/FrameBuffer.cpp           \
+    $(SRCDIR)/GeneralCombiner.cpp       \
+    $(SRCDIR)/GraphicsContext.cpp       \
+    $(SRCDIR)/OGLCombiner.cpp           \
+    $(SRCDIR)/OGLDecodedMux.cpp         \
+    $(SRCDIR)/OGLExtCombiner.cpp        \
+    $(SRCDIR)/OGLExtRender.cpp          \
+    $(SRCDIR)/OGLES2FragmentShaders.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                 \
+    $(SRCDIR)/osal_dynamiclib_unix.c    \
+    $(SRCDIR)/osal_files_unix.c         \
+    $(SRCDIR)/liblinux/BMGImage.c       \
+    $(SRCDIR)/liblinux/BMGUtils.c       \
+    $(SRCDIR)/liblinux/bmp.c            \
+    $(SRCDIR)/liblinux/pngrw.c          \
+
+LOCAL_CFLAGS :=         \
+    $(COMMON_CFLAGS)    \
+    -DANDROID           \
+    -DNO_ASM            \
+    -DPAULSCODE         \
+    -fsigned-char       \
+    #-DBGR_SHADER        \
+    #-DSDL_NO_COMPAT     \
+    
+LOCAL_CPPFLAGS := $(COMMON_CPPFLAGS)
+    
+LOCAL_CPP_FEATURES := exceptions
+
+LOCAL_LDFLAGS := -Wl,-version-script,$(LOCAL_PATH)/$(SRCDIR)/video_api_export.ver
+
+LOCAL_LDLIBS :=         \
+    -lGLESv2            \
+    -llog               \
+
+ifeq ($(TARGET_ARCH_ABI), armeabi-v7a)
+    # Use for ARM7a:
+    LOCAL_CFLAGS += -mfpu=vfp
+    LOCAL_CFLAGS += -mfloat-abi=softfp
+    
+else ifeq ($(TARGET_ARCH_ABI), armeabi)
+    # Use for pre-ARM7a:
+    
+else ifeq ($(TARGET_ARCH_ABI), x86)
+    # TODO: set the proper flags here
+    
+else
+    # Any other architectures that Android could be running on?
+    
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/source/gles2rice/projects/msvc11/mupen64plus-video-rice.vcxproj b/source/gles2rice/projects/msvc11/mupen64plus-video-rice.vcxproj
new file mode 100644 (file)
index 0000000..e0708c2
--- /dev/null
@@ -0,0 +1,217 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{7D4AFF6A-B7D9-4C25-975A-038B8079098E}</ProjectGuid>
+    <RootNamespace>mupen64plusvideorice</RootNamespace>
+    <Keyword>Win32Proj</Keyword>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <CharacterSet>MultiByte</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <CharacterSet>MultiByte</CharacterSet>
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+    <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+    <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+    <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+    <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>..\..\..\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)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MinimalRebuild>true</MinimalRebuild>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>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)</AdditionalDependencies>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <AdditionalIncludeDirectories>..\..\..\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)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <CompileAs>Default</CompileAs>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>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)</AdditionalDependencies>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <OptimizeReferences>true</OptimizeReferences>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\src\Blender.cpp" />
+    <ClCompile Include="..\..\src\liblinux\BMGImage.c" />
+    <ClCompile Include="..\..\src\liblinux\BMGUtils.c" />
+    <ClCompile Include="..\..\src\liblinux\bmp.c" />
+    <ClCompile Include="..\..\src\CNvTNTCombiner.cpp" />
+    <ClCompile Include="..\..\src\Combiner.cpp" />
+    <ClCompile Include="..\..\src\CombinerTable.cpp" />
+    <ClCompile Include="..\..\src\Config.cpp" />
+    <ClCompile Include="..\..\src\ConvertImage.cpp" />
+    <ClCompile Include="..\..\src\ConvertImage16.cpp" />
+    <ClCompile Include="..\..\src\Debugger.cpp" />
+    <ClCompile Include="..\..\src\DecodedMux.cpp" />
+    <ClCompile Include="..\..\src\DeviceBuilder.cpp" />
+    <ClCompile Include="..\..\src\DirectXDecodedMux.cpp" />
+    <ClCompile Include="..\..\src\FrameBuffer.cpp" />
+    <ClCompile Include="..\..\src\GeneralCombiner.cpp" />
+    <ClCompile Include="..\..\src\GraphicsContext.cpp" />
+    <ClCompile Include="..\..\src\OGLCombiner.cpp" />
+    <ClCompile Include="..\..\src\OGLCombinerNV.cpp" />
+    <ClCompile Include="..\..\src\OGLCombinerTNT2.cpp" />
+    <ClCompile Include="..\..\src\OGLDecodedMux.cpp" />
+    <ClCompile Include="..\..\src\OGLExtCombiner.cpp" />
+    <ClCompile Include="..\..\src\OGLExtensions.cpp" />
+    <ClCompile Include="..\..\src\OGLExtRender.cpp" />
+    <ClCompile Include="..\..\src\OGLFragmentShaders.cpp" />
+    <ClCompile Include="..\..\src\OGLGraphicsContext.cpp" />
+    <ClCompile Include="..\..\src\OGLRender.cpp" />
+    <ClCompile Include="..\..\src\OGLRenderExt.cpp" />
+    <ClCompile Include="..\..\src\OGLTexture.cpp" />
+    <ClCompile Include="..\..\src\osal_dynamiclib_win32.c" />
+    <ClCompile Include="..\..\src\osal_files_win32.c" />
+    <ClCompile Include="..\..\src\liblinux\pngrw.c" />
+    <ClCompile Include="..\..\src\Render.cpp" />
+    <ClCompile Include="..\..\src\RenderBase.cpp" />
+    <ClCompile Include="..\..\src\RenderExt.cpp" />
+    <ClCompile Include="..\..\src\RenderTexture.cpp" />
+    <ClCompile Include="..\..\src\RSP_Parser.cpp" />
+    <ClCompile Include="..\..\src\RSP_S2DEX.cpp" />
+    <ClCompile Include="..\..\src\Texture.cpp" />
+    <ClCompile Include="..\..\src\TextureFilters.cpp" />
+    <ClCompile Include="..\..\src\TextureFilters_2xsai.cpp" />
+    <ClCompile Include="..\..\src\TextureFilters_hq2x.cpp" />
+    <ClCompile Include="..\..\src\TextureFilters_hq4x.cpp" />
+    <ClCompile Include="..\..\src\TextureManager.cpp" />
+    <ClCompile Include="..\..\src\VectorMath.cpp" />
+    <ClCompile Include="..\..\src\Video.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\src\Blender.h" />
+    <ClInclude Include="..\..\src\liblinux\BMGDLL.h" />
+    <ClInclude Include="..\..\src\liblinux\BMGImage.h" />
+    <ClInclude Include="..\..\src\liblinux\BMGLibPNG.h" />
+    <ClInclude Include="..\..\src\liblinux\BMGUtils.h" />
+    <ClInclude Include="..\..\src\CNvTNTCombiner.h" />
+    <ClInclude Include="..\..\src\COLOR.h" />
+    <ClInclude Include="..\..\src\Combiner.h" />
+    <ClInclude Include="..\..\src\CombinerDefs.h" />
+    <ClInclude Include="..\..\src\Config.h" />
+    <ClInclude Include="..\..\src\ConvertImage.h" />
+    <ClInclude Include="..\..\src\CritSect.h" />
+    <ClInclude Include="..\..\src\CSortedList.h" />
+    <ClInclude Include="..\..\src\Debugger.h" />
+    <ClInclude Include="..\..\src\DecodedMux.h" />
+    <ClInclude Include="..\..\src\DeviceBuilder.h" />
+    <ClInclude Include="..\..\src\DirectXDecodedMux.h" />
+    <ClInclude Include="..\..\src\ExtendedRender.h" />
+    <ClInclude Include="..\..\src\FrameBuffer.h" />
+    <ClInclude Include="..\..\src\GeneralCombiner.h" />
+    <ClInclude Include="..\..\src\GraphicsContext.h" />
+    <ClInclude Include="..\..\src\IColor.h" />
+    <ClInclude Include="..\..\src\liblinux\inffixed.h" />
+    <ClInclude Include="..\..\src\liblinux\jpegrw.h" />
+    <ClInclude Include="..\..\src\OGLCombiner.h" />
+    <ClInclude Include="..\..\src\OGLCombinerNV.h" />
+    <ClInclude Include="..\..\src\OGLCombinerTNT2.h" />
+    <ClInclude Include="..\..\src\OGLDebug.h" />
+    <ClInclude Include="..\..\src\OGLDecodedMux.h" />
+    <ClInclude Include="..\..\src\OGLExtCombiner.h" />
+    <ClInclude Include="..\..\src\OGLExtensions.h" />
+    <ClInclude Include="..\..\src\OGLExtRender.h" />
+    <ClInclude Include="..\..\src\OGLFragmentShaders.h" />
+    <ClInclude Include="..\..\src\OGLGraphicsContext.h" />
+    <ClInclude Include="..\..\src\OGLRender.h" />
+    <ClInclude Include="..\..\src\OGLTexture.h" />
+    <ClInclude Include="..\..\src\osal_dynamiclib.h" />
+    <ClInclude Include="..\..\src\osal_files.h" />
+    <ClInclude Include="..\..\src\osal_preproc.h" />
+    <ClInclude Include="..\..\src\liblinux\pngrw.h" />
+    <ClInclude Include="..\..\src\RDP_Texture.h" />
+    <ClInclude Include="..\..\src\Render.h" />
+    <ClInclude Include="..\..\src\RenderBase.h" />
+    <ClInclude Include="..\..\src\RenderTexture.h" />
+    <ClInclude Include="..\..\src\RSP_GBI0.h" />
+    <ClInclude Include="..\..\src\RSP_GBI1.h" />
+    <ClInclude Include="..\..\src\RSP_GBI2.h" />
+    <ClInclude Include="..\..\src\RSP_GBI2_ext.h" />
+    <ClInclude Include="..\..\src\RSP_GBI_Others.h" />
+    <ClInclude Include="..\..\src\RSP_GBI_Sprite2D.h" />
+    <ClInclude Include="..\..\src\RSP_Parser.h" />
+    <ClInclude Include="..\..\src\RSP_S2DEX.h" />
+    <ClInclude Include="..\..\src\Texture.h" />
+    <ClInclude Include="..\..\src\TextureFilters.h" />
+    <ClInclude Include="..\..\src\TextureFilters_hq2x.h" />
+    <ClInclude Include="..\..\src\TextureFilters_hq4x.h" />
+    <ClInclude Include="..\..\src\TextureFilters_lq2x.h" />
+    <ClInclude Include="..\..\src\TextureManager.h" />
+    <ClInclude Include="..\..\src\liblinux\tiffrw.h" />
+    <ClInclude Include="..\..\src\Timing.h" />
+    <ClInclude Include="..\..\src\typedefs.h" />
+    <ClInclude Include="..\..\src\ucode.h" />
+    <ClInclude Include="..\..\src\UcodeDefs.h" />
+    <ClInclude Include="..\..\src\VectorMath.h" />
+    <ClInclude Include="..\..\src\version.h" />
+    <ClInclude Include="..\..\src\VertexShaderConstantDef.h" />
+    <ClInclude Include="..\..\src\Video.h" />
+    <ClInclude Include="..\..\src\liblinux\zconf.h" />
+    <ClInclude Include="..\..\src\liblinux\zlib.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/source/gles2rice/projects/msvc8/mupen64plus-video-rice.vcproj b/source/gles2rice/projects/msvc8/mupen64plus-video-rice.vcproj
new file mode 100644 (file)
index 0000000..7b8a9a6
--- /dev/null
@@ -0,0 +1,652 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mupen64plus-video-rice"
+       ProjectGUID="{7D4AFF6A-B7D9-4C25-975A-038B8079098E}"
+       RootNamespace="mupen64plusvideorice"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+                       IntermediateDirectory="$(ConfigurationName)"
+                       ConfigurationType="2"
+                       CharacterSet="2"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="0"
+                               AdditionalIncludeDirectories="..\..\..\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"
+                               PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE"
+                               MinimalRebuild="true"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="3"
+                               UsePrecompiledHeader="0"
+                               WarningLevel="3"
+                               Detect64BitPortabilityProblems="false"
+                               DebugInformationFormat="4"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="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"
+                               LinkIncremental="2"
+                               GenerateDebugInformation="true"
+                               SubSystem="2"
+                               TargetMachine="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+                       IntermediateDirectory="$(ConfigurationName)"
+                       ConfigurationType="2"
+                       CharacterSet="2"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="..\..\..\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"
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE"
+                               RuntimeLibrary="2"
+                               UsePrecompiledHeader="0"
+                               WarningLevel="3"
+                               Detect64BitPortabilityProblems="false"
+                               DebugInformationFormat="3"
+                               CompileAs="0"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="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"
+                               LinkIncremental="1"
+                               GenerateDebugInformation="true"
+                               SubSystem="2"
+                               OptimizeReferences="2"
+                               EnableCOMDATFolding="2"
+                               TargetMachine="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="Source Files"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+                       >
+                       <File
+                               RelativePath="..\..\src\Blender.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\liblinux\BMGImage.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\liblinux\BMGUtils.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\liblinux\bmp.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\CNvTNTCombiner.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\Combiner.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\CombinerTable.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\Config.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\ConvertImage.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\ConvertImage16.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\Debugger.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\DecodedMux.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\DeviceBuilder.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\DirectXDecodedMux.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\FrameBuffer.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\GeneralCombiner.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\GraphicsContext.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLCombiner.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLCombinerNV.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLCombinerTNT2.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLDecodedMux.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLExtCombiner.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLExtensions.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLExtRender.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLFragmentShaders.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLGraphicsContext.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLRender.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLRenderExt.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLTexture.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\osal_dynamiclib_win32.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\osal_files_win32.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\liblinux\pngrw.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\Render.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RenderBase.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RenderExt.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RenderTexture.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RSP_Parser.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RSP_S2DEX.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\Texture.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\TextureFilters.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\TextureFilters_2xsai.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\TextureFilters_hq2x.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\TextureFilters_hq4x.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\TextureManager.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\VectorMath.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\Video.cpp"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="Header Files"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath="..\..\src\Blender.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\liblinux\BMGDLL.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\liblinux\BMGImage.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\liblinux\BMGLibPNG.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\liblinux\BMGUtils.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\CNvTNTCombiner.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\COLOR.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\Combiner.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\CombinerDefs.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\Config.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\ConvertImage.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\CritSect.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\CSortedList.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\Debugger.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\DecodedMux.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\DeviceBuilder.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\DirectXDecodedMux.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\ExtendedRender.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\FrameBuffer.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\GeneralCombiner.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\GraphicsContext.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\IColor.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\liblinux\inffixed.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\liblinux\jpegrw.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLCombiner.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLCombinerNV.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLCombinerTNT2.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLDebug.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLDecodedMux.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLExtCombiner.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLExtensions.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLExtRender.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLFragmentShaders.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLGraphicsContext.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLRender.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\OGLTexture.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\osal_dynamiclib.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\osal_files.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\osal_preproc.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\liblinux\pngrw.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RDP_Texture.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\Render.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RenderBase.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RenderTexture.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RSP_GBI0.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RSP_GBI1.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RSP_GBI2.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RSP_GBI2_ext.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RSP_GBI_Others.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RSP_GBI_Sprite2D.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RSP_Parser.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\RSP_S2DEX.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\Texture.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\TextureFilters.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\TextureFilters_hq2x.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\TextureFilters_hq4x.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\TextureFilters_lq2x.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\TextureManager.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\liblinux\tiffrw.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\Timing.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\typedefs.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\ucode.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\UcodeDefs.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\VectorMath.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\version.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\VertexShaderConstantDef.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\Video.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\liblinux\zconf.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\liblinux\zlib.h"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/source/gles2rice/projects/unix/Makefile b/source/gles2rice/projects/unix/Makefile
new file mode 100755 (executable)
index 0000000..688f27c
--- /dev/null
@@ -0,0 +1,429 @@
+#/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+# *   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
+    CFLAGS += -mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp -mtune=cortex-a8 -fsigned-char -ffast-math
+    CFLAGS += -DANDROID
+    CFLAGS += -DPAULSCODE 
+    $(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
+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)
+  GL_CFLAGS += -I/mnt/utmp/codeblocks/usr/include/GLES2
+  GL_LDLIBS += -lGLESv2 -lrt
+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)/Blender.cpp               \
+    $(SRCDIR)/Combiner.cpp              \
+    $(SRCDIR)/CombinerTable.cpp         \
+    $(SRCDIR)/Config.cpp                \
+    $(SRCDIR)/ConvertImage.cpp          \
+    $(SRCDIR)/ConvertImage16.cpp        \
+    $(SRCDIR)/Debugger.cpp              \
+    $(SRCDIR)/DecodedMux.cpp            \
+    $(SRCDIR)/DeviceBuilder.cpp         \
+    $(SRCDIR)/DirectXDecodedMux.cpp     \
+    $(SRCDIR)/FrameBuffer.cpp           \
+    $(SRCDIR)/GeneralCombiner.cpp       \
+    $(SRCDIR)/GraphicsContext.cpp       \
+    $(SRCDIR)/OGLCombiner.cpp           \
+    $(SRCDIR)/OGLDecodedMux.cpp         \
+    $(SRCDIR)/OGLExtCombiner.cpp        \
+    $(SRCDIR)/OGLExtRender.cpp          \
+    $(SRCDIR)/OGLES2FragmentShaders.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                 \
+    $(SRCDIR)/liblinux/BMGImage.c       \
+    $(SRCDIR)/liblinux/BMGUtils.c       \
+    $(SRCDIR)/liblinux/bmp.c            \
+    $(SRCDIR)/liblinux/pngrw.c          \
+
+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
diff --git a/source/gles2rice/src/Blender.cpp b/source/gles2rice/src/Blender.cpp
new file mode 100644 (file)
index 0000000..6a720a8
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+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;
+        }
+    }
+}
+
diff --git a/source/gles2rice/src/Blender.h b/source/gles2rice/src/Blender.h
new file mode 100644 (file)
index 0000000..9ea3ec0
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+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
+
+
+
diff --git a/source/gles2rice/src/CNvTNTCombiner.cpp b/source/gles2rice/src/CNvTNTCombiner.cpp
new file mode 100644 (file)
index 0000000..c79b4a2
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+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 <SDL_opengl.h>
+
+#include "CNvTNTCombiner.h"
+
+CNvTNTCombiner::CNvTNTCombiner()
+{
+    m_lastIndexTNT = 0;
+}
+
+CNvTNTCombiner::~CNvTNTCombiner()
+{
+}
+
+
+int CNvTNTCombiner::FindCompiledMux( )
+{
+    for( uint32 i=0; i<m_vCompiledTNTSettings.size(); i++ )
+    {
+        if( m_vCompiledTNTSettings[i].dwMux0 == (*m_ppDecodedMux)->m_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; i<res.numOfUnits*2; i++ ) // Set combiner for each texture unit
+    {
+        // For each texture unit, set both RGB and Alpha channel
+        // Keep in mind that the m_pDecodeMux has been reformated and simplified very well
+
+        TNT2CombinerType &unit = res.units[i/2];
+        TNT2CombType &comb = unit.Combs[i%2];
+
+        CombinerFormatType type = (*m_ppDecodedMux)->splitType[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
+
diff --git a/source/gles2rice/src/CNvTNTCombiner.h b/source/gles2rice/src/CNvTNTCombiner.h
new file mode 100644 (file)
index 0000000..13da609
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+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 <vector>
+
+#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<TNT2CombinerSaveType>   m_vCompiledTNTSettings;
+    int m_lastIndexTNT;
+    DecodedMux **m_ppDecodedMux;
+};
+
+#endif
+
diff --git a/source/gles2rice/src/COLOR.h b/source/gles2rice/src/COLOR.h
new file mode 100644 (file)
index 0000000..cc1e4e3
--- /dev/null
@@ -0,0 +1,84 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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
+
diff --git a/source/gles2rice/src/CSortedList.h b/source/gles2rice/src/CSortedList.h
new file mode 100644 (file)
index 0000000..91fa9fa
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+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 <cstring>
+
+template<class Key, class Element>
+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<curSize; i++ )
+        {
+            if( keys[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
+
diff --git a/source/gles2rice/src/Combiner.cpp b/source/gles2rice/src/Combiner.cpp
new file mode 100644 (file)
index 0000000..bc121c6
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+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
+
diff --git a/source/gles2rice/src/Combiner.h b/source/gles2rice/src/Combiner.h
new file mode 100644 (file)
index 0000000..d1a6c81
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+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<uint64, DecodedMux> 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
+
diff --git a/source/gles2rice/src/CombinerDefs.h b/source/gles2rice/src/CombinerDefs.h
new file mode 100644 (file)
index 0000000..e56df56
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+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
+
+
+
diff --git a/source/gles2rice/src/CombinerTable.cpp b/source/gles2rice/src/CombinerTable.cpp
new file mode 100644 (file)
index 0000000..e6a18c4
--- /dev/null
@@ -0,0 +1,5125 @@
+/*
+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);
+
diff --git a/source/gles2rice/src/Config.cpp b/source/gles2rice/src/Config.cpp
new file mode 100644 (file)
index 0000000..125be0b
--- /dev/null
@@ -0,0 +1,1470 @@
+/*
+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 <vector>
+#include <fstream>
+
+#include <stdlib.h>
+
+#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<IniSection> 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)/*&&sectionno<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;
+}
+
+
diff --git a/source/gles2rice/src/Config.h b/source/gles2rice/src/Config.h
new file mode 100644 (file)
index 0000000..c834b97
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+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 <stdio.h>
+
+#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
+
diff --git a/source/gles2rice/src/ConvertImage.cpp b/source/gles2rice/src/ConvertImage.cpp
new file mode 100644 (file)
index 0000000..f295936
--- /dev/null
@@ -0,0 +1,1470 @@
+/*
+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();
+}
+
diff --git a/source/gles2rice/src/ConvertImage.h b/source/gles2rice/src/ConvertImage.h
new file mode 100644 (file)
index 0000000..6c004cb
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+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
+
diff --git a/source/gles2rice/src/ConvertImage16.cpp b/source/gles2rice/src/ConvertImage16.cpp
new file mode 100644 (file)
index 0000000..319388b
--- /dev/null
@@ -0,0 +1,1213 @@
+/*
+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();
+}
+
diff --git a/source/gles2rice/src/CritSect.h b/source/gles2rice/src/CritSect.h
new file mode 100644 (file)
index 0000000..b1793c9
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+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 <SDL.h>
+
+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)
+
diff --git a/source/gles2rice/src/Debugger.cpp b/source/gles2rice/src/Debugger.cpp
new file mode 100644 (file)
index 0000000..438931e
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+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; i<GetNumLights()+2; i++)
+        {
+            DebuggerAppendMsg("Light %d:\t%08X, (%d,%d,%d)\n", i, gRSPn64lights[i].dwRGBA,gRSPn64lights[i].x,gRSPn64lights[i].y,gRSPn64lights[i].z );
+        }
+        break;
+    case DUMP_TEXTURE_AT:
+        {
+        }
+        break;
+    case DUMP_CUR_TEXTURE_RGBA:
+        DumpTexture(gRSP.curTile, TXT_RGBA);
+        break;
+    case DUMP_CUR_1_TEXTURE_RGBA:
+        DumpTexture((1+gRSP.curTile)%7, TXT_RGBA);
+        break;
+    case DUMP_CUR_TEXTURE_RGB:
+        DumpTexture(gRSP.curTile, TXT_RGB);
+        break;
+    case DUMP_CUR_1_TEXTURE_RGB:
+        DumpTexture((1+gRSP.curTile)%7, TXT_RGB);
+        break;
+    case DUMP_CUR_TEXTURE_TO_FILE:
+        DumpTextureToFile(0,TXT_RGB);
+        DumpTextureToFile(0,TXT_ALPHA);
+        DumpTextureToFile(0,TXT_RGBA);
+        break;
+    case DUMP_CUR_1_TEXTURE_TO_FILE:
+        DumpTextureToFile(1,TXT_RGB);
+        DumpTextureToFile(1,TXT_ALPHA);
+        DumpTextureToFile(1,TXT_RGBA);
+        break;
+    case DUMP_CUR_TEXTURE_ALPHA:
+        DumpTexture(0, TXT_ALPHA);
+        break;
+    case DUMP_CUR_1_TEXTURE_ALPHA:
+        DumpTexture(1, TXT_ALPHA);
+        break;
+    case DUMP_TLUT:
+        DumpTlut(g_wRDPTlut);
+        break;
+    case DUMP_OBJ_TLUT:
+        DumpTlut((uint16*)(g_pRDRAMu8+gObjTlutAddr));
+        break;
+    case DUMP_TILE_AT:
+        {
+        }
+        break;
+    case DUMP_VERTEXES:
+        DumpVertexArray();
+        break;
+    case DUMP_VI_REGS:
+        DumpVIRegisters();
+        break;
+    case DUMP_SIMPLE_MUX:
+        CRender::GetRender()->m_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
+
diff --git a/source/gles2rice/src/Debugger.h b/source/gles2rice/src/Debugger.h
new file mode 100644 (file)
index 0000000..04c44b4
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+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)
+
diff --git a/source/gles2rice/src/DecodedMux.cpp b/source/gles2rice/src/DecodedMux.cpp
new file mode 100644 (file)
index 0000000..f776c19
--- /dev/null
@@ -0,0 +1,1559 @@
+/*
+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 <algorithm>
+
+#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<end; i++ )
+    {
+        if( (pmux[i]&mask) == (val&mask) )
+        {
+            count++;
+        }
+    }
+
+    return count;
+}
+
+
+bool DecodedMux::isUsed(uint8 val, uint8 mask)
+{
+    uint8* pmux = m_bytes;
+    bool isUsed = false;
+    for( int i=0; i<16; i++ )
+    {
+        if( (pmux[i]&mask) == (val&mask) )
+        {
+            isUsed = true;
+            break;
+        }
+    }
+
+    return isUsed;
+}
+
+bool DecodedMux::isUsedInAlphaChannel(uint8 val, uint8 mask)
+{
+    uint8* pmux = m_bytes;
+    bool isUsed = false;
+    for( int i=0; i<16; i++ )
+    {
+        if( (i/4)%2 == 0 )
+            continue;   //Don't test color channel
+
+        if( (pmux[i]&mask) == (val&mask) )
+        {
+            isUsed = true;
+            break;
+        }
+    }
+
+    return isUsed;
+}
+
+bool DecodedMux::isUsedInColorChannel(uint8 val, uint8 mask)
+{
+    uint8* pmux = m_bytes;
+    bool isUsed = false;
+    for( int i=0; i<16; i++ )
+    {
+        if( (i/4)%2 == 0 && (pmux[i]&mask) == (val&mask) )
+        {
+            isUsed = true;
+            break;
+        }
+    }
+
+    return isUsed;
+}
+
+
+bool DecodedMux::isUsedInCycle(uint8 val, int cycle, CombineChannel channel, uint8 mask)
+{
+    cycle *=2;
+    if( channel == ALPHA_CHANNEL ) cycle++;
+
+    uint8* pmux = m_bytes;
+    for( int i=0; i<4; i++ )
+    {
+        if( (pmux[i+cycle*4]&mask) == (val&mask) )
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool DecodedMux::isUsedInCycle(uint8 val, int cycle, uint8 mask)
+{
+    return isUsedInCycle(val, cycle/2, cycle%2?ALPHA_CHANNEL:COLOR_CHANNEL, mask);
+}
+
+
+void DecodedMux::ConvertComplements()
+{
+    //For (A-B)*C+D, if A=1, then we can convert A-B to Ac-0
+    if( aRGB0 != MUX_1 && bRGB0 != MUX_0 )
+    {
+        aRGB0 = bRGB0|MUX_COMPLEMENT;
+        bRGB0 = MUX_0;
+    }
+    if( aRGB1 != MUX_1 && bRGB1 != MUX_0 )
+    {
+        aRGB1 = bRGB1|MUX_COMPLEMENT;
+        bRGB1 = MUX_0;
+    }
+    if( aA0 != MUX_1 && bA0 != MUX_0 )
+    {
+        aA0 = bA0|MUX_COMPLEMENT;
+        bA0 = MUX_0;
+    }
+    if( aA1 != MUX_1 && bA1 != MUX_0 )
+    {
+        aA1 = bA1|MUX_COMPLEMENT;
+        bA1 = MUX_0;
+    }
+}
+
+
+CombinerFormatType DecodedMux::GetCombinerFormatType(uint32 cycle)
+{
+    //Analyze the formula
+    /*
+    C=0                 = D
+    A==B                = D
+    B=0, C=1, D=0       = A
+    A=1, B=0, D=0       = C
+    C=1, B==D           = A
+    A=1, C=1, D=0       = 1-B
+    D = 1               = 1
+    */
+    return CM_FMT_TYPE_D;
+}
+
+void DecodedMuxForPixelShader::Simplify(void)
+{
+    CheckCombineInCycle1();
+    //Reformat();
+
+    if( g_curRomInfo.bTexture1Hack )
+    {
+        ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,2);
+        ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,3);
+    }
+    splitType[0] = CM_FMT_TYPE_NOT_USED;
+    splitType[1] = CM_FMT_TYPE_NOT_USED;
+    splitType[2] = CM_FMT_TYPE_NOT_USED;
+    splitType[3] = CM_FMT_TYPE_NOT_USED;
+    mType = CM_FMT_TYPE_NOT_USED;
+
+    m_bTexel0IsUsed = isUsed(MUX_TEXEL0);
+    m_bTexel1IsUsed = isUsed(MUX_TEXEL1);
+}
+
+void DecodedMuxForSemiPixelShader::Reset(void)
+{
+    Decode(m_dwMux0, m_dwMux1);
+    splitType[0] = CM_FMT_TYPE_NOT_CHECKED;
+    splitType[1] = CM_FMT_TYPE_NOT_CHECKED;
+    splitType[2] = CM_FMT_TYPE_NOT_CHECKED;
+    splitType[3] = CM_FMT_TYPE_NOT_CHECKED;
+
+    Hack();
+
+    gRSP.bProcessDiffuseColor = false;
+    gRSP.bProcessSpecularColor = false;
+
+    CheckCombineInCycle1();
+    if( g_curRomInfo.bTexture1Hack )
+    {
+        ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,2);
+        ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,3);
+    }
+
+    m_bTexel0IsUsed = isUsed(MUX_TEXEL0);
+    m_bTexel1IsUsed = isUsed(MUX_TEXEL1);
+}
+
+void DecodedMuxForOGL14V2::Simplify(void)
+{
+    CheckCombineInCycle1();
+    if( g_curRomInfo.bTexture1Hack )
+    {
+        ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,2);
+        ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,3);
+    }
+    Reformat();
+
+    UseTextureForConstant();
+    Reformat();
+
+    m_bTexel0IsUsed = isUsed(MUX_TEXEL0);
+    m_bTexel1IsUsed = isUsed(MUX_TEXEL1);
+}
+
+void DecodedMux::Simplify(void)
+{
+    CheckCombineInCycle1();
+    if( gRDP.otherMode.text_lod )
+        ConvertLODFracTo0();
+    if( g_curRomInfo.bTexture1Hack )
+    {
+        ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,2);
+        ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,3);
+    }
+    Reformat();
+
+    UseShadeForConstant();
+    Reformat();
+
+    if( m_dwShadeColorChannelFlag == MUX_0 )
+    {
+        MergeShadeWithConstants();
+        Reformat();
+    }
+
+#ifdef ALLOW_USE_TEXTURE_FOR_CONSTANTS
+    UseTextureForConstant();
+    for( int i=0; i<2; i++ )
+    {
+        if( m_ColorTextureFlag[i] != 0 )
+        {
+            if( m_dwShadeColorChannelFlag == m_ColorTextureFlag[i] )
+            {
+                ReplaceVal(MUX_SHADE,MUX_TEXEL0+i,N64Cycle0RGB);
+                ReplaceVal(MUX_SHADE,MUX_TEXEL0+i,N64Cycle1RGB);
+                m_dwShadeColorChannelFlag = 0;
+            }
+            if( m_dwShadeAlphaChannelFlag == m_ColorTextureFlag[i] )
+            {
+                ReplaceVal(MUX_SHADE,MUX_TEXEL0+i,N64Cycle0Alpha);
+                ReplaceVal(MUX_SHADE,MUX_TEXEL0+i,N64Cycle1Alpha);
+                ReplaceVal(MUX_SHADE|MUX_ALPHAREPLICATE,(MUX_TEXEL0+i)|MUX_ALPHAREPLICATE,N64Cycle0RGB,MUX_MASK_WITH_ALPHA);
+                ReplaceVal(MUX_SHADE|MUX_ALPHAREPLICATE,(MUX_TEXEL0+i)|MUX_ALPHAREPLICATE,N64Cycle1RGB,MUX_MASK_WITH_ALPHA);
+                m_dwShadeAlphaChannelFlag = 0;
+            }
+        }
+    }
+    Reformat();
+#endif
+
+    m_bTexel0IsUsed = isUsed(MUX_TEXEL0);
+    m_bTexel1IsUsed = isUsed(MUX_TEXEL1);
+}
+
+void DecodedMux::Reformat(bool do_complement)
+{
+    if( m_dWords[N64Cycle0RGB] == m_dWords[N64Cycle1RGB] )
+    {
+        aRGB1 = MUX_0;
+        bRGB1 = MUX_0;
+        cRGB1 = MUX_0;
+        dRGB1 = MUX_COMBINED;
+        splitType[N64Cycle1RGB] = CM_FMT_TYPE_NOT_USED;
+    }
+
+    if( m_dWords[N64Cycle0Alpha] == m_dWords[N64Cycle1Alpha] )
+    {
+        aA1 = MUX_0;
+        bA1 = MUX_0;
+        cA1 = MUX_0;
+        dA1 = MUX_COMBINED;
+        splitType[N64Cycle1Alpha] = CM_FMT_TYPE_NOT_USED;
+    }
+
+    for( int i=0; i<4; i++ )
+    {
+        if( splitType[i] == CM_FMT_TYPE_NOT_USED )
+        {
+            continue;   //Skip this, it is not used
+        }
+
+        N64CombinerType &m = m_n64Combiners[i];
+        //if( m.a == MUX_0 || m.c == MUX_0 || m.a ==  m.b ) m.a = m.b = m.c = MUX_0;
+        if( m.c == MUX_0 || m.a ==  m.b )   m.a = m.b = m.c = MUX_0;
+        if( do_complement && (m.b == MUX_1 || m.d == MUX_1) )  m.a = m.b = m.c = MUX_0;
+        if( m.a == MUX_0 && m.b == m.d ) 
+        {
+            m.a = m.b;
+            m.b = m.d = 0;
+            //Hack for Mario Tennis
+            if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS && m.c == MUX_TEXEL1 )
+            {
+                if( do_complement )
+                    m.c = MUX_TEXEL0|MUX_COMPLEMENT;
+                else
+                {
+                    m.a = m.c;
+                    m.c = m.b;
+                    m.b = m.a;
+                    m.a = MUX_1;
+                }
+            }
+            //m.c ^= MUX_COMPLEMENT;
+        }
+
+        //Type 1    == D
+        //Analyze the formula
+        //Check Type 1
+        //D = 1             = D(=1)
+        //C=0               = D
+        //A==B              = D
+        //B=0, C=1, D=0     = A
+        //C=1, B==D         = A
+        //A=1, B=0, D=0     = C
+        //A=1, C=1, D=0     = 1-B
+
+        splitType[i] = CM_FMT_TYPE_NOT_CHECKED; //All Type 1 will be changed to = D
+        if( m.c == MUX_0 || m.a==m.b || ( do_complement && (m.d == MUX_1 || m.b==MUX_1)) )
+        {
+            splitType[i] = CM_FMT_TYPE_D;   //All Type 1 will be changed to = D
+            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.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; i<end; i++ )
+    {
+        if( (pmux[i]&mask) == (val1&mask) )
+        {
+            pmux[i] &= (~mask);
+            pmux[i] |= val2;
+        }
+    }
+}
+
+uint32 DecodedMux::GetCycle(int cycle, CombineChannel channel)
+{
+    uint32* pmux = m_dWords;
+    if( channel == COLOR_CHANNEL )
+    {
+        return pmux[cycle*2];
+    }
+    else
+    {
+        return pmux[cycle*2+1];
+    }
+
+}
+
+uint32 DecodedMux::GetCycle(int cycle)
+{
+    return m_dWords[cycle];
+}
+
+enum ShadeConstMergeType
+{
+    SHADE_DO_NOTHING,
+    SHADE_ADD_PRIM,             // Shade+PRIM
+    SHADE_ADD_ENV,              // Shade+ENV
+    SHADE_ADD_PRIM_ALPHA,           // Shade+PRIM_ALPHA
+    SHADE_ADD_ENV_ALPHA,            // Shade+ENV_ALPHA
+    SHADE_MINUS_PRIM_PLUS_ENV,  
+    SHADE_MINUS_ENV_PLUS_PRIM,
+    SHADE_MOD_ENV,
+};
+
+typedef struct 
+{
+uint64 mux; // simplified
+ShadeConstMergeType op;
+} ShadeConstMergeMapType;
+
+ShadeConstMergeMapType MergeShadeWithConstantsMaps[] =
+{
+{0, SHADE_DO_NOTHING},
+{0x0007000600070006LL, SHADE_MOD_ENV}, // SHADE * ENV
+};
+
+// 0x05070501, 0x00070006       //(1 - PRIM) * ENV + PRIM
+// 0x00050003, 0x00050003       //(TEXEL0 - 0) * PRIM + 0
+
+void DecodedMux::MergeShadeWithConstants(void)
+{
+    // This function should be called afte the mux has been simplified
+    // The goal of this function is to merge as many as possible constants with shade
+    // so to reduce the totally number of constants to 0 or 1
+    // And at the same time, to reduce the complexity of the whole mux
+    // so we can implement the mux easiler when lower end video cards
+
+    // We can only try to merge shade with constants for:
+    // 1 cycle mode or 2 cycle mode and shade is not used in the 2nd cycle
+
+    if( m_bShadeIsUsed[0] ) MergeShadeWithConstantsInChannel(COLOR_CHANNEL);
+    if( m_bShadeIsUsed[1] ) MergeShadeWithConstantsInChannel(ALPHA_CHANNEL);
+}
+
+void DecodedMux::MergeShadeWithConstantsInChannel(CombineChannel channel)
+{
+    bool usedIn[2];
+    uint32 cycleVal;
+    int cycleNum;
+
+    usedIn[0] = isUsedInCycle(MUX_SHADE,channel);
+    usedIn[1] = isUsedInCycle(MUX_SHADE,channel+2);
+    if( usedIn[0] && usedIn[1] && GetCycle(channel)!=GetCycle(channel+2) )
+    {
+        //Shade is used in more than 1 cycles, and the ways it is used are different
+        //in cycles, so we can not merge shade with const factors
+        return; 
+    }
+
+    if( usedIn[0] ) { cycleVal = GetCycle(channel);cycleNum=0;}
+    else            {cycleVal = GetCycle(channel+2);cycleNum=1;}
+
+
+    //Update to here, Shade is either used only in 1 cycle, or the way it is used are totally
+    //the same in different cycles
+
+    if( cycleVal == 0x06000000 || isUsedInCycle(MUX_COMBINED,channel+cycleNum*2) )  // (0-0)*0+Shade
+    {
+        return;
+    }
+
+    //Now we can merge shade with consts
+    for( int i=0; i<2; i++ )
+    {
+        if( usedIn[i] )
+        {
+            N64CombinerType &m = m_n64Combiners[channel+i*2];
+            if( isUsedInCycle(MUX_TEXEL0,i*2+channel) || isUsedInCycle(MUX_TEXEL1,i*2+channel) )
+            {
+                if( (m.a&MUX_MASK) == MUX_TEXEL0 || (m.a&MUX_MASK) == MUX_TEXEL1 )
+                {
+                    // m.a is texel, can not merge constant with shade
+                    return;
+                }
+                else if( (m.b&MUX_MASK) == MUX_TEXEL0 || (m.b&MUX_MASK) == MUX_TEXEL1 )
+                {
+                    // m.b is texel, can not merge constant with shade
+                    return;
+                }
+                else if(( (m.c&MUX_MASK) == MUX_TEXEL0 || (m.c&MUX_MASK) == MUX_TEXEL1 ) )
+                {
+                    if( (m.d&MUX_MASK) != MUX_SHADE )
+                    {
+                        cycleVal &= 0x0000FFFF;     // A-B
+                    }
+                    else if( (m.a&MUX_MASK) == MUX_SHADE || (m.b&MUX_MASK) == MUX_SHADE )
+                    {
+                        return;
+                    }
+                }
+                else if( (m.d&MUX_MASK) == MUX_TEXEL0 || (m.d&MUX_MASK) == MUX_TEXEL1 )
+                {
+                    cycleVal &= 0x00FFFFFF;     // (A-B)*C
+                }
+            }
+            else
+            {
+                m.a = m.b = m.c = MUX_0;
+                m.d = MUX_SHADE;
+                splitType[i*2+channel] = CM_FMT_TYPE_D;
+            }
+        }
+    }
+
+    if( channel == COLOR_CHANNEL )
+        m_dwShadeColorChannelFlag = cycleVal;
+    else
+        m_dwShadeAlphaChannelFlag = cycleVal;
+}
+
+
+void DecodedMux::MergeConstants(void)
+{
+    // This function should be called afte the mux has been simplified
+    // The goal of this function is to merge remain constants and to reduce the
+    // total number of constants, so we can implement the mux easiler
+
+    // This function should be called after the MergeShadeWithConstants() function
+}
+
+
+void DecodedMux::UseShadeForConstant(void)
+{
+    // If shade is not used in the mux, we can use it for constants
+    // This function should be called after constants have been merged
+
+    bool doAlphaChannel = true;
+    uint8 mask = (uint8)~MUX_COMPLEMENT;
+
+    int constants = 0;
+    if( isUsed(MUX_ENV) ) constants++;
+    if( isUsed(MUX_PRIM) ) constants++;
+    if( isUsed(MUX_LODFRAC) ) constants++;
+    if( isUsed(MUX_PRIMLODFRAC) ) constants++;
+
+    bool forceToUsed = constants>m_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;
+        }
+    }
+}
+
diff --git a/source/gles2rice/src/DecodedMux.h b/source/gles2rice/src/DecodedMux.h
new file mode 100644 (file)
index 0000000..3e9698b
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+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 <string.h>
+#include <stdio.h>
+
+#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
+
+
diff --git a/source/gles2rice/src/DeviceBuilder.cpp b/source/gles2rice/src/DeviceBuilder.cpp
new file mode 100644 (file)
index 0000000..83275ec
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+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;
+}
+
diff --git a/source/gles2rice/src/DeviceBuilder.h b/source/gles2rice/src/DeviceBuilder.h
new file mode 100644 (file)
index 0000000..0d6961b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+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
+
+
diff --git a/source/gles2rice/src/DirectXDecodedMux.cpp b/source/gles2rice/src/DirectXDecodedMux.cpp
new file mode 100644 (file)
index 0000000..2fab963
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+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 <algorithm>
+
+#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]);
+}
+
+
diff --git a/source/gles2rice/src/DirectXDecodedMux.h b/source/gles2rice/src/DirectXDecodedMux.h
new file mode 100644 (file)
index 0000000..318ff31
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+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
+
+
diff --git a/source/gles2rice/src/ExtendedRender.h b/source/gles2rice/src/ExtendedRender.h
new file mode 100644 (file)
index 0000000..180e84c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+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
+
diff --git a/source/gles2rice/src/FrameBuffer.cpp b/source/gles2rice/src/FrameBuffer.cpp
new file mode 100644 (file)
index 0000000..4d86924
--- /dev/null
@@ -0,0 +1,2086 @@
+/*
+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 <vector>
+
+#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<numOfTxtBufInfos; i++ )
+    {
+        SAFE_DELETE(gRenderTextureInfos[i].pRenderTexture);
+    }
+}
+
+void FrameBufferManager::Initialize()
+{
+    m_isRenderingToTexture = false;
+    m_lastTextureBufferIndex = -1;
+    m_curRenderTextureIndex = -1;
+    
+    status.bCIBufferIsRendered = false;
+    status.bN64IsDrawingTextureBuffer = false;
+    status.bHandleN64RenderTexture = false;
+    status.bN64FrameBufferIsUsed = false;
+
+    memset(&gRenderTextureInfos[0], 0, sizeof(RenderTextureInfo)*numOfTxtBufInfos);
+}
+// ===========================================================================
+
+uint16 ConvertRGBATo555(uint8 r, uint8 g, uint8 b, uint8 a)
+{
+    uint8 ar = a>=0x20?1:0;
+    return ((r>>3)<<RGBA5551_RedShift) | ((g>>3)<<RGBA5551_GreenShift) | ((b>>3)<<RGBA5551_BlueShift) | ar;//(a>>7);
+}
+
+uint16 ConvertRGBATo555(uint32 color32)
+{
+    return (uint16)((((color32>>19)&0x1F)<<RGBA5551_RedShift) | (((color32>>11)&0x1F)<<RGBA5551_GreenShift) | (((color32>>3)&0x1F)<<RGBA5551_BlueShift) | ((color32>>31)));;
+}
+
+void FrameBufferManager::UpdateRecentCIAddr(SetImgInfo &ciinfo)
+{
+    if( ciinfo.dwAddr == g_uRecentCIInfoPtrs[0]->dwAddr )
+        return;
+
+    RecentCIInfo *temp;
+
+    int i;
+    for( i=1; i<numOfRecentCIInfos; i++ )
+    {
+        if( ciinfo.dwAddr == g_uRecentCIInfoPtrs[i]->dwAddr )
+        {
+            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)<<temp->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; i<numOfRecentCIInfos; i++ )
+    {
+        if( g_uRecentCIInfoPtrs[i]->dwAddr+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; i<numOfRecentCIInfos; i++ )
+    {
+        if( g_RecentVIOriginInfo[i].addr == addr )
+        {
+            g_RecentVIOriginInfo[i].FrameCount = status.gDlistCount;
+            return;
+        }
+    }
+
+    for( i=0; i<numOfRecentCIInfos; i++ )
+    {
+        if( g_RecentVIOriginInfo[i].addr == 0 )
+        {
+            // Never used
+            g_RecentVIOriginInfo[i].addr = addr;
+            g_RecentVIOriginInfo[i].FrameCount = status.gDlistCount;
+            return;
+        }
+    }
+
+    int index=0;
+    uint32 minFrameCount = 0xffffffff;
+
+    for( i=0; i<numOfRecentCIInfos; i++ )
+    {
+        if( g_RecentVIOriginInfo[i].FrameCount < minFrameCount )
+        {
+            index = i;
+            minFrameCount = g_RecentVIOriginInfo[i].FrameCount;
+        }
+    }
+
+    g_RecentVIOriginInfo[index].addr = addr;
+    g_RecentVIOriginInfo[index].FrameCount = status.gDlistCount;
+}
+
+bool FrameBufferManager::HasAddrBeenDisplayed(uint32 addr, uint32 width)
+{
+    addr &= (g_dwRamSize-1);
+    
+    int i;
+    for( i=0; i<numOfRecentCIInfos; i++ )
+    {
+        if( g_uRecentCIInfoPtrs[i]->dwAddr == 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<numOfRecentCIInfos; i++ )
+    {
+        if( g_RecentVIOriginInfo[i].addr != 0 )
+        {
+            if( g_RecentVIOriginInfo[i].addr > 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; i<numOfRecentCIInfos; i++ )
+    {
+        if( g_uRecentCIInfoPtrs[i]->dwAddr <= 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<numOfTxtBufInfos; i++ )
+        {
+            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( 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<<size)+1)/2;
+
+    if( currentRomOptions.bFastTexCRC && !options.bLoadHiResTextures && (height>=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<<size)+1)>>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<<size)+1)/2;
+
+            pAsmStart = (uint8*)(pPhysicalAddress);
+            pAsmStart += (top * pitchInBytes) + (((left<<size)+1)>>1);
+
+            dwAsmHeight = height - 1;
+            dwAsmPitch = pitchInBytes;
+
+#if defined(NO_ASM)
+            uint32 pitch = pitchInBytes>>2;
+            uint32* pStart = (uint32*)pPhysicalAddress;
+            pStart += (top * pitch) + (((left<<size)+1)>>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<height; y++ )
+        {
+            buf = (unsigned char*)pPhysicalAddress + left + pitchInBytes * (y+top);
+            for( x=0; x<width; x++ )
+            {
+                if( buf[x] > val )  val = buf[x];
+                if( val == 0xFF )
+                    return 0xFF;
+            }
+        }
+    }
+    else
+    {
+        unsigned char val1,val2;
+        left >>= 1;
+        width >>= 1;
+        for( y = 0; y<height; y++ )
+        {
+            buf = (unsigned char*)pPhysicalAddress + left + pitchInBytes * (y+top);
+            for( x=0; x<width; x++ )
+            {
+                val1 = buf[x]>>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<uint32> 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<RECT> 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; i<size; i++ )
+        {
+            off = frameWriteRecord[i]-base;
+            if( off < (int)g_uRecentCIInfoPtrs[index]->dwMemSize )
+            {
+                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<RECT> 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; i<size; i++)
+                {
+                CRender::GetRender()->DrawFrameBuffer(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)<<CIinfo.dwSize;
+
+    for( int i=0; i<numOfTxtBufInfos; i++ )
+    {
+        RenderTextureInfo &info = gRenderTextureInfos[i];
+        if( !info.isUsed )  continue;
+
+        bool covered = false;
+
+        if( info.CI_Info.dwAddr == CIinfo.dwAddr )
+        {
+            if( info.CI_Info.dwSize == CIinfo.dwSize &&
+                info.CI_Info.dwWidth == CIinfo.dwWidth &&
+                info.CI_Info.dwFormat == CIinfo.dwFormat &&
+                info.N64Height == height 
+                )
+            {
+                // This is the same texture at the same address
+                if( byNewTxtrBuf )
+                {
+                    matchidx = i;
+                    break;
+                }
+            }
+
+            // At the same address, but not the same size
+            //SAFE_DELETE(info.psurf);
+            covered = true;
+        }
+
+        if( !covered )
+        {
+            uint32 memsize2 = ((info.N64Height*info.N64Width)>>1)<<info.CI_Info.dwSize;
+
+            if( info.CI_Info.dwAddr > 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; i<numOfTxtBufInfos; i++ )
+    {
+        if( !gRenderTextureInfos[i].isUsed && gRenderTextureInfos[i].updateAtFrame < status.gDlistCount )
+        {
+            found = true;
+            idx = i;
+            break;
+        }
+    }
+
+    // If cannot find an empty slot, find the oldest slot and reuse the slot
+    if( !found )
+    {
+        uint32 oldestCount=0xFFFFFFFF;
+        uint32 oldestIdx = 0;
+        for( int i=0; i<numOfTxtBufInfos; i++ )
+        {
+            if( gRenderTextureInfos[i].updateAtUcodeCount < oldestCount )
+            {
+                oldestCount = gRenderTextureInfos[i].updateAtUcodeCount;
+                oldestIdx = i;
+            }
+        }
+
+        idx = oldestIdx;
+    }
+
+    DEBUGGER_IF_DUMP((logTextureBuffer && gRenderTextureInfos[idx].pRenderTexture ),TRACE2("Delete txtr buf %d at %08X, to reuse it.", idx, gRenderTextureInfos[idx].CI_Info.dwAddr ));
+    SAFE_DELETE(gRenderTextureInfos[idx].pRenderTexture) ;
+
+    return idx;
+}
+
+
+void FrameBufferManager::SetRenderTexture(void)
+{
+    memcpy(&(newRenderTextureInfo.CI_Info), &g_CI, sizeof(SetImgInfo));
+
+    newRenderTextureInfo.N64Width = newRenderTextureInfo.CI_Info.dwWidth;
+    newRenderTextureInfo.knownHeight = ComputeCImgHeight(g_CI, newRenderTextureInfo.N64Height);
+
+    status.bHandleN64RenderTexture = true;
+    newRenderTextureInfo.maxUsedHeight = 0;
+
+    if( defaultRomOptions.bInN64Resolution )
+    {
+        newRenderTextureInfo.bufferWidth = newRenderTextureInfo.N64Width;
+        newRenderTextureInfo.bufferHeight = newRenderTextureInfo.N64Height;
+    }
+    else if( defaultRomOptions.bDoubleSizeForSmallTxtrBuf && newRenderTextureInfo.N64Width<=128 && newRenderTextureInfo.N64Height<=128)
+    {
+        newRenderTextureInfo.bufferWidth = newRenderTextureInfo.N64Width*2;
+        newRenderTextureInfo.bufferHeight = newRenderTextureInfo.N64Height*2;
+    }
+    else
+    {
+        newRenderTextureInfo.bufferWidth = newRenderTextureInfo.N64Width;
+        newRenderTextureInfo.bufferHeight = newRenderTextureInfo.N64Height;
+    }
+
+    newRenderTextureInfo.scaleX = newRenderTextureInfo.bufferWidth / float(newRenderTextureInfo.N64Width);
+    newRenderTextureInfo.scaleY = newRenderTextureInfo.bufferHeight / float(newRenderTextureInfo.N64Height);
+
+    status.bFrameBufferIsDrawn = false;
+    status.bFrameBufferDrawnByTriangles = false;
+
+    newRenderTextureInfo.updateAtFrame = status.gDlistCount;
+    newRenderTextureInfo.updateAtUcodeCount = status.gUcodeCount;
+
+    // Delay activation of the render_texture until the 1st rendering
+
+    TXTRBUF_DUMP(TRACE1("Set render_texture: addr=%08X", g_CI.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",
+    g_CI.dwAddr, pszImgFormat[g_CI.dwFormat], pszImgSize[g_CI.dwSize], g_CI.dwWidth, g_pRenderTextureInfo->N64Height);});
+}
+
+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)<<tempRenderTextureInfo.CI_Info.dwSize;
+    int matchidx = CheckRenderTexturesWithNewCI(CIinfo,tempRenderTextureInfo.N64Height,false);
+    int idxToUse = (matchidx >= 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; y<height; y++)
+        {
+            for( uint32 x=0; x<width; x++ )
+            {
+                *(frameBufferBase+(y+top)*pitch+x+left) = 0;
+            }
+        }
+    }
+}
+
+uint8 RevTlutTable[0x10000];
+bool RevTlutTableNeedUpdate = false;
+void InitTlutReverseLookup(void)
+{
+    if( RevTlutTableNeedUpdate )
+    {
+        memset(RevTlutTable, 0, 0x10000);
+        for( int i=0; i<=0xFF; i++ )
+        {
+            RevTlutTable[g_wRDPTlut[i]] = uint8(i);
+        }
+
+        RevTlutTableNeedUpdate = false;
+    }
+}
+
+
+// Copies backbuffer to N64 framebuffer by notification by emu core
+// **buggy**
+void FrameBufferManager::CopyBackToFrameBufferIfReadByCPU(uint32 addr)
+{
+    int i = FindRecentCIInfoIndex(addr);
+    if( i != -1 )
+    {
+        //if( i == 0 ) CGraphicsContext::Get()->UpdateFrame();
+        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; i<numOfTxtBufInfos; i++ )
+    {
+        if( !gRenderTextureInfos[i].isUsed )    
+            continue;
+
+        if( gRenderTextureInfos[i].pRenderTexture->IsBeingRendered() )
+            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; i<numOfTxtBufInfos; i++ )
+    {
+        if( !gRenderTextureInfos[i].isUsed )    
+            continue;
+
+        if( gRenderTextureInfos[i].pRenderTexture->IsBeingRendered() )
+            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)<<newRenderTextureInfo.CI_Info.dwSize;
+
+        matchidx = CheckRenderTexturesWithNewCI(g_CI,newRenderTextureInfo.N64Height,true);
+
+        int idxToUse=-1;
+        if( matchidx >= 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; j<width; j++ )
+        {
+            sx = j*ratio;
+            sx0 = int(sx+0.5);
+            indexes[j] = 4*sx0;
+        }
+    }
+
+    if( siz == TXT_SIZE_16b )
+    {
+        uint16 *frameBufferBase = (uint16*)(g_pRDRAMu8+addr);
+
+        if( bufFmt==TEXTURE_FMT_A8R8G8B8 )
+        {
+            int  sy0;
+            float ratio = bufHeight/(float)height;
+
+            for( uint32 i=startline; i<endline; i++ )
+            {
+                sy0 = int(i*ratio+0.5);
+
+                uint16 *pD = frameBufferBase + i * pitch;
+                uint8 *pS0 = (uint8 *)buffer + sy0 * bufPitch;
+
+                for( uint32 j=0; j<width; j++ )
+                {
+                    // Point
+                    uint8 r = pS0[indexes[j]+2];
+                    uint8 g = pS0[indexes[j]+1];
+                    uint8 b = pS0[indexes[j]+0];
+                    uint8 a = pS0[indexes[j]+3];
+
+                    // Liner
+                    *(pD+(j^1)) = ConvertRGBATo555( r, g, b, a);
+                }
+            }
+        }
+        else
+        {
+            TRACE1("Copy %sb FrameBuffer to Rdram, not implemented", pszImgSize[siz]);
+        }
+    }
+    else if( siz == TXT_SIZE_8b && fmt == TXT_FMT_CI )
+    {
+        uint8 *frameBufferBase = (uint8*)(g_pRDRAMu8+addr);
+
+        if( bufFmt==TEXTURE_FMT_A8R8G8B8 )
+        {
+            uint16 tempword;
+            InitTlutReverseLookup();
+
+            for( uint32 i=startline; i<endline; i++ )
+            {
+                uint8 *pD = frameBufferBase + i * width;
+                uint8 *pS = (uint8 *)buffer + i*bufHeight/height * bufPitch;
+                for( uint32 j=0; j<width; j++ )
+                {
+                    int pos = 4*(j*bufWidth/width);
+                    tempword = ConvertRGBATo555((pS[pos+2]),        // Red
+                                                (pS[pos+1]),        // Green
+                                                (pS[pos+0]),        // Blue
+                                                (pS[pos+3]));       // Alpha
+                    
+                    //*pD = CIFindIndex(tempword);
+                    *(pD+(j^3)) = RevTlutTable[tempword];
+                }
+            }
+        }
+        else
+        {
+            TRACE1("Copy %sb FrameBuffer to Rdram, not implemented", pszImgSize[siz]);
+        }
+        DEBUGGER_IF_DUMP(pauseAtNext,{DebuggerAppendMsg("Copy %sb FrameBuffer to Rdram", pszImgSize[siz]);});
+    }
+    else if( siz == TXT_SIZE_8b && fmt == TXT_FMT_I )
+    {
+        uint8 *frameBufferBase = (uint8*)(g_pRDRAMu8+addr);
+
+        if( bufFmt==TEXTURE_FMT_A8R8G8B8 )
+        {
+            int sy0;
+            float ratio = bufHeight/(float)height;
+
+            for( uint32 i=startline; i<endline; i++ )
+            {
+                sy0 = int(i*ratio+0.5);
+
+                uint8 *pD = frameBufferBase + i * width;
+                uint8 *pS0 = (uint8 *)buffer + sy0 * bufPitch;
+
+                for( uint32 j=0; j<width; j++ )
+                {
+                    // Point
+                    uint32 r = pS0[indexes[j]+2];
+                    uint32 g = pS0[indexes[j]+1];
+                    uint32 b = pS0[indexes[j]+0];
+
+                    // Liner
+                    *(pD+(j^3)) = (uint8)((r+b+g)/3);
+                }
+            }
+        }
+        else
+        {
+            //DebuggerAppendMsg("Copy %sb FrameBuffer to Rdram, not implemented", pszImgSize[siz]);
+        }
+        DEBUGGER_IF_DUMP(pauseAtNext,{DebuggerAppendMsg("Copy %sb FrameBuffer to Rdram", pszImgSize[siz]);});
+    }
+}
+
+
+#ifdef DEBUGGER
+void FrameBufferManager::DisplayRenderTexture(int infoIdx)
+{
+    if( infoIdx < 0 )
+        infoIdx = m_lastTextureBufferIndex;
+
+    if( gRenderTextureInfos[infoIdx].pRenderTexture )
+    {
+        if( gRenderTextureInfos[infoIdx].pRenderTexture->IsBeingRendered() )
+        {
+            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;
+}
+
diff --git a/source/gles2rice/src/FrameBuffer.h b/source/gles2rice/src/FrameBuffer.h
new file mode 100644 (file)
index 0000000..1d796e9
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+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
+
diff --git a/source/gles2rice/src/GeneralCombiner.cpp b/source/gles2rice/src/GeneralCombiner.cpp
new file mode 100644 (file)
index 0000000..9329bd2
--- /dev/null
@@ -0,0 +1,1308 @@
+/*
+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 <algorithm>
+
+#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; i<gci.nStages; i++ )
+    {
+        GeneralCombineStage &s = gci.stages[i];
+        DebuggerAppendMsg("%d:Color: %s - %s, %s, %s%s\n", i,
+            cmopstrs[s.colorOp.op], DecodedMux::FormatStr((uint8)s.colorOp.Arg1, str1),     s.colorOp.Arg2==CM_IGNORE?"":DecodedMux::FormatStr((uint8)s.colorOp.Arg2, str2), 
+            s.colorOp.Arg0==CM_IGNORE?"":DecodedMux::FormatStr((uint8)s.colorOp.Arg0, str3),
+            s.dwTexture!=0?" -Tex1":"");
+    }
+    
+    for( int i=0; i<gci.nStages; i++ )
+    {
+        GeneralCombineStage &s = gci.stages[i];
+        DebuggerAppendMsg("%d:Alpha: %s - %s, %s, %s%s\n", i,
+            cmopstrs[s.alphaOp.op], DecodedMux::FormatStr((uint8)s.alphaOp.Arg1, str1), 
+            s.alphaOp.Arg2==CM_IGNORE?"":DecodedMux::FormatStr((uint8)s.alphaOp.Arg2, str2),
+            s.alphaOp.Arg0==CM_IGNORE?"":DecodedMux::FormatStr((uint8)s.alphaOp.Arg0, str3),
+            s.dwTexture!=0?" -Tex1":"");
+    }
+    TRACE0("\n\n");
+}
+#endif
+
+
+///////////////////////////////////////
+// Combiner gci generating functions //
+///////////////////////////////////////
+
+bool textureUsedInStage[8][2];
+bool resultIsGood;
+
+void CGeneralCombiner::GenCI_Init(GeneralCombinerInfo &gci)
+{
+    gci.specularPostOp=gci.TFactor=MUX_0;
+
+    gci.blendingFunc = ENABLE_BOTH;
+    resultIsGood = true;
+
+    //After the mux is reformated and simplified, we can use it to generate combine stages
+    //return false if we can not generate it
+
+    for( int i=0; i<8; i++)
+    {
+        gci.stages[i].dwTexture = 0;
+        textureUsedInStage[i][0] = false;       // For color
+        textureUsedInStage[i][1] = false;       // For alpha
+        gci.stages[i].bTextureUsed = false;
+        gci.stages[i].dwTexture = 0;
+        gci.stages[i].colorOp.op = gci.stages[i].alphaOp.op = CM_REPLACE;
+        gci.stages[i].colorOp.Arg1 = gci.stages[i].alphaOp.Arg1 = MUX_COMBINED;
+        gci.stages[i].colorOp.Arg2 = gci.stages[i].alphaOp.Arg2 = CM_IGNORE;
+        gci.stages[i].colorOp.Arg0 = gci.stages[i].alphaOp.Arg0 = CM_IGNORE;
+    }
+
+    DecodedMux &mux = *(*m_ppGeneralDecodedMux);
+
+    // Check some special cases of alpha channel
+    if( mux.splitType[N64Cycle0Alpha]==CM_FMT_TYPE_D && mux.splitType[N64Cycle1Alpha]==CM_FMT_TYPE_NOT_USED )
+    {
+        //if( mux.m_n64Combiners[N64Cycle0Alpha].d == MUX_0 )
+        //  gci.blendingFunc = DISABLE_COLOR;
+        //else 
+        if( mux.m_n64Combiners[N64Cycle0Alpha].d == MUX_1  )
+            gci.blendingFunc = DISABLE_ALPHA;
+    }
+    else if( mux.splitType[N64Cycle1Alpha]==CM_FMT_TYPE_D )
+    {
+        //if( mux.m_n64Combiners[N64Cycle1Alpha].d == MUX_0 )
+        //  gci.blendingFunc = DISABLE_COLOR;
+        //else 
+        if( mux.m_n64Combiners[N64Cycle1Alpha].d == MUX_1  )
+            gci.blendingFunc = DISABLE_ALPHA;
+    }
+
+    if( mux.splitType[N64Cycle0RGB]==CM_FMT_TYPE_D && mux.splitType[N64Cycle1RGB]==CM_FMT_TYPE_NOT_USED )
+    {
+        if( mux.m_n64Combiners[N64Cycle0RGB].d == MUX_0 )
+            gci.blendingFunc = DISABLE_COLOR;
+    }
+
+}
+
+int CGeneralCombiner::GenCI_Type_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.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 (curStage<m_dwGeneralMaxStages-1 && textureUsedInStage[curStage][0] && gci.stages[curStage].dwTexture != (unsigned int)(tex) )
+        {
+            StageOperate &op = ((StageOperate*)(&(gci.stages[curStage].colorOp)))[curN64Stage%2];
+            SkipStage(op, curStage);
+        }
+    }
+}
+
+
+int CGeneralCombiner::Check2TxtrForAlpha(int curN64Stage, int &curStage, GeneralCombinerInfo &gci, int tex1, int tex2)
+{
+    N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage];
+    if( curN64Stage%2 && IsTxtrUsed(m) )
+    {
+        if( tex1 == tex2 )
+        {
+            while (curStage<m_dwGeneralMaxStages-1 && textureUsedInStage[curStage][0] && gci.stages[curStage].dwTexture != (unsigned int)tex1 )
+            {
+                StageOperate &op = ((StageOperate*)(&(gci.stages[curStage].colorOp)))[curN64Stage%2];
+                SkipStage(op, curStage);
+            }
+            return 1;
+        }
+        else
+        {
+            int stage1 = curStage;
+            int stage2 = curStage;
+
+            while (stage1<m_dwGeneralMaxStages-1 && textureUsedInStage[stage1][0] && gci.stages[stage1].dwTexture != (unsigned int)tex1 )
+            {
+                StageOperate &op = ((StageOperate*)(&(gci.stages[stage1].colorOp)))[curN64Stage%2];
+                SkipStage(op, stage1);
+            }
+
+            while (stage2<m_dwGeneralMaxStages-1 && textureUsedInStage[stage2][0] && gci.stages[stage2].dwTexture != (unsigned int)tex2 )
+            {
+                StageOperate &op = ((StageOperate*)(&(gci.stages[stage2].colorOp)))[curN64Stage%2];
+                SkipStage(op, stage2);
+            }
+
+            if( stage1 <= stage2 )
+            {
+                curStage = stage1;
+                return 1;
+            }
+            else
+            {
+                curStage = stage2;
+                return 2;
+            }
+        }
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+
+int CGeneralCombiner::CheckWhichTexToUseInThisStage(int curN64Stage, int curStage, GeneralCombinerInfo &gci)
+{
+    // There are two texels to used, which one I should use in the current DirectX stage?
+    if( curN64Stage%2 )
+    {
+        if( !textureUsedInStage[curStage][0] )
+            return 0;
+        else
+            return gci.stages[curStage].dwTexture;
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+/*
+ *  
+ */
+
+int CGeneralCombiner::ParseDecodedMux()
+{
+    GeneralCombinerInfo gci;
+    int stages[2];
+
+    DecodedMux &mux = *(*m_ppGeneralDecodedMux);
+
+    GenCI_Init(gci);
+
+    for( int i=0; i<2; i++ )
+    {
+        //i=0       Color Channel
+        //i=1       Alpha Channel
+
+        stages[i] = 0;
+        int n=0;    //stage count
+
+        for( int j=0; j<2; j++ )
+        {
+            switch( mux.splitType[i+j*2] )
+            {
+            case CM_FMT_TYPE_NOT_USED:
+                continue;
+            case CM_FMT_TYPE_D:     // = D
+                // Alpha channel is using different texture from color channel
+                // and the color channel has already used texture, so alpha
+                // channel can not use different texture for this stage anymore,
+                // alpha channel need to skip a stage
+                n = GenCI_Type_D(j*2+i, n, gci);
+                if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n);  else n++;
+                break;
+            case CM_FMT_TYPE_A_ADD_D:       // = A+D
+                n=GenCI_Type_A_ADD_D(j*2+i, n, gci);
+                if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n);  else n++;
+                break;
+            case CM_FMT_TYPE_A_MOD_C:       // = A*C        can mapped to MOD(arg1,arg2)
+                n=GenCI_Type_A_MOD_C(j*2+i, n, gci);
+                if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n);  else n++;
+                break;
+            case CM_FMT_TYPE_A_SUB_B:       // = A-B        can mapped to SUB(arg1,arg2)
+                n=GenCI_Type_A_SUB_B(j*2+i, n, gci);
+                if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n);  else n++;
+                break;
+            case CM_FMT_TYPE_A_MOD_C_ADD_D:     // = A*C+D      can mapped to MULTIPLYADD(arg1,arg2,arg0)
+                n=GenCI_Type_A_MOD_C_ADD_D(j*2+i, n, gci);
+                if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n);  else n++;
+                break;
+            case 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
+                n=GenCI_Type_A_LERP_B_C(j*2+i, n, gci);
+                if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n);  else n++;
+                break;
+            case CM_FMT_TYPE_A_SUB_B_ADD_D:     // = A-B+C      can not map very well in 1 stage
+                n=GenCI_Type_A_SUB_B_ADD_D(j*2+i, n, gci);
+                if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n);  else n++;
+                break;
+            case CM_FMT_TYPE_A_SUB_B_MOD_C:     // = (A-B)*C    can not map very well in 1 stage
+                n=GenCI_Type_A_SUB_B_MOD_C(j*2+i, n, gci);
+                if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n);  else n++;
+                break;
+            case CM_FMT_TYPE_A_ADD_B_MOD_C:
+                n=GenCI_Type_A_ADD_B_MOD_C(j*2+i, n, gci);
+                if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n);  else n++;
+                break;
+            case CM_FMT_TYPE_A_B_C_A:
+                n=GenCI_Type_A_B_C_A(j*2+i, n, gci);
+                if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n);  else n++;
+                break;
+            case CM_FMT_TYPE_A_B_C_D:       // = (A-B)*C+D  can not map very well in 1 stage
+                n=GenCI_Type_A_B_C_D(j*2+i, n, gci);
+                if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n);  else n++;
+                break;
+             default:
+               break;
+            }
+        }
+        stages[i] = n;
+    }
+
+    gci.nStages = max(stages[0], stages[1]);
+    if( gci.nStages > 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<gci.nStages; i++ )
+        {
+            gci.stages[i].colorOp.op = CM_REPLACE;
+            gci.stages[i].colorOp.Arg1 = MUX_COMBINED;
+            gci.stages[i].colorOp.Arg2 = CM_IGNORE;
+            gci.stages[i].colorOp.Arg0 = CM_IGNORE;
+        }
+    }
+
+    if( gci.nStages > stages[1] )   // Color has less stages
+    {
+        for( int i=stages[1]; i<gci.nStages; i++ )
+        {
+            gci.stages[i].alphaOp.op = CM_REPLACE;
+            gci.stages[i].alphaOp.Arg1 = MUX_COMBINED;
+            gci.stages[i].alphaOp.Arg2 = CM_IGNORE;
+            gci.stages[i].alphaOp.Arg0 = CM_IGNORE;
+        }
+    }
+
+    for( int i=0;i<gci.nStages;i++)
+    {
+        gci.stages[i].bTextureUsed = IsTextureUsedInStage(gci.stages[i]);
+    }
+
+    if( !resultIsGood && gci.nStages >= m_dwGeneralMaxStages )
+    {
+        extern int noOfTwoStages;
+        extern GeneralCombinerInfo twostages[];
+
+        for( int k=0; k<noOfTwoStages; k++ )
+        {
+            GeneralCombinerInfo &info = twostages[k];
+            if( (mux.m_dwMux0 == info.dwMux0 && mux.m_dwMux1 == info.dwMux1) ||
+                (info.dwMux0+info.dwMux1 == 0 && info.muxDWords[0] == mux.m_dWords[0] && 
+                info.muxDWords[1] == mux.m_dWords[1] && info.muxDWords[2] == mux.m_dWords[2] && 
+                info.muxDWords[3] == mux.m_dWords[3] && info.m_dwShadeAlphaChannelFlag == mux.m_dwShadeAlphaChannelFlag &&
+                info.m_dwShadeColorChannelFlag == mux.m_dwShadeColorChannelFlag ) )
+            {
+                memcpy(&gci, &info, sizeof(GeneralCombinerInfo) );
+                resultIsGood = true;
+                break;
+            }
+        }
+    }
+
+#ifdef DEBUGGER
+    if( !resultIsGood )
+    {
+        DecodedMux &mux = *(*m_ppGeneralDecodedMux);
+        // Generated combiner mode is not good enough within the limited stages
+        DebuggerAppendMsg("\n/*");
+        mux.DisplayMuxString("Overflowed");
+        mux.DisplaySimpliedMuxString("Overflowed");
+        DebuggerAppendMsg("Generated combiners:");
+        General_DisplayBlendingStageInfo(gci);
+        DebuggerAppendMsg("*/\n");
+        DebuggerAppendMsg("\n\n");
+        DebuggerAppendMsg("{\n\t0x%08X, 0x%08X, 0x%08X, 0x%08X,\t// Simplified mux\n\t0x%08X, 0x%08X,\t\t// 64bit Mux\n",
+            mux.m_dWords[0],mux.m_dWords[1],mux.m_dWords[2],mux.m_dWords[3],mux.m_dwMux0,mux.m_dwMux1);
+        DebuggerAppendMsg("\t%d,\t// number of stages\n\tENABLE_BOTH,\n\t0,\t\t// Constant color\n\t0x%08X, 0x%08X, 0,\t// Shade and specular color flags\n\t0x%08X, 0x%08X,\t// constant color texture flags\n",
+            2,mux.m_dwShadeColorChannelFlag, mux.m_dwShadeAlphaChannelFlag,mux.m_ColorTextureFlag[0],mux.m_ColorTextureFlag[1]);
+        DebuggerAppendMsg("\t{\n\t\t{MOD(T0,DIF), MOD(T0,DIF), 0, true},    // Stage 0\n");
+        DebuggerAppendMsg("\t\t{MOD(T0,DIF), SKIP, 1, true},    // Stage 1\n\t}\n},");
+    }
+#else
+    if( !resultIsGood )
+    {
+        FILE *fp=NULL;
+        fp = fopen("C:\\rice\\RiceVideoMUX.log","a");
+        if( fp )
+        {
+            fprintf(fp,"\n/*\n");
+            mux.LogMuxString("Overflowed",fp);
+            fprintf(fp,"\n\n");
+            mux.LogSimpliedMuxString("Overflowed",fp);
+            fprintf(fp,"Generated combiners:");
+            //General_DisplayBlendingStageInfo(gci);
+            fprintf(fp,"\n*/\n");
+            fprintf(fp,"\n");
+            fprintf(fp,"{\n\t0x%08X, 0x%08X, 0x%08X, 0x%08X,\t// Simplified mux\n\t0x%08X, 0x%08X,\t\t// 64bit Mux\n",
+                mux.m_dWords[0],mux.m_dWords[1],mux.m_dWords[2],mux.m_dWords[3],mux.m_dwMux0,mux.m_dwMux1);
+            fprintf(fp,"\t%d,\t// number of stages\n\tENABLE_BOTH,\n\tMUX_ENV,\t\t// Constant color\n\t0x%08X, 0x%08X, 0,\t// Shade and specular color flags\n\t0x%08X, 0x%08X,\t// constant color texture flags\n",
+                2,mux.m_dwShadeColorChannelFlag, mux.m_dwShadeAlphaChannelFlag,mux.m_ColorTextureFlag[0],mux.m_ColorTextureFlag[1]);
+            fprintf(fp,"\t{\n\t\t{MOD(T0,DIF), MOD(T0,DIF), 0, true},   // Stage 0\n");
+            fprintf(fp,"\t\t{LERP(T1,CUR,DIF), SKIP, 1, true},  // Stage 1\n\t}\n},");
+
+            fclose(fp);
+        }
+    }
+#endif
+
+    return SaveParserResult(gci);
+}
+
+
+bool CGeneralCombiner::IsTextureUsedInStage(GeneralCombineStage &stage)
+{
+    if( (stage.colorOp.Arg1&MUX_MASK)==MUX_TEXEL0 || (stage.colorOp.Arg2&MUX_MASK)==MUX_TEXEL0 || (stage.colorOp.Arg0 &MUX_MASK)==MUX_TEXEL0 ||
+        (stage.alphaOp.Arg1&MUX_MASK)==MUX_TEXEL0 || (stage.alphaOp.Arg2&MUX_MASK)==MUX_TEXEL0 || (stage.alphaOp.Arg0 &MUX_MASK)==MUX_TEXEL0 ||
+        (stage.colorOp.Arg1&MUX_MASK)==MUX_TEXEL1 || (stage.colorOp.Arg2&MUX_MASK)==MUX_TEXEL1 || (stage.colorOp.Arg0 &MUX_MASK)==MUX_TEXEL1 ||
+        (stage.alphaOp.Arg1&MUX_MASK)==MUX_TEXEL1 || (stage.alphaOp.Arg2&MUX_MASK)==MUX_TEXEL1 || (stage.alphaOp.Arg0 &MUX_MASK)==MUX_TEXEL1 )
+    {
+        return true;
+    }
+    else
+        return false;
+}
+
+
+int CGeneralCombiner::SaveParserResult(GeneralCombinerInfo &result)
+{
+    result.muxDWords[0] = (*m_ppGeneralDecodedMux)->m_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; i<m_vCompiledCombinerStages.size(); i++ )
+    {
+        if( m_vCompiledCombinerStages[i].dwMux0 == (*m_ppGeneralDecodedMux)->m_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;
+}
+
diff --git a/source/gles2rice/src/GeneralCombiner.h b/source/gles2rice/src/GeneralCombiner.h
new file mode 100644 (file)
index 0000000..0e0d412
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+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 <vector>
+
+#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<GeneralCombinerInfo> 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
+
diff --git a/source/gles2rice/src/GraphicsContext.cpp b/source/gles2rice/src/GraphicsContext.cpp
new file mode 100644 (file)
index 0000000..37b91fa
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+
+  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();
+}
+
diff --git a/source/gles2rice/src/GraphicsContext.h b/source/gles2rice/src/GraphicsContext.h
new file mode 100644 (file)
index 0000000..e1d58b8
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+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
+
diff --git a/source/gles2rice/src/IColor.h b/source/gles2rice/src/IColor.h
new file mode 100644 (file)
index 0000000..179f6c0
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+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
+
+
diff --git a/source/gles2rice/src/OGLCombiner.cpp b/source/gles2rice/src/OGLCombiner.cpp
new file mode 100644 (file)
index 0000000..10c5334
--- /dev/null
@@ -0,0 +1,356 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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
+
diff --git a/source/gles2rice/src/OGLCombiner.h b/source/gles2rice/src/OGLCombiner.h
new file mode 100644 (file)
index 0000000..0846918
--- /dev/null
@@ -0,0 +1,77 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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
+
+
+
diff --git a/source/gles2rice/src/OGLCombinerNV.cpp b/source/gles2rice/src/OGLCombinerNV.cpp
new file mode 100644 (file)
index 0000000..5331ae3
--- /dev/null
@@ -0,0 +1,1146 @@
+/*
+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; i<m_vCompiledSettings.size(); i++ )
+    {
+        if( m_vCompiledSettings[i].dwMux0 == m_pDecodedMux->m_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
+
diff --git a/source/gles2rice/src/OGLCombinerNV.h b/source/gles2rice/src/OGLCombinerNV.h
new file mode 100644 (file)
index 0000000..b9ee16d
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+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 <vector>
+
+#include <SDL_opengl.h>
+
+#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<NVRegisterCombinerSettingType>  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
+
diff --git a/source/gles2rice/src/OGLCombinerTNT2.cpp b/source/gles2rice/src/OGLCombinerTNT2.cpp
new file mode 100644 (file)
index 0000000..03c6c45
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+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;
+            }
+        }
+    }
+}
+
+
diff --git a/source/gles2rice/src/OGLCombinerTNT2.h b/source/gles2rice/src/OGLCombinerTNT2.h
new file mode 100644 (file)
index 0000000..0571aab
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+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 <SDL_opengl.h>
+
+#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
+
diff --git a/source/gles2rice/src/OGLDebug.h b/source/gles2rice/src/OGLDebug.h
new file mode 100644 (file)
index 0000000..dccf2f3
--- /dev/null
@@ -0,0 +1,49 @@
+/* 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 */
diff --git a/source/gles2rice/src/OGLDecodedMux.cpp b/source/gles2rice/src/OGLDecodedMux.cpp
new file mode 100644 (file)
index 0000000..ed98307
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+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);
+    }
+}
+
diff --git a/source/gles2rice/src/OGLDecodedMux.h b/source/gles2rice/src/OGLDecodedMux.h
new file mode 100644 (file)
index 0000000..2edfd65
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+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
+
+
diff --git a/source/gles2rice/src/OGLES2FragmentShaders.cpp b/source/gles2rice/src/OGLES2FragmentShaders.cpp
new file mode 100644 (file)
index 0000000..4c5f06e
--- /dev/null
@@ -0,0 +1,822 @@
+/*
+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; i<size; i++)
+    {
+        GLuint ID = m_vCompiledShaders[i].programID;
+        glDeleteProgram(ID);
+
+        OPENGL_CHECK_ERRORS;
+        m_vCompiledShaders[i].programID = 0;
+    }
+
+    m_vCompiledShaders.clear();
+}
+
+bool COGL_FragmentProgramCombiner::Initialize(void)
+{
+    if( !COGLColorCombiner4::Initialize() )
+        return false;
+
+    COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext);
+//    if( pcontext->IsExtensionSupported("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("%s", 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; i<m_vCompiledShaders.size(); i++ )
+    {
+        if( m_vCompiledShaders[i].dwMux0 == m_pDecodedMux->m_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
+
diff --git a/source/gles2rice/src/OGLES2FragmentShaders.h b/source/gles2rice/src/OGLES2FragmentShaders.h
new file mode 100644 (file)
index 0000000..9e77eaa
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+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 <vector>
+
+#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<OGLShaderCombinerSaveType>      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
+
diff --git a/source/gles2rice/src/OGLExtCombiner.cpp b/source/gles2rice/src/OGLExtCombiner.cpp
new file mode 100644 (file)
index 0000000..9a249d0
--- /dev/null
@@ -0,0 +1,1258 @@
+/*
+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 <algorithm>
+#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; i<m_supportedStages; i++ )
+    {
+        pglActiveTexture(GL_TEXTURE0_ARB+i);
+        OPENGL_CHECK_ERRORS;
+        m_pOGLRender->EnableTexUnit(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]<res.numOfUnits )
+        {
+            for( int i=unitNos[j]; i<res.numOfUnits; i++ )
+            {
+                res.units[i].Combs[j].arg0 = MUX_COMBINED;
+                res.units[i].ops[j] = GL_REPLACE;
+            }
+        }
+    }
+
+    res.units[0].tex = 0;
+    res.units[1].tex = 1;
+
+    res.primIsUsed = mux.isUsed(MUX_PRIM);
+    res.envIsUsed = mux.isUsed(MUX_ENV);
+    res.lodFracIsUsed = mux.isUsed(MUX_LODFRAC) || mux.isUsed(MUX_PRIMLODFRAC);
+
+    return SaveParsedResult(res);
+
+#elif SDL_VIDEO_OPENGL_ES2
+    return 0;
+#endif
+}
+
+int COGLColorCombiner4::ParseDecodedMux2Units()
+{
+    OGLExtCombinerSaveType res;
+    for( int k=0; k<8; k++ )
+        res.units[k].tex = -1;
+
+    res.numOfUnits = 2;
+
+    for( int i=0; i<res.numOfUnits*2; i++ ) // Set combiner for each texture unit
+    {
+        // For each texture unit, set both RGB and Alpha channel
+        // Keep in mind that the m_pDecodeMux has been reformated and simplified very well
+
+        OGLExtCombinerType &unit = res.units[i/2];
+        OGLExt1CombType &comb = unit.Combs[i%2];
+
+        CombinerFormatType type = m_pDecodedMux->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<result.numOfUnits; n++ )
+    {
+        for( int i=0; i<3; i++ )
+        {
+            result.units[n].glRGBArgs[i] = 0;
+            result.units[n].glRGBFlags[i] = 0;
+            result.units[n].glAlphaArgs[i] = 0;
+            result.units[n].glAlphaFlags[i] = 0;
+            if( result.units[n].rgbComb.args[i] != CM_IGNORE_BYTE )
+            {
+                result.units[n].glRGBArgs[i] = MapRGBArgs(result.units[n].rgbComb.args[i]);
+                result.units[n].glRGBFlags[i] = MapRGBArgFlags(result.units[n].rgbComb.args[i]);
+            }
+            if( result.units[n].alphaComb.args[i] != CM_IGNORE_BYTE )
+            {
+                result.units[n].glAlphaArgs[i] = MapAlphaArgs(result.units[n].alphaComb.args[i]);
+                result.units[n].glAlphaFlags[i] = MapAlphaArgFlags(result.units[n].alphaComb.args[i]);
+            }
+        }
+    }
+
+    m_vCompiledSettings.push_back(result);
+    m_lastIndex = m_vCompiledSettings.size()-1;
+
+#ifdef DEBUGGER
+    if( logCombiners )
+    {
+        DisplaySimpleMuxString();
+    }
+#endif
+
+    return m_lastIndex;
+}
+
+bool isGLtex(GLint val)
+{
+    if( val >= 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; n<result.numOfUnits; n++ )
+    {
+        for( int i=0; i<3; i++ )
+        {
+            result.units[n].glRGBArgs[i] = 0;
+            result.units[n].glRGBFlags[i] = 0;
+            result.units[n].glAlphaArgs[i] = 0;
+            result.units[n].glAlphaFlags[i] = 0;
+            if( result.units[n].rgbComb.args[i] != CM_IGNORE_BYTE )
+            {
+                result.units[n].glRGBArgs[i] = MapRGBArgs(result.units[n].rgbComb.args[i]);
+                if( result.units[n].glRGBArgs[i] == GL_TEXTURE3_ARB && !result.envIsUsed )
+                    result.units[n].glRGBArgs[i] = GL_TEXTURE2_ARB;
+
+                result.units[n].glRGBFlags[i] = MapRGBArgFlags(result.units[n].rgbComb.args[i]);
+            }
+            if( result.units[n].alphaComb.args[i] != CM_IGNORE_BYTE )
+            {
+                result.units[n].glAlphaArgs[i] = MapAlphaArgs(result.units[n].alphaComb.args[i]);
+                if( result.units[n].glAlphaArgs[i] == GL_TEXTURE3_ARB && !result.envIsUsed )
+                    result.units[n].glAlphaArgs[i] = GL_TEXTURE2_ARB;
+
+                result.units[n].glAlphaFlags[i] = MapAlphaArgFlags(result.units[n].alphaComb.args[i]);
+            }
+        }
+
+        if( isGLtex(result.units[n].glRGBArgs[0]) && isGLtex(result.units[n].glRGBArgs[1]) && isGLtex(result.units[n].glRGBArgs[2]) )
+        {
+            result.units[n].glRGBArgs[2] = GL_CONSTANT_ARB;
+        }
+        if( isGLtex(result.units[n].glAlphaArgs[0]) && isGLtex(result.units[n].glAlphaArgs[1]) && isGLtex(result.units[n].glAlphaArgs[2]) )
+        {
+            result.units[n].glRGBArgs[2] = GL_CONSTANT_ARB;
+        }
+    }
+
+    int extraUnit = 0;
+    if( result.envIsUsed )  extraUnit++;
+    if( result.lodFracIsUsed ) extraUnit++;
+    for( n=result.numOfUnits; n<result.numOfUnits+extraUnit; n++ )
+    {
+        for( int i=0; i<3; i++ )
+        {
+            result.units[n].rgbComb.args[i]=CM_IGNORE_BYTE;
+            result.units[n].alphaComb.args[i]=CM_IGNORE_BYTE;
+            result.units[n].glRGBArgs[i] = 0;
+            result.units[n].glRGBFlags[i] = 0;
+            result.units[n].glAlphaArgs[i] = 0;
+            result.units[n].glAlphaFlags[i] = 0;
+        }
+        
+        result.units[n].rgbComb.args[0]=MUX_COMBINED;
+        result.units[n].alphaComb.args[0]=MUX_COMBINED;
+        result.units[n].rgbOp = GL_REPLACE;
+        result.units[n].alphaOp = GL_REPLACE;
+        result.units[n].glRGBArgs[0] = GL_PREVIOUS_ARB;
+        result.units[n].glRGBArgs[1] = GL_PREVIOUS_ARB;
+        result.units[n].rgbFlag0gl = GL_SRC_COLOR;
+        result.units[n].rgbFlag1gl = GL_SRC_COLOR;
+        result.units[n].glAlphaArgs[0] = GL_PREVIOUS_ARB;
+        result.units[n].glAlphaArgs[1] = GL_PREVIOUS_ARB;
+        result.units[n].alphaFlag0gl = GL_SRC_ALPHA;
+        result.units[n].alphaFlag1gl = GL_SRC_ALPHA;
+    }
+
+    result.numOfUnits += extraUnit;
+
+    m_vCompiledSettings.push_back(result);
+    m_lastIndex = m_vCompiledSettings.size()-1;
+
+#ifdef DEBUGGER
+    if( logCombiners )
+    {
+        DisplaySimpleMuxString();
+    }
+#endif
+
+    return m_lastIndex;
+}
+
+
+#ifdef DEBUGGER
+extern const char *translatedCombTypes[];
+void COGLColorCombiner4::DisplaySimpleMuxString(void)
+{
+    char buf0[30], buf1[30], buf2[30];
+    OGLExtCombinerSaveType &result = m_vCompiledSettings[m_lastIndex];
+
+    COGLColorCombiner::DisplaySimpleMuxString();
+    DebuggerAppendMsg("OpenGL 1.2: %d Stages", result.numOfUnits);      
+    for( int i=0; i<result.numOfUnits; i++ )
+    {
+        DebuggerAppendMsg("//aRGB%d:\t%s: %s, %s, %s\n", i,GetOpStr(result.units[i].rgbOp), DecodedMux::FormatStr(result.units[i].rgbArg0,buf0), DecodedMux::FormatStr(result.units[i].rgbArg1,buf1), DecodedMux::FormatStr(result.units[i].rgbArg2,buf2));     
+        DebuggerAppendMsg("//aAlpha%d:\t%s: %s, %s, %s\n", i,GetOpStr(result.units[i].alphaOp), DecodedMux::FormatStr(result.units[i].alphaArg0,buf0), DecodedMux::FormatStr(result.units[i].alphaArg1,buf1), DecodedMux::FormatStr(result.units[i].alphaArg2,buf2));       
+    }
+    TRACE0("\n\n");
+}
+void COGLColorCombiner2::DisplaySimpleMuxString(void)
+{
+    char buf0[30], buf1[30], buf2[30];
+    OGLExtCombinerSaveType &result = m_vCompiledSettings[m_lastIndex];
+
+    COGLColorCombiner::DisplaySimpleMuxString();
+    int generalCombinerIndex = CGeneralCombiner::FindCompiledMux();
+    if( generalCombinerIndex < 0 )      // Can not found
+    {
+        generalCombinerIndex = CGeneralCombiner::ParseDecodedMux();
+    }
+    DebuggerAppendMsg("Generated general combiners:");
+    GeneralCombinerInfo &generalRes = m_vCompiledCombinerStages[generalCombinerIndex];
+    General_DisplayBlendingStageInfo(generalRes);
+
+    DebuggerAppendMsg("OpenGL 1.2: %d Stages", result.numOfUnits);      
+    for( int i=0; i<result.numOfUnits; i++ )
+    {
+        DebuggerAppendMsg("//aRGB%d:\t%s: %s, %s, %s\n", i,GetOpStr(result.units[i].rgbOp), DecodedMux::FormatStr(result.units[i].rgbArg0,buf0), DecodedMux::FormatStr(result.units[i].rgbArg1,buf1), DecodedMux::FormatStr(result.units[i].rgbArg2,buf2));     
+        DebuggerAppendMsg("//aAlpha%d:\t%s: %s, %s, %s\n", i,GetOpStr(result.units[i].alphaOp), DecodedMux::FormatStr(result.units[i].alphaArg0,buf0), DecodedMux::FormatStr(result.units[i].alphaArg1,buf1), DecodedMux::FormatStr(result.units[i].alphaArg2,buf2));       
+    }
+    TRACE0("\n\n");
+}
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////
+int COGLColorCombiner4::FindCompiledMux()
+{
+#ifdef DEBUGGER
+    if( debuggerDropCombiners )
+    {
+        m_vCompiledSettings.clear();
+        //m_dwLastMux0 = m_dwLastMux1 = 0;
+        debuggerDropCombiners = false;
+    }
+#endif
+    for( uint32 i=0; i<m_vCompiledSettings.size(); i++ )
+    {
+        if( m_vCompiledSettings[i].dwMux0 == m_pDecodedMux->m_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; i<res.numOfUnits; i++ )
+    {
+        pglActiveTexture(GL_TEXTURE0_ARB+i);
+        OPENGL_CHECK_ERRORS;
+        m_pOGLRender->EnableTexUnit(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; i<m_maxTexUnits; i++ )
+        {
+            pglActiveTexture(GL_TEXTURE0_ARB+i);
+            OPENGL_CHECK_ERRORS;
+            m_pOGLRender->DisBindTexture(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; i<res.numOfUnits; i++ )
+        {
+            pglActiveTexture(GL_TEXTURE0_ARB+i);
+            OPENGL_CHECK_ERRORS;
+            glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,fv);
+            OPENGL_CHECK_ERRORS;
+        }
+    }
+}
+
+
+void COGLColorCombiner4v2::GenerateCombinerSettingConstants(int index)
+{
+    //COGLColorCombiner4::GenerateCombinerSettingConstants(index);
+    //return;
+
+    OGLExtCombinerSaveType &res = m_vCompiledSettings[index];
+    COGLExtRender *prender = (COGLExtRender *)m_pRender;
+
+    if( res.primIsUsed )
+    {
+        float *fv = GetPrimitiveColorfv();  // CONSTANT COLOR
+        for( int i=0; i<res.numOfUnits; i++ )
+        {
+            pglActiveTexture(GL_TEXTURE0_ARB+i);
+            OPENGL_CHECK_ERRORS;
+            glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,fv);
+            OPENGL_CHECK_ERRORS;
+        }
+    }
+
+    if( res.envIsUsed )
+    {
+        // Set Texture unit 2 to ENV
+        pglActiveTexture(GL_TEXTURE2_ARB);
+        OPENGL_CHECK_ERRORS;
+        prender->EnableTexUnit(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; unitNo<generalRes.nStages; unitNo++ )
+    {
+        OGLExtCombinerType &unit = res.units[unitNo];
+        //OGLExt1CombType &colorComb = unit.Combs[0];
+        //OGLExt1CombType &alphaComb = unit.Combs[1];
+
+        unit.rgbArg0 = (uint8)generalRes.stages[unitNo].colorOp.Arg1;
+        unit.rgbArg1 = (uint8)generalRes.stages[unitNo].colorOp.Arg2;
+        unit.rgbArg2 = (uint8)generalRes.stages[unitNo].colorOp.Arg0;
+        unit.alphaArg0 = (uint8)generalRes.stages[unitNo].alphaOp.Arg1;
+        unit.alphaArg1 = (uint8)generalRes.stages[unitNo].alphaOp.Arg2;
+        unit.alphaArg2 = (uint8)generalRes.stages[unitNo].alphaOp.Arg0;
+
+        unit.rgbOp = GeneralToGLMaps[generalRes.stages[unitNo].colorOp.op];
+        if( unit.rgbOp == GL_MODULATE_ADD_ATI && !m_bTxtOpMulAdd )
+        {
+            if( (unit.rgbArg0&MUX_MASK) == (unit.rgbArg2&MUX_MASK) && (unit.rgbArg0&MUX_COMPLEMENT) )
+            {
+                unit.rgbOp = GL_ADD;
+                unit.rgbArg0 &= ~MUX_COMPLEMENT;
+            }
+            else
+            {
+                unit.rgbOp = GL_MODULATE;
+            }
+        }
+        unit.alphaOp = GeneralToGLMaps[generalRes.stages[unitNo].alphaOp.op];
+        if( unit.alphaOp == GL_MODULATE_ADD_ATI && !m_bTxtOpMulAdd )    
+        {
+            if( (unit.alphaArg0&MUX_MASK) == (unit.alphaArg2&MUX_MASK) && (unit.alphaArg0&MUX_COMPLEMENT) )
+            {
+                unit.alphaOp = GL_ADD;
+                unit.alphaArg0 &= ~MUX_COMPLEMENT;
+            }
+            else
+            {
+                unit.alphaOp = GL_MODULATE;
+            }
+        }
+
+        unit.tex = generalRes.stages[unitNo].dwTexture;
+        unit.textureIsUsed = generalRes.stages[unitNo].bTextureUsed;
+    }
+
+    res.numOfUnits = generalRes.nStages;
+    res.constantColor = generalRes.TFactor;
+    return SaveParsedResult(res);
+}
+
+
+void COGLColorCombiner2::GenerateCombinerSettingConstants(int index)
+{
+    OGLExtCombinerSaveType &res = m_vCompiledSettings[index];
+
+    bool isused = true;
+
+    float *fv;
+    float tempf[4];
+
+    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; i<res.numOfUnits; i++ )
+        {
+            pglActiveTextureARB(GL_TEXTURE0_ARB+i);
+            OPENGL_CHECK_ERRORS;
+            glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,fv);
+            OPENGL_CHECK_ERRORS;
+        }
+    }
+}
+void COGLColorCombiner2::GenerateCombinerSetting(int index)
+{
+    OGLExtCombinerSaveType &res = m_vCompiledSettings[index];
+    COGLExtRender *prender = (COGLExtRender *)m_pRender;
+
+    for( int i=0; i<res.numOfUnits; i++ )
+    {
+        pglActiveTextureARB(GL_TEXTURE0_ARB+i);
+        OPENGL_CHECK_ERRORS;
+        //if(res.units[i].textureIsUsed)
+        {
+            prender->SetTextureToTextureUnitMap(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; i<m_maxTexUnits; i++ )
+        {
+            pglActiveTextureARB(GL_TEXTURE0_ARB+i);
+            OPENGL_CHECK_ERRORS;
+            m_pOGLRender->EnableTexUnit(i,FALSE);
+            prender->SetTextureToTextureUnitMap(-1,i);
+        }
+    }
+}
+
diff --git a/source/gles2rice/src/OGLExtCombiner.h b/source/gles2rice/src/OGLExtCombiner.h
new file mode 100644 (file)
index 0000000..8281c4d
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+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 <vector>
+
+#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<OGLExtCombinerSaveType>     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
+
diff --git a/source/gles2rice/src/OGLExtRender.cpp b/source/gles2rice/src/OGLExtRender.cpp
new file mode 100644 (file)
index 0000000..b87c80c
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+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<m_maxTexUnits; i++ )
+    {
+        //Compute iMinFilter and iMagFilter
+        if(m_dwMinFilter == FILTER_LINEAR) //Texture will use filtering
+        {
+            iMagFilter = GL_LINEAR;
+
+            //Texture filtering method user want
+            switch(options.mipmapping)
+            {
+            case TEXTURE_BILINEAR_FILTER:
+                iMinFilter = GL_LINEAR_MIPMAP_NEAREST;
+                break;
+            case TEXTURE_TRILINEAR_FILTER:
+                iMinFilter = GL_LINEAR_MIPMAP_LINEAR;
+                break;
+            case TEXTURE_NO_FILTER:
+                iMinFilter = GL_NEAREST_MIPMAP_NEAREST;
+                break;
+            case TEXTURE_NO_MIPMAP:
+            default:
+                //Bilinear without mipmap
+                iMinFilter = GL_LINEAR;
+            }
+        }
+        else    //dont use filtering, all is nearest
+        {
+            iMagFilter = GL_NEAREST;
+
+            if(options.mipmapping)
+            {
+                iMinFilter = GL_NEAREST_MIPMAP_NEAREST;
+            }
+            else
+            {
+                iMinFilter = GL_NEAREST;
+            }
+        }
+
+        if( m_texUnitEnabled[i] )
+        {
+            if( mtex[i] != m_curBoundTex[i] )
+            {
+                mtex[i] = m_curBoundTex[i];
+                pglActiveTexture(GL_TEXTURE0_ARB+i);
+                OPENGL_CHECK_ERRORS;
+                minflag[i] = m_dwMinFilter;
+                magflag[i] = m_dwMagFilter;
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, iMinFilter);
+                OPENGL_CHECK_ERRORS;
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, iMagFilter);
+                OPENGL_CHECK_ERRORS;
+            }
+            else
+            {
+                if( minflag[i] != (unsigned int)m_dwMinFilter )
+                {
+                    minflag[i] = m_dwMinFilter;
+                    pglActiveTexture(GL_TEXTURE0_ARB+i);
+                    OPENGL_CHECK_ERRORS;
+                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, iMinFilter);
+                    OPENGL_CHECK_ERRORS;
+                }
+                if( magflag[i] != (unsigned int)m_dwMagFilter )
+                {
+                    magflag[i] = m_dwMagFilter;
+                    pglActiveTexture(GL_TEXTURE0_ARB+i);
+                    OPENGL_CHECK_ERRORS;
+                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, iMagFilter);
+                    OPENGL_CHECK_ERRORS;
+                }
+            }
+        }
+    }
+}
+
+void COGLExtRender::SetTextureToTextureUnitMap(int tex, int unit)
+{
+    if( unit < 8 && (tex >= -1 || tex <= 1))
+        m_textureUnitMap[unit] = tex;
+}
+
diff --git a/source/gles2rice/src/OGLExtRender.h b/source/gles2rice/src/OGLExtRender.h
new file mode 100644 (file)
index 0000000..8a8eab8
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+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
+
diff --git a/source/gles2rice/src/OGLExtensions.cpp b/source/gles2rice/src/OGLExtensions.cpp
new file mode 100644 (file)
index 0000000..a8897f3
--- /dev/null
@@ -0,0 +1,80 @@
+/* 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 <SDL_opengl.h>
+#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);
+}
+
+
diff --git a/source/gles2rice/src/OGLExtensions.h b/source/gles2rice/src/OGLExtensions.h
new file mode 100644 (file)
index 0000000..2b3cdef
--- /dev/null
@@ -0,0 +1,71 @@
+/* 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 <SDL_opengl.h>
+
+/* 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
+
diff --git a/source/gles2rice/src/OGLFragmentShaders.cpp b/source/gles2rice/src/OGLFragmentShaders.cpp
new file mode 100644 (file)
index 0000000..8c38ba6
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+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; i<size; i++)
+    {
+        GLuint ID = m_vCompiledShaders[i].programID;
+        pglDeleteProgramsARB(1, &ID);
+        OPENGL_CHECK_ERRORS;
+        m_vCompiledShaders[i].programID = 0;
+    }
+
+    m_vCompiledShaders.clear();
+}
+
+bool COGL_FragmentProgramCombiner::Initialize(void)
+{
+    if( !COGLColorCombiner4::Initialize() )
+        return false;
+
+    COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext);
+    if( pcontext->IsExtensionSupported("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; i<m_vCompiledShaders.size(); i++ )
+    {
+        if( m_vCompiledShaders[i].dwMux0 == m_pDecodedMux->m_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
+
diff --git a/source/gles2rice/src/OGLFragmentShaders.h b/source/gles2rice/src/OGLFragmentShaders.h
new file mode 100644 (file)
index 0000000..4f98f4f
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+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 <vector>
+
+#include <SDL_opengl.h>
+
+#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<OGLShaderCombinerSaveType>      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
+
diff --git a/source/gles2rice/src/OGLGraphicsContext.cpp b/source/gles2rice/src/OGLGraphicsContext.cpp
new file mode 100644 (file)
index 0000000..ab394f1
--- /dev/null
@@ -0,0 +1,526 @@
+/*
+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;
+}
diff --git a/source/gles2rice/src/OGLGraphicsContext.h b/source/gles2rice/src/OGLGraphicsContext.h
new file mode 100644 (file)
index 0000000..ce05219
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+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
+
+
+
diff --git a/source/gles2rice/src/OGLRender.cpp b/source/gles2rice/src/OGLRender.cpp
new file mode 100755 (executable)
index 0000000..4b66a6c
--- /dev/null
@@ -0,0 +1,1296 @@
+/*
+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"
+
+#ifdef PAULSCODE
+//include "ae_bridge.h"
+//static int hardwareType = HARDWARE_TYPE_UNKNOWN;
+#endif
+
+// 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)
+    unsigned int white[8*8];
+       for (int i=0; i<8*8; i++) {
+               //white[i].r = white[i].g = white[i].b = 0;
+               //white[i].a = 0;
+               white[i] = 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, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, white);
+    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
+
+#ifdef PAULSCODE
+//    hardwareType = Android_JNI_GetHardwareType();
+#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
+
+#ifdef PAULSCODE
+//    Android_JNI_GetPolygonOffset(hardwareType, bias, &f1, &f2);
+//     glPolygonOffset(0.2f, 0.2f);
+#endif
+
+    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;
+    }
+}
+
diff --git a/source/gles2rice/src/OGLRender.h b/source/gles2rice/src/OGLRender.h
new file mode 100644 (file)
index 0000000..d5fb387
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+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
+
+
diff --git a/source/gles2rice/src/OGLRenderExt.cpp b/source/gles2rice/src/OGLRenderExt.cpp
new file mode 100644 (file)
index 0000000..e632208
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+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);
+    }
+}
+
+
diff --git a/source/gles2rice/src/OGLTexture.cpp b/source/gles2rice/src/OGLTexture.cpp
new file mode 100644 (file)
index 0000000..55d6d64
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+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 <stdlib.h>
+
+#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
+
diff --git a/source/gles2rice/src/OGLTexture.h b/source/gles2rice/src/OGLTexture.h
new file mode 100644 (file)
index 0000000..a2642b8
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+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
+
+
+
diff --git a/source/gles2rice/src/RDP_Texture.h b/source/gles2rice/src/RDP_Texture.h
new file mode 100644 (file)
index 0000000..eb35d5c
--- /dev/null
@@ -0,0 +1,2246 @@
+/*
+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 <algorithm>
+
+#include <stdlib.h>
+#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<<mask) : 0;
+    widthToCreate = widthToLoad = width;
+
+    if( mask > 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 &gti)
+{
+    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<<info->dwSize)>>tile.dwSize;
+        gti.TopToLoad = info->tl;
+    }
+    else
+    {
+        gti.LeftToLoad = (info->sl<<info->dwSize)>>tile.dwSize;
+        gti.TopToLoad = (info->tl<<info->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 &gti)
+{
+    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<<info->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<<info->dwSize)>>tile.dwSize;
+        gti.TopToLoad = (info->tl<<info->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<<g_TI.dwSize)>>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<<g_TI.dwSize)>>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 <<RSP_SETOTHERMODE_SHIFT_TEXTLUT;
+    if (gti.Format == TXT_FMT_CI && gti.TLutFmt == TLUT_FMT_NONE )
+        gti.TLutFmt = TLUT_FMT_RGBA16;      // Force RGBA
+
+    gti.PalAddress = (uchar *) (&g_wRDPTlut[0]);
+    if( !options.bUseFullTMEM && tile.dwSize == TXT_SIZE_4b )
+        gti.PalAddress += 16  * 2 * tile.dwPalette; 
+
+    gti.Address = (info->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(&gti, 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; i<dwCount && i<0x100; i++)
+    g_wRDPTlut[(i+dwTMEMOffset)^1] = srcPal[i^1];
+
+if( options.bUseFullTMEM )
+    {
+    for (uint32 i=0; i<dwCount && i+tile.dwTMem<0x200; i++)
+        *(uint16*)(&g_Tmem.g_Tmem64bit[tile.dwTMem+i]) = srcPal[i^1];
+    }
+
+LOG_TEXTURE(
+{
+DebuggerAppendMsg("LoadTLut Tile: %d Start: 0x%X+0x%X, Count: 0x%X\nFmt is %s, TMEM=0x%X\n", 
+                 tileno, g_TI.dwAddr, dwRDRAMOffset, dwCount,textluttype[dwTLutFmt],
+                 dwTMEMOffset);
+
+DebuggerAppendMsg("    :ULS: 0x%X, ULT:0x%X, LRS: 0x%X, LRT:0x%X\n", uls, ult, lrs,lrt);
+
+if( pauseAtNext && eventToPause == NEXT_LOADTLUT && dwCount == 16 ) 
+    {
+    char buf[2000];
+    strcpy(buf, "Data:\n");
+    for(uint32 i=0; i<16; i++ )
+        {
+        sprintf(buf+strlen(buf), "%04X ", g_wRDPTlut[dwTMEMOffset+i]);
+        if(i%4 == 3)
+            sprintf(buf+strlen(buf), "\n");
+        }
+    sprintf(buf+strlen(buf), "\n");
+    TRACE0(buf);
+    }
+});
+
+DEBUGGER_PAUSE_COUNT_N(NEXT_LOADTLUT);
+
+extern bool RevTlutTableNeedUpdate;
+RevTlutTableNeedUpdate = true;
+g_TxtLoadBy = CMD_LOADTLUT;
+}
+
+
+void DLParser_LoadBlock(Gfx *gfx)
+{
+    gRDP.textureIsChanged = true;
+
+    uint32 tileno   = gfx->loadtile.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<<tile.dwMaskS);
+        tile.th = tile.tl + (1<<tile.dwMaskT);
+        tile.hilite_sl = tile.sl;
+        tile.hilite_tl = tile.tl;
+    }
+    */
+
+    tile.lastTileCmd = CMD_SETTILE;
+
+    LOG_TEXTURE(
+    {
+    DebuggerAppendMsg("SetTile:%d  Fmt: %s/%s Line:%d TMem:0x%04x Palette:%d\n",
+        tileno, pszImgFormat[tile.dwFormat], pszImgSize[tile.dwSize],
+        tile.dwLine,  tile.dwTMem, tile.dwPalette);
+    DebuggerAppendMsg("         S: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x\n",
+        pszOnOff[tile.bClampS],pszOnOff[tile.bMirrorS],
+        tile.dwMaskS, tile.dwShiftS);
+    DebuggerAppendMsg("         T: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x\n",
+        pszOnOff[tile.bClampT],pszOnOff[tile.bMirrorT],
+        tile.dwMaskT, tile.dwShiftT);
+    });
+
+    DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD);
+
+    LOG_UCODE("    Tile:%d  Fmt: %s/%s Line:%d TMem:0x%04x Palette:%d",
+        tileno, pszImgFormat[tile.dwFormat], pszImgSize[tile.dwSize],
+        tile.dwLine, tile.dwTMem, tile.dwPalette);
+    LOG_UCODE("         S: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x",
+        pszOnOff[tile.bClampS],pszOnOff[tile.bMirrorS],
+        tile.dwMaskS, tile.dwShiftS);
+    LOG_UCODE("         T: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x",
+        pszOnOff[tile.bClampT],pszOnOff[tile.bMirrorT],
+        tile.dwMaskT, tile.dwShiftT);
+}
+
+void DLParser_SetTileSize(Gfx *gfx)
+{
+    gRDP.textureIsChanged = true;
+
+    uint32 tileno   = gfx->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; i<tmenMaxEntry; i++ )
+    {
+        tmenEntryBuffer[i].start=0;
+        tmenEntryBuffer[i].length=0;
+        tmenEntryBuffer[i].rdramAddr=0;
+        tmenEntryBuffer[i].next = &(tmenEntryBuffer[i+1]);
+    }
+    tmenEntryBuffer[i-1].next = NULL;
+}
+
+void TMEM_SetBlock(uint32 tmemstart, uint32 length, uint32 rdramaddr)
+{
+    TmemInfoEntry *p=g_pTMEMInfo;
+
+    if( p == NULL )
+    {
+        // Move an entry from freelist and link it to the header
+        p = g_pTMEMFreeList;
+        g_pTMEMFreeList = g_pTMEMFreeList->next;
+
+        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<<bitIndex))!=0);
+}
+
+uint32 GetValidTmemInfoIndex(uint32 tmemAddr)
+{
+    return 0;
+    uint32 index = tmemAddr>>5;
+    uint32 bitIndex = (tmemAddr&0x1F);
+
+    if ((g_TmemFlag[index] & (1<<bitIndex))!=0 )    //This address is valid
+        return tmemAddr;
+    else
+    {
+        for( uint32 x=index+1; x != 0; x-- )
+        {
+            uint32 i = x - 1;
+            if( g_TmemFlag[i] != 0 )
+            {
+                for( uint32 y=0x20; y != 0; y-- )
+                {
+                    uint32 j = y - 1;
+                    if( (g_TmemFlag[i] & (1<<j)) != 0 )
+                    {
+                        return ((i<<5)+j);
+                    }
+                }
+            }
+        }
+        TRACE0("Error, check me");
+        return 0;
+    }
+}
+
+
+void SetTmemFlag(uint32 tmemAddr, uint32 size)
+{
+    uint32 index = tmemAddr>>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<<bitIndex);
+            g_TmemFlag[index] = val;
+        }
+        else
+        {
+            //ErrorMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size);
+            uint32 val = g_TmemFlag[index];
+            uint32 mask = (1<<bitIndex)-1;
+            val &= mask;
+            val |= (1<<bitIndex);
+            g_TmemFlag[index] = val;
+            index++;
+            size -= (0x20-bitIndex);
+
+            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);
+            }
+        }
+    }
+}
+
diff --git a/source/gles2rice/src/RSP_GBI0.h b/source/gles2rice/src/RSP_GBI0.h
new file mode 100644 (file)
index 0000000..bf28e04
--- /dev/null
@@ -0,0 +1,904 @@
+/*
+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 <cmath>
+#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<<dwLength)-1)<<dwShift;
+
+    uint32 modeL = gRDP.otherModeL;
+    modeL = (modeL&(~dwMask)) | dwData;
+
+    Gfx tempgfx;
+    tempgfx.words.w0 = gRDP.otherModeH;
+    tempgfx.words.w1 = modeL;
+    DLParser_RDPSetOtherMode(&tempgfx);
+}
+
+
+void RSP_GBI1_SetOtherModeH(Gfx *gfx)
+{
+    SP_Timing(RSP_GBI1_SetOtherModeH);
+
+    uint32 dwShift = ((gfx->words.w0)>>8)&0xFF;
+    uint32 dwLength= ((gfx->words.w0)   )&0xFF;
+    uint32 dwData  = (gfx->words.w1);
+
+    uint32 dwMask = ((1<<dwLength)-1)<<dwShift;
+    uint32 dwModeH = gRDP.otherModeH;
+
+    dwModeH = (dwModeH&(~dwMask)) | dwData;
+    Gfx tempgfx;
+    tempgfx.words.w0 = dwModeH;
+    tempgfx.words.w1 = gRDP.otherModeL;
+    DLParser_RDPSetOtherMode(&tempgfx );
+}
+
+
+void RSP_GBI1_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;
+    }
+#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; i<gDlistStackPointer; i++ )
+        {
+            DebuggerAppendMsg("  %08X", gDlistStack[i].pc);
+        }
+
+        uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
+        DebuggerAppendMsg("PC=%08X",dwPC);
+        DebuggerAppendMsg("Warning, unknown ucode PC=%08X: 0x%08x 0x%08x\n", dwPC, gfx->words.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
+}
+
diff --git a/source/gles2rice/src/RSP_GBI1.h b/source/gles2rice/src/RSP_GBI1.h
new file mode 100644 (file)
index 0000000..ace52ab
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+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);
+}
+
diff --git a/source/gles2rice/src/RSP_GBI2.h b/source/gles2rice/src/RSP_GBI2.h
new file mode 100644 (file)
index 0000000..22eb286
--- /dev/null
@@ -0,0 +1,923 @@
+/*
+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<<dwLength)-1)<<dwShift;
+    uint32 dwModeH = gRDP.otherModeH;
+    dwModeH = (dwModeH&(~dwMask2)) | dwData;
+
+    Gfx tempgfx;
+    tempgfx.words.w0 = dwModeH;
+    tempgfx.words.w1 = gRDP.otherModeL;
+    DLParser_RDPSetOtherMode(&tempgfx );
+}
+
+
+void RSP_GBI2_SubModule(Gfx *gfx)
+{
+    SP_Timing(RSP_GBI2_SubModule);
+
+    RSP_RDP_NOIMPL("RDP: RSP_GBI2_SubModule (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1));
+}
+
diff --git a/source/gles2rice/src/RSP_GBI2_ext.h b/source/gles2rice/src/RSP_GBI2_ext.h
new file mode 100644 (file)
index 0000000..76f7da0
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+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);
+    }
+}
+
+
diff --git a/source/gles2rice/src/RSP_GBI_Others.h b/source/gles2rice/src/RSP_GBI_Others.h
new file mode 100644 (file)
index 0000000..c8649d6
--- /dev/null
@@ -0,0 +1,1731 @@
+/*
+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 <algorithm>
+
+#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<gDlistStackPointer; i++ )
+           {
+           if(gDlistStack[i].addr == dwAddr+8)
+               {
+               TRACE1("Detected DL looping, PC=%08X", dwPC );
+               DLParser_Ucode8_EndDL(0,0);
+               return;
+               }
+           }
+        }*/
+
+    if( gDlistStackPointer < MAX_DL_STACK_SIZE-1 )
+    {
+        gDlistStackPointer++;
+        gDlistStack[gDlistStackPointer].pc = dwAddr+16;
+        gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT;
+    }
+    else
+    {
+        DebuggerAppendMsg("Error, gDlistStackPointer overflow");
+        RDP_GFX_PopDL();
+    }
+
+    GSBlkAddrSaves[gDlistStackPointer][0]=GSBlkAddrSaves[gDlistStackPointer][1]=0;
+    if( (dwCmd2>>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);
+}
+
diff --git a/source/gles2rice/src/RSP_GBI_Sprite2D.h b/source/gles2rice/src/RSP_GBI_Sprite2D.h
new file mode 100644 (file)
index 0000000..a69d354
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+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);
+}
+
diff --git a/source/gles2rice/src/RSP_Parser.cpp b/source/gles2rice/src/RSP_Parser.cpp
new file mode 100644 (file)
index 0000000..d3a69d3
--- /dev/null
@@ -0,0 +1,1787 @@
+/*
+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 <algorithm>
+#include <SDL.h>
+
+#include "ConvertImage.h"
+#include "GraphicsContext.h"
+#include "Render.h"
+#include "RenderTexture.h"
+#include "Video.h"
+#include "ucode.h"
+#include <time.h>
+
+//////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////
+//                    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; i<MAX_UCODE_INFO; i++ )
+    {
+        memset(&ucodeInfo[i], 0, sizeof(UcodeInfo));
+    }
+
+    status.bUseModifiedUcodeMap = false;
+    status.ucodeHasBeenSet = false;
+    status.bAllowLoadFromTMEM = true;
+    
+    char name[200];
+    strcpy(name, (char*)g_curRomInfo.szGameName);
+
+    memset(&lastUcodeInfo, 0, sizeof(UcodeInfo));
+    memset(&UsedUcodes, 0, sizeof(UsedUcodes));
+    memset(&g_TmemFlag, 0, sizeof(g_TmemFlag));
+    memset(&g_RecentCIInfo, 0, sizeof(RecentCIInfo)*5);
+    memset(&g_RecentVIOriginInfo, 0, sizeof(RecentViOriginInfo)*5);
+    memset(&g_ZI_saves, 0, sizeof(RenderTextureInfo)*2);
+    memset(&g_ZI, 0, sizeof(SetImgInfo));
+    memset(&g_CI, 0, sizeof(SetImgInfo));
+    memset(&g_TI, 0, sizeof(SetImgInfo));
+
+    status.UseLargerTile[0] = status.UseLargerTile[1] = false;
+    status.LargerTileRealLeft[0] = status.LargerTileRealLeft[1] = 0;
+}
+
+
+void RDP_GFX_Reset()
+{
+    gDlistStackPointer=-1;
+    status.bUcodeIsKnown = FALSE;
+    gTextureManager.RecycleAllTextures();
+}
+
+
+void RDP_Cleanup()
+{
+    if( status.bHandleN64RenderTexture )
+    {
+        g_pFrameBufferManager->CloseRenderTexture(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<maxUsedUcodes; usedUcodeIndex++ )
+    {
+        if( UsedUcodes[usedUcodeIndex].used == false )
+        {
+            break;
+        }
+
+        if( UsedUcodes[usedUcodeIndex].ucStart == ucStart && UsedUcodes[usedUcodeIndex].ucSize == ucSize &&
+            UsedUcodes[usedUcodeIndex].ucDStart == ucDStart /*&& UsedUcodes[usedUcodeIndex].ucDSize == ucDSize*/ )
+        {
+#ifdef DEBUGGER
+            if(gRSP.ucode != (int)UsedUcodes[usedUcodeIndex].ucode && logMicrocode)
+            {
+                DebuggerAppendMsg("Check, ucode = %d, crc = %08X, %s", UsedUcodes[usedUcodeIndex].ucode, 
+                    UsedUcodes[usedUcodeIndex].crc_800 , UsedUcodes[usedUcodeIndex].rspstr);
+            }
+#endif
+            lastUcodeInfo.ucStart = ucStart;
+            lastUcodeInfo.used = true;
+            lastUcodeInfo.ucDStart = ucDStart;
+            lastUcodeInfo.ucSize = ucSize;
+            return UsedUcodes[usedUcodeIndex].ucode;
+        }
+    }
+
+    uint32 base = ucDStart & 0x1fffffff;
+    unsigned char str[300] = "";
+    if( base < g_dwRamSize+0x1000 )
+    {
+        for ( uint32 i = 0; i < 0x1000; i++ )
+        {
+            if ( g_pRDRAMs8[ base + ((i+0) ^ 3) ] == 'R' &&
+                 g_pRDRAMs8[ base + ((i+1) ^ 3) ] == 'S' &&
+                 g_pRDRAMs8[ base + ((i+2) ^ 3) ] == 'P' )
+            {
+                unsigned char * p = str;
+                while ( g_pRDRAMs8[ base + (i ^ 3) ] >= ' ')
+                {
+                    *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; i<gDlistStackPointer; i++ )
+        {
+            DebuggerAppendMsg("  %08X", gDlistStack[i].pc);
+        }
+        uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
+        DebuggerAppendMsg("PC=%08X",dwPC);
+        DebuggerAppendMsg(op, word0, word1);
+    }
+    DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_UNKNOWN_OP, {TRACE0("Paused at unimplemented ucode\n");})
+#endif
+}
+
+void RDP_NOIMPL_WARN(const char* op)
+{
+#ifdef DEBUGGER
+    if(logWarning)
+    {
+        TRACE0(op);
+    }
+#endif
+}
+
+
+void RSP_GBI1_Noop(Gfx *gfx)
+{
+}
+
+
+void RDP_GFX_PopDL()
+{
+    LOG_UCODE("Returning from DisplayList: level=%d", gDlistStackPointer+1);
+    LOG_UCODE("############################################");
+    LOG_UCODE("/\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\");
+    LOG_UCODE("");
+
+    gDlistStackPointer--;
+}
+
+uint32 CalcalateCRC(uint32* srcPtr, uint32 srcSize)
+{
+    uint32 crc=0;
+    for( uint32 i=0; i<srcSize; i++ )
+    {
+        crc += srcPtr[i];
+    }
+    return crc;
+}
+
+
+void RSP_GFX_InitGeometryMode()
+{
+    bool bCullFront     = (gRDP.geometryMode & G_CULL_FRONT) ? true : false;
+    bool bCullBack      = (gRDP.geometryMode & G_CULL_BACK) ? true : false;
+    if( bCullFront && bCullBack ) // should never cull front
+    {
+        bCullFront = false;
+    }
+    CRender::g_pRender->SetCullMode(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<<RSP_SETOTHERMODE_SHIFT_TEXTFILT);
+    }
+
+    if( gRDP.otherModeL != (gfx->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; i<y1; i++ )
+            {
+                for( uint32 j=x0; j<x1; j++ )
+                {
+                    *(uint16*)((base+pitch*i+j)^2) = color;
+                }
+            }
+        }
+    }
+    else if( status.bHandleN64RenderTexture )
+    {
+        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);
+
+        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; i<y1; i++ )
+                {
+                    for( uint32 j=x0; j<x1; j++ )
+                    {
+                        *(uint16*)((base+pitch*i+j)^2) = color;
+                    }
+                }
+            }
+            else
+            {
+                uint8 color = (uint8)gRDP.originalFillColor;
+                uint32 pitch = g_pRenderTextureInfo->N64Width;
+                long long base = (long long) (g_pRDRAMu8 + g_pRenderTextureInfo->CI_Info.dwAddr);
+                for( uint32 i=y0; i<y1; i++ )
+                {
+                    for( uint32 j=x0; j<x1; j++ )
+                    {
+                        *(uint8*)((base+pitch*i+j)^3) = color;
+                    }
+                }
+            }
+
+            status.bFrameBufferDrawnByTriangles = false;
+        }
+        else
+        {
+            status.bFrameBufferDrawnByTriangles = true;
+        }
+        status.bFrameBufferDrawnByTriangles = true;
+
+        if( !status.bDirectWriteIntoRDRAM )
+        {
+            status.bFrameBufferIsDrawn = true;
+
+            //if( x0==0 && y0==0 && (x1 == g_pRenderTextureInfo->N64Width || 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
+}
+
diff --git a/source/gles2rice/src/RSP_Parser.h b/source/gles2rice/src/RSP_Parser.h
new file mode 100644 (file)
index 0000000..2e4b6ae
--- /dev/null
@@ -0,0 +1,630 @@
+/*
+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__
+
diff --git a/source/gles2rice/src/RSP_S2DEX.cpp b/source/gles2rice/src/RSP_S2DEX.cpp
new file mode 100644 (file)
index 0000000..7623360
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+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; i<offset+size; i++ )
+        {
+            g_wRDPTlut[i^1] = RDRAM_UHALF(addr);
+            addr += 2;
+            //g_wRDPTlut[i] = (*(uint16 *)(addr+g_pRDRAMu8));
+            //g_wRDPTlut[i] = *(srcPal++);
+        }
+    }
+    else
+    {
+        // Loading ObjSprite
+        g_TxtLoadBy = CMD_LOAD_OBJ_TXTR;
+    }
+
+    DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI),
+        {
+            DumpTxtrInfo(gObjTxtr);
+            TRACE0("Paused at RSP_S2DEX_SPObjLoadTxtr");
+        }
+    );
+}
+
+// Yoshi's Story uses this - 0xc2
+void RSP_S2DEX_SPObjLoadTxSprite(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->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");
+        }
+    );
+}
+
diff --git a/source/gles2rice/src/RSP_S2DEX.h b/source/gles2rice/src/RSP_S2DEX.h
new file mode 100644 (file)
index 0000000..8acd904
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+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
+
diff --git a/source/gles2rice/src/Render.cpp b/source/gles2rice/src/Render.cpp
new file mode 100644 (file)
index 0000000..d90633f
--- /dev/null
@@ -0,0 +1,2086 @@
+/*
+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 <algorithm>
+
+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; i<MAX_TEXTURES; i++ )
+    {
+        g_textures[i].m_lpsTexturePtr = NULL;
+        g_textures[i].m_pCTexture = NULL;
+        
+        g_textures[i].m_dwTileWidth = 64;       // Value doesn't really matter, as tex not set
+        g_textures[i].m_dwTileHeight = 64;
+        g_textures[i].m_fTexWidth = 64.0f;      // Value doesn't really matter, as tex not set
+        g_textures[i].m_fTexHeight = 64.0f;
+        g_textures[i].pTextureEntry = NULL;
+
+        TileUFlags[i] = TileVFlags[i] = TEXTURE_UV_FLAG_CLAMP;
+    }
+
+
+    //for( i=0; i<MAX_VERTS; i++)
+    //{
+    //  g_dwVtxFlags[i] = 0;
+    //}
+    
+    m_pColorCombiner = CDeviceBuilder::GetBuilder()->CreateColorCombiner(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<<mask) : tileWidth;
+    if( width == 0 ) return false;
+
+    int divs0 = s0/width; if( divs0*width > 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<gRSP.numVertices; i++ )
+            {
+                if( t == 0 )
+                {
+                    g_vtxBuffer[i].tcord[t].u += gRSP.tex0OffsetX;
+                    g_vtxBuffer[i].tcord[t].u /= 2;
+                    g_vtxBuffer[i].tcord[t].u -= gRSP.tex0OffsetX;
+                    g_vtxBuffer[i].tcord[t].v += gRSP.tex0OffsetY;
+                    g_vtxBuffer[i].tcord[t].v /= 2;
+                    g_vtxBuffer[i].tcord[t].v -= gRSP.tex0OffsetY;
+                }
+                else
+                {
+                    g_vtxBuffer[i].tcord[t].u += gRSP.tex1OffsetX;
+                    g_vtxBuffer[i].tcord[t].u /= 2;
+                    g_vtxBuffer[i].tcord[t].u -= gRSP.tex1OffsetX;
+                    g_vtxBuffer[i].tcord[t].v += gRSP.tex1OffsetY;
+                    g_vtxBuffer[i].tcord[t].v /= 2;
+                    g_vtxBuffer[i].tcord[t].v -= gRSP.tex1OffsetY;
+                }
+            }
+        }
+
+        /*
+        // The code here is disabled because it could cause incorrect texture repeating flag 
+        // for later DrawTriangles
+        bool clampS=true;
+        bool clampT=true;
+
+        for( uint32 i=0; i<gRSP.numVertices; i++ )
+        {
+            float w = CDeviceBuilder::GetGeneralDeviceType() == OGL_DEVICE ? g_vtxProjected5[i][3] : g_vtxBuffer[i].rhw; 
+            if( w < 0 || g_vtxBuffer[i].tcord[t].u > 1.0 || g_vtxBuffer[i].tcord[t].u < 0.0  )
+            {
+                clampS = false;
+                break;
+            }
+        }
+
+        for( uint32 i=0; i<gRSP.numVertices; i++ )
+        {
+            float w = CDeviceBuilder::GetGeneralDeviceType() == OGL_DEVICE ? g_vtxProjected5[i][3] : g_vtxBuffer[i].rhw; 
+            if( w < 0 || g_vtxBuffer[i].tcord[t].v > 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<size; i++)
+    {
+        if( pTable[i] == val )
+            return i;
+    }
+
+    TRACE0("Cannot find value in CI table");
+    return 0;
+}
+
+bool SaveCITextureToFile(TxtrCacheEntry &entry, char *filename, bool bShow, bool bWholeTexture )
+{
+    if( !( (gRDP.otherMode.text_tlut>=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<width; j++)
+            {
+                int val = ReverseCITableLookup(pTable, tableSize, *pSrc);
+                pSrc++;
+
+                if( entry.ti.Size == TXT_SIZE_4b )
+                {
+                    // 4 bits
+                    if( idx%2 )
+                    {
+                        // 1
+                        pbuf[idx>>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<width; j++)
+                    {
+                        *pbuf2++ = *pSrc++;
+                    }
+                }
+
+                if( SaveRGBABufferToPNGFile(filename, (unsigned char*)pbuf, width, height ) )
+                //if( SaveRGBABufferToPNGFile(filename, (unsigned char*)srcInfo.lpSurface, width, height, srcInfo.lPitch ) )
+                {
+                }
+            }
+            else
+            {
+                unsigned char *pbuf2 = pbuf;
+                for( int i=height-1; i>=0; i--)
+                {
+                    unsigned char *pSrc = (unsigned char*)srcInfo.lpSurface+srcInfo.lPitch * i;
+                    for( int j=0; j<width; j++)
+                    {
+                        if( channel == TXT_ALPHA )
+                        {
+                            pbuf2[0] = pbuf2[1] = pbuf2[2] = pSrc[3];
+                        }
+                        else
+                        {
+                            pbuf2[0] = pSrc[0];
+                            pbuf2[1] = pSrc[1];
+                            pbuf2[2] = pSrc[2];
+                        }
+
+                        pbuf2 += 3;
+                        pSrc += 4;
+                    }
+                }
+
+                if( SaveRGBBufferToFile(filename, pbuf, width, height ) )
+                {
+                }
+            }
+            texture.EndUpdate(&srcInfo);
+        }
+        else
+        {
+            TRACE0("Cannot lock texture");
+        }
+        delete [] pbuf;
+    }
+    else
+    {
+        TRACE0("Out of memory");
+    }
+}
+
+
+#ifdef DEBUGGER
+bool CRender::DrawTexture(int tex, TextureChannel channel)
+{
+    if( g_textures[tex].m_pCTexture == NULL )
+    {
+        TRACE0("Can't draw null texture");
+        return false;
+    }
+
+    SaveTextureToFile(tex, channel, true);  // Save to file instead of draw to screen
+    DebuggerAppendMsg("Texture %d (CurTile:%d): W=%f, H=%f, Real W=%d, H=%d", tex, gRSP.curTile, 
+        g_textures[tex].m_fTexWidth, g_textures[tex].m_fTexHeight, g_textures[tex].m_dwTileWidth, g_textures[tex].m_dwTileHeight);
+    DebuggerAppendMsg("X scale: %f, Y scale: %f, %s", gRSP.fTexScaleX, gRSP.fTexScaleY, gRSP.bTextureEnabled?"Enabled":"Disabled");
+
+    return true;
+}
+
+void CRender::SaveTextureToFile(int tex, TextureChannel channel, bool bShow)
+{
+    TxtrCacheEntry &entry = *(g_textures[tex].pTextureEntry);
+
+    CTexture *pBaseTexture = entry.pTexture;
+    if( pBaseTexture == NULL )
+    {
+        TRACE0("Can't dump null texture");
+        return;
+    }
+    CTexture *pEnhancedTexture = entry.pEnhancedTexture ? entry.pEnhancedTexture : entry.pTexture;
+
+    bool bInWhole = false;
+    if( entry.ti.HeightToCreate == entry.ti.HeightToLoad && entry.ti.WidthToCreate == entry.ti.WidthToLoad 
+        && pEnhancedTexture == pBaseTexture )
+        bInWhole = true;
+
+    char filename[256];
+    if( (gRDP.otherMode.text_tlut>=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;
+}
+
diff --git a/source/gles2rice/src/Render.h b/source/gles2rice/src/Render.h
new file mode 100644 (file)
index 0000000..9ae2849
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+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
+
diff --git a/source/gles2rice/src/RenderBase.cpp b/source/gles2rice/src/RenderBase.cpp
new file mode 100644 (file)
index 0000000..d5d2f7c
--- /dev/null
@@ -0,0 +1,2406 @@
+/*
+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 <cmath>
+#include <vector>
+
+#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<MAX_VERTS; i++ )
+    {
+        g_clipFlag[i] = 0;
+        g_vtxNonTransformed[i].w = 1;
+    }
+
+    memset(gRSPn64lights, 0, sizeof(N64Light)*16);
+}
+
+void SetFogMinMax(float fMin, float fMax, float fMul, float fOffset)
+{
+    if( fMin > 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<XVECTOR3>& points)
+{
+    int size = points.size();
+    for( int i=0; i<size; i++)
+    {
+        XVECTOR3 &v = points[i];
+        v.z = (float)HackZ(v.z);
+    }
+}
+
+void HackZAll()
+{
+    if( CDeviceBuilder::m_deviceGeneralType == DIRECTX_DEVICE )
+    {
+        for( uint32 i=0; i<gRSP.numVertices; i++)
+        {
+            g_vtxBuffer[i].z = HackZ(g_vtxBuffer[i].z);
+        }
+    }
+    else
+    {
+        for( uint32 i=0; i<gRSP.numVertices; i++)
+        {
+            float w = g_vtxProjected5[i][3];
+            g_vtxProjected5[i][2] = HackZ(g_vtxProjected5[i][2]/w)*w;
+        }
+    }
+}
+
+
+extern XMATRIX reverseXY;
+extern XMATRIX reverseY;
+
+void UpdateCombinedMatrix()
+{
+    if( gRSP.bMatrixIsUpdated )
+    {
+        gRSPworldProject = gRSP.modelviewMtxs[gRSP.modelViewMtxTop] * gRSP.projectionMtxs[gRSP.projectionMtxTop];
+        gRSP.bMatrixIsUpdated = false;
+        gRSP.bCombinedMatrixIsUpdated = true;
+    }
+
+    if( gRSP.bCombinedMatrixIsUpdated )
+    {
+        if( options.enableHackForGames == HACK_REVERSE_XY_COOR )
+        {
+            gRSPworldProject = gRSPworldProject * reverseXY;
+        }
+        if( options.enableHackForGames == HACK_REVERSE_Y_COOR )
+        {
+            gRSPworldProject = gRSPworldProject * reverseY;
+        }
+#if !defined(NO_ASM)
+        if( status.isSSEEnabled )
+        {
+            MatrixTranspose(&gRSPworldProjectTransported, &gRSPworldProject);
+        }
+#endif
+        gRSP.bCombinedMatrixIsUpdated = false;
+    }
+
+    //if( gRSP.bWorldMatrixIsUpdated || gRSP.bLightIsUpdated )
+    //{
+    //  // Update lights with transported world matrix
+    //  for( unsigned int l=0; l<gRSPnumLights; l++)
+    //  {
+    //      Vec3TransformCoord(&gRSPlights[l].td, &gRSPlights[l].od, &gRSPmodelViewTopTranspose);
+    //      Vec3Normalize(&gRSPlights[l].td,&gRSPlights[l].td);
+    //  }
+
+    //  gRSP.bWorldMatrixIsUpdated = false;
+    //  gRSP.bLightIsUpdated = false;
+    //}
+}
+
diff --git a/source/gles2rice/src/RenderBase.h b/source/gles2rice/src/RenderBase.h
new file mode 100644 (file)
index 0000000..ceeb385
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+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_BASE_H
+#define _RICE_RENDER_BASE_H
+
+#include "osal_preproc.h"
+#include "Debugger.h"
+#include "RSP_Parser.h"
+#include "Video.h"
+
+/*
+ *  Global variables defined in this file were moved out of Render class
+ *  to make them be accessed faster
+ */
+
+#define RICE_MATRIX_STACK   60
+#define MAX_TEXTURES         8
+
+enum FillMode
+{
+    RICE_FILLMODE_WINFRAME,
+    RICE_FILLMODE_SOLID,
+};
+
+enum { MAX_VERTS = 80 };        // F3DLP.Rej supports up to 80 verts!
+
+void myVec3Transform(float *vecout, float *vecin, float* m);
+
+// All these arrays are moved out of the class CRender
+// to be accessed in faster speed
+extern ALIGN(16, XVECTOR4 g_vtxTransformed[MAX_VERTS])
+extern ALIGN(16, XVECTOR4 g_vecProjected[MAX_VERTS])
+extern float        g_vtxProjected5[1000][5];
+extern float        g_vtxProjected5Clipped[2000][5];
+extern VECTOR2      g_fVtxTxtCoords[MAX_VERTS];
+extern uint32       g_dwVtxDifColor[MAX_VERTS];
+//extern uint32     g_dwVtxFlags[MAX_VERTS];            // Z_POS Z_NEG etc
+
+extern RenderTexture g_textures[MAX_TEXTURES];
+
+extern TLITVERTEX       g_vtxBuffer[1000];
+extern unsigned short   g_vtxIndex[1000];
+
+extern TLITVERTEX       g_clippedVtxBuffer[2000];
+extern int              g_clippedVtxCount;
+
+extern uint8            g_oglVtxColors[1000][4];
+extern uint32           g_clipFlag[MAX_VERTS];
+extern uint32           g_clipFlag2[MAX_VERTS];
+extern float            g_fFogCoord[MAX_VERTS];
+
+extern TLITVERTEX       g_texRectTVtx[4];
+
+extern EXTERNAL_VERTEX  g_vtxForExternal[MAX_VERTS];
+
+
+//#define INIT_VERTEX_METHOD_2
+
+/*
+ *  Global variables
+ */
+
+/************************************************************************/
+/*      Don't move                                                      */
+/************************************************************************/
+
+extern uint32             gRSPnumLights;
+extern Light              gRSPlights[16];
+extern ALIGN(16, Matrix   gRSPworldProjectTransported)
+extern ALIGN(16, Matrix   gRSPworldProject)
+extern N64Light           gRSPn64lights[16];
+extern ALIGN(16, Matrix   gRSPmodelViewTop)
+extern ALIGN(16, Matrix   gRSPmodelViewTopTranspose)
+extern float              gRSPfFogMin;
+extern float              gRSPfFogMax;
+extern float              gRSPfFogDivider;
+
+/************************************************************************/
+/*      Don't move                                                      */
+/************************************************************************/
+typedef struct 
+{
+    /************************************************************************/
+    /*      Don't move                                                      */
+    /************************************************************************/
+    union {     
+        struct {
+            float   fAmbientLightR;
+            float   fAmbientLightG;
+            float   fAmbientLightB;
+            float   fAmbientLightA;
+        };
+        float fAmbientColors[4];
+    };
+    /************************************************************************/
+    /*      Don't move above                                                */
+    /************************************************************************/
+    bool    bTextureEnabled;
+    uint32  curTile;
+    float   fTexScaleX;
+    float   fTexScaleY;
+
+    RenderShadeMode shadeMode;
+    bool    bCullFront;
+    bool    bCullBack;
+    bool    bLightingEnable;
+    bool    bTextureGen;
+    bool    bFogEnabled;
+    BOOL    bZBufferEnabled;
+
+    uint32  ambientLightColor;
+    uint32  ambientLightIndex;
+
+    uint32  projectionMtxTop;
+    uint32  modelViewMtxTop;
+
+    uint32  numVertices;
+    uint32  maxVertexID;
+
+    int     nVPLeftN, nVPTopN, nVPRightN, nVPBottomN, nVPWidthN, nVPHeightN, maxZ;
+    int     clip_ratio_negx,    clip_ratio_negy,    clip_ratio_posx,    clip_ratio_posy;
+    int     clip_ratio_left,    clip_ratio_top, clip_ratio_right,   clip_ratio_bottom;
+    int     real_clip_scissor_left, real_clip_scissor_top,  real_clip_scissor_right,    real_clip_scissor_bottom;
+    float   real_clip_ratio_negx,   real_clip_ratio_negy,   real_clip_ratio_posx,   real_clip_ratio_posy;
+
+    Matrix  projectionMtxs[RICE_MATRIX_STACK];
+    Matrix  modelviewMtxs[RICE_MATRIX_STACK];
+
+    bool    bWorldMatrixIsUpdated;
+    bool    bMatrixIsUpdated;
+    bool    bCombinedMatrixIsUpdated;
+    bool    bLightIsUpdated;
+
+    uint32      segments[16];
+
+    int     DKRCMatrixIndex;
+    int     DKRVtxCount;
+    bool    DKRBillBoard;
+    uint32  dwDKRVtxAddr;
+    uint32  dwDKRMatrixAddr;
+    Matrix  DKRMatrixes[4];
+    XVECTOR4        DKRBaseVec;
+
+    int     ucode;
+    int     vertexMult; 
+    bool    bNearClip;
+    bool    bRejectVtx;
+
+    bool    bProcessDiffuseColor;
+    bool    bProcessSpecularColor;
+
+    float   vtxXMul;
+    float   vtxXAdd;
+    float   vtxYMul;
+    float   vtxYAdd;
+
+    // Texture coordinates computation constants
+    float   tex0scaleX;
+    float   tex0scaleY;
+    float   tex1scaleX;
+    float   tex1scaleY;
+    float   tex0OffsetX;
+    float   tex0OffsetY;
+    float   tex1OffsetX;
+    float   tex1OffsetY;
+    float   texGenYRatio;
+    float   texGenXRatio;
+
+} RSP_Options;
+
+extern ALIGN(16, RSP_Options gRSP)
+
+typedef struct {
+    uint32  keyR;
+    uint32  keyG;
+    uint32  keyB;
+    uint32  keyA;
+    uint32  keyRGB;
+    uint32  keyRGBA;
+    float   fKeyA;
+    
+    bool    bFogEnableInBlender;
+
+    uint32  fogColor;
+    uint32  primitiveColor;
+    uint32  envColor;
+    uint32  primitiveDepth;
+    uint32  primLODMin;
+    uint32  primLODFrac;
+    uint32  LODFrac;
+
+    float   fPrimitiveDepth;
+    float   fvFogColor[4];
+    float   fvPrimitiveColor[4];
+    float   fvEnvColor[4];
+
+    uint32  fillColor;
+    uint32  originalFillColor;
+
+    uint32  geometryMode;
+    uint32  otherModeL;
+    uint32  otherModeH;
+    RDP_OtherMode otherMode;
+
+    Tile    tiles[8];
+    ScissorType scissor;
+
+    bool    textureIsChanged;
+    bool    texturesAreReloaded;
+    bool    colorsAreReloaded;
+} RDP_Options;
+
+extern ALIGN(16, RDP_Options gRDP)
+
+/*
+*   Global functions
+*/
+void InitRenderBase();
+void SetFogMinMax(float fMin, float fMax, float fMul, float fOffset);
+void InitVertex(uint32 dwV, uint32 vtxIndex, bool bTexture, bool openGL = true );
+void InitVertexTextureConstants();
+bool PrepareTriangle(uint32 dwV0, uint32 dwV1, uint32 dwV2);
+bool IsTriangleVisible(uint32 dwV0, uint32 dwV1, uint32 dwV2);
+extern void (*ProcessVertexData)(uint32 dwAddr, uint32 dwV0, uint32 dwNum);
+#if !defined(NO_ASM)
+void ProcessVertexDataSSE(uint32 dwAddr, uint32 dwV0, uint32 dwNum);
+#endif
+void ProcessVertexDataNoSSE(uint32 dwAddr, uint32 dwV0, uint32 dwNum);
+void ProcessVertexDataExternal(uint32 dwAddr, uint32 dwV0, uint32 dwNum);
+void SetPrimitiveColor(uint32 dwCol, uint32 LODMin, uint32 LODFrac);
+void SetPrimitiveDepth(uint32 z, uint32 dwDZ);
+void SetVertexXYZ(uint32 vertex, float x, float y, float z);
+void ModifyVertexInfo(uint32 where, uint32 vertex, uint32 val);
+void ProcessVertexDataDKR(uint32 dwAddr, uint32 dwV0, uint32 dwNum);
+void SetLightCol(uint32 dwLight, uint32 dwCol);
+void SetLightDirection(uint32 dwLight, float x, float y, float z, float range);
+void ForceMainTextureIndex(int dwTile); 
+void UpdateCombinedMatrix();
+
+void ClipVertexes();
+void ClipVertexesOpenGL();
+void ClipVertexesForRect();
+
+void LogTextureCoords(float fTex0S, float fTex0T, float fTex1S, float fTex1T);
+bool CheckTextureCoords(int tex);
+void ResetTextureCoordsLog(float maxs0, float maxt0, float maxs1, float maxt1);
+
+inline float ViewPortTranslatef_x(float x) { return ( (x+1) * windowSetting.vpWidthW/2) + windowSetting.vpLeftW; }
+inline float ViewPortTranslatef_y(float y) { return ( (1-y) * windowSetting.vpHeightW/2) + windowSetting.vpTopW; }
+inline float ViewPortTranslatei_x(int x) { return x*windowSetting.fMultX; }
+inline float ViewPortTranslatei_y(int y) { return y*windowSetting.fMultY; }
+inline float ViewPortTranslatei_x(float x) { return x*windowSetting.fMultX; }
+inline float ViewPortTranslatei_y(float y) { return y*windowSetting.fMultY; }
+
+inline float GetPrimitiveDepth() { return gRDP.fPrimitiveDepth; }
+inline uint32 GetPrimitiveColor() { return gRDP.primitiveColor; }
+inline float* GetPrimitiveColorfv() { return gRDP.fvPrimitiveColor; }
+inline uint32 GetLODFrac() { return gRDP.LODFrac; }
+inline void SetEnvColor(uint32 dwCol) 
+{ 
+    gRDP.colorsAreReloaded = true;
+    gRDP.envColor = dwCol; 
+    gRDP.fvEnvColor[0] = ((dwCol>>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
+
diff --git a/source/gles2rice/src/RenderExt.cpp b/source/gles2rice/src/RenderExt.cpp
new file mode 100644 (file)
index 0000000..564f49a
--- /dev/null
@@ -0,0 +1,927 @@
+/*
+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(&gti, 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(&gti, false);
+    //Upto here, the texture is loaded wrong because the format is wrong
+
+    DrawInfo info;  
+    if( pEntry->pTexture->StartUpdate(&info) )
+    {
+        for( uint32 i=0; i<height; i++)
+        {
+            uint32 *psrc = (uint32*)((uint8*)buf+pitch*(i+top))+left;
+            uint32 *pdst = (uint32*)((uint8*)info.lpSurface+i*info.lPitch);
+            for( uint32 j=0; j<width; j++)
+            {
+                pdst[j]=psrc[j];
+            }
+        }
+        pEntry->pTexture->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(&gti, 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(&gti, 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(&gti, 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(&gti, 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(&gti, false);
+    SetCurrentTexture(0,pEntry);
+}
+
diff --git a/source/gles2rice/src/RenderTexture.cpp b/source/gles2rice/src/RenderTexture.cpp
new file mode 100644 (file)
index 0000000..adaeca5
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+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)
+{
+}
+
diff --git a/source/gles2rice/src/RenderTexture.h b/source/gles2rice/src/RenderTexture.h
new file mode 100644 (file)
index 0000000..34fa75e
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+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
+
+
+
diff --git a/source/gles2rice/src/Texture.cpp b/source/gles2rice/src/Texture.cpp
new file mode 100644 (file)
index 0000000..9eb82f4
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+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<m_dwHeight; y++ )
+                {
+                    uint32* line = (uint32*)((uint8*)di.lpSurface+di.lPitch*y);
+                    uint32 val = line[m_dwWidth-1];
+                    for( uint32 x=m_dwWidth; x<m_dwCreatedTextureWidth; x++ )
+                    {
+                        line[x] = val;
+                    }
+                }
+            }
+            else
+            {
+                for( uint32 y = 0; y<m_dwHeight; y++ )
+                {
+                    uint16* line = (uint16*)((uint8*)di.lpSurface+di.lPitch*y);
+                    uint16 val = line[m_dwWidth-1];
+                    for( uint32 x=m_dwWidth; x<m_dwCreatedTextureWidth; x++ )
+                    {
+                        line[x] = val;
+                    }
+                }
+            }
+            EndUpdate(&di);
+        }
+    }
+    m_bClampedS = true;
+}
+
+void CTexture::ClampImageToSurfaceT()
+{
+    if( !m_bClampedT && m_dwHeight < m_dwCreatedTextureHeight )
+    {
+        DrawInfo di;
+        if( StartUpdate(&di) )
+        {
+            if(  m_dwTextureFmt == TEXTURE_FMT_A8R8G8B8 )
+            {
+                uint32* linesrc = (uint32*)((uint8*)di.lpSurface+di.lPitch*(m_dwHeight-1));
+                for( uint32 y = m_dwHeight; y<m_dwCreatedTextureHeight; y++ )
+                {
+                    uint32* linedst = (uint32*)((uint8*)di.lpSurface+di.lPitch*y);
+                    for( uint32 x=0; x<m_dwCreatedTextureWidth; x++ )
+                    {
+                        linedst[x] = linesrc[x];
+                    }
+                }
+            }
+            else
+            {
+                uint16* linesrc = (uint16*)((uint8*)di.lpSurface+di.lPitch*(m_dwHeight-1));
+                for( uint32 y = m_dwHeight; y<m_dwCreatedTextureHeight; y++ )
+                {
+                    uint16* linedst = (uint16*)((uint8*)di.lpSurface+di.lPitch*y);
+                    for( uint32 x=0; x<m_dwCreatedTextureWidth; x++ )
+                    {
+                        linedst[x] = linesrc[x];
+                    }
+                }
+            }
+            EndUpdate(&di);
+        }
+    }
+    m_bClampedT = true;
+}
+
+void CTexture::RestoreAlphaChannel(void)
+{
+    DrawInfo di;
+
+    if ( StartUpdate(&di) )
+    {
+        uint32 *pSrc = (uint32 *)di.lpSurface;
+        int lPitch = di.lPitch;
+
+        for (uint32 y = 0; y < m_dwHeight; y++)
+        {
+            uint32 * dwSrc = (uint32 *)((uint8 *)pSrc + y*lPitch);
+            for (uint32 x = 0; x < m_dwWidth; x++)
+            {
+                uint32 dw = dwSrc[x];
+                uint32 dwRed   = (uint8)((dw & 0x00FF0000)>>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");
+    }
+}
+
diff --git a/source/gles2rice/src/Texture.h b/source/gles2rice/src/Texture.h
new file mode 100644 (file)
index 0000000..49df8c0
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+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
+
diff --git a/source/gles2rice/src/TextureFilters.cpp b/source/gles2rice/src/TextureFilters.cpp
new file mode 100644 (file)
index 0000000..5f36816
--- /dev/null
@@ -0,0 +1,2235 @@
+/*
+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 <sys/types.h>
+#include <algorithm>
+
+#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<nWidth-1 )
+            {
+                b2 = (pSrc[xSrc+1]>>0)&0xFF;
+                g2 = (pSrc[xSrc+1]>>8)&0xFF;
+                r2 = (pSrc[xSrc+1]>>16)&0xFF;
+                a2 = (pSrc[xSrc+1]>>24)&0xFF;
+            }
+
+            if( ySrc<nHeight-1 )
+            {
+                b3 = (pSrc2[xSrc]>>0)&0xFF;
+                g3 = (pSrc2[xSrc]>>8)&0xFF;
+                r3 = (pSrc2[xSrc]>>16)&0xFF;
+                a3 = (pSrc2[xSrc]>>24)&0xFF;
+                if( xSrc<nWidth-1 )
+                {
+                    b4 = (pSrc2[xSrc+1]>>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<nWidth-1 )
+            {
+                pDst1[xSrc*2+1] = DWORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
+            }
+            else
+                pDst1[xSrc*2+1] = pSrc[xSrc];
+
+
+            // Pixel 3
+            if( ySrc<nHeight-1 )
+            {
+                pDst2[xSrc*2] = DWORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
+            }
+            else
+                pDst2[xSrc*2] = pSrc[xSrc];
+
+            // Pixel 4
+            if( xSrc<nWidth-1 )
+            {
+                if( ySrc<nHeight-1 )
+                {
+                    pDst2[xSrc*2+1] = DWORD_MAKE((r1+r2+r3+r4)/4, (g1+g2+g3+g4)/4, (b1+b2+b3+b4)/4, (a1+a2+a3+a4)/4);
+                }
+                else
+                {
+                    pDst2[xSrc*2+1] = DWORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
+                }
+            }
+            else
+            {
+                if( ySrc<nHeight-1 )
+                {
+                    pDst2[xSrc*2+1] = DWORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
+                }
+                else
+                    pDst2[xSrc*2+1] = pSrc[xSrc];
+            }
+        }
+    }
+}
+
+// Basic 2x R4G4B4A4 filter with interpolation
+void Texture2x_16( DrawInfo &srcInfo, DrawInfo &destInfo )
+{
+    uint16 *pDst1, *pDst2;
+    uint16 *pSrc, *pSrc2;
+    uint32 nWidth = srcInfo.dwWidth;
+    uint32 nHeight = srcInfo.dwHeight;
+
+    uint16 b1;
+    uint16 g1;
+    uint16 r1;
+    uint16 a1;
+    uint16 b2 = 0;
+    uint16 g2 = 0;
+    uint16 r2 = 0;
+    uint16 a2 = 0;
+    uint16 b3 = 0;
+    uint16 g3 = 0;
+    uint16 r3 = 0;
+    uint16 a3 = 0;
+    uint16 b4 = 0;
+    uint16 g4 = 0;
+    uint16 r4 = 0;
+    uint16 a4 = 0;
+
+    for (uint16 ySrc = 0; ySrc < nHeight; ySrc++)
+    {
+        pSrc = (uint16*)(((uint8*)srcInfo.lpSurface)+ySrc*srcInfo.lPitch);
+        pSrc2 = (uint16*)(((uint8*)srcInfo.lpSurface)+(ySrc+1)*srcInfo.lPitch);
+        pDst1 = (uint16*)(((uint8*)destInfo.lpSurface)+(ySrc*2)*destInfo.lPitch);
+        pDst2 = (uint16*)(((uint8*)destInfo.lpSurface)+(ySrc*2+1)*destInfo.lPitch);
+
+        for (uint16 xSrc = 0; xSrc < nWidth; xSrc++)
+        {
+            b1 = (pSrc[xSrc]>> 0)&0xF;
+            g1 = (pSrc[xSrc]>> 4)&0xF;
+            r1 = (pSrc[xSrc]>> 8)&0xF;
+            a1 = (pSrc[xSrc]>>12)&0xF;
+
+            if( xSrc<nWidth-1 )
+            {
+                b2 = (pSrc[xSrc+1]>> 0)&0xF;
+                g2 = (pSrc[xSrc+1]>> 4)&0xF;
+                r2 = (pSrc[xSrc+1]>> 8)&0xF;
+                a2 = (pSrc[xSrc+1]>>12)&0xF;
+            }
+
+            if( ySrc<nHeight-1 )
+            {
+                b3 = (pSrc2[xSrc]>> 0)&0xF;
+                g3 = (pSrc2[xSrc]>> 4)&0xF;
+                r3 = (pSrc2[xSrc]>> 8)&0xF;
+                a3 = (pSrc2[xSrc]>>12)&0xF;
+                if( xSrc<nWidth-1 )
+                {
+                    b4 = (pSrc2[xSrc+1]>> 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<nWidth-1 )
+            {
+                pDst1[xSrc*2+1] = WORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
+            }
+            else
+                pDst1[xSrc*2+1] = pSrc[xSrc];
+
+
+            // Pixel 3
+            if( ySrc<nHeight-1 )
+            {
+                pDst2[xSrc*2] = WORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
+            }
+            else
+                pDst2[xSrc*2] = pSrc[xSrc];
+
+            // Pixel 4
+            if( xSrc<nWidth-1 )
+            {
+                if( ySrc<nHeight-1 )
+                {
+                    pDst2[xSrc*2+1] = WORD_MAKE((r1+r2+r3+r4)/4, (g1+g2+g3+g4)/4, (b1+b2+b3+b4)/4, (a1+a2+a3+a4)/4);
+                }
+                else
+                {
+                    pDst2[xSrc*2+1] = WORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
+                }
+            }
+            else
+            {
+                if( ySrc<nHeight-1 )
+                {
+                    pDst2[xSrc*2+1] = WORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
+                }
+                else
+                    pDst2[xSrc*2+1] = pSrc[xSrc];
+            }
+        }
+    }
+}
+
+/************************************************************************/
+/* Sharpen filters                                                      */
+/************************************************************************/
+void SharpenFilter_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_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;
+    uint32 *src1, *src2, *src3, *dest;
+    uint32 val[4];
+    uint32 t1,t2,t3,t4,t5,t6,t7,t8,t9;
+
+    for( y=1; y<height-1; y++)
+    {
+        dest = pdata+y*pitch;
+        src1 = pcopy+(y-1)*pitch;
+        src2 = src1 + pitch;
+        src3 = src2 + pitch;
+        for( x=1; x<width-1; x++)
+        {
+            for( z=0; z<4; z++ )
+            {
+                t1 = *((uint8*)(src1+x-1)+z);
+                t2 = *((uint8*)(src1+x  )+z);
+                t3 = *((uint8*)(src1+x+1)+z);
+                t4 = *((uint8*)(src2+x-1)+z);
+                t5 = *((uint8*)(src2+x  )+z);
+                t6 = *((uint8*)(src2+x+1)+z);
+                t7 = *((uint8*)(src3+x-1)+z);
+                t8 = *((uint8*)(src3+x  )+z);
+                t9 = *((uint8*)(src3+x+1)+z);
+                val[z]=t5;
+                if( (t5*mul2) > (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<height-1; y++)
+    {
+        dest = pdata+y*pitch;
+        src1 = pcopy+(y-1)*pitch;
+        src2 = src1 + pitch;
+        src3 = src2 + pitch;
+        for( x=1; x<width-1; x++)
+        {
+            for( z=0; z<4; z++ )
+            {
+                uint32 shift = (z%1)?4:0;
+                t1 = (*((uint8*)(src1+x-1)+(z>>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<height-1; y+=2)
+        {
+            dest = pdata+y*pitch;
+            src1 = pcopy+(y-1)*pitch;
+            src2 = src1 + pitch;
+            src3 = src2 + pitch;
+            for( x=0; x<width; x++)
+            {
+                for( z=0; z<4; z++ )
+                {
+                    t2 = *((uint8*)(src1+x  )+z);
+                    t5 = *((uint8*)(src2+x  )+z);
+                    t8 = *((uint8*)(src3+x  )+z);
+                    val[z] = ((t2+t8)*mul2+(t5*mul3))>>shift4;
+                }
+                dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24);
+            }
+        }
+    }
+    else
+    {
+        for( y=0; y<height; y++)
+        {
+            dest = pdata+y*pitch;
+            if( y>0 )
+            {
+                src1 = pcopy+(y-1)*pitch;
+                src2 = src1 + pitch;
+            }
+            else
+            {
+                src1 = src2 = pcopy;
+            }
+
+            src3 = src2;
+            if( y<height-1) src3 += pitch;
+
+            for( x=1; x<width-1; x++)
+            {
+                for( z=0; z<4; z++ )
+                {
+                    t1 = *((uint8*)(src1+x-1)+z);
+                    t2 = *((uint8*)(src1+x  )+z);
+                    t3 = *((uint8*)(src1+x+1)+z);
+                    t4 = *((uint8*)(src2+x-1)+z);
+                    t5 = *((uint8*)(src2+x  )+z);
+                    t6 = *((uint8*)(src2+x+1)+z);
+                    t7 = *((uint8*)(src3+x-1)+z);
+                    t8 = *((uint8*)(src3+x  )+z);
+                    t9 = *((uint8*)(src3+x+1)+z);
+                    val[z] = ((t1+t3+t7+t9)*mul1+((t2+t4+t6+t8)*mul2)+(t5*mul3))>>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<height-1; y+=2)
+        {
+            dest = pdata+y*pitch;
+            src1 = pcopy+(y-1)*pitch;
+            src2 = src1 + pitch;
+            src3 = src2 + pitch;
+            for( x=0; x<width; x++)
+            {
+                for( z=0; z<4; z++ )
+                {
+                    uint32 shift = (z&1)?4:0;
+                    t2 = (*((uint8*)(src1+x  )+(z>>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; y<height; y++)
+        {
+            dest = pdata+y*pitch;
+            if( y>0 )
+            {
+                src1 = pcopy+(y-1)*pitch;
+                src2 = src1 + pitch;
+            }
+            else
+            {
+                src1 = src2 = pcopy;
+            }
+
+            src3 = src2;
+            if( y<height-1) src3 += pitch;
+
+            for( x=1; x<width-1; x++)
+            {
+                for( z=0; z<4; z++ )
+                {
+                    uint32 shift = (z&1)?4:0;
+                    t1 = (*((uint8*)(src1+x-1)+(z>>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<uint64,ExtTxtrInfo> gTxtrDumpInfos;
+CSortedList<uint64,ExtTxtrInfo> 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<uint64,ExtTxtrInfo> &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
+
+            <internal Rom name>#<DRAM CRC>#<24bit>#<RGBA>#<PAL CRC>_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:
+                // <DRAM(or texture)-CRC><texture type><texture format><PAL(or palette)-CRC>
+                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:
+                // <DRAM(or texture)-CRC><texture type><texture format>
+                // 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<infos.size(); k++)
+            {
+                // Check if texture already exists in the list
+                // microdev: that's why I somehow love documenting code: that makes the implementation of a WIP folder check
+                // fucking easy :-)
+                if( infos[k].crc32 == crc && infos[k].pal_crc32 == palcrc32 )
+                {
+                    // Indeeed, the texture already exists
+                    // microdev: MAYBE ADD CODE TO MOVE IT TO A 'DUBLICATE' FOLDER TO EASE WORK OF RETEXTURERS
+                    foundIdx = k;
+                    break;
+                }
+            }
+
+            if( foundIdx < 0 || type != infos[foundIdx].type)
+            {
+                // Create a new entry
+                ExtTxtrInfo newinfo;
+                // Store the width
+                newinfo.width = imgInfo.Width;
+                // Store the height
+                newinfo.height = imgInfo.Height;
+                // Store the name of the folder it has been found in
+                //strcpy(newinfo.name,g_curRomInfo.szGameName);
+                newinfo.foldername = new char[strlen(foldername)+1];
+                strcpy(newinfo.foldername,foldername);
+                // store the filename
+                newinfo.filename = strdup(foundfilename);
+                newinfo.filename_a = NULL;
+                // Store the format
+                newinfo.fmt = fmt;
+                // Store the size (bit-size, not texture size)
+                newinfo.siz = siz;
+                // Store DRAM (texture) CRC
+                newinfo.crc32 = crc;
+                // Store PAL (palette) CRC (the actual one, or the dummy value ('FFFFFFFF'))
+                newinfo.pal_crc32 = palcrc32;
+                // Store the texture type
+                newinfo.type = type;
+                //Indicate if there is a separate alpha file that has to be loaded
+                newinfo.bSeparatedAlpha = bSeparatedAlpha;
+                if (bSeparatedAlpha) {
+                    char filename2[PATH_MAX];
+                    strcpy(filename2, foundfilename);
+                    strcpy(filename2+strlen(filename2)-8,"_a.png");
+                    newinfo.filename_a = strdup(filename2);
+                }
+                // Generate the key for the record describing the hires texture.
+                // This key is used to find it back in the list
+                // The key format is: <DRAM(texture)-CRC-8byte><PAL(palette)-CRC-6byte(2bytes have been truncated to have space for format and size)><format-1byte><size-1byte>
+                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<gHiresTxtrInfos.size(); i++)
+    {
+        if( gHiresTxtrInfos[i].foldername )
+            delete [] gHiresTxtrInfos[i].foldername;
+        if( gHiresTxtrInfos[i].filename )
+            delete [] gHiresTxtrInfos[i].filename;
+        if( gHiresTxtrInfos[i].filename_a )
+            delete [] gHiresTxtrInfos[i].filename_a;
+    }
+
+    gHiresTxtrInfos.clear();
+}
+
+void CloseTextureDump(void)
+{
+    for( int i=0; i<gTxtrDumpInfos.size(); i++)
+    {
+        if( gTxtrDumpInfos[i].foldername )  
+            delete [] gTxtrDumpInfos[i].foldername;
+        if( gTxtrDumpInfos[i].filename )
+            delete [] gTxtrDumpInfos[i].filename;
+        if( gTxtrDumpInfos[i].filename_a )
+            delete [] gTxtrDumpInfos[i].filename_a;
+    }
+
+    gTxtrDumpInfos.clear();
+}
+
+void CloseExternalTextures(void)
+{
+    CloseHiresTextures();
+    CloseTextureDump();
+}
+
+/********************************************************************************************************************
+ * Scans the hires folder for hires textures and creates a list with records of properties of the hires textures.
+ * in case of enabled hires caching also the actual hires textures will be added to the record. Before textures will
+ * be loaded, existing list of texture information will be truncated.
+ * parameter:
+ * bWIPFolder: Indicates if all textures should be inited or just the WIP folder. Just the content of the WIP folder
+ *             will be reloaded if a savestate has been loaded or if there has been a switch between window and full-
+ *             screen mode. (Not implemented yet)
+ * return:
+ * none
+ ********************************************************************************************************************/
+void InitHiresTextures(void)
+{
+    if( options.bLoadHiResTextures )
+    {
+        DebugMessage(M64MSG_INFO, "Texture loading option is enabled. Finding all hires textures");
+        FindAllHiResTextures();
+    }
+}
+
+void InitTextureDump(void)
+{
+    if( options.bDumpTexturesToFiles )
+    {
+        DebugMessage(M64MSG_INFO, "Texture dump option is enabled. Finding all dumpped textures");
+        FindAllDumpedTextures();
+    }
+}
+
+/********************************************************************************************************************
+ * Inits the hires textures. For doing so, all hires textures info & the cached textures (for dumping and the hires ones)
+ * are deleted. Afterwards they are reloaded from file system. This only takes place if a new rom has been loaded.
+ * parameter:
+ * none
+ * return:
+ * none
+ ********************************************************************************************************************/
+void InitExternalTextures(void)
+{
+    DebugMessage(M64MSG_VERBOSE, "InitExternalTextures");
+    // remove all hires & dump textures from cache
+    CloseExternalTextures();
+    // reload and recache hires textures
+    InitHiresTextures();
+    // prepare list of already dumped textures (for avoiding to redump them). Available hires textures will
+    // also be excluded from dumping
+    InitTextureDump();
+}
+
+/********************************************************************************************************************
+ * Determines the scale factor for resizing the original texture to the hires replacement. The scale factor is a left
+ * shift. That means scale factor 1 = size(original texture)*2= size(hires texture),
+ * factor 2 = size(original texture)*4= size(hires texture), etc. (I'm not yet sure why it has to be 2^x. Most probably
+ * because of block size. Has to be further determined.
+ * parameter:
+ * info: the record describing the external texture
+ * entry: the original texture in the texture cache
+ * return:
+ * info.scaleShift: the value for left shift the original texture size to the corresponding hires texture size
+ * return value: the value for left shift the original texture size to the corresponding hires texture size.
+ *               The function returns -1 if the dimensions of the hires texture are not a power of two of the
+ *               original texture.
+ ********************************************************************************************************************/
+int FindScaleFactor(const ExtTxtrInfo &info, TxtrCacheEntry &entry)
+{
+    // init scale shift
+    int scaleShift = 0;
+    // check if the original texture dimensions (x and y) scaled with the current shift is still smaller or of the same size as the hires one
+    while(info.height >= entry.ti.HeightToLoad*(1<<scaleShift)  && info.width >= entry.ti.WidthToLoad*(1<<scaleShift))
+    {
+        // check if the original texture dimensions (x and y)scaled with the current shift have the same size as the hires one
+        if(info.height == entry.ti.HeightToLoad*(1<<scaleShift)  && info.width == entry.ti.WidthToLoad*(1<<scaleShift))
+            // found appropriate scale shift, return it
+            return scaleShift;
+
+        scaleShift++;
+    }
+
+    // original texture dimensions (x or y or both) scaled with the last scale shift have become larger than the dimensions
+    // of the hires texture. That means the dimensions of the hires replacement are not power of 2 of the original texture.
+    // Therefore indicate a crop shift (or -1 when the hires_texture was smaller from the beginning)
+    scaleShift -= 1;
+    return scaleShift;
+}
+
+
+/********************************************************************************************************************
+ * Checks if a hires replacement for a texture is available.
+ * parameter:
+ * infos: The list of external textures
+ * entry: the original texture in the texture cache
+ * return:
+ * indexa: returns the index in "infos" where a hires replacement for a texture without
+ *         palette crc or a RGBA_PNG_FOR_ALL_CI texture has been found
+ * return value: the index in "infos" where the corresponding hires texture has been found
+ ********************************************************************************************************************/
+int CheckTextureInfos( CSortedList<uint64,ExtTxtrInfo> &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; j<entry.ti.WidthToLoad; j++)
+                        {
+                            aFF &= pSrc[3];
+                            pSrc += 4;
+                        }
+                    }
+                    pSrcTexture->EndUpdate(&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<width; j++)
+                    {
+                        if( entry.ti.Size == TXT_SIZE_4b )
+                        {
+                            // 4 bits
+                            if( idx%2 )
+                            {
+                                // 1
+                                *pbuf2++ = pTable[colorIdxBuf[(idx++)>>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<height; i++)
+            {
+                unsigned char *pRGB = buf_rgba + (input_height_shift + i) * input_pitch_rgb;
+                unsigned char *pA = buf_a + (input_height_shift + i) * input_pitch_a;
+                unsigned char* pdst = (unsigned char*)info.lpSurface + (height - i - 1)*info.lPitch;
+                for( int j=0; j<width; j++)
+                {
+                    *pdst++ = *pRGB++;      // R
+                    *pdst++ = *pRGB++;      // G
+                    *pdst++ = *pRGB++;      // B
+
+                    if( gHiresTxtrInfos[idx].bSeparatedAlpha )
+                    {
+                        *pdst++ = *pA;
+                        pA += 3;
+                    }
+                    else if( entry.ti.Format == TXT_FMT_I )
+                    {
+                        *pdst++ = pRGB[-1];
+                    }
+                    else
+                    {
+                        *pdst++ = 0xFF;
+                    }
+                }
+            }
+        }
+        else
+        {
+            input_pitch_rgb *= 4;
+
+            // Update the texture by using the buffer
+            for( int i=height-1; 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; j<width; j++)
+                {
+                    *pdst++ = *pRGB++;      // RGBA
+                }
+            }
+        }
+
+        if (mirrorx == 2)
+        {
+            //printf("Mirror: ToCreate: (%d,%d) ToLoad: (%d,%d) Scale: (%i,%i) Mirror: (%i,%i) Size: (%i,%i) Mask: %i\n", entry.ti.WidthToCreate, entry.ti.HeightToCreate, entry.ti.WidthToLoad, entry.ti.HeightToLoad, scale, scale, mirrorx, mirrory, width, height, entry.ti.maskS+scaleShift);
+            gTextureManager.Mirror(info.lpSurface, width, entry.ti.maskS+scaleShift, width*2, width*2, height, S_FLAG, 4 );
+        }
+
+        if (mirrory == 2)
+        {
+            //printf("Mirror: ToCreate: (%d,%d) ToLoad: (%d,%d) Scale: (%i,%i) Mirror: (%i,%i) Size: (%i,%i) Mask: %i\n", entry.ti.WidthToCreate, entry.ti.HeightToCreate, entry.ti.WidthToLoad, entry.ti.HeightToLoad, scale, scale, mirrorx, mirrory, width, height, entry.ti.maskT+scaleShift);
+            gTextureManager.Mirror(info.lpSurface, height, entry.ti.maskT+scaleShift, height*2, entry.pEnhancedTexture->m_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;
+    }
+}
+
diff --git a/source/gles2rice/src/TextureFilters.h b/source/gles2rice/src/TextureFilters.h
new file mode 100644 (file)
index 0000000..093d2ac
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+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
+
diff --git a/source/gles2rice/src/TextureFilters_2xsai.cpp b/source/gles2rice/src/TextureFilters_2xsai.cpp
new file mode 100644 (file)
index 0000000..72d6fa9
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+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));
+    }
+}
+
diff --git a/source/gles2rice/src/TextureFilters_hq2x.cpp b/source/gles2rice/src/TextureFilters_hq2x.cpp
new file mode 100644 (file)
index 0000000..6774f04
--- /dev/null
@@ -0,0 +1,846 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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;i<count;++i) {
+        unsigned char mask;
+
+        uint16 c[9];
+
+        c[1] = src0[0];
+        c[4] = src1[0];
+        c[7] = src2[0];
+
+        if (i>0) {
+            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<count-1) {
+            c[2] = src0[1];
+            c[5] = src1[1];
+            c[8] = src2[1];
+        } else {
+            c[2] = c[1];
+            c[5] = c[4];
+            c[8] = c[7];
+        }
+
+        mask = 0;
+
+        if (hq2x_interp_16_diff(c[0], c[4]))
+            mask |= 1 << 0;
+        if (hq2x_interp_16_diff(c[1], c[4]))
+            mask |= 1 << 1;
+        if (hq2x_interp_16_diff(c[2], c[4]))
+            mask |= 1 << 2;
+        if (hq2x_interp_16_diff(c[3], c[4]))
+            mask |= 1 << 3;
+        if (hq2x_interp_16_diff(c[5], c[4]))
+            mask |= 1 << 4;
+        if (hq2x_interp_16_diff(c[6], c[4]))
+            mask |= 1 << 5;
+        if (hq2x_interp_16_diff(c[7], c[4]))
+            mask |= 1 << 6;
+        if (hq2x_interp_16_diff(c[8], c[4]))
+            mask |= 1 << 7;
+
+#define P0 dst0[0]
+#define P1 dst0[1]
+#define P2 dst1[0]
+#define P3 dst1[1]
+#define HQ2X_MUR hq2x_interp_16_diff(c[1], c[5])
+#define HQ2X_MDR hq2x_interp_16_diff(c[5], c[7])
+#define HQ2X_MDL hq2x_interp_16_diff(c[7], c[3])
+#define HQ2X_MUL hq2x_interp_16_diff(c[3], c[1])
+#define IC(p0) c[p0]
+#define I11(p0,p1) hq2x_interp_16_11(c[p0], c[p1])
+#define I211(p0,p1,p2) hq2x_interp_16_211(c[p0], c[p1], c[p2])
+#define I31(p0,p1) hq2x_interp_16_31(c[p0], c[p1])
+#define I332(p0,p1,p2) hq2x_interp_16_332(c[p0], c[p1], c[p2])
+#define I431(p0,p1,p2) hq2x_interp_16_431(c[p0], c[p1], c[p2])
+#define I521(p0,p1,p2) hq2x_interp_16_521(c[p0], c[p1], c[p2])
+#define I53(p0,p1) hq2x_interp_16_53(c[p0], c[p1])
+#define I611(p0,p1,p2) hq2x_interp_16_611(c[p0], c[p1], c[p2])
+#define I71(p0,p1) hq2x_interp_16_71(c[p0], c[p1])
+#define I772(p0,p1,p2) hq2x_interp_16_772(c[p0], c[p1], c[p2])
+#define I97(p0,p1) hq2x_interp_16_97(c[p0], c[p1])
+#define I1411(p0,p1,p2) hq2x_interp_16_1411(c[p0], c[p1], c[p2])
+#define I151(p0,p1) hq2x_interp_16_151(c[p0], c[p1])
+
+        switch (mask) {
+#include "TextureFilters_hq2x.h"
+        }
+
+#undef P0
+#undef P1
+#undef P2
+#undef P3
+#undef HQ2X_MUR
+#undef HQ2X_MDR
+#undef HQ2X_MDL
+#undef HQ2X_MUL
+#undef IC
+#undef I11
+#undef I211
+#undef I31
+#undef I332
+#undef I431
+#undef I521
+#undef I53
+#undef I611
+#undef I71
+#undef I772
+#undef I97
+#undef I1411
+#undef I151
+
+        src0 += 1;
+        src1 += 1;
+        src2 += 1;
+        dst0 += 2;
+        dst1 += 2;
+    }
+}
+
+static void hq2x_32_def(uint32* dst0, uint32* dst1, const uint32* src0, const uint32* src1, const uint32* src2, unsigned count)
+{
+    unsigned i;
+
+    for(i=0;i<count;++i) {
+        unsigned char mask;
+
+        uint32 c[9];
+
+        c[1] = src0[0];
+        c[4] = src1[0];
+        c[7] = src2[0];
+
+        if (i>0) {
+            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 (i<count-1) {
+            c[2] = src0[1];
+            c[5] = src1[1];
+            c[8] = src2[1];
+        } else {
+            c[2] = src0[0];
+            c[5] = src1[0];
+            c[8] = src2[0];
+        }
+
+        mask = 0;
+
+        if (hq2x_interp_32_diff(c[0], c[4]))
+            mask |= 1 << 0;
+        if (hq2x_interp_32_diff(c[1], c[4]))
+            mask |= 1 << 1;
+        if (hq2x_interp_32_diff(c[2], c[4]))
+            mask |= 1 << 2;
+        if (hq2x_interp_32_diff(c[3], c[4]))
+            mask |= 1 << 3;
+        if (hq2x_interp_32_diff(c[5], c[4]))
+            mask |= 1 << 4;
+        if (hq2x_interp_32_diff(c[6], c[4]))
+            mask |= 1 << 5;
+        if (hq2x_interp_32_diff(c[7], c[4]))
+            mask |= 1 << 6;
+        if (hq2x_interp_32_diff(c[8], c[4]))
+            mask |= 1 << 7;
+
+#define P0 dst0[0]
+#define P1 dst0[1]
+#define P2 dst1[0]
+#define P3 dst1[1]
+#define HQ2X_MUR hq2x_interp_32_diff(c[1], c[5])
+#define HQ2X_MDR hq2x_interp_32_diff(c[5], c[7])
+#define HQ2X_MDL hq2x_interp_32_diff(c[7], c[3])
+#define HQ2X_MUL hq2x_interp_32_diff(c[3], c[1])
+#define IC(p0) c[p0]
+#define I11(p0,p1) hq2x_interp_32_11(c[p0], c[p1])
+#define I211(p0,p1,p2) hq2x_interp_32_211(c[p0], c[p1], c[p2])
+#define I31(p0,p1) hq2x_interp_32_31(c[p0], c[p1])
+#define I332(p0,p1,p2) hq2x_interp_32_332(c[p0], c[p1], c[p2])
+#define I431(p0,p1,p2) hq2x_interp_32_431(c[p0], c[p1], c[p2])
+#define I521(p0,p1,p2) hq2x_interp_32_521(c[p0], c[p1], c[p2])
+#define I53(p0,p1) hq2x_interp_32_53(c[p0], c[p1])
+#define I611(p0,p1,p2) hq2x_interp_32_611(c[p0], c[p1], c[p2])
+#define I71(p0,p1) hq2x_interp_32_71(c[p0], c[p1])
+#define I772(p0,p1,p2) hq2x_interp_32_772(c[p0], c[p1], c[p2])
+#define I97(p0,p1) hq2x_interp_32_97(c[p0], c[p1])
+#define I1411(p0,p1,p2) hq2x_interp_32_1411(c[p0], c[p1], c[p2])
+#define I151(p0,p1) hq2x_interp_32_151(c[p0], c[p1])
+
+        switch (mask) {
+#include "TextureFilters_hq2x.h"
+        }
+
+#undef P0
+#undef P1
+#undef P2
+#undef P3
+#undef HQ2X_MUR
+#undef HQ2X_MDR
+#undef HQ2X_MDL
+#undef HQ2X_MUL
+#undef IC
+#undef I11
+#undef I211
+#undef I31
+#undef I332
+#undef I431
+#undef I521
+#undef I53
+#undef I611
+#undef I71
+#undef I772
+#undef I97
+#undef I1411
+#undef I151
+
+        src0 += 1;
+        src1 += 1;
+        src2 += 1;
+        dst0 += 2;
+        dst1 += 2;
+    }
+}
+
+/***************************************************************************/
+/* LQ2x C implementation */
+
+/*
+* This effect is derived from the hq2x effect made by Maxim Stepin
+*/
+
+static void lq2x_16_def(uint16* dst0, uint16* dst1, const uint16* src0, const uint16* src1, const uint16* src2, unsigned count)
+{
+    unsigned i;
+
+    for(i=0;i<count;++i) {
+        unsigned char mask;
+
+        uint16 c[9];
+
+        c[1] = src0[0];
+        c[4] = src1[0];
+        c[7] = src2[0];
+
+        if (i>0) {
+            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<count-1) {
+            c[2] = src0[1];
+            c[5] = src1[1];
+            c[8] = src2[1];
+        } else {
+            c[2] = c[1];
+            c[5] = c[4];
+            c[8] = c[7];
+        }
+
+        mask = 0;
+
+        if (c[0] != c[4])
+            mask |= 1 << 0;
+        if (c[1] != c[4])
+            mask |= 1 << 1;
+        if (c[2] != c[4])
+            mask |= 1 << 2;
+        if (c[3] != c[4])
+            mask |= 1 << 3;
+        if (c[5] != c[4])
+            mask |= 1 << 4;
+        if (c[6] != c[4])
+            mask |= 1 << 5;
+        if (c[7] != c[4])
+            mask |= 1 << 6;
+        if (c[8] != c[4])
+            mask |= 1 << 7;
+
+#define P0 dst0[0]
+#define P1 dst0[1]
+#define P2 dst1[0]
+#define P3 dst1[1]
+#define HQ2X_MUR (c[1] != c[5])
+#define HQ2X_MDR (c[5] != c[7])
+#define HQ2X_MDL (c[7] != c[3])
+#define HQ2X_MUL (c[3] != c[1])
+#define IC(p0) c[p0]
+#define I11(p0,p1) hq2x_interp_16_11(c[p0], c[p1])
+#define I211(p0,p1,p2) hq2x_interp_16_211(c[p0], c[p1], c[p2])
+#define I31(p0,p1) hq2x_interp_16_31(c[p0], c[p1])
+#define I332(p0,p1,p2) hq2x_interp_16_332(c[p0], c[p1], c[p2])
+#define I431(p0,p1,p2) hq2x_interp_16_431(c[p0], c[p1], c[p2])
+#define I521(p0,p1,p2) hq2x_interp_16_521(c[p0], c[p1], c[p2])
+#define I53(p0,p1) hq2x_interp_16_53(c[p0], c[p1])
+#define I611(p0,p1,p2) hq2x_interp_16_611(c[p0], c[p1], c[p2])
+#define I71(p0,p1) hq2x_interp_16_71(c[p0], c[p1])
+#define I772(p0,p1,p2) hq2x_interp_16_772(c[p0], c[p1], c[p2])
+#define I97(p0,p1) hq2x_interp_16_97(c[p0], c[p1])
+#define I1411(p0,p1,p2) hq2x_interp_16_1411(c[p0], c[p1], c[p2])
+#define I151(p0,p1) hq2x_interp_16_151(c[p0], c[p1])
+
+        switch (mask) {
+#include "TextureFilters_lq2x.h"
+        }
+
+#undef P0
+#undef P1
+#undef P2
+#undef P3
+#undef HQ2X_MUR
+#undef HQ2X_MDR
+#undef HQ2X_MDL
+#undef HQ2X_MUL
+#undef IC
+#undef I11
+#undef I211
+#undef I31
+#undef I332
+#undef I431
+#undef I521
+#undef I53
+#undef I611
+#undef I71
+#undef I772
+#undef I97
+#undef I1411
+#undef I151
+
+        src0 += 1;
+        src1 += 1;
+        src2 += 1;
+        dst0 += 2;
+        dst1 += 2;
+    }
+}
+
+static void lq2x_32_def(uint32* dst0, uint32* dst1, const uint32* src0, const uint32* src1, const uint32* src2, unsigned count)
+{
+    unsigned i;
+
+    for(i=0;i<count;++i) {
+        unsigned char mask;
+
+        uint32 c[9];
+
+        c[1] = src0[0];
+        c[4] = src1[0];
+        c[7] = src2[0];
+
+        if (i>0) {
+            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<count-1) {
+            c[2] = src0[1];
+            c[5] = src1[1];
+            c[8] = src2[1];
+        } else {
+            c[2] = c[1];
+            c[5] = c[4];
+            c[8] = c[7];
+        }
+
+        mask = 0;
+
+        if (c[0] != c[4])
+            mask |= 1 << 0;
+        if (c[1] != c[4])
+            mask |= 1 << 1;
+        if (c[2] != c[4])
+            mask |= 1 << 2;
+        if (c[3] != c[4])
+            mask |= 1 << 3;
+        if (c[5] != c[4])
+            mask |= 1 << 4;
+        if (c[6] != c[4])
+            mask |= 1 << 5;
+        if (c[7] != c[4])
+            mask |= 1 << 6;
+        if (c[8] != c[4])
+            mask |= 1 << 7;
+
+#define P0 dst0[0]
+#define P1 dst0[1]
+#define P2 dst1[0]
+#define P3 dst1[1]
+#define HQ2X_MUR (c[1] != c[5])
+#define HQ2X_MDR (c[5] != c[7])
+#define HQ2X_MDL (c[7] != c[3])
+#define HQ2X_MUL (c[3] != c[1])
+#define IC(p0) c[p0]
+#define I11(p0,p1) hq2x_interp_32_11(c[p0], c[p1])
+#define I211(p0,p1,p2) hq2x_interp_32_211(c[p0], c[p1], c[p2])
+#define I31(p0,p1) hq2x_interp_32_31(c[p0], c[p1])
+#define I332(p0,p1,p2) hq2x_interp_32_332(c[p0], c[p1], c[p2])
+#define I431(p0,p1,p2) hq2x_interp_32_431(c[p0], c[p1], c[p2])
+#define I521(p0,p1,p2) hq2x_interp_32_521(c[p0], c[p1], c[p2])
+#define I53(p0,p1) hq2x_interp_32_53(c[p0], c[p1])
+#define I611(p0,p1,p2) hq2x_interp_32_611(c[p0], c[p1], c[p2])
+#define I71(p0,p1) hq2x_interp_32_71(c[p0], c[p1])
+#define I772(p0,p1,p2) hq2x_interp_32_772(c[p0], c[p1], c[p2])
+#define I97(p0,p1) hq2x_interp_32_97(c[p0], c[p1])
+#define I1411(p0,p1,p2) hq2x_interp_32_1411(c[p0], c[p1], c[p2])
+#define I151(p0,p1) hq2x_interp_32_151(c[p0], c[p1])
+
+        switch (mask) {
+#include "TextureFilters_lq2x.h"
+        }
+
+#undef P0
+#undef P1
+#undef P2
+#undef P3
+#undef HQ2X_MUR
+#undef HQ2X_MDR
+#undef HQ2X_MDL
+#undef HQ2X_MUL
+#undef IC
+#undef I11
+#undef I211
+#undef I31
+#undef I332
+#undef I431
+#undef I521
+#undef I53
+#undef I611
+#undef I71
+#undef I772
+#undef I97
+#undef I1411
+#undef I151
+
+        src0 += 1;
+        src1 += 1;
+        src2 += 1;
+        dst0 += 2;
+        dst1 += 2;
+    }
+}
+
+void hq2x_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);
+
+    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                                                      */
+/************************************************************************/
+
diff --git a/source/gles2rice/src/TextureFilters_hq2x.h b/source/gles2rice/src/TextureFilters_hq2x.h
new file mode 100644 (file)
index 0000000..bf81408
--- /dev/null
@@ -0,0 +1,1846 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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;
+
diff --git a/source/gles2rice/src/TextureFilters_hq4x.cpp b/source/gles2rice/src/TextureFilters_hq4x.cpp
new file mode 100644 (file)
index 0000000..4045d77
--- /dev/null
@@ -0,0 +1,578 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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 <stdlib.h>
+
+#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; j<Yres; j++)
+    {
+        if (j>0)      prevline = -SrcPPL*2; else prevline = 0;
+        if (j<Yres-1) nextline =  SrcPPL*2; else nextline = 0;
+
+        for (i=0; i<Xres; i++)
+        {
+            w[2] = *((uint16*)(pIn + prevline));
+            w[5] = *((uint16*)pIn);
+            w[8] = *((uint16*)(pIn + nextline));
+
+            if (i>0)
+            {
+                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<Xres-1)
+            {
+                w[3] = *((uint16*)(pIn + prevline + 2));
+                w[6] = *((uint16*)(pIn + 2));
+                w[9] = *((uint16*)(pIn + nextline + 2));
+            }
+            else
+            {
+                w[3] = w[2];
+                w[6] = w[5];
+                w[9] = w[8];
+            }
+
+            int pattern = 0;
+            int flag = 1;
+
+            YUV1 = RGB16toYUV(w[5]);
+
+            for (k=1; k<=9; k++)
+            {
+                if (k==5) continue;
+
+                if ( w[k] != w[5] )
+                {
+                    YUV2 = RGB16toYUV(w[k]);
+                    if ( ( abs((YUV1 & Amask) - (YUV2 & Amask)) > 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; j<Yres; j++)
+    {
+        if (j>0)      prevline = -SrcPPL*4; else prevline = 0;
+        if (j<Yres-1) nextline =  SrcPPL*4; else nextline = 0;
+
+        for (i=0; i<Xres; i++)
+        {
+            w[2] = *((uint32*)(pIn + prevline));
+            w[5] = *((uint32*)pIn);
+            w[8] = *((uint32*)(pIn + nextline));
+
+            if (i>0)
+            {
+                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<Xres-1)
+            {
+                w[3] = *((uint32*)(pIn + prevline + 4));
+                w[6] = *((uint32*)(pIn + 4));
+                w[9] = *((uint32*)(pIn + nextline + 4));
+            }
+            else
+            {
+                w[3] = w[2];
+                w[6] = w[5];
+                w[9] = w[8];
+            }
+
+            int pattern = 0;
+            int flag = 1;
+
+            YUV1 = RGB32toYUV(w[5]);
+
+            for (k=1; k<=9; k++)
+            {
+                if (k==5) continue;
+
+                if ( w[k] != w[5] )
+                {
+                    YUV2 = RGB32toYUV(w[k]);
+                    if ( ( abs((YUV1 & Amask) - (YUV2 & Amask)) > 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;
+    }
+}
+
diff --git a/source/gles2rice/src/TextureFilters_hq4x.h b/source/gles2rice/src/TextureFilters_hq4x.h
new file mode 100644 (file)
index 0000000..5283420
--- /dev/null
@@ -0,0 +1,4996 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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;
+    }
+}
+
diff --git a/source/gles2rice/src/TextureFilters_lq2x.h b/source/gles2rice/src/TextureFilters_lq2x.h
new file mode 100644 (file)
index 0000000..a261fc4
--- /dev/null
@@ -0,0 +1,1306 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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;
+
diff --git a/source/gles2rice/src/TextureManager.cpp b/source/gles2rice/src/TextureManager.cpp
new file mode 100644 (file)
index 0000000..fb868e2
--- /dev/null
@@ -0,0 +1,1546 @@
+/*
+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 <exception>
+#include <cmath>
+
+#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<<mask);
+    int size = pEntry->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; y<rows; y++ )
+    {
+        uint32* line = array+y*arrayWidth;
+        uint32 val = line[width-1];
+        for( uint32 x=width; x<towidth; x++ )
+        {
+            line[x] = val;
+        }
+    }
+}
+
+void CTextureManager::ClampS16(uint16 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows)
+{
+    if ((int) width <= 0 || (int) towidth < 0)
+        return;
+
+    for( uint32 y = 0; y<rows; y++ )
+    {
+        uint16* line = array+y*arrayWidth;
+        uint16 val = line[width-1];
+        for( uint32 x=width; x<towidth; x++ )
+        {
+            line[x] = val;
+        }
+    }
+}
+
+void CTextureManager::ClampT32(uint32 *array, uint32 height, uint32 toheight, uint32 arrayWidth, uint32 cols)
+{
+    if ((int) height <= 0 || (int) toheight < 0)
+        return;
+
+    uint32* linesrc = array+arrayWidth*(height-1);
+    for( uint32 y = height; y<toheight; y++ )
+    {
+        uint32* linedst = array+arrayWidth*y;
+        for( uint32 x=0; x<arrayWidth; x++ )
+        {
+            linedst[x] = linesrc[x];
+        }
+    }
+}
+
+void CTextureManager::ClampT16(uint16 *array, uint32 height, uint32 toheight, uint32 arrayWidth, uint32 cols)
+{
+    if ((int) height <= 0 || (int) toheight < 0)
+        return;
+
+    uint16* linesrc = array+arrayWidth*(height-1);
+    for( uint32 y = height; y<toheight; y++ )
+    {
+        uint16* linedst = array+arrayWidth*y;
+        for( uint32 x=0; x<arrayWidth; x++ )
+        {
+            linedst[x] = linesrc[x];
+        }
+    }
+}
+
+void CTextureManager::MirrorS32(uint32 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
+{
+    uint32 maskval1 = (1<<mask)-1;
+    uint32 maskval2 = (1<<(mask+1))-1;
+
+    for( uint32 y = 0; y<rows; y++ )
+    {
+        uint32* line = array+y*arrayWidth;
+        for( uint32 x=width; x<towidth; x++ )
+        {
+            line[x] = (x&maskval2)<=maskval1 ? line[x&maskval1] : line[maskval2-(x&maskval2)];
+        }
+    }
+}
+
+void CTextureManager::MirrorS16(uint16 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
+{
+    uint32 maskval1 = (1<<mask)-1;
+    uint32 maskval2 = (1<<(mask+1))-1;
+
+    for( uint32 y = 0; y<rows; y++ )
+    {
+        uint16* line = array+y*arrayWidth;
+        for( uint32 x=width; x<towidth; x++ )
+        {
+            line[x] = (x&maskval2)<=maskval1 ? line[x&maskval1] : line[maskval2-(x&maskval2)];
+        }
+    }
+}
+
+void CTextureManager::MirrorT32(uint32 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
+{
+    uint32 maskval1 = (1<<mask)-1;
+    uint32 maskval2 = (1<<(mask+1))-1;
+
+    for( uint32 y = height; y<toheight; y++ )
+    {
+        uint32 srcy = (y&maskval2)<=maskval1 ? y&maskval1 : maskval2-(y&maskval2);
+        uint32* linesrc = array+arrayWidth*srcy;
+        uint32* linedst = array+arrayWidth*y;;
+        for( uint32 x=0; x<arrayWidth; x++ )
+        {
+            linedst[x] = linesrc[x];
+        }
+    }
+}
+
+void CTextureManager::MirrorT16(uint16 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
+{
+    uint32 maskval1 = (1<<mask)-1;
+    uint32 maskval2 = (1<<(mask+1))-1;
+
+    for( uint32 y = height; y<toheight; y++ )
+    {
+        uint32 srcy = (y&maskval2)<=maskval1 ? y&maskval1 : maskval2-(y&maskval2);
+        uint16* linesrc = array+arrayWidth*srcy;
+        uint16* linedst = array+arrayWidth*y;;
+        for( uint32 x=0; x<arrayWidth; x++ )
+        {
+            linedst[x] = linesrc[x];
+        }
+    }
+}
+
+void CTextureManager::WrapS32(uint32 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
+{
+    uint32 maskval = (1<<mask)-1;
+
+    for( uint32 y = 0; y<rows; y++ )
+    {
+        uint32* line = array+y*arrayWidth;
+        for( uint32 x=width; x<towidth; x++ )
+        {
+            line[x] = line[(x&maskval)<width?(x&maskval):towidth-(x&maskval)];
+        }
+    }
+}
+
+void CTextureManager::WrapS16(uint16 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
+{
+    uint32 maskval = (1<<mask)-1;
+
+    for( uint32 y = 0; y<rows; y++ )
+    {
+        uint16* line = array+y*arrayWidth;
+        for( uint32 x=width; x<towidth; x++ )
+        {
+            line[x] = line[(x&maskval)<width?(x&maskval):towidth-(x&maskval)];
+        }
+    }
+}
+
+void CTextureManager::WrapT32(uint32 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
+{
+    uint32 maskval = (1<<mask)-1;
+    for( uint32 y = height; y<toheight; y++ )
+    {
+        uint32* linesrc = array+arrayWidth*(y>maskval?y&maskval:y-height);
+        uint32* linedst = array+arrayWidth*y;;
+        for( uint32 x=0; x<arrayWidth; x++ )
+        {
+            linedst[x] = linesrc[x];
+        }
+    }
+}
+
+void CTextureManager::WrapT16(uint16 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
+{
+    uint32 maskval = (1<<mask)-1;
+    for( uint32 y = height; y<toheight; y++ )
+    {
+        uint16* linesrc = array+arrayWidth*(y>maskval?y&maskval:y-height);
+        uint16* linedst = array+arrayWidth*y;;
+        for( uint32 x=0; x<arrayWidth; x++ )
+        {
+            linedst[x] = linesrc[x];
+        }
+    }
+}
+
+void CTextureManager::Clamp(void *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
+{
+    if( flag == S_FLAG )    // s
+    {
+        if( size == 4 ) // 32 bit
+        {
+            ClampS32((uint32*)array, width, towidth, arrayWidth, rows);
+        }
+        else    // 16 bits
+        {
+            ClampS16((uint16*)array, width, towidth, arrayWidth, rows);
+        }
+    }
+    else    // t
+    {
+        if( size == 4 ) // 32 bit
+        {
+            ClampT32((uint32*)array, width, towidth, arrayWidth, rows);
+        }
+        else    // 16 bits
+        {
+            ClampT16((uint16*)array, width, towidth, arrayWidth, rows);
+        }
+    }
+}
+void CTextureManager::Wrap(void *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
+{
+    if( flag == S_FLAG )    // s
+    {
+        if( size == 4 ) // 32 bit
+        {
+            WrapS32((uint32*)array, width, mask, towidth, arrayWidth, rows);
+        }
+        else    // 16 bits
+        {
+            WrapS16((uint16*)array, width, mask, towidth, arrayWidth, rows);
+        }
+    }
+    else    // t
+    {
+        if( size == 4 ) // 32 bit
+        {
+            WrapT32((uint32*)array, width, mask, towidth, arrayWidth, rows);
+        }
+        else    // 16 bits
+        {
+            WrapT16((uint16*)array, width, mask, towidth, arrayWidth, rows);
+        }
+    }
+}
+void CTextureManager::Mirror(void *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
+{
+    if( flag == S_FLAG )    // s
+    {
+        if( size == 4 ) // 32 bit
+        {
+            MirrorS32((uint32*)array, width, mask, towidth, arrayWidth, rows);
+        }
+        else    // 16 bits
+        {
+            MirrorS16((uint16*)array, width, mask, towidth, arrayWidth, rows);
+        }
+    }
+    else    // t
+    {
+        if( size == 4 ) // 32 bit
+        {
+            MirrorT32((uint32*)array, width, mask, towidth, arrayWidth, rows);
+        }
+        else    // 16 bits
+        {
+            MirrorT16((uint16*)array, width, mask, towidth, arrayWidth, rows);
+        }
+    }
+
+}
+
+
+#ifdef DEBUGGER
+TxtrCacheEntry * CTextureManager::GetCachedTexture(uint32 tex)
+{
+    uint32 size = 0;
+    for( uint32 i=0; i<m_numOfCachedTxtrList; i++ )
+    {
+        if( m_pCacheTxtrList[i] == NULL )
+            continue;
+        else
+        {
+            TxtrCacheEntry *pEntry;
+
+            for (pEntry = m_pCacheTxtrList[i]; pEntry; pEntry = pEntry->pNext)
+            {
+                if( size == tex )
+                    return pEntry;
+                else
+                    size++;
+            }
+        }
+    }
+    return NULL;
+}
+uint32 CTextureManager::GetNumOfCachedTexture()
+{
+    uint32 size = 0;
+    for( uint32 i=0; i<m_numOfCachedTxtrList; i++ )
+    {
+        if( m_pCacheTxtrList[i] == NULL )
+            continue;
+        else
+        {
+            TxtrCacheEntry *pEntry;
+
+            for (pEntry = m_pCacheTxtrList[i]; pEntry; pEntry = pEntry->pNext)
+            {
+                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);
+    }
+}
+
diff --git a/source/gles2rice/src/TextureManager.h b/source/gles2rice/src/TextureManager.h
new file mode 100644 (file)
index 0000000..78efe8e
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+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 <string.h>
+
+#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
+
diff --git a/source/gles2rice/src/Timing.h b/source/gles2rice/src/Timing.h
new file mode 100644 (file)
index 0000000..8c0b275
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+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
+
diff --git a/source/gles2rice/src/UcodeDefs.h b/source/gles2rice/src/UcodeDefs.h
new file mode 100644 (file)
index 0000000..4ed9c73
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+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
+
diff --git a/source/gles2rice/src/VectorMath.cpp b/source/gles2rice/src/VectorMath.cpp
new file mode 100644 (file)
index 0000000..e729275
--- /dev/null
@@ -0,0 +1,316 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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 <string.h>
+
+#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;
+}
+
diff --git a/source/gles2rice/src/VectorMath.h b/source/gles2rice/src/VectorMath.h
new file mode 100644 (file)
index 0000000..790fdae
--- /dev/null
@@ -0,0 +1,176 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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
+
diff --git a/source/gles2rice/src/VertexShaderConstantDef.h b/source/gles2rice/src/VertexShaderConstantDef.h
new file mode 100644 (file)
index 0000000..788ca22
--- /dev/null
@@ -0,0 +1,91 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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
+
diff --git a/source/gles2rice/src/Video.cpp b/source/gles2rice/src/Video.cpp
new file mode 100644 (file)
index 0000000..d49d829
--- /dev/null
@@ -0,0 +1,998 @@
+/*
+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 <vector>
+
+#include <stdarg.h>
+
+#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<RECT> frameWriteByCPURects;
+RECT frameWriteByCPURectArray[20][20];
+bool frameWriteByCPURectFlag[20][20];
+std::vector<uint32> 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
+
diff --git a/source/gles2rice/src/Video.h b/source/gles2rice/src/Video.h
new file mode 100644 (file)
index 0000000..30a23d7
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+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
+
diff --git a/source/gles2rice/src/liblinux/BMGDLL.h b/source/gles2rice/src/liblinux/BMGDLL.h
new file mode 100644 (file)
index 0000000..90cc2db
--- /dev/null
@@ -0,0 +1,155 @@
+#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
+
diff --git a/source/gles2rice/src/liblinux/BMGImage.c b/source/gles2rice/src/liblinux/BMGImage.c
new file mode 100644 (file)
index 0000000..1d4dd6e
--- /dev/null
@@ -0,0 +1,1053 @@
+/*
+// 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 <memory.h>
+#include <setjmp.h>
+#include <stdlib.h>
+
+#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
+// <http://rocq.home.att.net/pseudoGrey.html>. 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() );
+}
+
diff --git a/source/gles2rice/src/liblinux/BMGImage.h b/source/gles2rice/src/liblinux/BMGImage.h
new file mode 100644 (file)
index 0000000..0776a5d
--- /dev/null
@@ -0,0 +1,169 @@
+#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
+
diff --git a/source/gles2rice/src/liblinux/BMGLibPNG.h b/source/gles2rice/src/liblinux/BMGLibPNG.h
new file mode 100644 (file)
index 0000000..b74382a
--- /dev/null
@@ -0,0 +1,61 @@
+#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
+
diff --git a/source/gles2rice/src/liblinux/BMGUtils.c b/source/gles2rice/src/liblinux/BMGUtils.c
new file mode 100644 (file)
index 0000000..f341b04
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+//  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 <stdlib.h>
+#include "BMGUtils.h"
+
+#ifndef _WIN32
+#include <string.h>
+#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);
+}
+
diff --git a/source/gles2rice/src/liblinux/BMGUtils.h b/source/gles2rice/src/liblinux/BMGUtils.h
new file mode 100644 (file)
index 0000000..7578508
--- /dev/null
@@ -0,0 +1,56 @@
+#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
+
diff --git a/source/gles2rice/src/liblinux/bmp.c b/source/gles2rice/src/liblinux/bmp.c
new file mode 100644 (file)
index 0000000..9055563
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+//  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 <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+#ifndef _WIN32
+#include <string.h>
+#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
+
diff --git a/source/gles2rice/src/liblinux/jpegrw.h b/source/gles2rice/src/liblinux/jpegrw.h
new file mode 100644 (file)
index 0000000..8745c0b
--- /dev/null
@@ -0,0 +1,36 @@
+#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
+
diff --git a/source/gles2rice/src/liblinux/pngrw.c b/source/gles2rice/src/liblinux/pngrw.c
new file mode 100644 (file)
index 0000000..f9a3b86
--- /dev/null
@@ -0,0 +1,698 @@
+/*
+//  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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _BMG_LIBPNG_STANDALONE
+#include "BMGLibPNG.h"
+#else
+#include "pngrw.h"
+#endif
+#include <png.h>
+
+#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
+
diff --git a/source/gles2rice/src/liblinux/pngrw.h b/source/gles2rice/src/liblinux/pngrw.h
new file mode 100644 (file)
index 0000000..077b134
--- /dev/null
@@ -0,0 +1,55 @@
+#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
+
diff --git a/source/gles2rice/src/liblinux/tiffrw.h b/source/gles2rice/src/liblinux/tiffrw.h
new file mode 100644 (file)
index 0000000..863d05d
--- /dev/null
@@ -0,0 +1,75 @@
+#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
+
diff --git a/source/gles2rice/src/osal_dynamiclib.h b/source/gles2rice/src/osal_dynamiclib.h
new file mode 100644 (file)
index 0000000..c24377b
--- /dev/null
@@ -0,0 +1,38 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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 */
+
diff --git a/source/gles2rice/src/osal_dynamiclib_unix.c b/source/gles2rice/src/osal_dynamiclib_unix.c
new file mode 100644 (file)
index 0000000..b3b7ba5
--- /dev/null
@@ -0,0 +1,37 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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 <stdlib.h>
+#include <stdio.h>
+#include <dlfcn.h>
+
+#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);
+}
+
+
diff --git a/source/gles2rice/src/osal_dynamiclib_win32.c b/source/gles2rice/src/osal_dynamiclib_win32.c
new file mode 100644 (file)
index 0000000..685d717
--- /dev/null
@@ -0,0 +1,74 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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 <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#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;
+}
diff --git a/source/gles2rice/src/osal_files.h b/source/gles2rice/src/osal_files.h
new file mode 100644 (file)
index 0000000..1890e94
--- /dev/null
@@ -0,0 +1,63 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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 <limits.h>  // 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 */
+
diff --git a/source/gles2rice/src/osal_files_unix.c b/source/gles2rice/src/osal_files_unix.c
new file mode 100644 (file)
index 0000000..c586f97
--- /dev/null
@@ -0,0 +1,116 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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 <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <dirent.h>
+
+#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);
+}
+
diff --git a/source/gles2rice/src/osal_files_win32.c b/source/gles2rice/src/osal_files_win32.c
new file mode 100644 (file)
index 0000000..dd06fbe
--- /dev/null
@@ -0,0 +1,145 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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 <windows.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <direct.h>
+
+#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);
+    }
+}
diff --git a/source/gles2rice/src/osal_opengl.h b/source/gles2rice/src/osal_opengl.h
new file mode 100755 (executable)
index 0000000..5fd341c
--- /dev/null
@@ -0,0 +1,90 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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 <SDL_config.h>
+
+#undef SDL_VIDEO_OPENGL
+#define SDL_VIDEO_OPENGL_ES2 1
+
+
+#if SDL_VIDEO_OPENGL
+#include <SDL_opengl.h>
+#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 <SDL_opengles2.h>
+#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
diff --git a/source/gles2rice/src/osal_preproc.h b/source/gles2rice/src/osal_preproc.h
new file mode 100644 (file)
index 0000000..50cefd7
--- /dev/null
@@ -0,0 +1,96 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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 <windows.h>
+  #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
diff --git a/source/gles2rice/src/typedefs.h b/source/gles2rice/src/typedefs.h
new file mode 100644 (file)
index 0000000..89164c2
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+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
+
diff --git a/source/gles2rice/src/ucode.h b/source/gles2rice/src/ucode.h
new file mode 100644 (file)
index 0000000..0cd7ff1
--- /dev/null
@@ -0,0 +1,784 @@
+/*
+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
+
diff --git a/source/gles2rice/src/version.h b/source/gles2rice/src/version.h
new file mode 100644 (file)
index 0000000..bdcc317
--- /dev/null
@@ -0,0 +1,38 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   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 */
+
diff --git a/source/gles2rice/src/video_api_export.ver b/source/gles2rice/src/video_api_export.ver
new file mode 100644 (file)
index 0000000..c4db656
--- /dev/null
@@ -0,0 +1,22 @@
+{ global:
+PluginStartup;
+PluginShutdown;
+PluginGetVersion;
+ChangeWindow;
+InitiateGFX;
+MoveScreen;
+ProcessDList;
+ProcessRDPList;
+RomClosed;
+RomOpen;
+ShowCFB;
+UpdateScreen;
+ViStatusChanged;
+ViWidthChanged;
+ReadScreen2;
+SetRenderingCallback;
+ResizeVideoOutput;
+FBRead;
+FBWrite;
+FBGetFrameBufferInfo;
+local: *; };