From b54fb9e6a6a2b4d4bf4656ed1450e190afdb3a26 Mon Sep 17 00:00:00 2001 From: null_ptr Date: Wed, 9 Jul 2014 23:40:12 +0000 Subject: [PATCH] Added mupen64plus-video-z64 --- .../projects/msvc11/mupen64plus.sln | 6 + libmupen64plus/mupen64plus-video-z64/COPYING | 339 ++++ .../msvc11/mupen64plus-video-z64.vcxproj | 114 ++ .../projects/unix/Makefile | 391 ++++ .../mupen64plus-video-z64/src/disasm.cpp | 422 +++++ .../mupen64plus-video-z64/src/glshader.cpp | 121 ++ .../mupen64plus-video-z64/src/glshader.h | 38 + .../mupen64plus-video-z64/src/maingl.cpp | 387 ++++ .../src/osal_dynamiclib.h | 38 + .../src/osal_dynamiclib_unix.c | 37 + .../src/osal_dynamiclib_win32.c | 74 + .../mupen64plus-video-z64/src/queue.h | 557 ++++++ .../mupen64plus-video-z64/src/rdp.cpp | 858 +++++++++ .../mupen64plus-video-z64/src/rdp.h | 279 +++ .../mupen64plus-video-z64/src/rgl.cpp | 1682 +++++++++++++++++ .../mupen64plus-video-z64/src/rgl.h | 279 +++ .../mupen64plus-video-z64/src/rgl_assert.h | 42 + .../src/rgl_debugger.cpp | 861 +++++++++ .../src/rgl_geometry.cpp | 576 ++++++ .../mupen64plus-video-z64/src/rgl_glut.cpp | 218 +++ .../mupen64plus-video-z64/src/rgl_glut.h | 30 + .../mupen64plus-video-z64/src/rgl_osdep.cpp | 102 + .../src/rgl_rendermode.cpp | 722 +++++++ .../src/rgl_settings.cpp | 71 + .../mupen64plus-video-z64/src/rgl_tiles.cpp | 676 +++++++ .../src/video_api_export.ver | 22 + .../mupen64plus-video-z64/src/z64.h | 90 + 27 files changed, 9032 insertions(+) create mode 100644 libmupen64plus/mupen64plus-video-z64/COPYING create mode 100644 libmupen64plus/mupen64plus-video-z64/projects/msvc11/mupen64plus-video-z64.vcxproj create mode 100644 libmupen64plus/mupen64plus-video-z64/projects/unix/Makefile create mode 100644 libmupen64plus/mupen64plus-video-z64/src/disasm.cpp create mode 100644 libmupen64plus/mupen64plus-video-z64/src/glshader.cpp create mode 100644 libmupen64plus/mupen64plus-video-z64/src/glshader.h create mode 100644 libmupen64plus/mupen64plus-video-z64/src/maingl.cpp create mode 100644 libmupen64plus/mupen64plus-video-z64/src/osal_dynamiclib.h create mode 100644 libmupen64plus/mupen64plus-video-z64/src/osal_dynamiclib_unix.c create mode 100644 libmupen64plus/mupen64plus-video-z64/src/osal_dynamiclib_win32.c create mode 100644 libmupen64plus/mupen64plus-video-z64/src/queue.h create mode 100644 libmupen64plus/mupen64plus-video-z64/src/rdp.cpp create mode 100644 libmupen64plus/mupen64plus-video-z64/src/rdp.h create mode 100644 libmupen64plus/mupen64plus-video-z64/src/rgl.cpp create mode 100644 libmupen64plus/mupen64plus-video-z64/src/rgl.h create mode 100644 libmupen64plus/mupen64plus-video-z64/src/rgl_assert.h create mode 100644 libmupen64plus/mupen64plus-video-z64/src/rgl_debugger.cpp create mode 100644 libmupen64plus/mupen64plus-video-z64/src/rgl_geometry.cpp create mode 100644 libmupen64plus/mupen64plus-video-z64/src/rgl_glut.cpp create mode 100644 libmupen64plus/mupen64plus-video-z64/src/rgl_glut.h create mode 100644 libmupen64plus/mupen64plus-video-z64/src/rgl_osdep.cpp create mode 100644 libmupen64plus/mupen64plus-video-z64/src/rgl_rendermode.cpp create mode 100644 libmupen64plus/mupen64plus-video-z64/src/rgl_settings.cpp create mode 100644 libmupen64plus/mupen64plus-video-z64/src/rgl_tiles.cpp create mode 100644 libmupen64plus/mupen64plus-video-z64/src/video_api_export.ver create mode 100644 libmupen64plus/mupen64plus-video-z64/src/z64.h diff --git a/libmupen64plus/mupen64plus-sln/projects/msvc11/mupen64plus.sln b/libmupen64plus/mupen64plus-sln/projects/msvc11/mupen64plus.sln index 63716e1ffd..a929a32707 100644 --- a/libmupen64plus/mupen64plus-sln/projects/msvc11/mupen64plus.sln +++ b/libmupen64plus/mupen64plus-sln/projects/msvc11/mupen64plus.sln @@ -12,6 +12,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupen64plus-audio-bkm", ".. EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupen64plus-input-bkm", "..\..\..\mupen64plus-input-bkm\mupen64plus-input-bkm\mupen64plus-input-bkm.vcxproj", "{3D8BD211-6002-4698-B5C1-A0F3146B6ACF}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupen64plus-video-z64", "..\..\..\mupen64plus-video-z64\projects\msvc11\mupen64plus-video-z64.vcxproj", "{7708C1D2-3303-4F90-BCE8-3BCE4046BFD7}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupen64plus-video-jabo", "..\..\..\mupen64plus-video-jabo\mupen64plus-video-jabo\mupen64plus-video-jabo.vcxproj", "{0C220B26-3D4D-431D-B829-CADE6508A771}" EndProject Global @@ -44,6 +46,10 @@ Global {3D8BD211-6002-4698-B5C1-A0F3146B6ACF}.Debug|Win32.Build.0 = Debug|Win32 {3D8BD211-6002-4698-B5C1-A0F3146B6ACF}.Release|Win32.ActiveCfg = Release|Win32 {3D8BD211-6002-4698-B5C1-A0F3146B6ACF}.Release|Win32.Build.0 = Release|Win32 + {7708C1D2-3303-4F90-BCE8-3BCE4046BFD7}.Debug|Win32.ActiveCfg = Debug|Win32 + {7708C1D2-3303-4F90-BCE8-3BCE4046BFD7}.Debug|Win32.Build.0 = Debug|Win32 + {7708C1D2-3303-4F90-BCE8-3BCE4046BFD7}.Release|Win32.ActiveCfg = Release|Win32 + {7708C1D2-3303-4F90-BCE8-3BCE4046BFD7}.Release|Win32.Build.0 = Release|Win32 {0C220B26-3D4D-431D-B829-CADE6508A771}.Debug|Win32.ActiveCfg = Debug|Win32 {0C220B26-3D4D-431D-B829-CADE6508A771}.Debug|Win32.Build.0 = Debug|Win32 {0C220B26-3D4D-431D-B829-CADE6508A771}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/libmupen64plus/mupen64plus-video-z64/COPYING b/libmupen64plus/mupen64plus-video-z64/COPYING new file mode 100644 index 0000000000..d511905c16 --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/libmupen64plus/mupen64plus-video-z64/projects/msvc11/mupen64plus-video-z64.vcxproj b/libmupen64plus/mupen64plus-video-z64/projects/msvc11/mupen64plus-video-z64.vcxproj new file mode 100644 index 0000000000..ac5ed36161 --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/projects/msvc11/mupen64plus-video-z64.vcxproj @@ -0,0 +1,114 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {7708C1D2-3303-4F90-BCE8-3BCE4046BFD7} + Win32Proj + mupen64plusvideoz64 + + + + DynamicLibrary + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + + + + + + + + + + + true + $(SolutionDir)..\..\..\..\output\dll\ + + + false + $(SolutionDir)..\..\..\..\output\dll\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MUPEN64PLUSVIDEOZ64_EXPORTS;%(PreprocessorDefinitions) + ..\..\..\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;..\..\..\mupen64plus-win32-deps\glew-1.10.0\include\GL + 4996;4005;4244 + + + Windows + true + + + opengl32.lib;..\..\..\mupen64plus-win32-deps\glew-1.10.0\lib\Release\Win32\glew32.lib;..\..\..\mupen64plus-win32-deps\SDL-1.2.14\lib\SDL.lib + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MUPEN64PLUSVIDEOZ64_EXPORTS;%(PreprocessorDefinitions) + ..\..\..\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;..\..\..\mupen64plus-win32-deps\glew-1.10.0\include\GL + 4996;4005;4244 + + + Windows + true + true + true + opengl32.lib;..\..\..\mupen64plus-win32-deps\glew-1.10.0\lib\Release\Win32\glew32.lib;..\..\..\mupen64plus-win32-deps\SDL-1.2.14\lib\SDL.lib + + + + + + + + \ No newline at end of file diff --git a/libmupen64plus/mupen64plus-video-z64/projects/unix/Makefile b/libmupen64plus/mupen64plus-video-z64/projects/unix/Makefile new file mode 100644 index 0000000000..1f622274fa --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/projects/unix/Makefile @@ -0,0 +1,391 @@ +#/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +# * Mupen64plus-video-z64 - Makefile * +# * https://github.com/mupen64plus/mupen64plus-video-z64/ * +# * Copyright (C) 2010 Jon Ring * +# * 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 Z64 Video 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 +endif +ifeq ("$(UNAME)","FreeBSD") + OS = FREEBSD + SO_EXTENSION = so + SHARED = -shared +endif +ifeq ("$(UNAME)","OpenBSD") + OS = FREEBSD + SO_EXTENSION = so + SHARED = -shared + $(warning OS type "$(UNAME)" not officially supported.') +endif +ifneq ("$(filter GNU/kFreeBSD kfreebsd,$(UNAME))","") + OS = LINUX + SO_EXTENSION = so + SHARED = -shared +endif +ifeq ("$(patsubst MINGW%,MINGW,$(UNAME))","MINGW") + OS = MINGW + SO_EXTENSION = dll + SHARED = -shared + PIC = 0 +endif +ifeq ("$(OS)","NONE") + $(error OS type "$(UNAME)" not supported. Please file bug report at 'http://code.google.com/p/mupen64plus/issues') +endif + +# detect system architecture +HOST_CPU ?= $(shell uname -m) +CPU := NONE +ifneq ("$(filter x86_64 amd64,$(HOST_CPU))","") + CPU := X86 + ifeq ("$(BITS)", "32") + ARCH_DETECTED := 64BITS_32 + PIC ?= 0 + else + ARCH_DETECTED := 64BITS + PIC ?= 1 + endif +endif +ifneq ("$(filter pentium i%86,$(HOST_CPU))","") + CPU := X86 + ARCH_DETECTED := 32BITS + PIC ?= 0 +endif +ifneq ("$(filter ppc macppc socppc powerpc,$(HOST_CPU))","") + CPU := PPC + ARCH_DETECTED := 32BITS + BIG_ENDIAN := 1 + PIC ?= 1 + NO_ASM := 1 + $(warning Architecture "$(HOST_CPU)" not officially supported.') +endif +ifneq ("$(filter ppc64 powerpc64,$(HOST_CPU))","") + CPU := PPC + ARCH_DETECTED := 64BITS + BIG_ENDIAN := 1 + PIC ?= 1 + NO_ASM := 1 + $(warning Architecture "$(HOST_CPU)" not officially supported.') +endif +ifneq ("$(filter arm%,$(HOST_CPU))","") + ifeq ("$(filter arm%b,$(HOST_CPU))","") + CPU := ARM + ARCH_DETECTED := 32BITS + PIC ?= 1 + NO_ASM := 1 + $(warning Architecture "$(HOST_CPU)" not officially supported.') + endif +endif +ifeq ("$(CPU)","NONE") + $(error CPU type "$(HOST_CPU)" not supported. Please file bug report at 'http://code.google.com/p/mupen64plus/issues') +endif + +# base CFLAGS, LDLIBS, and LDFLAGS +OPTFLAGS ?= -O3 -flto +WARNFLAGS ?= -Wall +CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -ffast-math -fno-strict-aliasing -fvisibility=hidden -I../../src +CXXFLAGS += -fvisibility-inlines-hidden +LDFLAGS += $(SHARED) + +# 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) + # 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 +ifeq ($(OS), LINUX) + LDLIBS += -ldl +endif +ifeq ($(OS), FREEBSD) + LDLIBS += -lc +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 GLEW_CFLAGS) $(origin GLEW_LDLIBS), undefined undefined) + ifeq ($(shell $(PKG_CONFIG) --modversion glew 2>/dev/null),) + $(error No GLEW development libraries found!) + endif + GLEW_CFLAGS += $(shell $(PKG_CONFIG) --cflags glew) + GLEW_LDLIBS += $(shell $(PKG_CONFIG) --libs glew) +endif +CFLAGS += $(GLEW_CFLAGS) +LDLIBS += $(GLEW_LDLIBS) + +# search for OpenGL libraries +ifeq ($(OS), OSX) + GL_LDLIBS = -framework OpenGL +endif +ifeq ($(OS), MINGW) + GL_LDLIBS = -lopengl32 +endif +ifeq ($(origin GL_CFLAGS) $(origin GL_LDLIBS), undefined undefined) + ifeq ($(shell $(PKG_CONFIG) --modversion gl 2>/dev/null),) + $(error No OpenGL development libraries found!) + endif + GL_CFLAGS += $(shell $(PKG_CONFIG) --cflags gl) + GL_LDLIBS += $(shell $(PKG_CONFIG) --libs gl) +endif +CFLAGS += $(GL_CFLAGS) +LDLIBS += $(GL_LDLIBS) + +# test for presence of SDL +ifeq ($(origin SDL_CFLAGS) $(origin SDL_LDLIBS), undefined undefined) + SDL_CONFIG = $(CROSS_COMPILE)sdl-config + ifeq ($(shell which $(SDL_CONFIG) 2>/dev/null),) + $(error No SDL development libraries found!) + endif + ifeq ($(OS),OSX) + SDL_CFLAGS += $(shell $(SDL_CONFIG) --cflags) + # sdl-config on mac screws up when we're trying to build a library and not an executable + # SDL 1.3 is supposed to fix that, if it's ever released + SDL_LDLIBS += -L/usr/local/lib -lSDL -Wl,-framework,Cocoa + else + SDL_CFLAGS += $(shell $(SDL_CONFIG) --cflags) + SDL_LDLIBS += $(shell $(SDL_CONFIG) --libs) + endif +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 + INSTALL_STRIP_FLAG ?= -s +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)/rgl.cpp \ + $(SRCDIR)/rgl_settings.cpp \ + $(SRCDIR)/rgl_tiles.cpp \ + $(SRCDIR)/rgl_rendermode.cpp \ + $(SRCDIR)/rgl_geometry.cpp \ + $(SRCDIR)/rgl_debugger.cpp \ + $(SRCDIR)/rgl_osdep.cpp \ + $(SRCDIR)/rdp.cpp \ + $(SRCDIR)/glshader.cpp \ + $(SRCDIR)/disasm.cpp \ + $(SRCDIR)/maingl.cpp + +ifeq ($(OS),MINGW) +SOURCE += $(SRCDIR)/osal_dynamiclib_win32.c +else +SOURCE += $(SRCDIR)/osal_dynamiclib_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-z64$(POSTFIX).$(SO_EXTENSION) + +targets: + @echo "Mupen64plus-video-z64 N64 Graphics plugin makefile. " + @echo " Targets:" + @echo " all == Build Mupen64plus-video-z64 plugin" + @echo " clean == remove object files" + @echo " rebuild == clean and re-build all" + @echo " install == Install Mupen64Plus-video-z64 plugin" + @echo " uninstall == Uninstall Mupen64Plus-video-z64 plugin" + @echo " Options:" + @echo " BITS=32 == build 32-bit binaries on 64-bit machine" + @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)" + +uninstall: + $(RM) "$(DESTDIR)$(PLUGINDIR)/$(TARGET)" + +clean: + $(RM) -r $(OBJDIR) $(TARGET) + +rebuild: clean all + +# build dependency files +CFLAGS += -MD -MP +-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/libmupen64plus/mupen64plus-video-z64/src/disasm.cpp b/libmupen64plus/mupen64plus-video-z64/src/disasm.cpp new file mode 100644 index 0000000000..98515c5dc0 --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/disasm.cpp @@ -0,0 +1,422 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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 "z64.h" +#include + +static const char *image_format[] = { "RGBA", "YUV", "CI", "IA", "I", "???", "???", "???" }; +static const char *image_size[] = { "4-bit", "8-bit", "16-bit", "32-bit" }; + +static const int rdp_command_length[64] = +{ + 8, // 0x00, No Op + 8, // 0x01, ??? + 8, // 0x02, ??? + 8, // 0x03, ??? + 8, // 0x04, ??? + 8, // 0x05, ??? + 8, // 0x06, ??? + 8, // 0x07, ??? + 32, // 0x08, Non-Shaded Triangle + 32+16, // 0x09, Non-Shaded, Z-Buffered Triangle + 32+64, // 0x0a, Textured Triangle + 32+64+16, // 0x0b, Textured, Z-Buffered Triangle + 32+64, // 0x0c, Shaded Triangle + 32+64+16, // 0x0d, Shaded, Z-Buffered Triangle + 32+64+64, // 0x0e, Shaded+Textured Triangle + 32+64+64+16,// 0x0f, Shaded+Textured, Z-Buffered Triangle + 8, // 0x10, ??? + 8, // 0x11, ??? + 8, // 0x12, ??? + 8, // 0x13, ??? + 8, // 0x14, ??? + 8, // 0x15, ??? + 8, // 0x16, ??? + 8, // 0x17, ??? + 8, // 0x18, ??? + 8, // 0x19, ??? + 8, // 0x1a, ??? + 8, // 0x1b, ??? + 8, // 0x1c, ??? + 8, // 0x1d, ??? + 8, // 0x1e, ??? + 8, // 0x1f, ??? + 8, // 0x20, ??? + 8, // 0x21, ??? + 8, // 0x22, ??? + 8, // 0x23, ??? + 16, // 0x24, Texture_Rectangle + 16, // 0x25, Texture_Rectangle_Flip + 8, // 0x26, Sync_Load + 8, // 0x27, Sync_Pipe + 8, // 0x28, Sync_Tile + 8, // 0x29, Sync_Full + 8, // 0x2a, Set_Key_GB + 8, // 0x2b, Set_Key_R + 8, // 0x2c, Set_Convert + 8, // 0x2d, Set_Scissor + 8, // 0x2e, Set_Prim_Depth + 8, // 0x2f, Set_Other_Modes + 8, // 0x30, Load_TLUT + 8, // 0x31, ??? + 8, // 0x32, Set_Tile_Size + 8, // 0x33, Load_Block + 8, // 0x34, Load_Tile + 8, // 0x35, Set_Tile + 8, // 0x36, Fill_Rectangle + 8, // 0x37, Set_Fill_Color + 8, // 0x38, Set_Fog_Color + 8, // 0x39, Set_Blend_Color + 8, // 0x3a, Set_Prim_Color + 8, // 0x3b, Set_Env_Color + 8, // 0x3c, Set_Combine + 8, // 0x3d, Set_Texture_Image + 8, // 0x3e, Set_Mask_Image + 8 // 0x3f, Set_Color_Image +}; + +int rdp_dasm(UINT32 * rdp_cmd_data, int rdp_cmd_cur, int length, char *buffer) +{ + //int i; + int tile; + const char *format, *size; + char sl[32], tl[32], sh[32], th[32]; + char s[32], t[32];//, w[32]; + char dsdx[32], dtdy[32]; +#if 0 + char dsdx[32], dtdx[32], dwdx[32]; + char dsdy[32], dtdy[32], dwdy[32]; + char dsde[32], dtde[32], dwde[32]; + char yl[32], yh[32], ym[32], xl[32], xh[32], xm[32]; + char dxldy[32], dxhdy[32], dxmdy[32]; + char rt[32], gt[32], bt[32], at[32]; + char drdx[32], dgdx[32], dbdx[32], dadx[32]; + char drdy[32], dgdy[32], dbdy[32], dady[32]; + char drde[32], dgde[32], dbde[32], dade[32]; +#endif + UINT32 r,g,b,a; + + UINT32 cmd[64]; + UINT32 command; + + if (length < 8) + { + sprintf(buffer, "ERROR: length = %d\n", length); + return 0; + } + + cmd[0] = rdp_cmd_data[rdp_cmd_cur+0]; + cmd[1] = rdp_cmd_data[rdp_cmd_cur+1]; + + tile = (cmd[1] >> 24) & 0x7; + sprintf(sl, "%4.2f", (float)((cmd[0] >> 12) & 0xfff) / 4.0f); + sprintf(tl, "%4.2f", (float)((cmd[0] >> 0) & 0xfff) / 4.0f); + sprintf(sh, "%4.2f", (float)((cmd[1] >> 12) & 0xfff) / 4.0f); + sprintf(th, "%4.2f", (float)((cmd[1] >> 0) & 0xfff) / 4.0f); + + format = image_format[(cmd[0] >> 21) & 0x7]; + size = image_size[(cmd[0] >> 19) & 0x3]; + + r = (cmd[1] >> 24) & 0xff; + g = (cmd[1] >> 16) & 0xff; + b = (cmd[1] >> 8) & 0xff; + a = (cmd[1] >> 0) & 0xff; + + command = (cmd[0] >> 24) & 0x3f; + //printf("command %x\n", command); + switch (command) + { + case 0x00: sprintf(buffer, "No Op"); break; + case 0x08: + sprintf(buffer, "Tri_NoShade (%08X %08X)", cmd[0], cmd[1]); break; + case 0x0a: + sprintf(buffer, "Tri_Tex (%08X %08X)", cmd[0], cmd[1]); break; + case 0x0c: + sprintf(buffer, "Tri_Shade (%08X %08X)", cmd[0], cmd[1]); break; + case 0x0e: + sprintf(buffer, "Tri_TexShade (%08X %08X)", cmd[0], cmd[1]); break; + case 0x09: + sprintf(buffer, "TriZ_NoShade (%08X %08X)", cmd[0], cmd[1]); break; + case 0x0b: + sprintf(buffer, "TriZ_Tex (%08X %08X)", cmd[0], cmd[1]); break; + case 0x0d: + sprintf(buffer, "TriZ_Shade (%08X %08X)", cmd[0], cmd[1]); break; + case 0x0f: + sprintf(buffer, "TriZ_TexShade (%08X %08X)", cmd[0], cmd[1]); break; + +#if 0 + case 0x08: // Tri_NoShade + { + int lft = (command >> 23) & 0x1; + + if (length < rdp_command_length[command]) + { + sprintf(buffer, "ERROR: Tri_NoShade length = %d\n", length); + return 0; + } + + cmd[2] = rdp_cmd_data[rdp_cmd_cur+2]; + cmd[3] = rdp_cmd_data[rdp_cmd_cur+3]; + cmd[4] = rdp_cmd_data[rdp_cmd_cur+4]; + cmd[5] = rdp_cmd_data[rdp_cmd_cur+5]; + cmd[6] = rdp_cmd_data[rdp_cmd_cur+6]; + cmd[7] = rdp_cmd_data[rdp_cmd_cur+7]; + + sprintf(yl, "%4.4f", (float)((cmd[0] >> 0) & 0x1fff) / 4.0f); + sprintf(ym, "%4.4f", (float)((cmd[1] >> 16) & 0x1fff) / 4.0f); + sprintf(yh, "%4.4f", (float)((cmd[1] >> 0) & 0x1fff) / 4.0f); + sprintf(xl, "%4.4f", (float)(cmd[2] / 65536.0f)); + sprintf(dxldy, "%4.4f", (float)(cmd[3] / 65536.0f)); + sprintf(xh, "%4.4f", (float)(cmd[4] / 65536.0f)); + sprintf(dxhdy, "%4.4f", (float)(cmd[5] / 65536.0f)); + sprintf(xm, "%4.4f", (float)(cmd[6] / 65536.0f)); + sprintf(dxmdy, "%4.4f", (float)(cmd[7] / 65536.0f)); + + sprintf(buffer, "Tri_NoShade %d, XL: %s, XM: %s, XH: %s, YL: %s, YM: %s, YH: %s\n", lft, xl,xm,xh,yl,ym,yh); + break; + } + case 0x0a: // Tri_Tex + { + int lft = (command >> 23) & 0x1; + + if (length < rdp_command_length[command]) + { + sprintf(buffer, "ERROR: Tri_Tex length = %d\n", length); + return 0; + } + + for (i=2; i < 24; i++) + { + cmd[i] = rdp_cmd_data[rdp_cmd_cur+i]; + } + + sprintf(yl, "%4.4f", (float)((cmd[0] >> 0) & 0x1fff) / 4.0f); + sprintf(ym, "%4.4f", (float)((cmd[1] >> 16) & 0x1fff) / 4.0f); + sprintf(yh, "%4.4f", (float)((cmd[1] >> 0) & 0x1fff) / 4.0f); + sprintf(xl, "%4.4f", (float)((INT32)cmd[2] / 65536.0f)); + sprintf(dxldy, "%4.4f", (float)((INT32)cmd[3] / 65536.0f)); + sprintf(xh, "%4.4f", (float)((INT32)cmd[4] / 65536.0f)); + sprintf(dxhdy, "%4.4f", (float)((INT32)cmd[5] / 65536.0f)); + sprintf(xm, "%4.4f", (float)((INT32)cmd[6] / 65536.0f)); + sprintf(dxmdy, "%4.4f", (float)((INT32)cmd[7] / 65536.0f)); + + sprintf(s, "%4.4f", (float)(INT32)((cmd[ 8] & 0xffff0000) | ((cmd[12] >> 16) & 0xffff)) / 65536.0f); + sprintf(t, "%4.4f", (float)(INT32)(((cmd[ 8] & 0xffff) << 16) | (cmd[12] & 0xffff)) / 65536.0f); + sprintf(w, "%4.4f", (float)(INT32)((cmd[ 9] & 0xffff0000) | ((cmd[13] >> 16) & 0xffff)) / 65536.0f); + sprintf(dsdx, "%4.4f", (float)(INT32)((cmd[10] & 0xffff0000) | ((cmd[14] >> 16) & 0xffff)) / 65536.0f); + sprintf(dtdx, "%4.4f", (float)(INT32)(((cmd[10] & 0xffff) << 16) | (cmd[14] & 0xffff)) / 65536.0f); + sprintf(dwdx, "%4.4f", (float)(INT32)((cmd[11] & 0xffff0000) | ((cmd[15] >> 16) & 0xffff)) / 65536.0f); + sprintf(dsde, "%4.4f", (float)(INT32)((cmd[16] & 0xffff0000) | ((cmd[20] >> 16) & 0xffff)) / 65536.0f); + sprintf(dtde, "%4.4f", (float)(INT32)(((cmd[16] & 0xffff) << 16) | (cmd[20] & 0xffff)) / 65536.0f); + sprintf(dwde, "%4.4f", (float)(INT32)((cmd[17] & 0xffff0000) | ((cmd[21] >> 16) & 0xffff)) / 65536.0f); + sprintf(dsdy, "%4.4f", (float)(INT32)((cmd[18] & 0xffff0000) | ((cmd[22] >> 16) & 0xffff)) / 65536.0f); + sprintf(dtdy, "%4.4f", (float)(INT32)(((cmd[18] & 0xffff) << 16) | (cmd[22] & 0xffff)) / 65536.0f); + sprintf(dwdy, "%4.4f", (float)(INT32)((cmd[19] & 0xffff0000) | ((cmd[23] >> 16) & 0xffff)) / 65536.0f); + + + buffer+=sprintf(buffer, "Tri_Tex %d, XL: %s, XM: %s, XH: %s, YL: %s, YM: %s, YH: %s\n", lft, xl,xm,xh,yl,ym,yh); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " S: %s, T: %s, W: %s\n", s, t, w); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " DSDX: %s, DTDX: %s, DWDX: %s\n", dsdx, dtdx, dwdx); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " DSDE: %s, DTDE: %s, DWDE: %s\n", dsde, dtde, dwde); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " DSDY: %s, DTDY: %s, DWDY: %s\n", dsdy, dtdy, dwdy); + break; + } + case 0x0c: // Tri_Shade + { + int lft = (command >> 23) & 0x1; + + if (length < rdp_command_length[command]) + { + sprintf(buffer, "ERROR: Tri_Shade length = %d\n", length); + return 0; + } + + for (i=2; i < 24; i++) + { + cmd[i] = rdp_cmd_data[i]; + } + + sprintf(yl, "%4.4f", (float)((cmd[0] >> 0) & 0x1fff) / 4.0f); + sprintf(ym, "%4.4f", (float)((cmd[1] >> 16) & 0x1fff) / 4.0f); + sprintf(yh, "%4.4f", (float)((cmd[1] >> 0) & 0x1fff) / 4.0f); + sprintf(xl, "%4.4f", (float)((INT32)cmd[2] / 65536.0f)); + sprintf(dxldy, "%4.4f", (float)((INT32)cmd[3] / 65536.0f)); + sprintf(xh, "%4.4f", (float)((INT32)cmd[4] / 65536.0f)); + sprintf(dxhdy, "%4.4f", (float)((INT32)cmd[5] / 65536.0f)); + sprintf(xm, "%4.4f", (float)((INT32)cmd[6] / 65536.0f)); + sprintf(dxmdy, "%4.4f", (float)((INT32)cmd[7] / 65536.0f)); + sprintf(rt, "%4.4f", (float)(INT32)((cmd[8] & 0xffff0000) | ((cmd[12] >> 16) & 0xffff)) / 65536.0f); + sprintf(gt, "%4.4f", (float)(INT32)(((cmd[8] & 0xffff) << 16) | (cmd[12] & 0xffff)) / 65536.0f); + sprintf(bt, "%4.4f", (float)(INT32)((cmd[9] & 0xffff0000) | ((cmd[13] >> 16) & 0xffff)) / 65536.0f); + sprintf(at, "%4.4f", (float)(INT32)(((cmd[9] & 0xffff) << 16) | (cmd[13] & 0xffff)) / 65536.0f); + sprintf(drdx, "%4.4f", (float)(INT32)((cmd[10] & 0xffff0000) | ((cmd[14] >> 16) & 0xffff)) / 65536.0f); + sprintf(dgdx, "%4.4f", (float)(INT32)(((cmd[10] & 0xffff) << 16) | (cmd[14] & 0xffff)) / 65536.0f); + sprintf(dbdx, "%4.4f", (float)(INT32)((cmd[11] & 0xffff0000) | ((cmd[15] >> 16) & 0xffff)) / 65536.0f); + sprintf(dadx, "%4.4f", (float)(INT32)(((cmd[11] & 0xffff) << 16) | (cmd[15] & 0xffff)) / 65536.0f); + sprintf(drde, "%4.4f", (float)(INT32)((cmd[16] & 0xffff0000) | ((cmd[20] >> 16) & 0xffff)) / 65536.0f); + sprintf(dgde, "%4.4f", (float)(INT32)(((cmd[16] & 0xffff) << 16) | (cmd[20] & 0xffff)) / 65536.0f); + sprintf(dbde, "%4.4f", (float)(INT32)((cmd[17] & 0xffff0000) | ((cmd[21] >> 16) & 0xffff)) / 65536.0f); + sprintf(dade, "%4.4f", (float)(INT32)(((cmd[17] & 0xffff) << 16) | (cmd[21] & 0xffff)) / 65536.0f); + sprintf(drdy, "%4.4f", (float)(INT32)((cmd[18] & 0xffff0000) | ((cmd[22] >> 16) & 0xffff)) / 65536.0f); + sprintf(dgdy, "%4.4f", (float)(INT32)(((cmd[18] & 0xffff) << 16) | (cmd[22] & 0xffff)) / 65536.0f); + sprintf(dbdy, "%4.4f", (float)(INT32)((cmd[19] & 0xffff0000) | ((cmd[23] >> 16) & 0xffff)) / 65536.0f); + sprintf(dady, "%4.4f", (float)(INT32)(((cmd[19] & 0xffff) << 16) | (cmd[23] & 0xffff)) / 65536.0f); + + buffer+=sprintf(buffer, "Tri_Shade %d, XL: %s, XM: %s, XH: %s, YL: %s, YM: %s, YH: %s\n", lft, xl,xm,xh,yl,ym,yh); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " R: %s, G: %s, B: %s, A: %s\n", rt, gt, bt, at); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " DRDX: %s, DGDX: %s, DBDX: %s, DADX: %s\n", drdx, dgdx, dbdx, dadx); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " DRDE: %s, DGDE: %s, DBDE: %s, DADE: %s\n", drde, dgde, dbde, dade); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " DRDY: %s, DGDY: %s, DBDY: %s, DADY: %s\n", drdy, dgdy, dbdy, dady); + break; + } + case 0x0e: // Tri_TexShade + { + int lft = (command >> 23) & 0x1; + + if (length < rdp_command_length[command]) + { + sprintf(buffer, "ERROR: Tri_TexShade length = %d\n", length); + return 0; + } + + for (i=2; i < 40; i++) + { + cmd[i] = rdp_cmd_data[rdp_cmd_cur+i]; + } + + sprintf(yl, "%4.4f", (float)((cmd[0] >> 0) & 0x1fff) / 4.0f); + sprintf(ym, "%4.4f", (float)((cmd[1] >> 16) & 0x1fff) / 4.0f); + sprintf(yh, "%4.4f", (float)((cmd[1] >> 0) & 0x1fff) / 4.0f); + sprintf(xl, "%4.4f", (float)((INT32)cmd[2] / 65536.0f)); + sprintf(dxldy, "%4.4f", (float)((INT32)cmd[3] / 65536.0f)); + sprintf(xh, "%4.4f", (float)((INT32)cmd[4] / 65536.0f)); + sprintf(dxhdy, "%4.4f", (float)((INT32)cmd[5] / 65536.0f)); + sprintf(xm, "%4.4f", (float)((INT32)cmd[6] / 65536.0f)); + sprintf(dxmdy, "%4.4f", (float)((INT32)cmd[7] / 65536.0f)); + sprintf(rt, "%4.4f", (float)(INT32)((cmd[8] & 0xffff0000) | ((cmd[12] >> 16) & 0xffff)) / 65536.0f); + sprintf(gt, "%4.4f", (float)(INT32)(((cmd[8] & 0xffff) << 16) | (cmd[12] & 0xffff)) / 65536.0f); + sprintf(bt, "%4.4f", (float)(INT32)((cmd[9] & 0xffff0000) | ((cmd[13] >> 16) & 0xffff)) / 65536.0f); + sprintf(at, "%4.4f", (float)(INT32)(((cmd[9] & 0xffff) << 16) | (cmd[13] & 0xffff)) / 65536.0f); + sprintf(drdx, "%4.4f", (float)(INT32)((cmd[10] & 0xffff0000) | ((cmd[14] >> 16) & 0xffff)) / 65536.0f); + sprintf(dgdx, "%4.4f", (float)(INT32)(((cmd[10] & 0xffff) << 16) | (cmd[14] & 0xffff)) / 65536.0f); + sprintf(dbdx, "%4.4f", (float)(INT32)((cmd[11] & 0xffff0000) | ((cmd[15] >> 16) & 0xffff)) / 65536.0f); + sprintf(dadx, "%4.4f", (float)(INT32)(((cmd[11] & 0xffff) << 16) | (cmd[15] & 0xffff)) / 65536.0f); + sprintf(drde, "%4.4f", (float)(INT32)((cmd[16] & 0xffff0000) | ((cmd[20] >> 16) & 0xffff)) / 65536.0f); + sprintf(dgde, "%4.4f", (float)(INT32)(((cmd[16] & 0xffff) << 16) | (cmd[20] & 0xffff)) / 65536.0f); + sprintf(dbde, "%4.4f", (float)(INT32)((cmd[17] & 0xffff0000) | ((cmd[21] >> 16) & 0xffff)) / 65536.0f); + sprintf(dade, "%4.4f", (float)(INT32)(((cmd[17] & 0xffff) << 16) | (cmd[21] & 0xffff)) / 65536.0f); + sprintf(drdy, "%4.4f", (float)(INT32)((cmd[18] & 0xffff0000) | ((cmd[22] >> 16) & 0xffff)) / 65536.0f); + sprintf(dgdy, "%4.4f", (float)(INT32)(((cmd[18] & 0xffff) << 16) | (cmd[22] & 0xffff)) / 65536.0f); + sprintf(dbdy, "%4.4f", (float)(INT32)((cmd[19] & 0xffff0000) | ((cmd[23] >> 16) & 0xffff)) / 65536.0f); + sprintf(dady, "%4.4f", (float)(INT32)(((cmd[19] & 0xffff) << 16) | (cmd[23] & 0xffff)) / 65536.0f); + + sprintf(s, "%4.4f", (float)(INT32)((cmd[24] & 0xffff0000) | ((cmd[28] >> 16) & 0xffff)) / 65536.0f); + sprintf(t, "%4.4f", (float)(INT32)(((cmd[24] & 0xffff) << 16) | (cmd[28] & 0xffff)) / 65536.0f); + sprintf(w, "%4.4f", (float)(INT32)((cmd[25] & 0xffff0000) | ((cmd[29] >> 16) & 0xffff)) / 65536.0f); + sprintf(dsdx, "%4.4f", (float)(INT32)((cmd[26] & 0xffff0000) | ((cmd[30] >> 16) & 0xffff)) / 65536.0f); + sprintf(dtdx, "%4.4f", (float)(INT32)(((cmd[26] & 0xffff) << 16) | (cmd[30] & 0xffff)) / 65536.0f); + sprintf(dwdx, "%4.4f", (float)(INT32)((cmd[27] & 0xffff0000) | ((cmd[31] >> 16) & 0xffff)) / 65536.0f); + sprintf(dsde, "%4.4f", (float)(INT32)((cmd[32] & 0xffff0000) | ((cmd[36] >> 16) & 0xffff)) / 65536.0f); + sprintf(dtde, "%4.4f", (float)(INT32)(((cmd[32] & 0xffff) << 16) | (cmd[36] & 0xffff)) / 65536.0f); + sprintf(dwde, "%4.4f", (float)(INT32)((cmd[33] & 0xffff0000) | ((cmd[37] >> 16) & 0xffff)) / 65536.0f); + sprintf(dsdy, "%4.4f", (float)(INT32)((cmd[34] & 0xffff0000) | ((cmd[38] >> 16) & 0xffff)) / 65536.0f); + sprintf(dtdy, "%4.4f", (float)(INT32)(((cmd[34] & 0xffff) << 16) | (cmd[38] & 0xffff)) / 65536.0f); + sprintf(dwdy, "%4.4f", (float)(INT32)((cmd[35] & 0xffff0000) | ((cmd[39] >> 16) & 0xffff)) / 65536.0f); + + + buffer+=sprintf(buffer, "Tri_TexShade %d, XL: %s, XM: %s, XH: %s, YL: %s, YM: %s, YH: %s\n", lft, xl,xm,xh,yl,ym,yh); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " R: %s, G: %s, B: %s, A: %s\n", rt, gt, bt, at); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " DRDX: %s, DGDX: %s, DBDX: %s, DADX: %s\n", drdx, dgdx, dbdx, dadx); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " DRDE: %s, DGDE: %s, DBDE: %s, DADE: %s\n", drde, dgde, dbde, dade); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " DRDY: %s, DGDY: %s, DBDY: %s, DADY: %s\n", drdy, dgdy, dbdy, dady); + + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " S: %s, T: %s, W: %s\n", s, t, w); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " DSDX: %s, DTDX: %s, DWDX: %s\n", dsdx, dtdx, dwdx); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " DSDE: %s, DTDE: %s, DWDE: %s\n", dsde, dtde, dwde); + buffer+=sprintf(buffer, " "); + buffer+=sprintf(buffer, " DSDY: %s, DTDY: %s, DWDY: %s\n", dsdy, dtdy, dwdy); + break; + } +#endif + case 0x24: + case 0x25: + { + if (length < 16) + { + sprintf(buffer, "ERROR: Texture_Rectangle length = %d\n", length); + return 0; + } + cmd[2] = rdp_cmd_data[rdp_cmd_cur+2]; + cmd[3] = rdp_cmd_data[rdp_cmd_cur+3]; + sprintf(s, "%4.4f", (float)(INT16)((cmd[2] >> 16) & 0xffff) / 32.0f); + sprintf(t, "%4.4f", (float)(INT16)((cmd[2] >> 0) & 0xffff) / 32.0f); + sprintf(dsdx, "%4.4f", (float)(INT16)((cmd[3] >> 16) & 0xffff) / 1024.0f); + sprintf(dtdy, "%4.4f", (float)(INT16)((cmd[3] >> 16) & 0xffff) / 1024.0f); + + if (command == 0x24) + sprintf(buffer, "Texture_Rectangle %d, %s, %s, %s, %s, %s, %s, %s, %s", tile, sh, th, sl, tl, s, t, dsdx, dtdy); + else + sprintf(buffer, "Texture_Rectangle_Flip %d, %s, %s, %s, %s, %s, %s, %s, %s", tile, sh, th, sl, tl, s, t, dsdx, dtdy); + + break; + } + case 0x26: sprintf(buffer, "Sync_Load"); break; + case 0x27: sprintf(buffer, "Sync_Pipe"); break; + case 0x28: sprintf(buffer, "Sync_Tile"); break; + case 0x29: sprintf(buffer, "Sync_Full"); break; + case 0x2d: sprintf(buffer, "Set_Scissor %s, %s, %s, %s", sl, tl, sh, th); break; + case 0x2e: sprintf(buffer, "Set_Prim_Depth %04X, %04X", (cmd[1] >> 16) & 0xffff, cmd[1] & 0xffff); break; + case 0x2f: sprintf(buffer, "Set_Other_Modes %08X %08X", cmd[0], cmd[1]); break; + case 0x30: sprintf(buffer, "Load_TLUT %d, %s, %s, %s, %s", tile, sl, tl, sh, th); break; + case 0x32: sprintf(buffer, "Set_Tile_Size %d, %s, %s, %s, %s", tile, sl, tl, sh, th); break; + case 0x33: sprintf(buffer, "Load_Block %d, %03X, %03X, %03X, %03X", tile, (cmd[0] >> 12) & 0xfff, cmd[0] & 0xfff, (cmd[1] >> 12) & 0xfff, cmd[1] & 0xfff); break; + case 0x34: sprintf(buffer, "Load_Tile %d, %s, %s, %s, %s", tile, sl, tl, sh, th); break; + case 0x35: sprintf(buffer, "Set_Tile %d, %s, %s, %d, %04X", tile, format, size, ((cmd[0] >> 9) & 0x1ff) * 8, (cmd[0] & 0x1ff) * 8); break; + case 0x36: sprintf(buffer, "Fill_Rectangle %s, %s, %s, %s", sh, th, sl, tl); break; + case 0x37: sprintf(buffer, "Set_Fill_Color R: %d, G: %d, B: %d, A: %d", r, g, b, a); break; + case 0x38: sprintf(buffer, "Set_Fog_Color R: %d, G: %d, B: %d, A: %d", r, g, b, a); break; + case 0x39: sprintf(buffer, "Set_Blend_Color R: %d, G: %d, B: %d, A: %d", r, g, b, a); break; + case 0x3a: sprintf(buffer, "Set_Prim_Color %d, %d, R: %d, G: %d, B: %d, A: %d", (cmd[0] >> 8) & 0x1f, cmd[0] & 0xff, r, g, b, a); break; + case 0x3b: sprintf(buffer, "Set_Env_Color R: %d, G: %d, B: %d, A: %d", r, g, b, a); break; + case 0x3c: sprintf(buffer, "Set_Combine %08X %08X", cmd[0], cmd[1]); break; + case 0x3d: sprintf(buffer, "Set_Texture_Image %s, %s, %d, %08X", format, size, (cmd[0] & 0x1ff)+1, cmd[1]); break; + case 0x3e: sprintf(buffer, "Set_Mask_Image %08X", cmd[1]); break; + case 0x3f: sprintf(buffer, "Set_Color_Image %s, %s, %d, %08X", format, size, (cmd[0] & 0x1ff)+1, cmd[1]); break; + default: sprintf(buffer, "??? (%08X %08X)", cmd[0], cmd[1]); break; + } + + return rdp_command_length[command]; +} diff --git a/libmupen64plus/mupen64plus-video-z64/src/glshader.cpp b/libmupen64plus/mupen64plus-video-z64/src/glshader.cpp new file mode 100644 index 0000000000..47299451ed --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/glshader.cpp @@ -0,0 +1,121 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * +**/ + +#include +#include +#include +#include "rgl_assert.h" +#include +#if defined(__MACOSX__) +#include +#include +#elif defined(__MACOS__) +#include +#include +#else +#include +#ifndef WIN32 + #include +#endif +#endif +#include "glshader.h" + +static void printInfoLog(GLhandleARB obj, const char * src) +{ + int infologLength = 0; + int charsWritten = 0; + char *infoLog; + + glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, + &infologLength); + + if (infologLength > 0) + { + infoLog = (char *)malloc(infologLength); + glGetInfoLogARB(obj, infologLength, &charsWritten, infoLog); + if (*infoLog) + rdp_log(M64MSG_INFO, "%s\n%s", src, infoLog); + free(infoLog); + } +} + +//#define rglAssert(...) +rglShader_t * rglCreateShader(const char * vsrc, const char * fsrc) +{ + GLhandleARB vs, fs, prog; + + //printf("Compiling shader :\n%s", fsrc); + + vs = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); + rglAssert(glGetError() == GL_NO_ERROR); + fs = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); + rglAssert(glGetError() == GL_NO_ERROR); + + glShaderSourceARB(vs, 1, &vsrc,NULL); + rglAssert(glGetError() == GL_NO_ERROR); + glShaderSourceARB(fs, 1, &fsrc,NULL); + rglAssert(glGetError() == GL_NO_ERROR); + glCompileShaderARB(vs); + rglAssert(glGetError() == GL_NO_ERROR); + glCompileShaderARB(fs); + rglAssert(glGetError() == GL_NO_ERROR); + printInfoLog(vs, vsrc); + printInfoLog(fs, fsrc); + prog = glCreateProgramObjectARB(); + glAttachObjectARB(prog, fs); + rglAssert(glGetError() == GL_NO_ERROR); + glAttachObjectARB(prog, vs); + rglAssert(glGetError() == GL_NO_ERROR); + + glLinkProgramARB(prog); + rglAssert(glGetError() == GL_NO_ERROR); + + rglShader_t * s = (rglShader_t *) malloc(sizeof(rglShader_t)); + s->vs = vs; + s->fs = fs; + s->prog = prog; + //LOG("Creating shader %d %d %d\n", s->vs, s->fs, s->prog); +#ifdef RDP_DEBUG + s->vsrc = strdup(vsrc); + s->fsrc = strdup(fsrc); +#endif + return s; +} + +void rglUseShader(rglShader_t * shader) +{ + if (!shader) + glUseProgramObjectARB(0); + else + glUseProgramObjectARB(shader->prog); +} + +void rglDeleteShader(rglShader_t * shader) +{ + //LOG("Deleting shader %d %d %d\n", shader->vs, shader->fs, shader->prog); + glDeleteObjectARB(shader->prog); + rglAssert(glGetError() == GL_NO_ERROR); + glDeleteObjectARB(shader->vs); + rglAssert(glGetError() == GL_NO_ERROR); + glDeleteObjectARB(shader->fs); + rglAssert(glGetError() == GL_NO_ERROR); + free(shader); +} diff --git a/libmupen64plus/mupen64plus-video-z64/src/glshader.h b/libmupen64plus/mupen64plus-video-z64/src/glshader.h new file mode 100644 index 0000000000..e445657471 --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/glshader.h @@ -0,0 +1,38 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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 _GLSHADER_H_ +#define _GLSHADER_H_ + +#include "rdp.h" + +typedef struct { + GLhandleARB vs, fs, prog; +#ifdef RDP_DEBUG + const char * vsrc, * fsrc; +#endif +} rglShader_t; + +rglShader_t * rglCreateShader(const char * vsrc, const char * fsrc); +void rglUseShader(rglShader_t * shader); +void rglDeleteShader(rglShader_t * shader); + +#endif diff --git a/libmupen64plus/mupen64plus-video-z64/src/maingl.cpp b/libmupen64plus/mupen64plus-video-z64/src/maingl.cpp new file mode 100644 index 0000000000..fcec523bcf --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/maingl.cpp @@ -0,0 +1,387 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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 "rdp.h" +#include "rgl.h" +#include "osal_dynamiclib.h" +#include + +#define THREADED + +#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) + +GFX_INFO gfx; + +void (*render_callback)(int) = NULL; +static void (*l_DebugCallback)(void *, int, const char *) = NULL; +static void *l_DebugCallContext = 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_SwapBuffers CoreVideo_GL_SwapBuffers = 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; + +#ifdef THREADED +volatile static int waiting; +SDL_sem * rdpCommandSema; +SDL_sem * rdpCommandCompleteSema; +SDL_Thread * rdpThread; +int rdpThreadFunc(void * dummy) +{ + while (1) { + SDL_SemWait(rdpCommandSema); + waiting = 1; + if (rglNextStatus == RGL_STATUS_CLOSED) + rglUpdateStatus(); + else + rdp_process_list(); + if (!rglSettings.async) + SDL_SemPost(rdpCommandCompleteSema); + + if (rglStatus == RGL_STATUS_CLOSED) { + rdpThread = NULL; + return 0; + } + } + return 0; +} + +void rdpSignalFullSync() +{ + SDL_SemPost(rdpCommandCompleteSema); +} +void rdpWaitFullSync() +{ + SDL_SemWait(rdpCommandCompleteSema); +} + +void rdpPostCommand() +{ + int sync = rdp_store_list(); + SDL_SemPost(rdpCommandSema); + if (!rglSettings.async) + SDL_SemWait(rdpCommandCompleteSema); + else if (sync) { + rdpWaitFullSync(); + *gfx.MI_INTR_REG |= 0x20; + gfx.CheckInterrupts(); + } + + waiting = 0; +} + +void rdpCreateThread() +{ + if (!rdpCommandSema) { + rdpCommandSema = SDL_CreateSemaphore(0); + rdpCommandCompleteSema = SDL_CreateSemaphore(0); + } + if (!rdpThread) { + LOG("Creating rdp thread\n"); +#if SDL_VERSION_ATLEAST(2,0,0) + rdpThread = SDL_CreateThread(rdpThreadFunc, "z64rdp", 0); +#else + rdpThread = SDL_CreateThread(rdpThreadFunc, 0); +#endif + } +} +#endif + +void rdp_log(m64p_msg_level level, const char *msg, ...) +{ + char buf[1024]; + va_list args; + va_start(args, msg); + vsnprintf(buf, 1023, msg, args); + buf[1023]='\0'; + va_end(args); + if (l_DebugCallback) + { + l_DebugCallback(l_DebugCallContext, level, buf); + } +} + +#ifdef __cplusplus +extern "C" { +#endif + + EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context, + void (*DebugCallback)(void *, int, const char *)) + { + ///* first thing is to set the callback function for debug info */ + l_DebugCallback = DebugCallback; + l_DebugCallContext = Context; + + /* 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_SwapBuffers = (ptr_VidExt_GL_SwapBuffers) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SwapBuffers"); + + if (!CoreVideo_Init || !CoreVideo_Quit || !CoreVideo_ListFullscreenModes || !CoreVideo_SetVideoMode || + !CoreVideo_SetCaption || !CoreVideo_ToggleFullScreen || !CoreVideo_GL_GetProcAddress || + !CoreVideo_GL_SetAttribute || !CoreVideo_GL_SwapBuffers || !CoreVideo_ResizeWindow) + { + rdp_log(M64MSG_ERROR, "Couldn't connect to Core video functions"); + return M64ERR_INCOMPATIBLE; + } + + /* 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) + { + rdp_log(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)) + { + rdp_log(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)) + { + rdp_log(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"); + if (!ConfigOpenSection || !ConfigSetParameter || !ConfigGetParameter || + !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString || + !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString) + { + rdp_log(M64MSG_ERROR, "Couldn't connect to Core configuration functions"); + return M64ERR_INCOMPATIBLE; + } + + rglReadSettings(); + + return M64ERR_SUCCESS; + } + + EXPORT m64p_error CALL PluginShutdown(void) + { + 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 = "Z64gl"; + + if (Capabilities != NULL) + { + *Capabilities = 0; + } + + return M64ERR_SUCCESS; + } + + EXPORT void CALL SetRenderingCallback(void (*callback)(int)) + { + render_callback = callback; + } + + EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int front) + { + LOG("ReadScreen\n"); + *width = rglSettings.resX; + *height = rglSettings.resY; + if (dest) + { + GLint oldMode; + glGetIntegerv( GL_READ_BUFFER, &oldMode ); + if (front) + glReadBuffer( GL_FRONT ); + else + glReadBuffer( GL_BACK ); + glReadPixels( 0, 0, rglSettings.resX, rglSettings.resY, + GL_BGRA, GL_UNSIGNED_BYTE, dest ); + glReadBuffer( oldMode ); + } + } + + EXPORT int CALL InitiateGFX (GFX_INFO Gfx_Info) + { + LOG("InitiateGFX\n"); + gfx = Gfx_Info; + memset(rdpTiles, 0, sizeof(rdpTiles)); + memset(rdpTmem, 0, 0x1000); + memset(&rdpState, 0, sizeof(rdpState)); +#ifdef THREADED + if (rglSettings.threaded) + rdpCreateThread(); +#endif + return true; + } + + EXPORT void CALL MoveScreen (int xpos, int ypos) + { + } + + EXPORT void CALL ChangeWindow() + { + } + + EXPORT void CALL ProcessDList(void) + { + } + + + EXPORT void CALL ProcessRDPList(void) + { +#ifdef THREADED + if (rglSettings.threaded) { + rdpCreateThread(); + rdpPostCommand(); + } else +#endif + { + rdp_process_list(); + } + + return; + } + + EXPORT void CALL ResizeVideoOutput(int Width, int Height) + { + } + + EXPORT void CALL RomClosed (void) + { +#ifdef THREADED + if (rglSettings.threaded) { + rglNextStatus = RGL_STATUS_CLOSED; + do + rdpPostCommand(); + while (rglStatus != RGL_STATUS_CLOSED); + } else +#endif + { + rglNextStatus = rglStatus = RGL_STATUS_CLOSED; + rglCloseScreen(); + } + } + + EXPORT int CALL RomOpen() + { + int success = 1; +#ifdef THREADED + if (rglSettings.threaded) { + rdpCreateThread(); + //while (rglStatus != RGL_STATUS_CLOSED); + rglNextStatus = RGL_STATUS_WINDOWED; + } + else +#endif + { + rglNextStatus = rglStatus = RGL_STATUS_WINDOWED; + success = rglOpenScreen(); + } + return success; + } + + EXPORT void CALL ShowCFB (void) + { + } + + EXPORT void CALL UpdateScreen (void) + { +#ifdef THREADED + if (rglSettings.threaded) { + rdpPostCommand(); + } else +#endif + { + rglUpdate(); + } + } + + EXPORT void CALL ViStatusChanged (void) + { + } + + EXPORT void CALL ViWidthChanged (void) + { + } + +#ifdef __cplusplus +} +#endif + diff --git a/libmupen64plus/mupen64plus-video-z64/src/osal_dynamiclib.h b/libmupen64plus/mupen64plus-video-z64/src/osal_dynamiclib.h new file mode 100644 index 0000000000..c24377b178 --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/osal_dynamiclib.h @@ -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/libmupen64plus/mupen64plus-video-z64/src/osal_dynamiclib_unix.c b/libmupen64plus/mupen64plus-video-z64/src/osal_dynamiclib_unix.c new file mode 100644 index 0000000000..b3b7ba52dc --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/osal_dynamiclib_unix.c @@ -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 +#include +#include + +#include "m64p_types.h" +#include "osal_dynamiclib.h" + +void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName) +{ + if (pccProcedureName == NULL) + return NULL; + + return dlsym(LibHandle, pccProcedureName); +} + + diff --git a/libmupen64plus/mupen64plus-video-z64/src/osal_dynamiclib_win32.c b/libmupen64plus/mupen64plus-video-z64/src/osal_dynamiclib_win32.c new file mode 100644 index 0000000000..685d717c99 --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/osal_dynamiclib_win32.c @@ -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 +#include +#include + +#include "m64p_types.h" +#include "osal_dynamiclib.h" + +m64p_error osal_dynlib_open(m64p_dynlib_handle *pLibHandle, const char *pccLibraryPath) +{ + if (pLibHandle == NULL || pccLibraryPath == NULL) + return M64ERR_INPUT_ASSERT; + + *pLibHandle = LoadLibrary(pccLibraryPath); + + if (*pLibHandle == NULL) + { + char *pchErrMsg; + DWORD dwErr = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL); + fprintf(stderr, "LoadLibrary('%s') error: %s\n", pccLibraryPath, pchErrMsg); + LocalFree(pchErrMsg); + return M64ERR_INPUT_NOT_FOUND; + } + + return M64ERR_SUCCESS; +} + +void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName) +{ + if (pccProcedureName == NULL) + return NULL; + + return GetProcAddress(LibHandle, pccProcedureName); +} + +m64p_error osal_dynlib_close(m64p_dynlib_handle LibHandle) +{ + int rval = FreeLibrary(LibHandle); + + if (rval == 0) + { + char *pchErrMsg; + DWORD dwErr = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL); + fprintf(stderr, "FreeLibrary() error: %s\n", pchErrMsg); + LocalFree(pchErrMsg); + return M64ERR_INTERNAL; + } + + return M64ERR_SUCCESS; +} diff --git a/libmupen64plus/mupen64plus-video-z64/src/queue.h b/libmupen64plus/mupen64plus-video-z64/src/queue.h new file mode 100644 index 0000000000..d3956c894a --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/queue.h @@ -0,0 +1,557 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The + * elements are singly linked for minimum space and pointer manipulation + * overhead at the expense of O(n) removal for arbitrary elements. New + * elements can be added to the list after an existing element or at the + * head of the list. Elements being removed from the head of the list + * should use the explicit macro for this purpose for optimum + * efficiency. A singly-linked list may only be traversed in the forward + * direction. Singly-linked lists are ideal for applications with large + * datasets and few or no removals or for implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + (head)->lh_first = NULL; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (/*CONSTCOND*/0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var); \ + (var) = ((var)->field.le_next)) + +/* + * List access methods. + */ +#define LIST_EMPTY(head) ((head)->lh_first == NULL) +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) do { \ + (head)->slh_first = NULL; \ +} while (/*CONSTCOND*/0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while(curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) + +/* + * Singly-linked List access methods. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_INIT(head) do { \ + (head)->stqh_first = NULL; \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (head)->stqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.stqe_next = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &(elm)->field.stqe_next; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (listelm)->field.stqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if ((head)->stqh_first == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->stqh_first; \ + while (curelm->field.stqe_next != (elm)) \ + curelm = curelm->field.stqe_next; \ + if ((curelm->field.stqe_next = \ + curelm->field.stqe_next->field.stqe_next) == NULL) \ + (head)->stqh_last = &(curelm)->field.stqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define STAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->stqh_first); \ + (var); \ + (var) = ((var)->field.stqe_next)) + +/* + * Singly-linked Tail queue access methods. + */ +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) +#define STAILQ_FIRST(head) ((head)->stqh_first) +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE(head, elm, type, field) do { \ + if ((head)->sqh_first == (elm)) { \ + SIMPLEQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->sqh_first; \ + while (curelm->field.sqe_next != (elm)) \ + curelm = curelm->field.sqe_next; \ + if ((curelm->field.sqe_next = \ + curelm->field.sqe_next->field.sqe_next) == NULL) \ + (head)->sqh_last = &(curelm)->field.sqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->sqh_first); \ + (var); \ + (var) = ((var)->field.sqe_next)) + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + + +/* + * Tail queue definitions. + */ +#define _TAILQ_HEAD(name, type, qual) \ +struct name { \ + qual type *tqh_first; /* first element */ \ + qual type *qual *tqh_last; /* addr of last next element */ \ +} +#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define _TAILQ_ENTRY(type, qual) \ +struct { \ + qual type *tqe_next; /* next element */ \ + qual type *qual *tqe_prev; /* address of previous next element */\ +} +#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var); \ + (var) = ((var)->field.tqe_next)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ + (var); \ + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +/* + * Tail queue access methods. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(type, head) \ + { (type *)&head, (type *)&head } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(type, head) do { \ + (head)->cqh_first = (type *)(head); \ + (head)->cqh_last = (type *)(head); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_AFTER(type, head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (type *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_BEFORE(type, head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (type *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_HEAD(type, head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (type *)(head); \ + if ((head)->cqh_last == (type *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_TAIL(type, head, elm, field) do { \ + (elm)->field.cqe_next = (type *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (type *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_FOREACH(type, var, head, field) \ + for ((var) = ((head)->cqh_first); \ + (var) != (const type *)(head); \ + (var) = ((var)->field.cqe_next)) + +#define CIRCLEQ_FOREACH_REVERSE(type, var, head, field) \ + for ((var) = ((head)->cqh_last); \ + (var) != (const type *)(head); \ + (var) = ((var)->field.cqe_prev)) + +/* + * Circular queue access methods. + */ +#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) + +#define CIRCLEQ_LOOP_NEXT(head, elm, field) \ + (((elm)->field.cqe_next == (void *)(head)) \ + ? ((head)->cqh_first) \ + : (elm->field.cqe_next)) +#define CIRCLEQ_LOOP_PREV(head, elm, field) \ + (((elm)->field.cqe_prev == (void *)(head)) \ + ? ((head)->cqh_last) \ + : (elm->field.cqe_prev)) + +#endif /* sys/queue.h */ diff --git a/libmupen64plus/mupen64plus-video-z64/src/rdp.cpp b/libmupen64plus/mupen64plus-video-z64/src/rdp.cpp new file mode 100644 index 0000000000..673522b78e --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/rdp.cpp @@ -0,0 +1,858 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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 "rdp.h" +#include "rgl.h" + +#include + +const char *rdpImageFormats[] = +{ "RGBA", "YUV", "CI", "IA", "I", "???", "???", "???" }; + +rdpState_t rdpState; +uint32_t rdpChanged; +//rdpColor_t rdpTlut[1024]; +uint8_t rdpTmem[4*0x1000]; +int rdpFbFormat; +int rdpFbSize; +int rdpFbWidth; +uint32_t rdpFbAddress; +uint32_t rdpZbAddress; +int rdpTiFormat; +int rdpTiSize; +int rdpTiWidth; +uint32_t rdpTiAddress; +rdpTile_t rdpTiles[8]; +int rdpTileSet; + +struct area_t { + int start, stop; + uint32_t from; + int fromLine, fromFormat, fromSize; +}; + +#define MAX_TMEM_AREAS 16 +static area_t tmemAreas[MAX_TMEM_AREAS]; +static int nbTmemAreas; + +#ifdef RDP_DEBUG +int rdp_dump; +#endif + +#define MAXCMD 0x100000 +static uint32_t rdp_cmd_data[MAXCMD+44]; +static volatile int rdp_cmd_ptr = 0; +static volatile int rdp_cmd_cur = 0; +static int rdp_cmd_left = 0; + +#ifdef RDP_DEBUG +uint32_t rdpTraceBuf[0x100000]; +int rdpTracePos; +#endif + + +static void MarkTmemArea(int start, int stop, uint32_t from, uint32_t fromLine, + int fromFormat, int fromSize) +{ + int i; + + // remove areas that intersect + for (i=0; istart) { + memmove(tmemAreas+i, tmemAreas+i+1, nbTmemAreas-i-1); + nbTmemAreas--; + } + + DUMP("marking tmem %x --> %x rdram %x\n", start, stop, from); + + // add new area + //rglAssert(nbTmemAreas < MAX_TMEM_AREAS); + if (nbTmemAreas == MAX_TMEM_AREAS) { + LOG("tmem areas buffer full, clearing\n"); + nbTmemAreas = 0; + } + tmemAreas[nbTmemAreas].start = start; + tmemAreas[nbTmemAreas].stop = stop; + tmemAreas[nbTmemAreas].from = from; + tmemAreas[nbTmemAreas].fromLine = fromLine; + tmemAreas[nbTmemAreas].fromFormat = fromFormat; + tmemAreas[nbTmemAreas].fromSize = fromSize; + nbTmemAreas++; +} + +uint32_t rdpGetTmemOrigin(int tmem, int * line, int * stop, int * format, int * size) +{ + int i; + for (i=0; i> 24) & 0x3f, w1, w2); +} + +static void rdp_noop(uint32_t w1, uint32_t w2) +{ + +} + +static void triangle(uint32_t w1, uint32_t w2, int shade, int texture, int zbuffer) +{ + rglTriangle(w1, w2, shade, texture, zbuffer, rdp_cmd_data + rdp_cmd_cur); +} + +static void rdp_tri_noshade(uint32_t w1, uint32_t w2) +{ + triangle(w1, w2, 0, 0, 0); +} + +static void rdp_tri_noshade_z(uint32_t w1, uint32_t w2) +{ + triangle(w1, w2, 0, 0, 1); +} + +static void rdp_tri_tex(uint32_t w1, uint32_t w2) +{ + triangle(w1, w2, 0, 1, 0); +} + +static void rdp_tri_tex_z(uint32_t w1, uint32_t w2) +{ + triangle(w1, w2, 0, 1, 1); +} + +static void rdp_tri_shade(uint32_t w1, uint32_t w2) +{ + triangle(w1, w2, 1, 0, 0); +} + +static void rdp_tri_shade_z(uint32_t w1, uint32_t w2) +{ + triangle(w1, w2, 1, 0, 1); +} + +static void rdp_tri_texshade(uint32_t w1, uint32_t w2) +{ + triangle(w1, w2, 1, 1, 0); +} + +static void rdp_tri_texshade_z(uint32_t w1, uint32_t w2) +{ + triangle(w1, w2, 1, 1, 1); +} + +static void rdp_tex_rect(uint32_t w1, uint32_t w2) +{ + uint32_t w3, w4; + rdpTexRect_t rect; + + w3 = rdp_cmd_data[rdp_cmd_cur+2]; + w4 = rdp_cmd_data[rdp_cmd_cur+3]; + + rect.tilenum = (w2 >> 24) & 0x7; + rect.xl = (w1 >> 12) & 0xfff; + rect.yl = (w1 >> 0) & 0xfff; + rect.xh = (w2 >> 12) & 0xfff; + rect.yh = (w2 >> 0) & 0xfff; + rect.s = (w3 >> 16) & 0xffff; + rect.t = (w3 >> 0) & 0xffff; + rect.dsdx = (w4 >> 16) & 0xffff; + rect.dtdy = (w4 >> 0) & 0xffff; + + rglTextureRectangle(&rect, 0); +} + +static void rdp_tex_rect_flip(uint32_t w1, uint32_t w2) +{ + uint32_t w3, w4; + rdpTexRect_t rect; + + w3 = rdp_cmd_data[rdp_cmd_cur+2]; + w4 = rdp_cmd_data[rdp_cmd_cur+3]; + + rect.tilenum = (w2 >> 24) & 0x7; + rect.xl = (w1 >> 12) & 0xfff; + rect.yl = (w1 >> 0) & 0xfff; + rect.xh = (w2 >> 12) & 0xfff; + rect.yh = (w2 >> 0) & 0xfff; + rect.t = (w3 >> 16) & 0xffff; + rect.s = (w3 >> 0) & 0xffff; + rect.dtdy = (w4 >> 16) & 0xffff; + rect.dsdx = (w4 >> 0) & 0xffff; + + rglTextureRectangle(&rect, 1); +} + +static void rdp_sync_load(uint32_t w1, uint32_t w2) +{ + // Nothing to do? +} + +static void rdp_sync_pipe(uint32_t w1, uint32_t w2) +{ + // Nothing to do? +} + +static void rdp_sync_tile(uint32_t w1, uint32_t w2) +{ + // Nothing to do? +} + +void rdpSignalFullSync(); +void rdpWaitFullSync(); +#ifdef RDP_DEBUG +int nbFullSync; +#endif +static void rdp_sync_full(uint32_t w1, uint32_t w2) +{ + //printf("full sync\n"); + rglFullSync(); + rglUpdate(); + + if (rglSettings.async) + rdpSignalFullSync(); + else { + *gfx.MI_INTR_REG |= 0x20; + gfx.CheckInterrupts(); + } +#ifdef RDP_DEBUG + nbFullSync++; +#endif +} + +static void rdp_set_key_gb(uint32_t w1, uint32_t w2) +{ + //osd_die("RDP: unhandled command set_key_gb, %08X %08X\n", w1, w2); +} + +static void rdp_set_key_r(uint32_t w1, uint32_t w2) +{ + //osd_die("RDP: unhandled command set_key_r, %08X %08X\n", w1, w2); +} + +static void rdp_set_convert(uint32_t w1, uint32_t w2) +{ + rdpState.k5 = w2&0xff; + //osd_die("RDP: unhandled command set_convert, %08X %08X\n", w1, w2); +} + +static void rdp_set_scissor(uint32_t w1, uint32_t w2) +{ + rdpChanged |= RDP_BITS_CLIP; + rdpState.clipMode = (w2 >> 24) & 3; + rdpState.clip.xh = (w1 >> 12) & 0xfff; + rdpState.clip.yh = (w1 >> 0) & 0xfff; + rdpState.clip.xl = (w2 >> 12) & 0xfff; + rdpState.clip.yl = (w2 >> 0) & 0xfff; + // TODO: handle f & o? +} + +static void rdp_set_prim_depth(uint32_t w1, uint32_t w2) +{ + rdpChanged |= RDP_BITS_MISC; + rdpState.primitiveZ = (uint16_t)(w2 >> 16); + rdpState.primitiveDeltaZ = (uint16_t)(w1); +} + +static void rdp_set_other_modes(uint32_t w1, uint32_t w2) +{ + rdpChanged |= RDP_BITS_OTHER_MODES; + rdpState.otherModes.w1 = w1; + rdpState.otherModes.w2 = w2; +} + +static void rdp_load_tlut(uint32_t w1, uint32_t w2) +{ + int tilenum = (w2 >> 24) & 0x7; + + rdpChanged |= RDP_BITS_TILE_SETTINGS; + +#define tile rdpTiles[tilenum] + //rdpTile_t tile; + tile.sl = (w1 >> 12) & 0xfff; + tile.tl = (w1 >> 0) & 0xfff; + tile.sh = (w2 >> 12) & 0xfff; + tile.th = (w2 >> 0) & 0xfff; + + int i; + + rdpChanged |= RDP_BITS_TLUT; + + int count = ((tile.sh - tile.sl + 4) >>2) * ((tile.th - tile.tl + 4) >>2); + + switch (rdpTiSize) + { + case RDP_PIXEL_SIZE_16BIT: + { + uint16_t *src = (uint16_t *)&rdram[(rdpTiAddress + (tile.tl >>2) * rdpTiWidth * 2 + ((tile.sl >>2) << rdpTiSize >> 1))/4]; + uint16_t *dst = (uint16_t *)(rdpTmem + rdpTiles[tilenum].tmem); + + // printf("loading TLUT from %x --> %x\n", + // tile.th * rdpTiWidth / 2 + (tile.sh << rdpTiSize >> 1)/4 + + for (i=0; i < count; i++) + { + dst[i*4] = src[i^1]; + } + break; + } + default: LOGERROR("RDP: load_tlut: size = %d\n", rdpTiSize); + } +#undef tile +} + +static void rdp_set_tile_size(uint32_t w1, uint32_t w2) +{ + int tilenum = (w2 >> 24) & 0x7; + + rdpChanged |= RDP_BITS_TILE_SETTINGS; + +#define tile rdpTiles[tilenum] + tile.sl = (w1 >> 12) & 0xfff; + tile.tl = (w1 >> 0) & 0xfff; + tile.sh = (w2 >> 12) & 0xfff; + tile.th = (w2 >> 0) & 0xfff; +#undef tile +} + +static void rdp_load_block(uint32_t w1, uint32_t w2) +{ + int i, width; + uint16_t sl, sh, tl, dxt; + int tilenum = (w2 >> 24) & 0x7; + uint32_t *src, *tc; + int tb; + + rdpChanged |= RDP_BITS_TMEM; + + sl = ((w1 >> 12) & 0xfff); + tl = ((w1 >> 0) & 0xfff) << 11; + sh = ((w2 >> 12) & 0xfff); + dxt = ((w2 >> 0) & 0xfff); + + width = (sh - sl + 1) << rdpTiSize >> 1; + + src = (uint32_t*)&rdram[0]; + tc = (uint32_t*)rdpTmem; + tb = rdpTiles[tilenum].tmem/4; + + //printf("Load block to %x width %x\n", rdpTiles[tilenum].tmem, width); + + MarkTmemArea(rdpTiles[tilenum].tmem, rdpTiles[tilenum].tmem + width, + tl * rdpTiWidth*4 + rdpTiAddress + sl*4, 0, ~0, ~0); + + if (tb+width/4 > 0x1000/4) { + LOG("load_block : fixup too large width\n"); + width = 0x1000-tb*4; + } + + if (dxt != 0) + { + int j=0; + + //rglAssert(tb+width/4 <= 0x1000/4); + + int swap = rdpTiles[tilenum].size == 3? 2 : 1; + + for (i=0; i < width / 4; i+=2) + { + int t = j >> 11; + + tc[(((tb+i) + 0) ^ ((t & 1) ? swap : 0))&0x3ff] = + src[rdpTiAddress / 4 + ((tl * rdpTiWidth) / 4) + sl + i + 0]; + tc[(((tb+i) + 1) ^ ((t & 1) ? swap : 0))&0x3ff] = + src[rdpTiAddress / 4 + ((tl * rdpTiWidth) / 4) + sl + i + 1]; + + j += dxt; + } + } + else + { + //rglAssert(tb+width/4 <= 0x1000/4); + for (i=0; i < width / 4; i++) + { + tc[(tb+i)&0x3ff] = src[((tl * rdpTiWidth) / 4) + rdpTiAddress / 4 + sl + i]; + } + } +} + +static void rdp_load_tile(uint32_t w1, uint32_t w2) +{ + int i, j; + uint16_t sl, sh, tl, th; + int width, height; + int tilenum = (w2 >> 24) & 0x7; + int line; + + rdpChanged |= RDP_BITS_TMEM; + + sl = ((w1 >> 12) & 0xfff) / 4; + tl = ((w1 >> 0) & 0xfff) / 4; + sh = ((w2 >> 12) & 0xfff) / 4; + th = ((w2 >> 0) & 0xfff) / 4; + + width = (sh - sl) + 1; + height = (th - tl) + 1; + + // printf("Load tile to %x line %x height %d\n", + // rdpTiles[tilenum].tmem, + // rdpTiles[tilenum].line, + // height); + + rdpTiles[tilenum].size = rdpTiSize; // CHECK THIS + line = rdpTiles[tilenum].line; + switch (rdpTiles[tilenum].size /*rdpTiSize*/) + { + case RDP_PIXEL_SIZE_8BIT: + { + uint8_t *src = (uint8_t*)&rdram[0]; + uint8_t *tc = (uint8_t*)rdpTmem; + int tb = rdpTiles[tilenum].tmem; + + MarkTmemArea(tb, tb + height*line, rdpTiAddress + tl * rdpTiWidth + sl, + rdpTiWidth, rdpTiFormat, rdpTiSize); + + if (tb + (line * (height-1) + width) > 4096) + { + LOGERROR("rdp_load_tile 8-bit: tmem %04X, width %d, height %d = %d\n", rdpTiles[tilenum].tmem, width, height, width*height); + height = (4096-tb)/line; + } + + for (j=0; j < height; j++) + { + int tline = tb + (rdpTiles[tilenum].line * j); + int s = ((j + tl) * rdpTiWidth) + sl; + + for (i=0; i < width; i++) + { + tc[(((tline+i) ^ BYTE_ADDR_XOR) ^ ((j & 1) ? 4 : 0))&0xfff] = src[(rdpTiAddress + s++) ^ BYTE_ADDR_XOR]; + } + } + break; + } + case RDP_PIXEL_SIZE_16BIT: + { + uint16_t *src = (uint16_t*)&rdram[0]; + uint16_t *tc = (uint16_t*)rdpTmem; + int tb = (rdpTiles[tilenum].tmem / 2); + + if (tb + (line/2 * (height-1) + width) > 2048) + { + LOGERROR("rdp_load_tile 16-bit: tmem %04X, width %d, height %d = %d\n", rdpTiles[tilenum].tmem, width, height, width*height); + height = (2048 - tb) / (line/2); + } + + MarkTmemArea(tb*2, tb*2 + height*line, + rdpTiAddress + (tl * rdpTiWidth + sl)*2, + rdpTiWidth*2, rdpTiFormat, rdpTiSize); + + for (j=0; j < height; j++) + { + int tline = tb + ((rdpTiles[tilenum].line / 2) * j); + int s = ((j + tl) * rdpTiWidth) + sl; + + for (i=0; i < width; i++) + { + tc[(((tline+i) ^ WORD_ADDR_XOR) ^ ((j & 1) ? 2 : 0))&0x7ff] = src[(rdpTiAddress / 2 + s++) ^ WORD_ADDR_XOR]; + } + } + break; + } + case RDP_PIXEL_SIZE_32BIT: + { + uint32_t *src = (uint32_t*)&rdram[0]; + uint32_t *tc = (uint32_t*)rdpTmem; + int tb = (rdpTiles[tilenum].tmem / 4); + + MarkTmemArea(tb*4, tb*4 + height*line*2, + rdpTiAddress + (tl * rdpTiWidth + sl)*4, + rdpTiWidth*4, rdpTiFormat, rdpTiSize); + + if (tb + (line/2 * (height-1) + width) > 1024) + { + rdp_log(M64MSG_ERROR, "rdp_load_tile 32-bit: tmem %04X, width %d, height %d = %d\n", rdpTiles[tilenum].tmem, width, height, width*height); + } + + for (j=0; j < height; j++) + { + int tline = tb + ((rdpTiles[tilenum].line / 2) * j); + int s = ((j + tl) * rdpTiWidth) + sl; + + for (i=0; i < width; i++) + { + tc[((tline+i) ^ ((j & 1) ? 2 : 0))&0x3ff] = src[(rdpTiAddress / 4 + s++)]; + } + } + break; + } + + default: + rdp_log(M64MSG_ERROR, "RDP: load_tile: size = %d\n", rdpTiSize); + } +} + +static void rdp_set_tile(uint32_t w1, uint32_t w2) +{ + int tilenum = (w2 >> 24) & 0x7; + //int i; + + rdpChanged |= RDP_BITS_TILE_SETTINGS; + rdpTileSet |= 1<> 21) & 0x7; + tile.size = (w1 >> 19) & 0x3; + tile.line = ((w1 >> 9) & 0x1ff) * 8; + tile.tmem = ((w1 >> 0) & 0x1ff) * 8; + tile.palette= (w2 >> 20) & 0xf; + tile.ct = (w2 >> 19) & 0x1; + tile.mt = (w2 >> 18) & 0x1; + tile.mask_t = (w2 >> 14) & 0xf; + tile.shift_t= (w2 >> 10) & 0xf; + if (tile.shift_t >= 12) tile.shift_t -= 16; + tile.cs = (w2 >> 9) & 0x1; + tile.ms = (w2 >> 8) & 0x1; + tile.mask_s = (w2 >> 4) & 0xf; + tile.shift_s= (w2 >> 0) & 0xf; + if (tile.shift_s >= 12) tile.shift_s -= 16; +#undef tile +} + +static void rdp_fill_rect(uint32_t w1, uint32_t w2) +{ + rdpRect_t rect; + rect.xl = (w1 >> 12) & 0xfff; + rect.yl = (w1 >> 0) & 0xfff; + rect.xh = (w2 >> 12) & 0xfff; + rect.yh = (w2 >> 0) & 0xfff; + + rglFillRectangle(&rect); +} + +static void rdp_set_fill_color(uint32_t w1, uint32_t w2) +{ + rdpChanged |= RDP_BITS_FILL_COLOR; + rdpState.fillColor = w2; +} + +static void rdp_set_fog_color(uint32_t w1, uint32_t w2) +{ + rdpChanged |= RDP_BITS_FOG_COLOR; + rdpState.fogColor = w2; +} + +static void rdp_set_blend_color(uint32_t w1, uint32_t w2) +{ + rdpChanged |= RDP_BITS_BLEND_COLOR; + rdpState.blendColor = w2; +} + +static void rdp_set_prim_color(uint32_t w1, uint32_t w2) +{ + rdpChanged |= RDP_BITS_PRIM_COLOR; + // TODO: prim min level, prim_level + rdpState.primColor = w2; +} + +static void rdp_set_env_color(uint32_t w1, uint32_t w2) +{ + rdpChanged |= RDP_BITS_ENV_COLOR; + rdpState.envColor = w2; +} + +static void rdp_set_combine(uint32_t w1, uint32_t w2) +{ + rdpChanged |= RDP_BITS_COMBINE_MODES; + + rdpState.combineModes.w1 = w1; + rdpState.combineModes.w2 = w2; +} + +static void rdp_set_texture_image(uint32_t w1, uint32_t w2) +{ + rdpChanged |= RDP_BITS_TI_SETTINGS; + + rdpTiFormat = (w1 >> 21) & 0x7; + rdpTiSize = (w1 >> 19) & 0x3; + rdpTiWidth = (w1 & 0x3ff) + 1; + rdpTiAddress = w2 & 0x01ffffff; +} + +static void rdp_set_mask_image(uint32_t w1, uint32_t w2) +{ + rdpChanged |= RDP_BITS_ZB_SETTINGS; + rdpZbAddress = w2 & 0x01ffffff; +} + +static void rdp_set_color_image(uint32_t w1, uint32_t w2) +{ + rdpChanged |= RDP_BITS_FB_SETTINGS; + rdpFbFormat = (w1 >> 21) & 0x7; + rdpFbSize = (w1 >> 19) & 0x3; + rdpFbWidth = (w1 & 0x3ff) + 1; + rdpFbAddress = w2 & 0x01ffffff; +} + +/*****************************************************************************/ + +static void (* rdp_command_table[64])(uint32_t w1, uint32_t w2) = +{ + /* 0x00 */ + rdp_noop, rdp_invalid, rdp_invalid, rdp_invalid, + rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, + rdp_tri_noshade, rdp_tri_noshade_z, rdp_tri_tex, rdp_tri_tex_z, + rdp_tri_shade, rdp_tri_shade_z, rdp_tri_texshade, rdp_tri_texshade_z, + /* 0x10 */ + rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, + rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, + rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, + rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, + /* 0x20 */ + rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, + rdp_tex_rect, rdp_tex_rect_flip, rdp_sync_load, rdp_sync_pipe, + rdp_sync_tile, rdp_sync_full, rdp_set_key_gb, rdp_set_key_r, + rdp_set_convert, rdp_set_scissor, rdp_set_prim_depth, rdp_set_other_modes, + /* 0x30 */ + rdp_load_tlut, rdp_invalid, rdp_set_tile_size, rdp_load_block, + rdp_load_tile, rdp_set_tile, rdp_fill_rect, rdp_set_fill_color, + rdp_set_fog_color, rdp_set_blend_color, rdp_set_prim_color, rdp_set_env_color, + rdp_set_combine, rdp_set_texture_image, rdp_set_mask_image, rdp_set_color_image +}; + +void rdp_process_list(void) +{ + //int i; + uint32_t cmd;//, length, cmd_length; + + rglUpdateStatus(); + if (!rglSettings.threaded) + rdp_store_list(); + + if (rglStatus == RGL_STATUS_CLOSED) + return; + + // this causes problem with depth writeback in zelda mm + // but is necessary for in fisherman + rglUpdate(); + + while (rdp_cmd_cur != rdp_cmd_ptr) + { + cmd = (rdp_cmd_data[rdp_cmd_cur] >> 24) & 0x3f; + // if (((rdp_cmd_data[rdp_cmd_cur] >> 24) & 0xc0) != 0xc0) + // { + // LOGERROR("rdp_process_list: invalid rdp command %08X at %08X\n", rdp_cmd_data[rdp_cmd_cur], dp_start+(rdp_cmd_cur * 4)); + // } + + if ((((rdp_cmd_ptr-rdp_cmd_cur)&(MAXCMD-1)) * 4) < rdp_command_length[cmd]) + { + // LOGERROR("rdp_process_list: not enough rdp command data: cur = %d, ptr = %d, expected = %d\n", rdp_cmd_cur, rdp_cmd_ptr, rdp_command_length[cmd]); + // return; + break; + } + +#ifdef RDP_DEBUG + if (rdp_dump) + { + char string[4000]; + int rdp_dasm(uint32_t * rdp_cmd_data, int rdp_cmd_cur, int length, char *buffer); + rdp_dasm(rdp_cmd_data, rdp_cmd_cur, rdp_command_length[cmd], string); + + fprintf(stderr, "%08X: %08X %08X %s\n", dp_start+(rdp_cmd_cur * 4), rdp_cmd_data[rdp_cmd_cur+0], rdp_cmd_data[rdp_cmd_cur+1], string); + } +#endif + +#ifdef RDP_DEBUG + memcpy(rdpTraceBuf+rdpTracePos, rdp_cmd_data+rdp_cmd_cur, rdp_command_length[cmd]); +#endif + + if (rdp_cmd_cur + rdp_command_length[cmd]/4 > MAXCMD) + memcpy(rdp_cmd_data + MAXCMD, rdp_cmd_data, rdp_command_length[cmd] - (MAXCMD - rdp_cmd_cur)*4); + + // execute the command + rdp_command_table[cmd](rdp_cmd_data[rdp_cmd_cur+0], rdp_cmd_data[rdp_cmd_cur+1]); + +#ifdef RDP_DEBUG + rdpTracePos += rdp_command_length[cmd] / 4; + rglAssert(rdpTracePos < sizeof(rdpTraceBuf)/sizeof(rdpTraceBuf[0])); +#endif + + rdp_cmd_cur = (rdp_cmd_cur + rdp_command_length[cmd] / 4) & (MAXCMD-1); + } + + // dp_current = dp_end; + // dp_start = dp_end; + dp_start = dp_current; + + dp_status &= ~0x0002; +} + +int rdp_store_list(void) +{ + uint32_t i; + uint32_t data, cmd, length; + int sync = 0; + + // while (dp_current < dp_end) { + + // } + // dp_status &= ~0x0002; + + length = dp_end - dp_current; + + // LOG("rdp start %x cur %x end %x length %d dp_status %x\n", + // dp_start, dp_current, dp_end, + // length, dp_status); + + if (dp_end <= dp_current) { + return 0; + } + + // load command data + for (i=0; i < length; i += 4) + { + data = READ_RDP_DATA(dp_current + i); + if (rglSettings.async) { + if (rdp_cmd_left) { + rdp_cmd_left--; + } else { + cmd = (data >> 24) & 0x3f; + rdp_cmd_left = rdp_command_length[cmd]/4-1; + if (cmd == 0x29) // full_sync + sync = 1; + } + } + rdp_cmd_data[rdp_cmd_ptr] = data; + rdp_cmd_ptr = (rdp_cmd_ptr + 1) & (MAXCMD-1); + } + + dp_current += length; + + return sync; +} + + +int rdp_init() +{ + rdp_cmd_cur = rdp_cmd_ptr = 0; + rdp_cmd_left = 0; +#ifdef RDP_DEBUG + rdpTracePos = 0; +#endif + nbTmemAreas = 0; + return rglInit(); +} + diff --git a/libmupen64plus/mupen64plus-video-z64/src/rdp.h b/libmupen64plus/mupen64plus-video-z64/src/rdp.h new file mode 100644 index 0000000000..606ffd0d37 --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/rdp.h @@ -0,0 +1,279 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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 _RDP_H_ +#define _RDP_H_ + +#include +#include +#include +#include + +#define M64P_PLUGIN_PROTOTYPES 1 +#include "m64p_types.h" +#include "m64p_common.h" +#include "m64p_plugin.h" +#include "m64p_vidext.h" +#include "m64p_config.h" + +#define LSB_FIRST 1 // TODO : check for platform +#ifdef LSB_FIRST +#define BYTE_ADDR_XOR 3 +#define WORD_ADDR_XOR 1 +#define BYTE4_XOR_BE(a) ((a) ^ 3) /* read/write a byte to a 32-bit space */ +#else +#define BYTE_ADDR_XOR 0 +#define WORD_ADDR_XOR 0 +#define BYTE4_XOR_BE(a) (a) +#endif + + + +#define RDP_PIXEL_SIZE_4BIT 0 +#define RDP_PIXEL_SIZE_8BIT 1 +#define RDP_PIXEL_SIZE_16BIT 2 +#define RDP_PIXEL_SIZE_32BIT 3 + +#define RDP_FORMAT_RGBA 0 +#define RDP_FORMAT_YUV 1 +#define RDP_FORMAT_CI 2 +#define RDP_FORMAT_IA 3 +#define RDP_FORMAT_I 4 + +#define RDP_CYCLE_TYPE_1 0 +#define RDP_CYCLE_TYPE_2 1 +#define RDP_CYCLE_TYPE_COPY 2 +#define RDP_CYCLE_TYPE_FILL 3 + +typedef uint32_t rdpColor_t; + +#define RDP_GETC32_R(c) ( ((c)>>24) & 0xff ) +#define RDP_GETC32_G(c) ( ((c)>>16) & 0xff ) +#define RDP_GETC32_B(c) ( ((c)>> 8) & 0xff ) +#define RDP_GETC32_A(c) ( ((c)>> 0) & 0xff ) + +#define RDP_GETC16_R(c) ( ((c)>>11) & 0x1f ) +#define RDP_GETC16_G(c) ( ((c)>> 6) & 0x1f ) +#define RDP_GETC16_B(c) ( ((c)>> 1) & 0x1f ) +#define RDP_GETC16_A(c) ( ((c)>> 0) & 0x1 ) + +struct rdpRect_t { + uint16_t xl, yl, xh, yh; // 10.2 fixed-point +}; + +struct rdpTexRect_t { + int tilenum; + uint16_t xl, yl, xh, yh; // 10.2 fixed-point + int16_t s, t; // 10.5 fixed-point + int16_t dsdx, dtdy; // 5.10 fixed-point +}; + +extern const char *rdpImageFormats[]; + +// TODO put ct ... palette in a bitfield +struct rdpTile_t { + uint16_t line; + uint16_t tmem; + uint16_t sl, tl, sh, th; // 10.2 fixed-point + uint16_t w, h; + int8_t format, size; + int8_t mask_t, shift_t, mask_s, shift_s; + int8_t ct, mt, cs, ms; + int8_t palette; +}; + +struct rdpCombineModes_t { + uint32_t w1, w2; +}; + +#define RDP_GETCM_SUB_A_RGB0(cm) (((cm).w1 >> 20) & 0xf) +#define RDP_GETCM_MUL_RGB0(cm) (((cm).w1 >> 15) & 0x1f) +#define RDP_GETCM_SUB_A_A0(cm) (((cm).w1 >> 12) & 0x7) +#define RDP_GETCM_MUL_A0(cm) (((cm).w1 >> 9) & 0x7) +#define RDP_GETCM_SUB_A_RGB1(cm) (((cm).w1 >> 5) & 0xf) +#define RDP_GETCM_MUL_RGB1(cm) (((cm).w1 >> 0) & 0x1f) + +#define RDP_GETCM_SUB_B_RGB0(cm) (((cm).w2 >> 28) & 0xf) +#define RDP_GETCM_SUB_B_RGB1(cm) (((cm).w2 >> 24) & 0xf) +#define RDP_GETCM_SUB_A_A1(cm) (((cm).w2 >> 21) & 0x7) +#define RDP_GETCM_MUL_A1(cm) (((cm).w2 >> 18) & 0x7) +#define RDP_GETCM_ADD_RGB0(cm) (((cm).w2 >> 15) & 0x7) +#define RDP_GETCM_SUB_B_A0(cm) (((cm).w2 >> 12) & 0x7) +#define RDP_GETCM_ADD_A0(cm) (((cm).w2 >> 9) & 0x7) +#define RDP_GETCM_ADD_RGB1(cm) (((cm).w2 >> 6) & 0x7) +#define RDP_GETCM_SUB_B_A1(cm) (((cm).w2 >> 3) & 0x7) +#define RDP_GETCM_ADD_A1(cm) (((cm).w2 >> 0) & 0x7) + +#define RDP_COMBINE_MASK11 ((0xfu<<20)|(0x1fu<<15)|(0x7u<<12)|(0x7u<<9)) +#define RDP_COMBINE_MASK12 ((0xfu<<28)|(0x7u<<15)|(0x7u<<12)|(0x7u<<9)) +#define RDP_COMBINE_MASK21 ((0xfu<<5)|(0x1fu<<0)) +#define RDP_COMBINE_MASK22 ((0xfu<<24)|(0x7u<<21)|(0x7u<<18)|(0x7u<<6)|(0x7u<<3)|(0x7u<<0)) + +static const rdpCombineModes_t rdpCombineMasks[4] = { + { ~RDP_COMBINE_MASK21, ~RDP_COMBINE_MASK22 }, + { ~0u, ~0u }, + { ~(RDP_COMBINE_MASK11|RDP_COMBINE_MASK21), ~(RDP_COMBINE_MASK12|RDP_COMBINE_MASK22) }, + { ~(RDP_COMBINE_MASK11|RDP_COMBINE_MASK21), ~(RDP_COMBINE_MASK12|RDP_COMBINE_MASK22) }, +}; + +struct rdpOtherModes_t { + uint32_t w1, w2; +}; + +#define RDP_OM_MISSING1 (~((3<<20)|0x80000|0x40000|0x20000|0x10000|0x08000| \ + 0x04000|0x02000|0x01000|0x00800|0x00400|0x00200| \ + 0x00100|(3<<6)|(3<<4))) +#define RDP_OM_MISSING2 (~(0xffff0000|0x4000|0x2000|0x1000|(3<<10)|(3<<8)| \ + 0x80|0x40|0x20|0x10|0x08|0x04|0x02|0x01)) + +#define RDP_GETOM_CYCLE_TYPE(om) (((om).w1 >> 20) & 0x3) +#define RDP_GETOM_PERSP_TEX_EN(om) (((om).w1 & 0x80000) ? 1 : 0) +#define RDP_GETOM_DETAIL_TEX_EN(om) (((om).w1 & 0x40000) ? 1 : 0) +#define RDP_GETOM_SHARPEN_TEX_EN(om) (((om).w1 & 0x20000) ? 1 : 0) +#define RDP_GETOM_TEX_LOD_EN(om) (((om).w1 & 0x10000) ? 1 : 0) +#define RDP_GETOM_EN_TLUT(om) (((om).w1 & 0x08000) ? 1 : 0) +#define RDP_GETOM_TLUT_TYPE(om) (((om).w1 & 0x04000) ? 1 : 0) +#define RDP_GETOM_SAMPLE_TYPE(om) (((om).w1 & 0x02000) ? 1 : 0) +#define RDP_GETOM_MID_TEXEL(om) (((om).w1 & 0x01000) ? 1 : 0) +#define RDP_GETOM_BI_LERP0(om) (((om).w1 & 0x00800) ? 1 : 0) +#define RDP_GETOM_BI_LERP1(om) (((om).w1 & 0x00400) ? 1 : 0) +#define RDP_GETOM_CONVERT_ONE(om) (((om).w1 & 0x00200) ? 1 : 0) +#define RDP_GETOM_KEY_EN(om) (((om).w1 & 0x00100) ? 1 : 0) +#define RDP_GETOM_RGB_DITHER_SEL(om) (((om).w1 >> 6) & 0x3) +#define RDP_GETOM_ALPHA_DITHER_SEL(om) (((om).w1 >> 4) & 0x3) +#define RDP_GETOM_BLEND_M1A_0(om) (((om).w2 >> 30) & 0x3) +#define RDP_GETOM_BLEND_M1A_1(om) (((om).w2 >> 28) & 0x3) +#define RDP_GETOM_BLEND_M1B_0(om) (((om).w2 >> 26) & 0x3) +#define RDP_GETOM_BLEND_M1B_1(om) (((om).w2 >> 24) & 0x3) +#define RDP_GETOM_BLEND_M2A_0(om) (((om).w2 >> 22) & 0x3) +#define RDP_GETOM_BLEND_M2A_1(om) (((om).w2 >> 20) & 0x3) +#define RDP_GETOM_BLEND_M2B_0(om) (((om).w2 >> 18) & 0x3) +#define RDP_GETOM_BLEND_M2B_1(om) (((om).w2 >> 16) & 0x3) +#define RDP_GETOM_FORCE_BLEND(om) (((om).w2 & 0x4000) ? 1 : 0) +#define RDP_GETOM_ALPHA_CVG_SELECT(om) (((om).w2 & 0x2000) ? 1 : 0) +#define RDP_GETOM_CVG_TIMES_ALPHA(om) (((om).w2 & 0x1000) ? 1 : 0) +#define RDP_GETOM_Z_MODE(om) (((om).w2 >> 10) & 0x3) +#define RDP_GETOM_CVG_DEST(om) (((om).w2 >> 8) & 0x3) +#define RDP_GETOM_COLOR_ON_CVG(om) (((om).w2 & 0x80) ? 1 : 0) +#define RDP_GETOM_IMAGE_READ_EN(om) (((om).w2 & 0x40) ? 1 : 0) +#define RDP_GETOM_Z_UPDATE_EN(om) (((om).w2 & 0x20) ? 1 : 0) +#define RDP_GETOM_Z_COMPARE_EN(om) (((om).w2 & 0x10) ? 1 : 0) +#define RDP_GETOM_ANTIALIAS_EN(om) (((om).w2 & 0x08) ? 1 : 0) +#define RDP_GETOM_Z_SOURCE_SEL(om) (((om).w2 & 0x04) ? 1 : 0) +#define RDP_GETOM_DITHER_ALPHA_EN(om) (((om).w2 & 0x02) ? 1 : 0) +#define RDP_GETOM_ALPHA_COMPARE_EN(om) (((om).w2 & 0x01) ? 1 : 0) + +#define RDP_BLEND_MASK1 ((3u<<30)|(3u<<26)|(3u<<22)|(3u<<18)) +#define RDP_BLEND_MASK2 ((3u<<28)|(3u<<24)|(3u<<20)|(3u<<16)) + +static const rdpOtherModes_t rdpBlendMasks[4] = { + { ~0u, ~RDP_BLEND_MASK2 }, + { ~0u, ~0u }, + { ~0u, ~(RDP_BLEND_MASK1|RDP_BLEND_MASK2) }, + { ~0u, ~(RDP_BLEND_MASK1|RDP_BLEND_MASK2) }, +}; + +struct rdpState_t { + rdpCombineModes_t combineModes; + rdpOtherModes_t otherModes; + rdpColor_t blendColor; + rdpColor_t primColor; + rdpColor_t envColor; + rdpColor_t fogColor; + rdpColor_t fillColor; + int primitiveZ; + int primitiveDeltaZ; + rdpRect_t clip; + uint8_t k5, clipMode; +}; + +extern rdpState_t rdpState; +extern uint32_t rdpChanged; +//extern rdpColor_t rdpTlut[]; +#define rdpTlut ((uint16_t *) (rdpTmem + 0x800)) +extern uint8_t rdpTmem[]; +extern int rdpFbFormat; +extern int rdpFbSize; +extern int rdpFbWidth; +extern uint32_t rdpFbAddress; +extern uint32_t rdpZbAddress; +extern int rdpTiFormat; +extern int rdpTiSize; +extern int rdpTiWidth; +extern uint32_t rdpTiAddress; +extern rdpTile_t rdpTiles[8]; +extern int rdpTileSet; + +#define RDP_BITS_COMBINE_MODES (1<<0) +#define RDP_BITS_OTHER_MODES (1<<1) +#define RDP_BITS_CLIP (1<<2) +#define RDP_BITS_BLEND_COLOR (1<<3) +#define RDP_BITS_PRIM_COLOR (1<<4) +#define RDP_BITS_ENV_COLOR (1<<5) +#define RDP_BITS_FOG_COLOR (1<<6) +#define RDP_BITS_FB_SETTINGS (1<<7) +#define RDP_BITS_ZB_SETTINGS (1<<8) +#define RDP_BITS_TI_SETTINGS (1<<9) +#define RDP_BITS_TMEM (1<<10) +#define RDP_BITS_TLUT (1<<11) +#define RDP_BITS_TILE_SETTINGS (1<<12) +#define RDP_BITS_FILL_COLOR (1<<13) +#define RDP_BITS_MISC (1<<14) + +// return where the data in rdram came from at this address in tmem +uint32_t rdpGetTmemOrigin(int tmem, int * line, int * stop, int * fromFormat, int * size); + + +int rdp_init(); +int rdp_dasm(uint32_t * rdp_cmd_data, int rdp_cmd_cur, int length, char *buffer); +void rdp_process_list(void); +int rdp_store_list(void); + +void rdp_log(m64p_msg_level level, const char *msg, ...); + +#ifdef RDP_DEBUG + +extern uint32_t rdpTraceBuf[]; +extern int rdpTracePos; + +extern int rdp_dump; + +#define DUMP if (!rdp_dump) ; else LOG + +static void LOG(const char * s, ...) +{ + va_list ap; + va_start(ap, s); + vfprintf(stderr, s, ap); + va_end(ap); +} +#define LOGERROR LOG + +#else // RDP_DEBUG + +#define DUMP(...) rdp_log(M64MSG_VERBOSE, __VA_ARGS__) +#define LOG(...) rdp_log(M64MSG_VERBOSE, __VA_ARGS__) +#define LOGERROR(...) rdp_log(M64MSG_WARNING, __VA_ARGS__) + +#endif // RDP_DEBUG + + +#endif // _RDP_H_ diff --git a/libmupen64plus/mupen64plus-video-z64/src/rgl.cpp b/libmupen64plus/mupen64plus-video-z64/src/rgl.cpp new file mode 100644 index 0000000000..83842c1046 --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/rgl.cpp @@ -0,0 +1,1682 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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. + * +**/ + +/* + * + * TODO + * + * - hires framebuffer : scale them accordingly to the GL screen resolution + * + * - multitexturing avec tilenum == 7, ca marche comment ? + * --> tilenum=7 should be translated to tilenum=0 for triangle and texrec primitives + * + * - CvgXAlpha mode not really correct, effect probably depends on the texture format + * --> apparently fixed, Intensity textures shouldn't be affected by this effect + * --> correction : it had nothing to do with the texture format, but with + * the alpha_cvg_select flag + * + * - fix fbo depth clear in LEGO racer (also affects beetle and reflection in rally 99) + * (also affects Zelda OOT subscreen) + * --> DONE + * + * - frame buffer ordering (LEGO racer) + * --> DONE but required also less conservative framebuffer check + * + * - format conversion for hires framebuffers when required (CBFD , Banjo) + * --> DONE (quick hack) + * + * - some texture (4 ? 8 bits ?) problems + * --> either they're fixed, either I forgot which problem it was + * + * - mirrored textures + * --> done but rely on a GL extension, do we care ? + * + * - better blend + * --> mostly done slow way, now need to implement the quick way + * --> done faster way, seems to work reasonably well + * + * - need to sort out combiner clamp modes + * --> started but not complete + * --> the problem is much more complicated, it's not combiner clamping + * but coverage calculation modes. + * + * - fog !! + * --> done + * + * PROBLEMS + * + * - this list needs to be updated :) + * - links not always rendered in the subscreen + * --> depth clear problem, anything else ? FIXED + * - texture problems in beetle + * --> mostly fixed, it was multitexturing, the sky still has a weird problem though + * --> completely fixed at last (the sky uses tex2 in the second combiner cycle, + * which should be interpreted as tex1 (apparently tex2 isn't available in the + * second cycle) + * UPDATE : in fact tex1 and tex2 need to be swapped in the second step of + * the combiner, weird but it fixes a few other problems as well + * +**/ + +#include "rdp.h" +#include "rgl.h" + +#include + +//#define NOFBO +#define ZTEX +#define FBORGBA + +rglTexCache_t rglTexCache[0x1000]; +uint8_t rglTmpTex[1024*1024*4]; +uint8_t rglTmpTex2[1024*1024*4]; + +volatile int rglStatus, rglNextStatus; + +static int wireframe; + +static uint32_t old_vi_origin; + +int rglFrameCounter; + +extern int viewportOffset; +rglSettings_t rglSettings; + +rglDepthBuffer_t zBuffers[MAX_DEPTH_BUFFERS]; +int nbZBuffers; + +rglRenderBuffer_t rBuffers[MAX_RENDER_BUFFERS]; +int nbRBuffers; +rglRenderBuffer_t * curRBuffer; +rglRenderBuffer_t * curZBuffer; +rglRenderBufferHead_t rBufferHead; + +int rglTexCacheCounter = 1; + +rglTexture_t rglTextures[RGL_TEX_CACHE_SIZE]; + +rglRenderChunk_t chunks[MAX_RENDER_CHUNKS]; +rglRenderChunk_t * curChunk; +int nbChunks, renderedChunks; + +rglStrip_t strips[MAX_STRIPS]; +rglVertex_t vtxs[6*MAX_STRIPS]; +int nbStrips, nbVtxs; + +rglRenderMode_t renderModesDb[MAX_RENDER_MODES]; +int nbRenderModes; + +rglShader_t * rglCopyShader; +rglShader_t * rglCopyDepthShader; + +int rglScreenWidth = 320, rglScreenHeight = 240; + +#define CHECK_FRAMEBUFFER_STATUS() \ +{\ + GLenum status; \ + status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); \ + /*LOGERROR("%x\n", status);*/\ + switch(status) { \ + case GL_FRAMEBUFFER_COMPLETE_EXT: \ + /*LOGERROR("framebuffer complete!\n");*/\ + break; \ + case GL_FRAMEBUFFER_UNSUPPORTED_EXT: \ + LOGERROR("framebuffer GL_FRAMEBUFFER_UNSUPPORTED_EXT\n");\ + /* you gotta choose different formats */ \ + /*rglAssert(0);*/ \ + break; \ + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: \ + LOGERROR("framebuffer INCOMPLETE_ATTACHMENT\n");\ + break; \ + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: \ + LOGERROR("framebuffer FRAMEBUFFER_MISSING_ATTACHMENT\n");\ + break; \ + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: \ + LOGERROR("framebuffer FRAMEBUFFER_DIMENSIONS\n");\ + break; \ + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: \ + LOGERROR("framebuffer INCOMPLETE_FORMATS\n");\ + break; \ + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: \ + LOGERROR("framebuffer INCOMPLETE_DRAW_BUFFER\n");\ + break; \ + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: \ + LOGERROR("framebuffer INCOMPLETE_READ_BUFFER\n");\ + break; \ + case GL_FRAMEBUFFER_BINDING_EXT: \ + LOGERROR("framebuffer BINDING_EXT\n");\ + break; \ + default: \ + LOGERROR("framebuffer generic error\n");\ + break; \ + /* programming error; will fail on all hardware */ \ + /*rglAssert(0);*/ \ +}\ +} +/* + case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: \ + LOGERROR("framebuffer INCOMPLETE_DUPLICATE_ATTACHMENT\n");\ + break; \ +*/ + +rglDepthBuffer_t * rglFindDepthBuffer(uint32_t address, int width, int height) +{ + int i; + rglDepthBuffer_t * buffer; + for (i=0; iaddress = address; + buffer->width = width; + buffer->height = height; + + // glGenRenderbuffersEXT(1, &buffer->zbid); + // glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buffer->zbid); + // rglAssert(glGetError() == GL_NO_ERROR); + // glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, + // buffer->width, buffer->height); + // rglAssert(glGetError() == GL_NO_ERROR); + +#ifdef ZTEX + glGenTextures(1, &buffer->zbid); + rglAssert(glGetError() == GL_NO_ERROR); + glBindTexture(GL_TEXTURE_2D, buffer->zbid); + rglAssert(glGetError() == GL_NO_ERROR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, + buffer->width, buffer->height, 0, + GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); + rglAssert(glGetError() == GL_NO_ERROR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glBindTexture(GL_TEXTURE_2D, 0); +#else + glGenRenderbuffersEXT(1, &buffer->zbid); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buffer->zbid); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, + buffer->width, buffer->height); + +#endif + + return buffer; +} + +void rglDeleteRenderBuffer(rglRenderBuffer_t & buffer) +{ + buffer.mod.xl = buffer.mod.yl = 0; + buffer.mod.xh = buffer.mod.yh = 8192; + buffer.depthBuffer = 0; +#ifndef NOFBO + if (buffer.fbid) { + glDeleteFramebuffersEXT(1, &buffer.fbid); + buffer.fbid = 0; + } + if (buffer.texid) { + glDeleteTextures(1, &buffer.texid); + buffer.texid = 0; + } + buffer.nbDepthSections = 0; +#ifdef RGL_EXACT_BLEND + glDeleteFramebuffersEXT(1, &buffer.fbid2); + buffer.fbid2 = 0; + glDeleteTextures(1, &buffer.texid2); + buffer.texid2 = 0; +#endif +#endif +} + +void rglFullSync() +{ + if (rglSettings.forceSwap) + // hack for starwars, perfect dark subscreen to prevent filling up our chunk table + old_vi_origin = ~0; +} + +// note : if "same" is 1 then both tiles use the same texture, in this +// case we can't safely modify the clamping mode +void rglFixupMapping(rglStrip_t & strip, rglTile_t & tile, + float ds, float dt, float ss, float st, + float & dsm, float & dtm, int same) +{ + float mins = strip.vtxs[0].s; + float mint = strip.vtxs[0].t; + int i; + if ( (tile.mask_s && !tile.cs) || (tile.mask_t && !tile.ct) ) + for (i=1; i>4)); + else + dsm = 0; + if (tile.mask_t && !tile.ct) + dtm = -((int(mint+0.5f - tile.tl*float(1<<(tile.shift_t+4))/64.0f) + (tile.mt<>4)); + else + dtm = 0; + + if (rglSettings.hiresFb && tile.hiresBuffer) + return; + else { + GLuint wws = tile.ws, wwt = tile.wt; + + if (same || wws != GL_REPEAT) + goto skips; + for (i=0; i 1 || (a+0.5f)/ss < 0) { + goto skips; + } + } + //LOG("fixing S clamp\n"); + wws = GL_CLAMP_TO_EDGE; +skips: + if (tile.tex->ws != wws) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wws); + tile.tex->ws = wws; + } + + if (same || wwt != GL_REPEAT) + goto skipt; + for (i=0; i 1 || (a+0.5f)/st < 0) + goto skipt; + } + //LOG("fixing T clamp\n"); + wwt = GL_CLAMP_TO_EDGE; +skipt: + if (tile.tex->wt != wwt) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wwt); + tile.tex->wt = wwt; + } + } +} + +int rglUseTile(rglTile_t & tile, float & ds, float & dt, float & ss, float & st) +{ + int res = 0; + ds = -tile.sl*float(1<<(tile.shift_s+4))/64.0f; + dt = -tile.tl*float(1<<(tile.shift_t+4))/64.0f; + if (rglSettings.hiresFb && tile.hiresBuffer) { + rglRenderBuffer_t & hbuf = *tile.hiresBuffer; + // if (hbuf.flags & RGL_RB_DEPTH) { + // glBindTexture(GL_TEXTURE_2D, hbuf.depthBuffer->zbid); + // res = RGL_COMB_IN0_DEPTH; + // } else + glBindTexture(GL_TEXTURE_2D, hbuf.texid); + rglAssert(glGetError() == GL_NO_ERROR); + ss = -(hbuf.width<<(tile.shift_s+4)>>4); + st = -(hbuf.height<<(tile.shift_t+4)>>4); + ds = -ds - (((int32_t(tile.hiresAddress) - int32_t(hbuf.addressStart)) % hbuf.line) >> hbuf.size << 1); + dt = -dt - (int32_t(tile.hiresAddress) - int32_t(hbuf.addressStart)) / hbuf.line; + ss /= float(hbuf.realWidth)/hbuf.fboWidth; + st /= float(hbuf.realHeight)/hbuf.fboHeight; + ds = ss - ds; + dt = st - dt; + + DUMP("texture fb %p shift %g x %g (scale %g x %g) tile %d x %d (sl %d tl %d)\n", + &hbuf, ds, dt, ss, st, tile.w, tile.h, + tile.sl, tile.tl); + } else { + glBindTexture(GL_TEXTURE_2D, tile.tex->id); + rglAssert(glGetError() == GL_NO_ERROR); + ss = tile.w<<(tile.shift_s+4)>>4; st = tile.h<<(tile.shift_t+4)>>4; + + if (tile.tex->filter != tile.filter) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tile.filter); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tile.filter); + rglAssert(glGetError() == GL_NO_ERROR); + tile.tex->filter = tile.filter; + } + } + return res; +} + +void rglPrepareFramebuffer(rglRenderBuffer_t & buffer) +{ + //int olderased = buffer.flags & RGL_RB_ERASED; + + if (buffer.area.xh == 8192) + return; + + GLuint restoreId = 0, restoreFbid = 0; + float d2 = -1; + float d = 0; + float restoreW = buffer.width+d2, restoreH = buffer.height+d2; + int w, h; + restoreW *= float(buffer.fboWidth+d) / (buffer.realWidth+d); + restoreH *= float(buffer.fboHeight+d) / (buffer.realHeight+d); + + buffer.flags &= ~RGL_RB_ERASED; + + // buffer.width = ((buffer.area.xl - buffer.area.xh >>2) + 15)&~15; + // buffer.height = ((buffer.area.yl - buffer.area.yh >>2) + 15)&~15; + // buffer.width = ((buffer.area.xl >>2) + 3)&~3; + // buffer.height = ((buffer.area.yl >>2) + 3)&~3; + //buffer.width = ((buffer.area.xl >>2))&~7; + buffer.width = buffer.fbWidth; + //buffer.height = ((buffer.area.yl >>2))&~7; + buffer.height = ((buffer.area.yl >>2)); + if (!buffer.width) buffer.width = 1; + if (!buffer.height) buffer.height = 1; + + buffer.addressStop = buffer.addressStart + buffer.line * ((buffer.area.yl >>2)+1); + + if (rglSettings.lowres) { + buffer.realWidth = buffer.width; + buffer.realHeight = buffer.height; + } else { + if (buffer.width <= 128 || buffer.height <= 128) { + buffer.realWidth = buffer.width*4; + buffer.realHeight = buffer.height*4; + buffer.flags &= ~RGL_RB_FULL; + } else { + buffer.realWidth = screen_width * buffer.width / rglScreenWidth; + buffer.realHeight = screen_height * buffer.height / rglScreenHeight; + // buffer.realWidth = screen_width * buffer.width / vi_width; + // if (buffer.height > 250) + // buffer.realHeight = screen_height * buffer.height / 480; + // else + // buffer.realHeight = screen_height * buffer.height / 240; + buffer.flags |= RGL_RB_FULL; + } + } + + if (rglSettings.noNpotFbos) { + w = 1; h = 1; + while (w < buffer.realWidth) w <<= 1; + while (h < buffer.realHeight) h <<= 1; + } else { + w = buffer.realWidth; + h = buffer.realHeight; + } + +#ifndef NOFBO + if (buffer.fboWidth == w && buffer.fboHeight == h) + buffer.redimensionStamp = rglFrameCounter; + + if (buffer.fbid && + (//buffer.fboWidth < w || buffer.fboHeight < h || + (rglFrameCounter - buffer.redimensionStamp > 4))) { + LOG("Redimensionning buffer\n"); + restoreId = buffer.texid; + restoreFbid = buffer.fbid; + buffer.texid = buffer.fbid = 0; + rglDeleteRenderBuffer(buffer); + } + + DUMP("Render buffer %p at %x --> %x\n", &buffer, + buffer.addressStart, buffer.addressStop); + + if (!buffer.fbid) { + int glfmt; + switch (buffer.format) { + // case RDP_FORMAT_I: + // case RDP_FORMAT_CI: + // glfmt = GL_LUMINANCE; + // break; + default: +#ifdef FBORGBA + glfmt = GL_RGBA; +#else + glfmt = GL_RGB; +#endif + } + + LOG("creating fbo %x %dx%d (%dx%d) fmt %x\n", buffer.addressStart, buffer.width, buffer.height, w, h, buffer.format); + + buffer.fboWidth = w; + buffer.fboHeight = h; + +#ifdef RGL_EXACT_BLEND + glGenFramebuffersEXT(1, &buffer.fbid2); + rglAssert(glGetError() == GL_NO_ERROR); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid2); + + // FIXME we should not need to allocate a color texture for depth only rendering + if (1||!(buffer.flags & RGL_RB_DEPTH)) { + glGenTextures(1, &buffer.texid2); + rglAssert(glGetError() == GL_NO_ERROR); + glBindTexture(GL_TEXTURE_2D, buffer.texid2); + rglAssert(glGetError() == GL_NO_ERROR); + glTexImage2D(GL_TEXTURE_2D, 0, glfmt, w, h, 0, + glfmt, GL_UNSIGNED_BYTE, NULL); + rglAssert(glGetError() == GL_NO_ERROR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + rglAssert(glGetError() == GL_NO_ERROR); + glBindTexture(GL_TEXTURE_2D, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, + buffer.texid2, 0); + } +#endif + + if (restoreId) { + buffer.fbid = restoreFbid; + } else { + glGenFramebuffersEXT(1, &buffer.fbid); + rglAssert(glGetError() == GL_NO_ERROR); + } + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid); + + // FIXME we should not need to allocate a color texture for depth only rendering + if (1||!(buffer.flags & RGL_RB_DEPTH)) { + glGenTextures(1, &buffer.texid); + rglAssert(glGetError() == GL_NO_ERROR); + glBindTexture(GL_TEXTURE_2D, buffer.texid); + rglAssert(glGetError() == GL_NO_ERROR); + glTexImage2D(GL_TEXTURE_2D, 0, glfmt, w, h, 0, + glfmt, GL_UNSIGNED_BYTE, NULL); + rglAssert(glGetError() == GL_NO_ERROR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + rglAssert(glGetError() == GL_NO_ERROR); + glBindTexture(GL_TEXTURE_2D, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, + buffer.texid, 0); + + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0 ); + + if (!restoreId) { + glClearColor(0, 0, 0, 1); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glClear(GL_COLOR_BUFFER_BIT); + } else { + glViewport(0, 0, buffer.realWidth, buffer.realHeight); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDisable(GL_DEPTH_TEST); + glBindTexture(GL_TEXTURE_2D, restoreId); + rglUseShader(rglCopyShader); + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f((buffer.width+d2)/restoreW, 0); glVertex2f(1, 0); + glTexCoord2f(0, 0); glVertex2f(0, 0); + glTexCoord2f((buffer.width+d2)/restoreW, (buffer.height+d2)/restoreH); glVertex2f(1, 1); + glTexCoord2f(0, (buffer.height+d2)/restoreH); glVertex2f(0, 1); + glEnd(); + glDeleteTextures(1, &restoreId); + } + } + } else + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid); +#endif + + rglAssert(glGetError() == GL_NO_ERROR); + + // hack for LEGO racer, real fix coming soon + // if (olderased) + // { + // glDepthMask(GL_TRUE); + // glClearDepth(1); + // glClear(GL_DEPTH_BUFFER_BIT); + // } +} + +void rglRenderChunks(rglRenderBuffer_t * upto) +{ + if (upto->area.xh != 8192 && renderedChunks < upto->chunkId) + rglRenderChunks(upto->chunkId); +} + +void rglRenderChunks(int upto) +{ + int i; + //printf("vi_origin %x nbChunks %d\n", vi_origin, nbChunks); + rglRenderBuffer_t * lastBuffer = 0; + uint32_t lastDepthAddress = ~0; + float zb = 0.0f; + + DUMP("rendering chunks upto %d / %d\n", upto, nbChunks); + + glEnable(GL_SCISSOR_TEST); + for (i=renderedChunks; inbDepthSections) { + // reselect the renderbuffer with correct width (needed by LEGO racer, + // because they clear a 320x240 depth buffer to render in small 64x64 framebuffer) + // and adjust the area to the associated color buffer + // no need to optimize this search because it's rare (i.e. mainly depth clear, + // so once per frame) + for (j=chunk.renderBuffer->nbDepthSections-1; j>=0; j--) { + // LOG("j %d %d %d %d\n", j, i, chunk.renderBuffer->depthSections[j].chunkId, + // chunk.renderBuffer->depthSections[j].buffer - rBuffers); + if (i >= chunk.renderBuffer->depthSections[j].chunkId) + break; + } + //rglAssert(j < chunk.renderBuffer->nbDepthSections-1); + if (j < chunk.renderBuffer->nbDepthSections-1) { + rglRenderBuffer_t * cbuffer = chunk.renderBuffer->depthSections[j+1].buffer; + chunk.renderBuffer = rglSelectRenderBuffer(chunk.renderBuffer->addressStart, cbuffer->fbWidth, chunk.renderBuffer->size, chunk.renderBuffer->format); + chunk.renderBuffer->area = cbuffer->area; + chunk.renderBuffer->flags |= RGL_RB_DEPTH; + } + } + + rglRenderBuffer_t & buffer = *chunk.renderBuffer; + int oldFlags = ~0; + int oldTilenum = ~0; + int combFormat = 0; + + rglAssert(buffer.area.xh != 8192); + + if (lastBuffer != &buffer) + rglPrepareFramebuffer(buffer); + + DUMP("Buffer %p at %x area %d -> %d x %d -> %d\n", + &buffer, buffer.addressStart, + buffer.area.xh>>2, buffer.area.xl>>2, + buffer.area.yh>>2, buffer.area.yl>>2); + // if (buffer.addressStart != vi_origin) + // continue; + + if (buffer.flags & RGL_RB_DEPTH) + chunk.depthAddress = buffer.addressStart; + + if (lastBuffer != &buffer || + lastDepthAddress != chunk.depthAddress) { + lastBuffer = &buffer; + lastDepthAddress = chunk.depthAddress; + int j; + for (j=0; j %x with %x --> %x overlap %x\n", + // j, + // rBuffers[j].addressStart, rBuffers[j].addressStop, + // buffer.addressStart, buffer.addressStop, + // overlap); + // check if more than 10% of the buffer was erased + if (rBuffers+j != &buffer && + overlap > int(rBuffers[j].addressStop - rBuffers[j].addressStart)/10 + // rBuffers[j].addressStop > buffer.addressStart && + // rBuffers[j].addressStart < buffer.addressStop + ) { + rBuffers[j].flags |= RGL_RB_ERASED; + DUMP("erasing fb #%d\n", j); + } + } + +#ifndef NOFBO + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid); + + rglDepthBuffer_t * zbuf = rglFindDepthBuffer(chunk.depthAddress, + buffer.fboWidth, buffer.fboHeight); + if (zbuf != buffer.depthBuffer) { + buffer.depthBuffer = zbuf; +#ifdef ZTEX + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, + GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, + buffer.depthBuffer->zbid, 0); +#else + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, buffer.depthBuffer->zbid ); +#endif + // glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, + // GL_RENDERBUFFER_EXT, depthBuffer->zbid ); + + CHECK_FRAMEBUFFER_STATUS(); + } +#endif + + glViewport(0, 0, buffer.realWidth, buffer.realHeight); + } + + if (chunk.rdpState.clip.yl < chunk.rdpState.clip.yh || + chunk.rdpState.clip.xl < chunk.rdpState.clip.xh) + continue; + + glScissor((chunk.rdpState.clip.xh >>2)*buffer.realWidth/buffer.width, + (chunk.rdpState.clip.yh >>2)*buffer.realHeight/buffer.height, + ((chunk.rdpState.clip.xl-chunk.rdpState.clip.xh) >>2)*buffer.realWidth/buffer.width, + ((chunk.rdpState.clip.yl-chunk.rdpState.clip.yh) >>2)*buffer.realHeight/buffer.height); + rglAssert(glGetError() == GL_NO_ERROR); + +#ifndef NOFBO +#ifdef RGL_EXACT_BLEND + glPushAttrib(GL_ALL_ATTRIB_BITS); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid2); + glBindTexture(GL_TEXTURE_2D, buffer.texid); + glEnable(GL_TEXTURE_2D); + rglUseShader(rglCopyShader); + glColor4ub(255,255,255,255); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDisable(GL_DEPTH_TEST); + + for (j=0; jrdpState.otherModes) < 2) + // glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + // else + // glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + + if (strip.flags & RGL_STRIP_TEX1) + rglFixupMapping(strip, tile, + ds[0], dt[0], ss[0], st[0], dsm[0], dtm[0], + (strip.flags & RGL_STRIP_TEX2) && tile.tex == tile2.tex); + if (strip.flags & RGL_STRIP_TEX2) { + glActiveTextureARB(GL_TEXTURE2_ARB); + rglFixupMapping(strip, tile2, + ds[1], dt[1], ss[1], st[1], dsm[1], dtm[1], + (strip.flags & RGL_STRIP_TEX1) && tile.tex == tile2.tex); + glActiveTextureARB(GL_TEXTURE0_ARB); + } + + glBegin(GL_TRIANGLE_STRIP); + for (k=0; k but it seems less precise ! + glMultiTexCoord2fARB(GL_TEXTURE1_ARB, + buffer.realWidth/2048.f, + buffer.realHeight/2048.f); +#endif + // if (ds || dt || ss!=1 || st!=1) { + // printf("%g x %g --> %g x %g\n", + // strip.vtxs[k].s*tile.w, + // strip.vtxs[k].t*tile.h, + // (strip.vtxs[k].s + ds) * ss, + // (strip.vtxs[k].t + dt) * st); + // } + + float + x = strip.vtxs[k].x*strip.vtxs[k].w, + y = strip.vtxs[k].y*strip.vtxs[k].w; + + if (buffer.flags & RGL_RB_DEPTH) + glVertex3f((strip.vtxs[k].x/(buffer.width)), + (strip.vtxs[k].y/(buffer.height)), + //rglZscale(chunk.rdpState.fillColor&0xffff)); + float(chunk.rdpState.fillColor&0xffff)/0xffff); + // glVertex4f((strip.vtxs[k].x/(buffer.width))*strip.vtxs[k].w, + // (strip.vtxs[k].y/(buffer.height))*strip.vtxs[k].w, + // float(chunk.rdpState.fillColor&0xffff)/0xffff*strip.vtxs[k].w, + // strip.vtxs[k].w); + else { + // glVertex4f(x/buffer.width, y/buffer.height, + // (strip.vtxs[k].z - 1.5f*zb)*(strip.vtxs[k].w), + // strip.vtxs[k].w); + + float iw = strip.vtxs[k].w; + if (iw > 1000) { + glVertex4f(x/buffer.width, y/buffer.height, + (strip.vtxs[k].z - 1.5f*zb)*strip.vtxs[k].w, + strip.vtxs[k].w); + } else { + iw = 1.0f/iw; + glVertex4f(x/buffer.width, y/buffer.height, + (strip.vtxs[k].z) / (iw + zb*0.35f), + strip.vtxs[k].w); + } + // glVertex4f(x/buffer.width, y/buffer.height, + // (strip.vtxs[k].z)*strip.vtxs[k].w, + // strip.vtxs[k].w); + } + + if (x < chunk.rdpState.clip.xh/4) + x = chunk.rdpState.clip.xh/4; + if (x > chunk.rdpState.clip.xl/4) + x = chunk.rdpState.clip.xl/4; + if (y < chunk.rdpState.clip.yh/4) + y = chunk.rdpState.clip.yh/4; + if (y > chunk.rdpState.clip.yl/4) + y = chunk.rdpState.clip.yl/4; + if (buffer.mod.xh > x) + buffer.mod.xh = x; + if (buffer.mod.xl < x) + buffer.mod.xl = x; + if (buffer.mod.yh > y) + buffer.mod.yh = y; + if (buffer.mod.yl < y) + buffer.mod.yl = y; + + } + glEnd(); + + // FIXME + // glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + } + + buffer.flags |= RGL_RB_FBMOD; + +#ifdef RGL_EXACT_BLEND + glActiveTextureARB(GL_TEXTURE1_ARB); + glDisable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTextureARB(GL_TEXTURE0_ARB); +#endif + } + + glActiveTextureARB(GL_TEXTURE2_ARB); + glDisable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTextureARB(GL_TEXTURE0_ARB); + + renderedChunks = i; +} + +void rglDisplayFramebuffers() +{ + if (!(vi_control & 3)) + return; + +#ifdef RDP_DEBUG + extern int nbFullSync; + LOG("nbFyllSync %d\n", nbFullSync); + nbFullSync = 0; +#endif + + int height = (vi_control & 0x40) ? 480 : 240; + int width = vi_width; + + // from glide64 + DWORD scale_x = *gfx.VI_X_SCALE_REG & 0xFFF; + if (!scale_x) return; + DWORD scale_y = *gfx.VI_Y_SCALE_REG & 0xFFF; + if (!scale_y) return; + + float fscale_x = (float)scale_x / 1024.0f; + float fscale_y = (float)scale_y / 1024.0f; + + DWORD dwHStartReg = *gfx.VI_H_START_REG; + DWORD dwVStartReg = *gfx.VI_V_START_REG; + + DWORD hstart = dwHStartReg >> 16; + DWORD hend = dwHStartReg & 0xFFFF; + + // dunno... but sometimes this happens + if (hend == hstart) { + LOG("fix hend\n"); + hend = (int)(*gfx.VI_WIDTH_REG / fscale_x); + } + + if (hstart > hend) { + DWORD tmp=hstart; hstart=hend; hend=tmp; + LOG("swap hstart hend\n"); + } + + DWORD vstart = dwVStartReg >> 16; + DWORD vend = dwVStartReg & 0xFFFF; + + if (vstart > vend) { + DWORD tmp=vstart; vstart=vend; vend=tmp; + LOG("swap vstart vend\n"); + } + + //if (*gfx.VI_WIDTH_REG != 0x500) + if (*gfx.VI_WIDTH_REG < 0x400) + fscale_y /= 2.0f; + + // fscale_x *= screen_width / float(vi_width); + // fscale_y *= screen_height / height; + //glViewport(0*hstart*fscale_x, 0*vstart*fscale_y, (hend-hstart)*fscale_x, (vend-vstart)*fscale_y); + width = (hend-hstart)*fscale_x; + height = (vend-vstart)*fscale_y; + if (!width || !height) return; + static int oldw, oldh; + if (width == oldw && width > 200) + rglScreenWidth = width; + if (height == oldh && height > 200) + rglScreenHeight = height; + oldw = width; + oldh = height; + int vi_line = vi_width * 2; // TODO take in account the format + int vi_start = *gfx.VI_ORIGIN_REG;// - vi_line; + int vi_stop = vi_start + height * vi_line; + + + if (*gfx.VI_WIDTH_REG >= 0x400) + vi_line /= 2; + + DUMP("%x screen %x --> %x %d --> %d x %d --> %d scale %g x %g clip %g --> %g x %g --> %g %dx%d\n", + vi_line, + vi_start, vi_stop, + hstart, hend, vstart, vend, + fscale_x, fscale_y, + hstart*fscale_x, hend*fscale_x, vstart*fscale_y, vend*fscale_y, + width, height + ); + + +#ifdef NOFBO + return; +#endif + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glDrawBuffer(GL_BACK); + glViewport(0, viewportOffset, screen_width, screen_height); + glDisable(GL_SCISSOR_TEST); + // wine seems to catch scissor test disabling so need to define an area nevertheless + glScissor(0, viewportOffset, screen_width, screen_height); + glClearColor(0, 0, 0, 0); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glClear(GL_COLOR_BUFFER_BIT); // TODO clear a minimal area + + rglRenderBuffer_t * buffer; + CIRCLEQ_FOREACH(rglRenderBuffer_t, buffer, &rBufferHead, link) + if (!(buffer->flags & RGL_RB_ERASED) && + (uint32_t)vi_stop > buffer->addressStart && + (uint32_t)vi_start < buffer->addressStop) { + + if (buffer->size != 2 || buffer->format != RDP_FORMAT_RGBA) + continue; // FIXME + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glDrawBuffer(GL_BACK); + glViewport(0, viewportOffset, screen_width, screen_height); + + glDisable(GL_SCISSOR_TEST); + // wine seems to catch scissor test disabling so need to define an area nevertheless + glScissor(0, viewportOffset, screen_width, screen_height); + + glDisable(GL_ALPHA_TEST); + glDisable(GL_BLEND); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glActiveTextureARB(GL_TEXTURE1_ARB); + glDisable(GL_TEXTURE_2D); + glActiveTextureARB(GL_TEXTURE0_ARB); + + + + float x = (int32_t(buffer->addressStart - vi_start) % int(vi_line)) / 2; + float y = height - buffer->height - (int32_t(buffer->addressStart - vi_start) / int(vi_line)); + //x=y=0; + DUMP("displaying fb %x %d x %d (%d x %d) at %g x %g\n", buffer->addressStart, + buffer->width, buffer->height, + buffer->realWidth, buffer->realHeight, + x, y); + y -= *gfx.VI_V_CURRENT_LINE_REG & 1; // prevent interlaced modes flickering + x = x / width; + y = y / height; + rglUseShader(rglCopyShader); + glBindTexture(GL_TEXTURE_2D, buffer->texid); + glEnable(GL_TEXTURE_2D); + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + glColor4ub(255, 255, 255, 255); + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(float(buffer->realWidth)/buffer->fboWidth, float(buffer->realHeight)/buffer->fboHeight); glVertex2f(x+float(buffer->width-1)/(width-1), y+0); + glTexCoord2f(0, float(buffer->realHeight)/buffer->fboHeight); glVertex2f(x+0, y+0); + glTexCoord2f(float(buffer->realWidth)/buffer->fboWidth, 0); glVertex2f(x+float(buffer->width-1)/(width-1), y+float(buffer->height-1)/(height-1)); + glTexCoord2f(0, 0); glVertex2f(x+0, y+float(buffer->height-1)/(height-1)); + glEnd(); + } +} + +void rglUpdate() +{ + int i; + + if (old_vi_origin == vi_origin) { + //printf("same\n"); + return; + } + old_vi_origin = vi_origin; + + DUMP("updating vi_origin %x vi_hstart %d vi_vstart %d\n", + vi_origin, *gfx.VI_H_START_REG, *gfx.VI_V_START_REG); + + glPolygonMode(GL_FRONT_AND_BACK, wireframe? GL_LINE : GL_FILL); + + rglRenderChunks(nbChunks); + + rglDisplayFramebuffers(); + +#ifndef NOFBO + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); +#endif + rglUseShader(0); + glDrawBuffer(GL_BACK); + rglSwapBuffers(); + + rglFrameCounter++; + + // for (i=0; i=0; i--) + if (rBuffers[i].addressStart == addr && + rBuffers[i].fbWidth == width && + rBuffers[i].size == size) + break; + + if (i >= 0) { + return rBuffers + i; + // TODO need to take care of framebuffer format possible change (?) + } + + rglAssert(nbRBuffers < MAX_RENDER_BUFFERS); + // if (nbRBuffers == MAX_RENDER_BUFFERS) + // rglClearRenderBuffers(); + + i = nbRBuffers++; + rglRenderBuffer_t * cur = rBuffers + i; + + cur->addressStart = addr; + cur->format = format; + cur->size = size; + cur->fbWidth = width; + cur->area = rdpState.clip; + cur->line = (width << size >> 1); + cur->flags = 0; + CIRCLEQ_INSERT_HEAD(rglRenderBuffer_t, &rBufferHead, cur, link); + return cur; +} + +void rglPrepareRendering(int texturing, int tilenum, int recth, int depth) +{ + if (!rdpChanged) + goto ok; + + //rglUpdate(); + + depth = /*depth && */(RDP_GETOM_CYCLE_TYPE(rdpState.otherModes) < 2) && + (RDP_GETOM_Z_UPDATE_EN(rdpState.otherModes) || + RDP_GETOM_Z_COMPARE_EN(rdpState.otherModes)); + + if (curRBuffer) + curRBuffer->chunkId = nbChunks; + + if (!curZBuffer || + (rdpChanged & (RDP_BITS_ZB_SETTINGS | RDP_BITS_FB_SETTINGS)) || + curZBuffer->addressStart != rdpZbAddress) { + // first search the most recent without considering the width of the buffer + rglRenderBuffer_t * buf; + curZBuffer = 0; + CIRCLEQ_FOREACH(rglRenderBuffer_t, buf, &rBufferHead, link) + if (buf->addressStart == rdpZbAddress) { + curZBuffer = buf; + break; + } + if (!curZBuffer) { + curZBuffer = rglSelectRenderBuffer(rdpZbAddress, rdpFbWidth, 2, RDP_FORMAT_RGBA); + CIRCLEQ_REMOVE(&rBufferHead, curZBuffer, link); + CIRCLEQ_INSERT_HEAD(rglRenderBuffer_t, &rBufferHead, curZBuffer, link); + } + } + + if (rdpChanged & (RDP_BITS_ZB_SETTINGS | RDP_BITS_FB_SETTINGS)) { + curRBuffer = rglSelectRenderBuffer(rdpFbAddress, rdpFbWidth, rdpFbSize, rdpFbFormat); + CIRCLEQ_REMOVE(&rBufferHead, curRBuffer, link); + CIRCLEQ_INSERT_HEAD(rglRenderBuffer_t, &rBufferHead, curRBuffer, link); + } + + if (rdpChanged & (RDP_BITS_TMEM | RDP_BITS_TLUT | RDP_BITS_TILE_SETTINGS)) + rglTouchTMEM(); + + if (rdpChanged & (RDP_BITS_CLIP | RDP_BITS_ZB_SETTINGS | RDP_BITS_FB_SETTINGS) && + rdpState.clip.xh <= rdpState.clip.xl && rdpState.clip.yh <= rdpState.clip.yl) + { + if (curRBuffer->area.xh == 8192) + curRBuffer->flags &= ~RGL_RB_HASTRIANGLES; + + if (curRBuffer->area.xh > rdpState.clip.xh) + curRBuffer->area.xh = rdpState.clip.xh; + if (curRBuffer->area.xl < rdpState.clip.xl) + curRBuffer->area.xl = rdpState.clip.xl; + if (curRBuffer->area.yh > rdpState.clip.yh) + curRBuffer->area.yh = rdpState.clip.yh; + if (curRBuffer->area.yl < rdpState.clip.yl) + curRBuffer->area.yl = rdpState.clip.yl; + } + + curRBuffer->chunkId = nbChunks; // don't include THIS chunk yet in case of feedback rendering (cf CBFD) + // if (curZBuffer) + // curZBuffer->chunkId = nbChunks; + + curChunk = chunks + nbChunks++; + rglAssert(nbChunks < MAX_RENDER_CHUNKS); + + curChunk->strips = strips + nbStrips; + curChunk->nbStrips = 0; + curChunk->renderBuffer = curRBuffer; + curChunk->flags = 0; + curChunk->rdpState = rdpState; + curChunk->depthAddress = rdpZbAddress; + +#ifdef RDP_DEBUG + curChunk->tracePos = rdpTracePos; +#endif + + if (depth) { + curZBuffer->flags |= RGL_RB_DEPTH; + //rglRenderChunks(curZBuffer); + + if (rdpFbAddress != rdpZbAddress) { + if (!curZBuffer->nbDepthSections || + curZBuffer->depthSections[curZBuffer->nbDepthSections-1].buffer != curRBuffer) { + rglAssert(curZBuffer->nbDepthSections < RGL_MAX_DEPTH_SECTIONS); + curZBuffer->depthSections[curZBuffer->nbDepthSections].buffer = curRBuffer; + curZBuffer->nbDepthSections++; + } + curZBuffer->depthSections[curZBuffer->nbDepthSections-1].chunkId = nbChunks; + } + } + + { + // eliminate useless bits + int cycle = RDP_GETOM_CYCLE_TYPE(curChunk->rdpState.otherModes); + curChunk->rdpState.otherModes.w2 &= rdpBlendMasks[cycle].w2; + curChunk->rdpState.combineModes.w1 &= rdpCombineMasks[cycle].w1; + curChunk->rdpState.combineModes.w2 &= rdpCombineMasks[cycle].w2; + } + + rdpChanged = 0; + +ok: + if (texturing && !(curChunk->flags & (1<flags |= (1<tiles[tilenum], recth); + } +} + + +void rglClose() +{ + +#ifdef RDP_DEBUG + rglCloseDebugger(); +#endif + + rglClearRenderBuffers(); + + rglResetTextureCache(); + + nbChunks = 0; + nbStrips = 0; + nbVtxs = 0; + + if (rglCopyShader) rglDeleteShader(rglCopyShader); + rglCopyShader = 0; + if (rglCopyDepthShader) rglDeleteShader(rglCopyDepthShader); + rglCopyDepthShader = 0; + rglClearCombiners(); +} + + +int rglInit() +{ + static int init; + if (!init) { + init = 1; + glewInit(); + } + + glViewport(0, 0, screen_width, screen_height); + + glLoadIdentity(); +#ifdef NOFBO + glScalef(2, -2, 1); +#else + glScalef(2, 2, 1); +#endif + glTranslatef(-0.5, -0.5, 0); + + glEnable(GL_DEPTH_TEST); + + rglClose(); + + rglCopyShader = rglCreateShader( + "void main() \n" + "{ \n" + " gl_Position = ftransform(); \n" + " gl_FrontColor = gl_Color; \n" + " gl_TexCoord[0] = gl_MultiTexCoord0; \n" + "} \n" + , + "uniform sampler2D texture0; \n" + " \n" + "void main() \n" + "{ \n" + " gl_FragColor = gl_Color * texture2D(texture0, vec2(gl_TexCoord[0])); \n" + "} \n" + ); + + rglCopyDepthShader = rglCreateShader( + "void main() \n" + "{ \n" + " gl_Position = ftransform(); \n" + " gl_FrontColor = gl_Color; \n" + " gl_TexCoord[0] = gl_MultiTexCoord0; \n" + "} \n" + , + "uniform sampler2D texture0; \n" + " \n" + "void main() \n" + "{ \n" + " gl_FragDepth = texture2D(texture0, vec2(gl_TexCoord[0]))[0]; \n" + "} \n" + ); + + rdpChanged = ~0; + return 1; +} + + +#ifdef __cplusplus +extern "C" { +#endif + + EXPORT void CALL FBWrite(DWORD addr, DWORD size) + { + if (!rglSettings.fbInfo || rglSettings.async) + return; + //LOG("FBWrite %x\n", addr); + rglRenderBuffer_t * buffer; + addr &= 0x7fffff; + CIRCLEQ_FOREACH(rglRenderBuffer_t, buffer, &rBufferHead, link) { + if (addr >= buffer->addressStart && addr+size <= buffer->addressStop) { + //LOG("FBWrite in fb #%d\n", buffer - rBuffers); + buffer->flags &= ~RGL_RB_FBMOD; + buffer->mod.xl = buffer->mod.yl = 0; + buffer->mod.xh = buffer->mod.yh = 8192; + //break; + } + } + //LOG("FBWrite %x %d\n", addr, size); + } + + //EXPORT void CALL FBWList(FrameBufferModifyEntry *plist, DWORD size) + //{ + // LOG("FBWList size %d\n", size); + //} + + EXPORT void CALL FBRead(DWORD addr) + { + if (!rglSettings.fbInfo || rglSettings.async) + return; + //LOG("FBRead %x\n", addr); + rglRenderBuffer_t * buffer; + addr &= 0x7fffff; + CIRCLEQ_FOREACH(rglRenderBuffer_t, buffer, &rBufferHead, link) { + if (addr >= buffer->addressStart && addr < buffer->addressStop) { + // LOG("writing to rdram buffer %x --> %x\n", + // buffer->addressStart, buffer->addressStop); + rglFramebuffer2Rdram(*buffer, buffer->addressStart, buffer->addressStop); + break; + } + } + } + + EXPORT void CALL FBGetFrameBufferInfo(void *p) + { + typedef struct + { + DWORD addr; + DWORD size; + DWORD width; + DWORD height; + } FrameBufferInfo; + + FrameBufferInfo * pinfo = (FrameBufferInfo *)p; + int i; + + if (!rglSettings.fbInfo) + return; + //LOG("GetFbInfo\n"); + + rglRenderBuffer_t * buffer; + i=0; + CIRCLEQ_FOREACH(rglRenderBuffer_t, buffer, &rBufferHead, link) { + // printf("#%d (%dx%d) %x --> %x\n", i, + // buffer->width, buffer->height, + // buffer->addressStart, + // buffer->addressStart + buffer->width*buffer->height*2); + pinfo[i].addr = buffer->addressStart; + pinfo[i].size = 2; // FIXME + pinfo[i].width = buffer->width; + pinfo[i].height = buffer->height; + i++; if (i>=6) break; + } + for ( ; i<6; i++) { + pinfo[i].addr = 0; + pinfo[i].size = 0; + pinfo[i].width = 4; + pinfo[i].height = 4; + } + } + + +#ifdef __cplusplus +} +#endif + +static char exptable[256]; + +static void build_exptable() +{ + LOG("Building depth exp table\n"); + int i; + for (i=0; i<256; i++) { + int s; + for (s=0; s<7; s++) + if (!(i&(1<<(6-s)))) + break; + exptable[i] = s; + } +} + +void rglFramebuffer2Rdram(rglRenderBuffer_t & buffer, uint32_t start, uint32_t stop) +{ + int depth; + + rglRenderChunks(&buffer); + + if (!(buffer.flags & RGL_RB_FBMOD)) + return; + + // if (buffer.area.xh == 8192) + // return; + // rglAssert (buffer.area.xh != 8192); + + depth = buffer.flags & RGL_RB_DEPTH; + //depth = 1; + + int glfmt, packed; + int x, y; + int rw, rh; + int rx, ry; + uint8_t * ram = gfx.RDRAM + buffer.addressStart; + static uint8_t * fb = rglTmpTex; + if (depth) { + glfmt = GL_DEPTH_COMPONENT; + //packed = GL_UNSIGNED_SHORT; + packed = GL_FLOAT; + } else { + glfmt = GL_RGBA; + packed = GL_UNSIGNED_BYTE; + } + + rx = buffer.mod.xh; + ry = buffer.mod.yh; + rw = (int(buffer.mod.xl) - int(buffer.mod.xh)); + rh = (int(buffer.mod.yl) - int(buffer.mod.yh)); + + if (rw > buffer.fbWidth) + rw = buffer.fbWidth; + + LOG("writing to rdram %x %s-%d %d %dx%d %dx%d %dx%d\n", + buffer.addressStart, depth? "depth":rdpImageFormats[buffer.format], buffer.size, + buffer.fbWidth, + buffer.width, buffer.height, + rx, ry, + rw, rh); + fflush(stderr); + + if (rw <= 0 || rh <= 0) + return; + + // rx=ry=0; + // rw = buffer.width; + // rh = buffer.height; + + glPushAttrib(GL_ALL_ATTRIB_BITS); +#ifndef NOFBO + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); +#endif + glDrawBuffer(GL_BACK); + glReadBuffer(GL_BACK); + glDisable(GL_SCISSOR_TEST); + glViewport(0, 0, buffer.width, buffer.height); // FIXME why +1 ? + // wine seems to catch scissor test disabling so need to define an area nevertheless + glScissor(0, 0, buffer.width+1, buffer.height+1); + glEnable(GL_TEXTURE_2D); + glDisable( GL_ALPHA_TEST ); + if (depth) { + glBindTexture(GL_TEXTURE_2D, buffer.depthBuffer->zbid); + rglUseShader(rglCopyDepthShader); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_TRUE); + glDisable( GL_POLYGON_OFFSET_FILL ); + } else { + glBindTexture(GL_TEXTURE_2D, buffer.texid); + rglUseShader(rglCopyShader); + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + glColor4ub(255, 255, 255, 255); + } + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(1, 1); glVertex2f(1, 1); + glTexCoord2f(0, 1); glVertex2f(0, 1); + glTexCoord2f(1, 0); glVertex2f(1, 0); + glTexCoord2f(0, 0); glVertex2f(0, 0); + glEnd(); + + glReadPixels(rx, ry, rw, rh, + glfmt, packed, + fb); + + + if (depth) { + if (!exptable[255]) + build_exptable(); + for (x=rx; x>(18-8)]; + + a = ( ( (e>=6? a : (a>>(6-e))) & ((1<<11)-1) ) << 2 ) | (e<<(16-3)); + + *(uint16_t *)&ram[(x*2 + y*buffer.line) ^ 2] = + a; + //int(*(uint16_t *)&fb[(x-rx)*2 + (y-ry)*rw*2])-2; + //(*(uint16_t *)&fb[(x-rx)*2 + (y-ry)*rw*2] - int(0x8000))*2; + //(*(float *)&fb[(x-rx)*4 + (y-ry)*rw*4]-0.5)*0x1ffff; + } + } else { + switch (buffer.size) { + case 1: + for (x=rx; x>2) | + ((a&0x80)>>7); + } + break; + } + } + + buffer.mod.xl = buffer.mod.yl = 0; + buffer.mod.xh = buffer.mod.yh = 8192; + + //if (start <= buffer.addressStart && stop >= buffer.addressStop) + buffer.flags &= ~RGL_RB_FBMOD; + + glPopAttrib(); +} + +void rglUpdateStatus() +{ + if (rglNextStatus != rglStatus) { + const char * status[] = { "closed", "windowed", "fullscreen" }; + LOG("Status %s --> %s\n", status[rglStatus], status[rglNextStatus]); + rglCloseScreen(); + rglStatus = rglNextStatus; + if (rglNextStatus != RGL_STATUS_CLOSED) + rglOpenScreen(); + } +} diff --git a/libmupen64plus/mupen64plus-video-z64/src/rgl.h b/libmupen64plus/mupen64plus-video-z64/src/rgl.h new file mode 100644 index 0000000000..c15f93fb1b --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/rgl.h @@ -0,0 +1,279 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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 _RGL_H_ +#define _RGL_H_ + +#include "queue.h" +#include "rgl_assert.h" +#include "rdp.h" + +#include +#if defined(__MACOSX__) +#include +#elif defined(__MACOS__) +#include +#else +#include +#endif + +#ifdef RDP_DEBUG +//#include +#endif + +#include "glshader.h" + +#include //for PATH_MAX + +#define DWORD unsigned int +extern GFX_INFO gfx; +#define rdram ((uint32_t*)gfx.RDRAM) +#define rsp_imem ((uint32_t*)gfx.IMEM) +#define rsp_dmem ((uint32_t*)gfx.DMEM) +#define vi_origin (*(uint32_t*)gfx.VI_ORIGIN_REG) +#define vi_width (*(uint32_t*)gfx.VI_WIDTH_REG) +#define vi_control (*(uint32_t*)gfx.VI_STATUS_REG) + +#define dp_start (*(uint32_t*)gfx.DPC_START_REG) +#define dp_end (*(uint32_t*)gfx.DPC_END_REG) +#define dp_current (*(uint32_t*)gfx.DPC_CURRENT_REG) +#define dp_status (*(uint32_t*)gfx.DPC_STATUS_REG) + +// highly experimental AND slow +//#define RGL_EXACT_BLEND + +struct rglSettings_t { + int hiresFb; + int resX, resY; + int fsResX, fsResY; + int fbInfo; + int forceSwap; + int threaded; + int async; + int noNpotFbos; + int lowres; + int fullscreen; +}; + +extern rglSettings_t rglSettings; +extern void (*render_callback)(int); + +struct rglDepthBuffer_t { + uint32_t address; + int width, height; + GLuint zbid; +}; +#define MAX_DEPTH_BUFFERS 16 +extern rglDepthBuffer_t zBuffers[MAX_DEPTH_BUFFERS]; +extern int nbZBuffers; + +struct rglRenderBuffer_t; +struct rglDepthSection_t { + rglRenderBuffer_t * buffer; + int chunkId; +}; +#define RGL_MAX_DEPTH_SECTIONS 16 + +struct rglRenderBuffer_t { + CIRCLEQ_ENTRY(rglRenderBuffer_t) link; + uint32_t addressStart, addressStop; + int format, size, fbWidth, line; + int width, height; + int flags; + GLuint texid, fbid; +#ifdef RGL_EXACT_BLEND + GLuint texid2, fbid2; +#endif + int realWidth, realHeight; + int fboWidth, fboHeight; + int redimensionStamp; + rdpRect_t area; + rdpRect_t mod; + rglDepthBuffer_t * depthBuffer; + int chunkId; + rglDepthSection_t depthSections[16]; + int nbDepthSections; +}; +#define RGL_RB_DEPTH 1 +#define RGL_RB_FULL 2 +#define RGL_RB_ERASED 4 +#define RGL_RB_FBMOD 8 // the GL framebuffer was modified +#define RGL_RB_RAMMOD 16 // the framebuffer was modified in rdram +#define RGL_RB_HASTRIANGLES 32 // we assume it's not a depth buffer in this case + +CIRCLEQ_HEAD(rglRenderBufferHead_t, rglRenderBuffer_t); + +#define MAX_RENDER_BUFFERS 64 +extern rglRenderBuffer_t rBuffers[MAX_RENDER_BUFFERS]; +extern int nbRBuffers; +extern rglRenderBuffer_t * curRBuffer; +extern rglRenderBuffer_t * curZBuffer; +extern rglRenderBufferHead_t rBufferHead; + +extern int rglTexCacheCounter; +struct rglTexture_t { + CIRCLEQ_ENTRY(rglTexture_t) byCrc, byUsage; + GLuint id, zid; + uint32_t crc; + int w, h, fmt; + int clipw, cliph; + GLuint ws, wt, filter; // current settings +}; +CIRCLEQ_HEAD(rglTextureHead_t, rglTexture_t); +#define RGL_TEX_CACHE_SIZE 1024 +extern rglTexture_t rglTextures[RGL_TEX_CACHE_SIZE]; +struct rglTexCache_t { + int counter; + rglTexture_t * tex; +}; +extern rglTexCache_t rglTexCache[0x1000]; +extern uint8_t rglTmpTex[]; +extern uint8_t rglTmpTex2[]; + +struct rglTile_t : public rdpTile_t { + rglTexture_t * tex; + rglRenderBuffer_t * hiresBuffer; + uint32_t hiresAddress; + GLuint ws, wt; // GL clamping modes + GLuint filter; // GL filter mode +}; + +struct rglVertex_t { + float x, y, z, w; + float s, t; + uint8_t r, g, b, a; +}; + +struct rglStrip_t { + int tilenum; + int nbVtxs; + int flags; + rglVertex_t * vtxs; +}; + +#define RGL_STRIP_TEX1 1 +#define RGL_STRIP_TEX2 2 +#define RGL_STRIP_SHADE 4 +#define RGL_STRIP_ZBUFFER 8 + +struct rglRenderChunk_t { + rdpState_t rdpState; + rglTile_t tiles[8]; + rglRenderBuffer_t * renderBuffer; + uint32_t depthAddress; + int flags; + int nbStrips; + rglStrip_t * strips; +#ifdef RDP_DEBUG + rglShader_t * shader; + int tracePos; +#endif +}; + +// first 8 bits used for tile usage +#define RGL_CHUNK_CLEAR (1<<8) + +#define MAX_RENDER_CHUNKS 40000 +extern rglRenderChunk_t chunks[MAX_RENDER_CHUNKS]; +extern rglRenderChunk_t * curChunk; +extern int nbChunks; + +#define MAX_STRIPS 80000 +extern rglStrip_t strips[MAX_STRIPS]; +extern rglVertex_t vtxs[6*MAX_STRIPS]; +extern int nbStrips, nbVtxs; + +struct rglRenderMode_t { + rdpOtherModes_t otherModes; + rdpCombineModes_t combineModes; + uint32_t flags; +}; + +#define RGL_RM_DEPTH 1 + +// TODO use a hash table +#define MAX_RENDER_MODES 1024 +extern rglRenderMode_t renderModesDb[MAX_RENDER_MODES]; +extern int nbRenderModes; + +extern rglShader_t * rglCopyShader; +extern rglShader_t * rglCopyDepthShader; + + +#define RGL_COMB_FMT_RGBA 0 +#define RGL_COMB_FMT_I 1 +#define RGL_COMB_FMT_DEPTH 2 +#define RGL_COMB_FMT 3 +#define RGL_COMB_IN0_DEPTH 4 +#define RGL_COMB_IN0 4 +#define RGL_COMB_IN1_DEPTH 8 +#define RGL_COMB_IN1 8 +#define RGL_COMB_TILE7 16 + +extern volatile int rglStatus, rglNextStatus; +#define RGL_STATUS_CLOSED 0 +#define RGL_STATUS_WINDOWED 1 +#define RGL_STATUS_FULLSCREEN 2 + + +void rglUpdateStatus(); +void rglTouchTMEM(); +void rglResetTextureCache(); +void rglTile(rdpTile_t & tile, rglTile_t & rtile, int recth); +void rglRenderMode(rglRenderChunk_t & chunk); +void rglBlender(rglRenderChunk_t & chunk); +void rglClearCombiners(); +void rglSetCombiner(rglRenderChunk_t & chunk, int format); +void rglPrepareRendering(int texturing, int tilenum, int recth, int depth); +rglRenderBuffer_t * rglSelectRenderBuffer(uint32_t addr, int width, int size, int format); +char * rglCombiner2String(rdpState_t & state); + + +int rglInit(); +void rglClose(); +int rglOpenScreen(); +void rglCloseScreen(); +int rglReadSettings(); +void rglUpdate(); +void rglFullSync(); +void rglTextureRectangle(rdpTexRect_t * rect, int flip); +void rglFillRectangle(rdpRect_t * rect); +void rglTriangle(uint32_t w1, uint32_t w2, int shade, int texture, int zbuffer, + uint32_t * rdp_cmd); +void rglRenderChunks(); +void rglDisplayFramebuffers(); +int rglT1Usage(rdpState_t & state); +int rglT2Usage(rdpState_t & state); +void rglDebugger(); +void rglCloseDebugger(); +void rglFramebuffer2Rdram(rglRenderBuffer_t & buffer, uint32_t start, uint32_t stop); +void rglRdram2Framebuffer(rglRenderBuffer_t & buffer, uint32_t start, uint32_t stop); +void rglRenderChunks(rglRenderBuffer_t * upto); +void rglRenderChunks(int upto); +float rglZscale(uint16_t z); + +void rglSwapBuffers(); + +extern int screen_width, screen_height; + +extern void check(); + +#endif diff --git a/libmupen64plus/mupen64plus-video-z64/src/rgl_assert.h b/libmupen64plus/mupen64plus-video-z64/src/rgl_assert.h new file mode 100644 index 0000000000..c2e406dadf --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/rgl_assert.h @@ -0,0 +1,42 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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 _RGL_ASSERT_H_ +#define _RGL_ASSERT_H_ + +#include + +#ifdef RGL_ASSERT +inline void _rglAssert(int test, const char * s, int line, const char * file) { + if (!test) { + fprintf(stderr, "z64 assert failed (%s : %d) : %s\n", file, line, s); + fflush(stdout); + fflush(stderr); + *(unsigned int *)0 = 0xdeadbeef; // hopefully will generate a segfault + exit(-1); + } +} +#define rglAssert(test) _rglAssert((test), #test, __LINE__, __FILE__) +#else +#define rglAssert(test) +#endif + +#endif diff --git a/libmupen64plus/mupen64plus-video-z64/src/rgl_debugger.cpp b/libmupen64plus/mupen64plus-video-z64/src/rgl_debugger.cpp new file mode 100644 index 0000000000..740be9e0c3 --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/rgl_debugger.cpp @@ -0,0 +1,861 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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 "rdp.h" +#include "rgl.h" + +static const char *saRGBText[] = +{ + "PREV", "TEXEL0", "TEXEL1", "PRIM", + "SHADE", "ENV", "NOISE", "1", + "0", "0", "0", "0", + "0", "0", "0", "0" +}; + +static const char *mRGBText[] = +{ + "PREV", "TEXEL0", "TEXEL1", "PRIM", + "SHADE", "ENV", "SCALE", "PREV_ALPHA", + "TEXEL0_ALPHA", "TEXEL1_ALPHA", "PRIM_ALPHA", "SHADE_ALPHA", + "ENV_ALPHA", "LOD_FRACTION", "PRIM_LOD_FRAC", "K5", + "0", "0", "0", "0", + "0", "0", "0", "0", + "0", "0", "0", "0", + "0", "0", "0", "0" +}; + +static const char *aRGBText[] = +{ + "PREV", "TEXEL0", "TEXEL1", "PRIM", + "SHADE", "ENV", "1", "0", +}; + +static const char *saAText[] = +{ + "PREV", "TEXEL0", "TEXEL1", "PRIM", + "SHADE", "ENV", "1", "0", +}; + +static const char *sbAText[] = +{ + "PREV", "TEXEL0", "TEXEL1", "PRIM", + "SHADE", "ENV", "1", "0", +}; + +static const char *mAText[] = +{ + "LOD_FRACTION", "TEXEL0", "TEXEL1", "PRIM", + "SHADE", "ENV", "PRIM_LOD_FRAC", "0", +}; + +static const char *aAText[] = +{ + "PREV", "TEXEL0", "TEXEL1", "PRIM", + "SHADE", "ENV", "1", "0", +}; + +const static char * bRGBText[] = { "PREV", "FRAG", "BLEND", "FOG" }; +const static char * bAText[2][4] = { {"PREVA", "FOGA", "SHADEA", "0"}, +{"(1.0-ALPHA)", "FRAGA", "1", "0"}}; + +char * rglCombiner2String(rdpState_t & state) +{ + rdpOtherModes_t om = state.otherModes; + int cycle = RDP_GETOM_CYCLE_TYPE(om); + static char res[256]; + char * p = res; + if (cycle < 2) { + p += sprintf( + p, + "c = [ (%s - %s) * %s + %s | (%s - %s) * %s + %s ]\n", + saRGBText[RDP_GETCM_SUB_A_RGB0(state.combineModes)], + saRGBText[RDP_GETCM_SUB_B_RGB0(state.combineModes)], + mRGBText[RDP_GETCM_MUL_RGB0(state.combineModes)], + aRGBText[RDP_GETCM_ADD_RGB0(state.combineModes)], + saAText[RDP_GETCM_SUB_A_A0(state.combineModes)], + sbAText[RDP_GETCM_SUB_B_A0(state.combineModes)], + mAText[RDP_GETCM_MUL_A0(state.combineModes)], + aAText[RDP_GETCM_ADD_A0(state.combineModes)]); + } + if (cycle == 1) { + p += sprintf( + p, + "c = [ (%s - %s) * %s + %s | (%s - %s) * %s + %s ]\n", + saRGBText[RDP_GETCM_SUB_A_RGB1(state.combineModes)], + saRGBText[RDP_GETCM_SUB_B_RGB1(state.combineModes)], + mRGBText[RDP_GETCM_MUL_RGB1(state.combineModes)], + aRGBText[RDP_GETCM_ADD_RGB1(state.combineModes)], + saAText[RDP_GETCM_SUB_A_A1(state.combineModes)], + sbAText[RDP_GETCM_SUB_B_A1(state.combineModes)], + mAText[RDP_GETCM_MUL_A1(state.combineModes)], + aAText[RDP_GETCM_ADD_A1(state.combineModes)]); + } + if (cycle < 2) { + p += sprintf( + p, + "%s*%s + %s*%s\n" + ,bAText[0][RDP_GETOM_BLEND_M1B_0(state.otherModes)], + bRGBText[RDP_GETOM_BLEND_M1A_0(state.otherModes)], + bAText[1][RDP_GETOM_BLEND_M2B_0(state.otherModes)], + bRGBText[RDP_GETOM_BLEND_M2A_0(state.otherModes)] + ); + } + if (cycle == 1) { + p += sprintf( + p, + "%s*%s + %s*%s\n" + ,bAText[0][RDP_GETOM_BLEND_M1B_1(state.otherModes)], + bRGBText[RDP_GETOM_BLEND_M1A_1(state.otherModes)], + bAText[1][RDP_GETOM_BLEND_M2B_1(state.otherModes)], + bRGBText[RDP_GETOM_BLEND_M2A_1(state.otherModes)] + ); + } + return res; +} + +#ifdef RDP_DEBUG + +#include +//#include +#include + +#include + +#define FONT "LucidaTypewriterRegular.ttf" +#define SMALLFONT "LucidaTypewriterRegular.ttf" +//#define SMALLFONT "/usr/share/fonts/corefonts/arial.ttf" +#define FS 12 +#define SMALLFS 12 + +static FTFont * font; +static FTFont * smallfont; +static FTFont * curfont; + +static int fbindex; +static int chunkindex, stripindex; +static int mx, my; +static float scalex, scaley; +static rglShader_t * alphaShader; + +static int lines[0x10000], nblines; +static char dasm[512]; + +void gglPrint(int x, int y, const char * text) +{ + glPushAttrib(GL_ALL_ATTRIB_BITS); + glPushMatrix(); + glTranslatef(x, y, 0); + + glEnable( GL_TEXTURE_2D); + glDisable( GL_DEPTH_TEST); + //glRasterPos2i( x , y); + curfont->Render(text); + + glPopMatrix(); + glPopAttrib(); + + //printf("%s\n", text); +} + +void gglPrintf(int x, int y, const char * s, ...) +{ + char buf[1024]; + va_list ap; + va_start(ap, s); + vsprintf(buf, s, ap); + va_end(ap); + gglPrint(x, y, buf); +} + +void rglDisplayTrace(int x, int y, int start, int lines) +{ + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + rglUseShader(0); + curfont = smallfont; + start = ::lines[start]; + while (lines-->0 && start <= rdpTracePos) { + glColor4f(0,0,0, 0.5); + glEnable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + glBegin(GL_TRIANGLE_STRIP); + glVertex2f(x, y); + glVertex2f(x+2*screen_width*3/4, y); + glVertex2f(x, y-(SMALLFS+2)); + glVertex2f(x+2*screen_width*3/4, y-(SMALLFS+2)); + glEnd(); + + glColor4f(1,1,0.5,1); + glDisable(GL_BLEND); + start += rdp_dasm(rdpTraceBuf, start, start+256, dasm)/4; + gglPrintf(x, y-(SMALLFS), "%4x %s", start, dasm); + y -= (SMALLFS+2); + } + curfont = font; + // glDisable(GL_BLEND); +} + +void rglDisplayColor(uint32_t color, int x , int y, const char * name, int sixteen = 0) +{ + float r, g, b, a; + if (sixteen) { + r = RDP_GETC16_R(color)/ 31.0f; + g = RDP_GETC16_G(color)/ 31.0f; + b = RDP_GETC16_B(color)/ 31.0f; + a = RDP_GETC16_A(color)/ 1.0f; + } else { + r = RDP_GETC32_R(color)/255.0f; + g = RDP_GETC32_G(color)/255.0f; + b = RDP_GETC32_B(color)/255.0f; + a = RDP_GETC32_A(color)/255.0f; + } + y -= FS+2; + glColor4f(r, g, b, 1); + glDisable(GL_TEXTURE_2D); + glBegin(GL_TRIANGLE_STRIP); + glVertex2f(x, y); + glVertex2f(x+128, y); + glVertex2f(x, y-16); + glVertex2f(x+128, y-16); + glEnd(); + + glEnable(GL_TEXTURE_2D); + glColor4f(1,1,1,1); + gglPrintf(x, y+2, "%5s %08x", name, color); + +} + +void rglDisplayChunkInfo(rglRenderChunk_t & chunk) +{ + int x = 0, y = screen_height; + int i; + rdpState_t & state = chunk.rdpState; + rdpOtherModes_t om = state.otherModes; + rdpCombineModes_t cm = state.combineModes; + int cycle = RDP_GETOM_CYCLE_TYPE(om); + + rglDisplayColor(chunk.rdpState.primColor, x, y, "prim"); + y -= 16+FS+10; + rglDisplayColor(chunk.rdpState.blendColor, x, y, "blend"); + y -= 16+FS+10; + rglDisplayColor(chunk.rdpState.envColor, x, y, "env"); + y -= 16+FS+10; + rglDisplayColor(chunk.rdpState.fogColor, x, y, "fog"); + y -= 16+FS+10; + rglDisplayColor(chunk.rdpState.fillColor, x, y, "fill", 1); + y -= 16+FS+10; + + y += 5*(16+FS+10); + x += 128+20; + + glColor4f(1,1,1,1); + int oldy = y; + for (i=0; i<8; i++) { + int j; + int oldx = x; + if (!(chunk.flags & (1< 64) w = 64; + if (h > 64) h = 64; + gglPrintf(x, y-h-FS, "#%d %dx%d %x", i, tile.w, tile.h, tile.hiresBuffer? 0 : tile.tex->crc); + gglPrintf(x, y-h-2*FS, "fmt %s-%d %d %d", rdpImageFormats[tile.format], tile.size, tile.line, tile.hiresBuffer? tile.hiresBuffer-rBuffers : -1); + gglPrintf(x, y-h-3*FS, "clip %dx%d %dx%d", tile.sl, tile.tl, tile.sh, tile.th); + gglPrintf(x, y-h-4*FS, "mask %dx%d shift %dx%d", tile.mask_s, tile.mask_t, tile.shift_s, tile.shift_t); + gglPrintf(x, y-h-5*FS, "%d %d %d %d pal %d", tile.cs, tile.ms, tile.ct, tile.ms, tile.palette); + glEnable(GL_TEXTURE_2D); + if (tile.hiresBuffer) + glBindTexture(GL_TEXTURE_2D, tile.hiresBuffer->texid); + else + glBindTexture(GL_TEXTURE_2D, tile.tex->id); + for (j=0; j<2; j++) { + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(0, 0); glVertex2f(x, y); + glTexCoord2f(0, 1); glVertex2f(x, y-h); + glTexCoord2f(1, 0); glVertex2f(x+w, y); + glTexCoord2f(1, 1); glVertex2f(x+w, y-h); + glEnd(); + rglUseShader(alphaShader); + x += w+2; + } + rglUseShader(0); + // if ((tile.w+2)*2 < 256) + // x += 256 - (tile.w+2)*2; + x = oldx; + y -= h + 5*FS + 5; + } + + y = oldy; + x = 128+210; + + y -= FS; + gglPrintf(x, y, "cycle %d persp %d detail %d sharpen %d tex_lod %d en_tlut %d tlut_type %d clipm %d", + RDP_GETOM_CYCLE_TYPE(om), + RDP_GETOM_PERSP_TEX_EN(om), + RDP_GETOM_DETAIL_TEX_EN(om), + RDP_GETOM_SHARPEN_TEX_EN(om), + RDP_GETOM_TEX_LOD_EN(om), + RDP_GETOM_EN_TLUT(om), + RDP_GETOM_TLUT_TYPE(om), + chunk.rdpState.clipMode); + + y -= FS; + gglPrintf(x, y, "sample_type %d mid %d lerp0 %d lerp1 %d convert1 %d key_en %d rgb_dith_sel %d", + RDP_GETOM_SAMPLE_TYPE(om), + RDP_GETOM_MID_TEXEL(om), + RDP_GETOM_BI_LERP0(om), + RDP_GETOM_BI_LERP1(om), + RDP_GETOM_CONVERT_ONE(om), + RDP_GETOM_KEY_EN(om), + RDP_GETOM_RGB_DITHER_SEL(om)); + + y -= FS; + gglPrintf(x, y, "A_dith_sel %d force_blend %d A_cvg_sel %d cvgXA %d Zmode %d cvg_dest %d col_on %d", + RDP_GETOM_ALPHA_DITHER_SEL(om), + RDP_GETOM_FORCE_BLEND(om), + RDP_GETOM_ALPHA_CVG_SELECT(om), + RDP_GETOM_CVG_TIMES_ALPHA(om), + RDP_GETOM_Z_MODE(om), + RDP_GETOM_CVG_DEST(om), + RDP_GETOM_COLOR_ON_CVG(om)); + + y -= FS; + gglPrintf(x, y, "img_read %d Zupdate %d Zcmp_sel %d antialias %d Zsource %d dith_A_en %d A_cmp %d", + RDP_GETOM_IMAGE_READ_EN(om), + RDP_GETOM_Z_UPDATE_EN(om), + RDP_GETOM_Z_COMPARE_EN(om), + RDP_GETOM_ANTIALIAS_EN(om), + RDP_GETOM_Z_SOURCE_SEL(om), + RDP_GETOM_DITHER_ALPHA_EN(om), + RDP_GETOM_ALPHA_COMPARE_EN(om)); + + y -= 2*FS; + + if (cycle < 2) { + gglPrintf(x, y, + "c = [ (%s - %s) * %s + %s | (%s - %s) * %s + %s ];", + saRGBText[RDP_GETCM_SUB_A_RGB0(state.combineModes)], + saRGBText[RDP_GETCM_SUB_B_RGB0(state.combineModes)], + mRGBText[RDP_GETCM_MUL_RGB0(state.combineModes)], + aRGBText[RDP_GETCM_ADD_RGB0(state.combineModes)], + saAText[RDP_GETCM_SUB_A_A0(state.combineModes)], + sbAText[RDP_GETCM_SUB_B_A0(state.combineModes)], + mAText[RDP_GETCM_MUL_A0(state.combineModes)], + aAText[RDP_GETCM_ADD_A0(state.combineModes)]); + + y -= FS; + } + if (cycle == 1) { + //if (cycle < 2) { + gglPrintf(x, y, + "c = [ (%s - %s) * %s + %s | (%s - %s) * %s + %s ];", + saRGBText[RDP_GETCM_SUB_A_RGB1(state.combineModes)], + saRGBText[RDP_GETCM_SUB_B_RGB1(state.combineModes)], + mRGBText[RDP_GETCM_MUL_RGB1(state.combineModes)], + aRGBText[RDP_GETCM_ADD_RGB1(state.combineModes)], + saAText[RDP_GETCM_SUB_A_A1(state.combineModes)], + sbAText[RDP_GETCM_SUB_B_A1(state.combineModes)], + mAText[RDP_GETCM_MUL_A1(state.combineModes)], + aAText[RDP_GETCM_ADD_A1(state.combineModes)]); + + y -= FS; + } + if (cycle < 2) { + gglPrintf(x, y, + "%s*%s + %s*%s" + ,bAText[0][RDP_GETOM_BLEND_M1B_0(state.otherModes)], + bRGBText[RDP_GETOM_BLEND_M1A_0(state.otherModes)], + bAText[1][RDP_GETOM_BLEND_M2B_0(state.otherModes)], + bRGBText[RDP_GETOM_BLEND_M2A_0(state.otherModes)] + ); + + y -= FS; + } + if (cycle == 1) { + //if (cycle < 2) { + gglPrintf(x, y, + "%s*%s + %s*%s" + ,bAText[0][RDP_GETOM_BLEND_M1B_1(state.otherModes)], + bRGBText[RDP_GETOM_BLEND_M1A_1(state.otherModes)], + bAText[1][RDP_GETOM_BLEND_M2B_1(state.otherModes)], + bRGBText[RDP_GETOM_BLEND_M2A_1(state.otherModes)] + ); + + y -= FS; + } + + if (chunk.nbStrips) { + y -= FS; + rglStrip_t & strip = chunk.strips[chunkindex >= 0? stripindex:0]; + + int i; + for (i=0; i>2)*buffer.realWidth/buffer.width, + // (chunk.rdpState.clip.yh >>2)*buffer.realHeight/buffer.height, + // (chunk.rdpState.clip.xl-chunk.rdpState.clip.xh >>2)*buffer.realWidth/buffer.width, + // (chunk.rdpState.clip.yl-chunk.rdpState.clip.yh >>2)*buffer.realHeight/buffer.height); + + + for (j=0; j= 0 && j == stripindex) { + glPushAttrib(GL_ALL_ATTRIB_BITS); + glColor4ub(255, 255, 128, 255); + } + glBegin(GL_TRIANGLE_STRIP); + for (k=0; k= 0 && j == stripindex) + glPopAttrib(); + } + + glPopAttrib(); +} + +int rglFindStrip(rglRenderChunk_t & chunk, float mx, float my) +{ + int j; + rglRenderBuffer_t & buffer = *chunk.renderBuffer; + for (j=chunk.nbStrips-1; j>=0; j--) { + rglStrip_t & strip = chunk.strips[j]; + int k; + struct { float x, y; } s[3]; + + for (k=0; k= 2) { + float last = 0; + int i; + for (i=0; i<3; i++) { + float dx1 = s[(i+1)%3].x - s[i].x; + float dy1 = s[(i+1)%3].y - s[i].y; + float dx2 = mx - s[i].x; + float dy2 = my - s[i].y; + dx1 = dx1*dy2-dx2*dy1; + if (dx1 == 0) goto next; + if (last*dx1 < 0) + goto next; + last = dx1; + } + stripindex = j; + return j; +next:; + } + } + } + return -1; +} + +void rglDisplayFlat(rglRenderBuffer_t & buffer) +{ + int i; + for (i=0; i=0; i--) { + rglRenderChunk_t & chunk = chunks[i]; + if (chunk.renderBuffer != &buffer) continue; + if (rglFindStrip(chunk, mx, my) >= 0) + return i; + } + return -1; +} + +void rglShowCursor(int state) +{ +#ifdef WIN32 +#else + SDL_ShowCursor(state); +#endif +} + +#ifndef WIN32 +static int keys[512]; +#define MOUSEBUT 511 +#else +# define MOUSEBUT VK_LBUTTON +# define SDLK_ESCAPE VK_ESCAPE +# define SDLK_KP_PLUS VK_ADD +# define SDLK_KP_MINUS VK_SUBTRACT +# define SDLK_TAB VK_TAB +# define SDLK_UP VK_UP +# define SDLK_DOWN VK_DOWN +# define SDLK_PAGEUP VK_PRIOR +# define SDLK_PAGEDOWN VK_NEXT +#endif + +int rglCheckKey(int key) +{ +#ifdef WIN32 + return GetAsyncKeyState (key) & 1; +#else + if (key >= 'A' && key <= 'Z') key += 'a' - 'A'; + int res = keys[key]; + keys[key] = 0; + return res; +#endif +} + +void rglDebugger() +{ + SDL_Event event; + int paused = 1; + int i, j; + int traceX = 1; + int tracepos = 0; + int tracepage = (screen_height*3/4)/(SMALLFS+2); + int oldchunkindex = -1; + + fbindex = 0; + chunkindex = -1; + + void rglInitDebugger(); + rglInitDebugger(); + + rglShowCursor(SDL_ENABLE); + + glActiveTextureARB(GL_TEXTURE1_ARB); + glDisable(GL_TEXTURE_2D); + glActiveTextureARB(GL_TEXTURE2_ARB); + glDisable(GL_TEXTURE_2D); + glActiveTextureARB(GL_TEXTURE0_ARB); + glDrawBuffer(GL_BACK); + + for (i=nblines=0; i<=rdpTracePos; i += rdp_dasm(rdpTraceBuf, i, i+256, dasm)/4, nblines++) + lines[nblines] = i; + + if (nbChunks > 1) + // skip chunk 0 as it's usually depth clear + fbindex = chunks[1].renderBuffer - rBuffers; + + while (paused) { +#ifndef WIN32 + int res = SDL_WaitEvent(&event); + while (res) { + switch (event.type) { + case SDL_MOUSEBUTTONDOWN: + keys[MOUSEBUT] = 1; + break; + case SDL_MOUSEBUTTONUP: + keys[MOUSEBUT] = 0; + break; + case SDL_KEYDOWN: + if (event.key.keysym.sym < MOUSEBUT) + keys[event.key.keysym.sym] = 1; + break; + case SDL_KEYUP: + if (event.key.keysym.sym < MOUSEBUT) + keys[event.key.keysym.sym] = 0; + break; + } + res = SDL_PollEvent(&event); + } +#endif + rglRenderBuffer_t & buffer = rBuffers[fbindex]; + scalex = buffer.realWidth; scaley = buffer.realHeight; + + if (rBuffers[fbindex].fbid) { + if (buffer.realWidth > scalex*3/4 || + buffer.realHeight > scaley*3/4) { + scalex = scalex*3/4; + scaley = scaley*3/4; + } + } + + if (rglCheckKey(MOUSEBUT)) { + if (buffer.fbid) { +#ifdef WIN32 + POINT pt; + GetCursorPos(&pt); + mx = pt.x; + my = pt.y; +#else + SDL_GetMouseState(&mx, &my); +#endif + int old = chunkindex; + if (old >= 0) + chunkindex++; + chunkindex = rglFindChunk(buffer, float(mx)/scalex, float(screen_height - my)/scaley); + if (old >= 0 && chunkindex == old) { + } else { + chunkindex = -1; + } + chunkindex = rglFindChunk(buffer, float(mx)/scalex, float(screen_height - my)/scaley); + if (chunkindex >= 0 && nbChunks) + printf("%s\n", chunks[chunkindex].shader->fsrc); + } + } + if (rglCheckKey('P') || rglCheckKey(SDLK_ESCAPE)) + paused = 0; + if (rglCheckKey(SDLK_KP_PLUS)) { + if (fbindex < MAX_RENDER_BUFFERS-1/* && + rBuffers[fbindex+1].fbid*/) + fbindex++; + chunkindex = -1; + } + if (rglCheckKey(SDLK_KP_MINUS)) { + if (fbindex > 0/* && + rBuffers[fbindex-1].fbid*/) + fbindex--; + chunkindex = -1; + } + if (rglCheckKey(SDLK_TAB)) + traceX = !traceX; + if (rglCheckKey(SDLK_UP)) + tracepos--; + if (rglCheckKey(SDLK_DOWN)) + tracepos++; + if (rglCheckKey(SDLK_PAGEUP)) + tracepos -= tracepage/2; + if (rglCheckKey(SDLK_PAGEDOWN)) + tracepos += tracepage/2; + if (tracepos < 0) + tracepos = 0; + if (tracepos > nblines-tracepage/2) + tracepos = nblines-tracepage/2; + + //rglRenderChunks(); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glDrawBuffer(GL_BACK); + glDisable(GL_SCISSOR_TEST); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glActiveTextureARB(GL_TEXTURE1_ARB); + glDisable(GL_TEXTURE_2D); + glActiveTextureARB(GL_TEXTURE0_ARB); + glDisable(GL_ALPHA_TEST); + + glClearColor(0, 0, 0, 0); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glClear(GL_COLOR_BUFFER_BIT); + + if (buffer.fbid) { + //glViewport(0, 0, scalex*screen_width/buffer.realWidth, scaley*screen_height/buffer.realHeight); + glViewport(0, 0, scalex, scaley); + rglDisplayFramebuffer(buffer, 0); + glViewport(scalex, 0, scalex, scaley); + rglDisplayFramebuffer(buffer, 1); + + glViewport(0, 0, scalex, scaley); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glEnable(GL_BLEND); + //glBlendFunc( GL_ONE, GL_ONE ); + glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_DST_COLOR); + if (chunkindex < 0) { + //glColor4f(0.1, 0, 0.1, 0.5); + glColor4f(0.6, 0, 0.6, 0.5); + rglDisplayFlat(buffer); + } else { + glColor4f(0.6, 0, 0.6, 0.5); + rglDisplayFlat(chunks[chunkindex]); + } + } + + { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDisable(GL_BLEND); + + + glMatrixMode( GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + gluOrtho2D(0, screen_width, 0, screen_height); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glViewport(0, 0, screen_width, screen_height); + rglUseShader(0); + + glColor3f(1,0.5,0.5); + gglPrintf(0, 0, "Fb #%d at $%x --> %x (%dx%d fmt %s-%d) upto %d %s", fbindex, + buffer.addressStart, buffer.addressStop, + buffer.width, buffer.height, + (buffer.flags & RGL_RB_DEPTH)? "Z":rdpImageFormats[buffer.format], buffer.size, + buffer.chunkId, + (buffer.flags & RGL_RB_ERASED)? "ERASED":""); + + if (chunkindex >= 0) { + gglPrintf(0, FS, "Chunk #%d", chunkindex); + + rglDisplayChunkInfo(chunks[chunkindex]); + } + + if (oldchunkindex != chunkindex) { + oldchunkindex = chunkindex; + if (chunkindex >= 0) + for (i=0; iFaceSize(FS); + smallfont->FaceSize(SMALLFS); + } + + if (!alphaShader) { + alphaShader = rglCreateShader( + "void main() \n" + "{ \n" + " gl_Position = ftransform(); \n" + " gl_FrontColor = gl_Color; \n" + " gl_TexCoord[0] = gl_MultiTexCoord0; \n" + "} \n" + , + "uniform sampler2D texture0; \n" + " \n" + "void main() \n" + "{ \n" + " gl_FragColor = gl_Color * texture2D(texture0, vec2(gl_TexCoord[0])).a; \n" + "} \n" + ); + } +} + +void rdpBacktrace() +{ + int i=0; + while (i <= rdpTracePos) { + i += rdp_dasm(rdpTraceBuf, i, i+256, dasm)/4; + printf("%4x %s\n", i, dasm); + } +} + +#endif diff --git a/libmupen64plus/mupen64plus-video-z64/src/rgl_geometry.cpp b/libmupen64plus/mupen64plus-video-z64/src/rgl_geometry.cpp new file mode 100644 index 0000000000..3d77856f8b --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/rgl_geometry.cpp @@ -0,0 +1,576 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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 "rdp.h" +#include "rgl.h" + +#include + +inline float _zscale(uint16_t z) +{ + uint32_t res; + int e = z>>(16-3); + int m = (z>>2)&((1<<11)-1); + + static struct { + int shift; + long add; + } z_format[8] = { + {6, 0x00000}, + {5, 0x20000}, + {4, 0x30000}, + {3, 0x38000}, + {2, 0x3c000}, + {1, 0x3e000}, + {0, 0x3f000}, + {0, 0x3f800}, + }; + + res = (m << z_format[e].shift) + + z_format[e].add; + return float(res)/0x3ffff; +} + +inline float zscale(uint16_t z) +{ + return float(z)/0xffff; +} +//#define zscale _zscale + +float rglZscale(uint16_t z) +{ + return _zscale(z); +} + +void rglTextureRectangle(rdpTexRect_t * rect, int flip) +{ + int tilenum = rect->tilenum; + int x1,x2,y1,y2,z; + int s, t; + int dx, dy; + + // if (tilenum == 7) { + // LOG("Fixing tilenum from 7 to 0\n"); + // tilenum = 0; + // } + + x1 = (rect->xh); + x2 = (rect->xl); + y1 = (rect->yh); + y2 = (rect->yl); + s = int(rect->s)<<5; + t = int(rect->t)<<5; + + DUMP("texrect %d x %d --> %d x %d s %d t %d flip %d\n", + x1, y1, x2, y2, s, t, flip); + + if (RDP_GETOM_CYCLE_TYPE(rdpState.otherModes) == RDP_CYCLE_TYPE_FILL || + RDP_GETOM_CYCLE_TYPE(rdpState.otherModes) == RDP_CYCLE_TYPE_COPY) + { + rect->dsdx /= 4; + //s /= 4; + x2 += 4; + y2 += 4; + } else { + x2 += 1; + y2 += 1; + } + + x1 /= 4; + x2 /= 4; + y1 /= 4; + y2 /= 4; + + if (x2 < x1) x2 = x1+1; // black gauge in SCARS (E) + + int t1 = rglT1Usage(rdpState)? RGL_STRIP_TEX1:0; + int t2 = (rect->tilenum < 7 && rglT2Usage(rdpState))? RGL_STRIP_TEX2:0; + if (t1) + rglPrepareRendering(1, (tilenum==7 && RDP_GETOM_CYCLE_TYPE(rdpState.otherModes)==1)? 0:tilenum, y2-y1, 1); + if (t2) + rglPrepareRendering(1, tilenum+1, y2-y1, 1); + else if (!t1) + rglPrepareRendering(0, 0, 0, 1); + + // TO BE REMOVED when we implement depth texture writing + curRBuffer->flags |= RGL_RB_HASTRIANGLES; + + // TO CHECK should this before or after the rescaling above ? + // s -= (rdpTiles[tilenum].sl << 8); + // t -= (rdpTiles[tilenum].tl << 8); + // if (/*!tile.ms && */tile.mask_s) + // s &= (1<nbStrips++; + rglVertex_t * vtx = vtxs + nbVtxs; + + strip->flags = t1 | t2 | RGL_STRIP_ZBUFFER; + strip->vtxs = vtx; + strip->tilenum = tilenum; + + float s2, tr; + s2 = s+int(rect->dsdx)*dx; + tr = t+int(rect->dtdy)*dy; + //LOG("%d %d\n", rect->dsdx, rect->dtdy); + if (0 && RDP_GETOM_CYCLE_TYPE(rdpState.otherModes) < 2) + { + //if (rect->dsdx == (1<<10)) + { + s += 1<<9; + s2 -= 1<<9; + } + //if (rect->dtdy == (1<<10)) + { + t += 1<<9; + tr -= 1<<9; + } + } + + if (flip) { vtx->t = SSCALE(s2); vtx->s = TSCALE(t); + } else { vtx->s = SSCALE(s2); vtx->t = TSCALE(t); } + vtx->x = XSCALE(x2); vtx->y = YSCALE(y1); vtx->z = ZSCALE(z); vtx++->w = 1; + if (flip) { vtx->t = SSCALE(s); vtx->s = TSCALE(t); + } else { vtx->s = SSCALE(s); vtx->t = TSCALE(t); } + vtx->x = XSCALE(x1); vtx->y = YSCALE(y1); vtx->z = ZSCALE(z); vtx++->w = 1; + if (flip) { vtx->t = SSCALE(s2); vtx->s = TSCALE(tr); + } else { vtx->s = SSCALE(s2); vtx->t = TSCALE(tr); } + vtx->x = XSCALE(x2); vtx->y = YSCALE(y2); vtx->z = ZSCALE(z); vtx++->w = 1; + if (flip) { vtx->t = SSCALE(s); vtx->s = TSCALE(tr); + } else { vtx->s = SSCALE(s); vtx->t = TSCALE(tr); } + vtx->x = XSCALE(x1); vtx->y = YSCALE(y2); vtx->z = ZSCALE(z); vtx++->w = 1; + + strip->nbVtxs = vtx - strip->vtxs; + nbVtxs = vtx - vtxs; +} + +void rglFillRectangle(rdpRect_t * rect) +{ + int x1,x2,y1,y2,z; + //int s, t; + //int dx, dy; + + rglPrepareRendering(0, 0, 0, 1); + DUMP("fillrect curRBuffer->flags %x %x %x\n", curRBuffer->flags, curRBuffer->addressStart, rdpZbAddress); + // if (/*(curRBuffer->flags & RGL_RB_DEPTH) &&*/ + // RDP_GETOM_CYCLE_TYPE(rdpState.otherModes) == RDP_CYCLE_TYPE_FILL && + // rect->xh-4 <= rdpState.clip.xh && rect->xl+8 >= rdpState.clip.xl && + // rect->yh-4 <= rdpState.clip.yh && rect->yl+8 >= rdpState.clip.yl + // ) { + // curChunk->flags |= RGL_CHUNK_CLEAR; + // return; + // } + + x1 = (rect->xh / 4); + x2 = (rect->xl / 4); + y1 = (rect->yh / 4); + y2 = (rect->yl / 4); + + if (RDP_GETOM_CYCLE_TYPE(rdpState.otherModes) == RDP_CYCLE_TYPE_FILL || + RDP_GETOM_CYCLE_TYPE(rdpState.otherModes) == RDP_CYCLE_TYPE_COPY) + { + x2 += 1; + y2 += 1; + } else { + //rglAssert(!(curRBuffer->flags & RGL_RB_DEPTH)); + // x2 -= 1; + // y2 -= 1; + } + + if (x2 < x1) x2 = x1+1; // black gauge in SCARS (E) + +#define XSCALE(x) (float(x)) +#define YSCALE(y) (float(y)) +#define ZSCALE(z) (zscale(z)) + + if (RDP_GETOM_Z_SOURCE_SEL(rdpState.otherModes)) + z = rdpState.primitiveZ; + else + z = 0xffff; + // if (dump) + // fprintf(stderr, "fillrect cycle %d\n", other_modes.cycle_type); + + rglStrip_t * strip = strips + nbStrips++; + rglAssert(nbStrips < MAX_STRIPS); + curChunk->nbStrips++; + rglVertex_t * vtx = vtxs + nbVtxs; + + strip->flags = RGL_STRIP_ZBUFFER; + strip->vtxs = vtx; + + vtx->x = XSCALE(x2); vtx->y = YSCALE(y1); vtx->z = ZSCALE(z); vtx++->w = 1; + vtx->x = XSCALE(x1); vtx->y = YSCALE(y1); vtx->z = ZSCALE(z); vtx++->w = 1; + vtx->x = XSCALE(x2); vtx->y = YSCALE(y2); vtx->z = ZSCALE(z); vtx++->w = 1; + vtx->x = XSCALE(x1); vtx->y = YSCALE(y2); vtx->z = ZSCALE(z); vtx++->w = 1; + + strip->nbVtxs = vtx - strip->vtxs; + nbVtxs = vtx - vtxs; +} + +void rglTriangle(uint32_t w1, uint32_t w2, int shade, int texture, int zbuffer, + uint32_t * rdp_cmd) +{ + int tilenum = (w1 >> 16) & 0x7; + // if (tilenum == 7) { + // LOG("Fixing tilenum from 7 to 0\n"); + // tilenum = 0; + // } + int j; + int xleft, xright, xleft_inc, xright_inc; + //int xstart, xend; + int r, g, b, a, z, s, t, w; + int drdx = 0, dgdx = 0, dbdx = 0, dadx = 0, dzdx = 0, dsdx = 0, dtdx = 0, dwdx = 0; + int drde = 0, dgde = 0, dbde = 0, dade = 0, dzde = 0, dsde = 0, dtde = 0, dwde = 0; + int flip = (w1 & 0x800000) ? 1 : 0; + + int32_t yl, ym, yh; + int32_t xl, xm, xh; + int64_t dxldy, dxhdy, dxmdy; + uint32_t w3, w4, w5, w6, w7, w8; + + uint32_t * shade_base = rdp_cmd + 8; + uint32_t * texture_base = rdp_cmd + 8; + uint32_t * zbuffer_base = rdp_cmd + 8; + + int t1 = (texture && rglT1Usage(rdpState))? RGL_STRIP_TEX1:0; + int t2 = (texture && tilenum < 7 && rglT2Usage(rdpState))? RGL_STRIP_TEX2:0; + if (t1) + rglPrepareRendering(1, (tilenum==7 && RDP_GETOM_CYCLE_TYPE(rdpState.otherModes)==1)? 0:tilenum, 0, zbuffer); + if (t2) + rglPrepareRendering(1, tilenum+1, 0, zbuffer); + else if (!t1) + rglPrepareRendering(0, 0, 0, zbuffer); + + curRBuffer->flags |= RGL_RB_HASTRIANGLES; + + if (shade) + { + texture_base += 16; + zbuffer_base += 16; + } + if (texture) + { + zbuffer_base += 16; + } + + w3 = rdp_cmd[2]; + w4 = rdp_cmd[3]; + w5 = rdp_cmd[4]; + w6 = rdp_cmd[5]; + w7 = rdp_cmd[6]; + w8 = rdp_cmd[7]; + + yl = (w1 & 0x3fff); + ym = ((w2 >> 16) & 0x3fff); + yh = ((w2 >> 0) & 0x3fff); + xl = (int32_t)(w3); + xh = (int32_t)(w5); + xm = (int32_t)(w7); + dxldy = (int32_t)(w4); + dxhdy = (int32_t)(w6); + dxmdy = (int32_t)(w8); + + if (yl & (0x800<<2)) yl |= 0xfffff000<<2; + if (ym & (0x800<<2)) ym |= 0xfffff000<<2; + if (yh & (0x800<<2)) yh |= 0xfffff000<<2; + + yh &= ~3; + + r = 0xff; g = 0xff; b = 0xff; a = 0xff; z = 0xffff0000; s = 0; t = 0; w = 0x30000; + + if (shade) + { + r = (shade_base[0] & 0xffff0000) | ((shade_base[+4 ] >> 16) & 0x0000ffff); + g = ((shade_base[0 ] << 16) & 0xffff0000) | (shade_base[4 ] & 0x0000ffff); + b = (shade_base[1 ] & 0xffff0000) | ((shade_base[5 ] >> 16) & 0x0000ffff); + a = ((shade_base[1 ] << 16) & 0xffff0000) | (shade_base[5 ] & 0x0000ffff); + drdx = (shade_base[2 ] & 0xffff0000) | ((shade_base[6 ] >> 16) & 0x0000ffff); + dgdx = ((shade_base[2 ] << 16) & 0xffff0000) | (shade_base[6 ] & 0x0000ffff); + dbdx = (shade_base[3 ] & 0xffff0000) | ((shade_base[7 ] >> 16) & 0x0000ffff); + dadx = ((shade_base[3 ] << 16) & 0xffff0000) | (shade_base[7 ] & 0x0000ffff); + drde = (shade_base[8 ] & 0xffff0000) | ((shade_base[12] >> 16) & 0x0000ffff); + dgde = ((shade_base[8 ] << 16) & 0xffff0000) | (shade_base[12] & 0x0000ffff); + dbde = (shade_base[9 ] & 0xffff0000) | ((shade_base[13] >> 16) & 0x0000ffff); + dade = ((shade_base[9 ] << 16) & 0xffff0000) | (shade_base[13] & 0x0000ffff); + } + if (texture) + { + s = (texture_base[0 ] & 0xffff0000) | ((texture_base[4 ] >> 16) & 0x0000ffff); + t = ((texture_base[0 ] << 16) & 0xffff0000) | (texture_base[4 ] & 0x0000ffff); + w = (texture_base[1 ] & 0xffff0000) | ((texture_base[5 ] >> 16) & 0x0000ffff); + dsdx = (texture_base[2 ] & 0xffff0000) | ((texture_base[6 ] >> 16) & 0x0000ffff); + dtdx = ((texture_base[2 ] << 16) & 0xffff0000) | (texture_base[6 ] & 0x0000ffff); + dwdx = (texture_base[3 ] & 0xffff0000) | ((texture_base[7 ] >> 16) & 0x0000ffff); + dsde = (texture_base[8 ] & 0xffff0000) | ((texture_base[12] >> 16) & 0x0000ffff); + dtde = ((texture_base[8 ] << 16) & 0xffff0000) | (texture_base[12] & 0x0000ffff); + dwde = (texture_base[9 ] & 0xffff0000) | ((texture_base[13] >> 16) & 0x0000ffff); + } + if (zbuffer) + { + //rglAssert(!(curRBuffer->flags & RGL_RB_DEPTH)); + + z = zbuffer_base[0]; + dzdx = zbuffer_base[1]; + dzde = zbuffer_base[2]; + } + + xh <<= 2; xm <<= 2; xl <<= 2; + r <<= 2; g <<= 2; b <<= 2; a <<= 2; + dsde >>= 2; dtde >>= 2; dsdx >>= 2; dtdx >>= 2; + dzdx >>= 2; dzde >>= 2; + dwdx >>= 2; dwde >>= 2; + + + // #define tile rdpTiles[tilenum] + // s -= (rdpTiles[tilenum].sl << 8); + // t -= (rdpTiles[tilenum].tl << 8); + // if (/*!tile.ms && */tile.mask_s) + // s &= (1< xright-0x10000))) { + xleft += xleft_inc; xright += xright_inc; + s += dsde; t += dtde; w += dwde; + r += drde; g += dgde; b += dbde; a += dade; + z += dzde; + yh++; + } + + j = ym-yh; + //rglAssert(j >= 0); +#undef XSCALE +#undef YSCALE +#undef ZSCALE +#undef SSCALE +#undef TSCALE +#define XSCALE(x) (float(x)/(1<<18)) +#define YSCALE(y) (float(y)/(1<<2)) +#define ZSCALE(z) (RDP_GETOM_Z_SOURCE_SEL(rdpState.otherModes)? zscale(rdpState.primitiveZ) : zscale((z)>>16)) +#define WSCALE(z) 1.0f/(RDP_GETOM_PERSP_TEX_EN(rdpState.otherModes)? (float(uint32_t(z) + 0x10000)/0xffff0000) : 1.0f) + //#define WSCALE(w) (RDP_GETOM_PERSP_TEX_EN(rdpState.otherModes)? 65536.0f*65536.0f/float((w+ 0x10000)) : 1.0f) +#define CSCALE(c) (((c)>0x3ff0000? 0x3ff0000:((c)<0? 0 : (c)))>>18) +#define _PERSP(w) ( w ) +#define PERSP(s, w) ( ((int64_t)(s) << 20) / (_PERSP(w)? _PERSP(w):1) ) +#define SSCALE(s, _w) (RDP_GETOM_PERSP_TEX_EN(rdpState.otherModes)? float(PERSP(s, _w))/(1 << 10) : float(s)/(1<<21)) +#define TSCALE(s, w) (RDP_GETOM_PERSP_TEX_EN(rdpState.otherModes)? float(PERSP(s, w))/(1 << 10) : float(s)/(1<<21)) + + rglStrip_t * strip = strips + nbStrips++; + rglAssert(nbStrips < MAX_STRIPS); + curChunk->nbStrips++; + rglVertex_t * vtx = vtxs + nbVtxs; + + strip->flags = (shade? RGL_STRIP_SHADE : 0) | t1 | t2 + | RGL_STRIP_ZBUFFER; + //| (zbuffer? RGL_STRIP_ZBUFFER : 0); + strip->vtxs = vtx; + strip->tilenum = tilenum; + + //int sw; + if (j > 0) + { + int dx = ((xleft-xright)>>16); + if ((!flip && xleft < xright) || + (flip/* && xleft > xright*/)) + { + if (shade) { + vtx->r = CSCALE(r+drdx*dx); + vtx->g = CSCALE(g+dgdx*dx); + vtx->b = CSCALE(b+dbdx*dx); + vtx->a = CSCALE(a+dadx*dx); + } + if (texture) { + vtx->s = SSCALE(s+dsdx*dx, w+dwdx*dx); + vtx->t = TSCALE(t+dtdx*dx, w+dwdx*dx); + } + vtx->x = XSCALE(xleft); + vtx->y = YSCALE(yh); + vtx->z = ZSCALE(z+dzdx*dx); + vtx->w = WSCALE(w+dwdx*dx); + vtx++; + } + if ((!flip/* && xleft < xright*/) || + (flip && xleft > xright)) + { + if (shade) { + vtx->r = CSCALE(r); + vtx->g = CSCALE(g); + vtx->b = CSCALE(b); + vtx->a = CSCALE(a); + } + if (texture) { + vtx->s = SSCALE(s, w); + vtx->t = TSCALE(t, w); + } + vtx->x = XSCALE(xright); + vtx->y = YSCALE(yh); + vtx->z = ZSCALE(z); + vtx->w = WSCALE(w); + vtx++; + } + } + xleft += xleft_inc*j; xright += xright_inc*j; + s += dsde*j; t += dtde*j; w += dwde*j; + r += drde*j; g += dgde*j; b += dbde*j; a += dade*j; + z += dzde*j; + // render ... + + xleft = xl; + + //if (yl-ym > 0) + { + int dx = ((xleft-xright)>>16); + if ((!flip && xleft <= xright) || + (flip/* && xleft >= xright*/)) + { + if (shade) { + vtx->r = CSCALE(r+drdx*dx); + vtx->g = CSCALE(g+dgdx*dx); + vtx->b = CSCALE(b+dbdx*dx); + vtx->a = CSCALE(a+dadx*dx); + } + if (texture) { + vtx->s = SSCALE(s+dsdx*dx, w+dwdx*dx); + vtx->t = TSCALE(t+dtdx*dx, w+dwdx*dx); + } + vtx->x = XSCALE(xleft); + vtx->y = YSCALE(ym); + vtx->z = ZSCALE(z+dzdx*dx); + vtx->w = WSCALE(w+dwdx*dx); + vtx++; + } + if ((!flip/* && xleft <= xright*/) || + (flip && xleft >= xright)) + { + if (shade) { + vtx->r = CSCALE(r); + vtx->g = CSCALE(g); + vtx->b = CSCALE(b); + vtx->a = CSCALE(a); + } + if (texture) { + vtx->s = SSCALE(s, w); + vtx->t = TSCALE(t, w); + } + vtx->x = XSCALE(xright); + vtx->y = YSCALE(ym); + vtx->z = ZSCALE(z); + vtx->w = WSCALE(w); + vtx++; + } + } + xleft_inc = dxldy; + xright_inc = dxhdy; + + j = yl-ym; + //rglAssert(j >= 0); + //j--; // ? + xleft += xleft_inc*j; xright += xright_inc*j; + s += dsde*j; t += dtde*j; w += dwde*j; + r += drde*j; g += dgde*j; b += dbde*j; a += dade*j; + z += dzde*j; + + while (yl>ym && + !((!flip && xleft < xright+0x10000) || + (flip && xleft > xright-0x10000))) { + xleft -= xleft_inc; xright -= xright_inc; + s -= dsde; t -= dtde; w -= dwde; + r -= drde; g -= dgde; b -= dbde; a -= dade; + z -= dzde; + j--; + yl--; + } + + // render ... + if (j >= 0) { + int dx = ((xleft-xright)>>16); + if ((!flip && xleft <= xright) || + (flip/* && xleft >= xright*/)) + { + if (shade) { + vtx->r = CSCALE(r+drdx*dx); + vtx->g = CSCALE(g+dgdx*dx); + vtx->b = CSCALE(b+dbdx*dx); + vtx->a = CSCALE(a+dadx*dx); + } + if (texture) { + vtx->s = SSCALE(s+dsdx*dx, w+dwdx*dx); + vtx->t = TSCALE(t+dtdx*dx, w+dwdx*dx); + } + vtx->x = XSCALE(xleft); + vtx->y = YSCALE(yl); + vtx->z = ZSCALE(z+dzdx*dx); + vtx->w = WSCALE(w+dwdx*dx); + vtx++; + } + if ((!flip/* && xleft <= xright*/) || + (flip && xleft >= xright)) + { + if (shade) { + vtx->r = CSCALE(r); + vtx->g = CSCALE(g); + vtx->b = CSCALE(b); + vtx->a = CSCALE(a); + } + if (texture) { + vtx->s = SSCALE(s, w); + vtx->t = TSCALE(t, w); + } + vtx->x = XSCALE(xright); + vtx->y = YSCALE(yl); + vtx->z = ZSCALE(z); + vtx->w = WSCALE(w); + vtx++; + } + } + + strip->nbVtxs = vtx - strip->vtxs; + nbVtxs = vtx - vtxs; +} diff --git a/libmupen64plus/mupen64plus-video-z64/src/rgl_glut.cpp b/libmupen64plus/mupen64plus-video-z64/src/rgl_glut.cpp new file mode 100644 index 0000000000..0bee4fad8c --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/rgl_glut.cpp @@ -0,0 +1,218 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * +**/ + +#include + +#include + +#include "rgl_glut.h" + +#ifdef RGL_USE_GLUT +#include + +extern int screen_width, screen_height; + +/** These are the live variables passed into GLUI ***/ +int wireframe = 0; +int segments = 8; +int main_window; + +static GLUI *glui; + +static SDL_sem * commandSem; +static SDL_cond * commandCond; +static SDL_mutex * commandMutex; +static SDL_sem * commandFinishedSem; +static rglGlutCommand_f command, nextCommand; + +/***************************************** myGlutIdle() ***********/ + +void myGlutIdle( ) +{ +// SDL_LockMutex(commandMutex); +// if (!SDL_CondWaitTimeout(commandCond, commandMutex, 1)) { + if (!SDL_SemWaitTimeout(commandSem, 1)) { + //if (!SDL_SemWait(commandSem)) { + //printf("receive a command\n"); + if ( glutGetWindow() && glutGetWindow() != main_window ) + glutSetWindow(main_window); + nextCommand = command; + command = 0; + glutPostRedisplay(); + } +// SDL_UnlockMutex(commandMutex); +} + +void myGlutTimer( int dummy ) +{ + + /* According to the GLUT specification, the current window is + undefined during an idle callback. So we need to explicitly change + it if necessary */ + if ( glutGetWindow() != main_window ) + glutSetWindow(main_window); + + glutPostRedisplay(); +} + + +/**************************************** myGlutReshape() *************/ + +void myGlutReshape( int x, int y ) +{ + float xy_aspect; + + xy_aspect = (float)x / (float)y; + glViewport( 0, 0, x, y ); + +// glMatrixMode( GL_PROJECTION ); +// glLoadIdentity(); +// glFrustum( -xy_aspect*.08, xy_aspect*.08, -.08, .08, .1, 15.0 ); + + glutPostRedisplay(); +} + +/***************************************** myGlutDisplay() *****************/ + +void myGlutDisplay( void ) +{ + if (nextCommand) { + nextCommand(); + nextCommand = 0; + SDL_SemPost(commandFinishedSem); + } + + //glutSwapBuffers(); + + //glutTimerFunc(1, myGlutTimer, 0); +} + + +/**************************************** main() ********************/ + +static int glutmain(int argc, char* argv[]) +{ + /****************************************/ + /* Initialize GLUT and create window */ + /****************************************/ + + glutInit(&argc, argv); + glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH ); + //glutInitWindowPosition( 50, 50 ); + glutInitWindowSize( screen_width, screen_height ); + + main_window = glutCreateWindow( "z64gl" ); + glutDisplayFunc( myGlutDisplay ); + glutReshapeFunc( myGlutReshape ); + + /****************************************/ + /* Here's the GLUI code */ + /****************************************/ + + glui = GLUI_Master.create_glui( "GLUI" ); + new GLUI_Checkbox( glui, "Wireframe", &wireframe ); + (new GLUI_Spinner( glui, "Segments:", &segments )) + ->set_int_limits( 3, 60 ); + + glui->set_main_gfx_window( main_window ); + + /* We register the idle callback with GLUI, *not* with GLUT */ + GLUI_Master.set_glutIdleFunc( myGlutIdle ); + //glutTimerFunc(1, myGlutTimer, 0); + + glutMainLoop(); + + return EXIT_SUCCESS; +} + + + + + +static SDL_Thread * thread; + +int rglGlutThread(void * dummy) +{ + int argc = 1; + char * argv[2] = { "z64gl", 0 }; + + glutmain(argc, argv); + + thread = 0; + + // in case of, but glutMainLoop never exits anyway + exit(0); +} + +void rglGlutMinimizeWindow() +{ + //glutDestroyWindow(main_window); + myGlutReshape(64, 64); +} + +void rglGlutRecreateWindow() +{ + int oldmain = main_window; + + glutInitWindowSize( screen_width, screen_height ); + main_window = glutCreateWindow( "z64gl" ); + glutDisplayFunc( myGlutDisplay ); + glutReshapeFunc( myGlutReshape ); + + glui->set_main_gfx_window( main_window ); + /* We register the idle callback with GLUI, *not* with GLUT */ + GLUI_Master.set_glutIdleFunc( myGlutIdle ); + //glutTimerFunc(1, myGlutTimer, 0); + + glutSetWindow(main_window); + + glutDestroyWindow(oldmain); +} + +void rglGlutCreateThread(int recreate) +{ + if (!thread) { + commandSem = SDL_CreateSemaphore(0); + commandCond = SDL_CreateCond(); + commandMutex = SDL_CreateMutex(); + commandFinishedSem = SDL_CreateSemaphore(0); + + thread = SDL_CreateThread(rglGlutThread, 0); + } else if (recreate) + rglGlutPostCommand(rglGlutRecreateWindow); +} + +void rglGlutPostCommand(rglGlutCommand_f c) +{ + command = c; + SDL_SemPost(commandSem); +// SDL_LockMutex(commandMutex); +// SDL_CondSignal(commandCond); +// SDL_UnlockMutex(commandMutex); + SDL_SemWait(commandFinishedSem); +} + +void rglSwapBuffers() +{ + glutSwapBuffers(); +} + +#endif diff --git a/libmupen64plus/mupen64plus-video-z64/src/rgl_glut.h b/libmupen64plus/mupen64plus-video-z64/src/rgl_glut.h new file mode 100644 index 0000000000..be858496ac --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/rgl_glut.h @@ -0,0 +1,30 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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. + * +**/ + +typedef void (* rglGlutCommand_f)(); + +void rglGlutCreateThread(int recreatewindows); + +void rglGlutPostCommand(rglGlutCommand_f c); + +void rglSwapBuffers(); + +void rglGlutMinimizeWindow(); diff --git a/libmupen64plus/mupen64plus-video-z64/src/rgl_osdep.cpp b/libmupen64plus/mupen64plus-video-z64/src/rgl_osdep.cpp new file mode 100644 index 0000000000..2f6d1202e0 --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/rgl_osdep.cpp @@ -0,0 +1,102 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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 "rdp.h" +#include "rgl.h" + +#include + +SDL_Surface *sdl_Screen; +int viewportOffset; + +/* definitions 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_SwapBuffers CoreVideo_GL_SwapBuffers; + +//int screen_width = 640, screen_height = 480; +int screen_width = 1024, screen_height = 768; +//int screen_width = 320, screen_height = 240; + +int viewport_offset; + +void rglSwapBuffers() +{ + //TODO: if screenshot capabilities are ever implemented, replace the + //hard-coded 1 with a value indicating whether the screen has been redrawn + if (render_callback != NULL) + render_callback(1); + CoreVideo_GL_SwapBuffers(); + return; +} + +int rglOpenScreen() +{ + if (CoreVideo_Init() != M64ERR_SUCCESS) { + rdp_log(M64MSG_ERROR, "Could not initialize video."); + return 0; + } + if (rglStatus == RGL_STATUS_WINDOWED) { + screen_width = rglSettings.resX; + screen_height = rglSettings.resY; + } else { + screen_width = rglSettings.fsResX; + screen_height = rglSettings.fsResY; + } + + m64p_video_mode screen_mode = M64VIDEO_WINDOWED; + if (rglSettings.fullscreen) + screen_mode = M64VIDEO_FULLSCREEN; + + viewportOffset = 0; + + if (CoreVideo_GL_SetAttribute(M64P_GL_DOUBLEBUFFER, 1) != M64ERR_SUCCESS || + CoreVideo_GL_SetAttribute(M64P_GL_BUFFER_SIZE, 32) != M64ERR_SUCCESS || + CoreVideo_GL_SetAttribute(M64P_GL_DEPTH_SIZE, 24) != M64ERR_SUCCESS) + { + rdp_log(M64MSG_ERROR, "Could not set video attributes."); + return 0; + } + + if (CoreVideo_SetVideoMode(screen_width, screen_height, 32, screen_mode, (m64p_video_flags) 0) != M64ERR_SUCCESS) + { + rdp_log(M64MSG_ERROR, "Could not set video mode."); + return 0; + } + + CoreVideo_SetCaption("Z64gl"); + + rdp_init(); + return 1; +} + +void rglCloseScreen() +{ + rglClose(); + CoreVideo_Quit(); +} diff --git a/libmupen64plus/mupen64plus-video-z64/src/rgl_rendermode.cpp b/libmupen64plus/mupen64plus-video-z64/src/rgl_rendermode.cpp new file mode 100644 index 0000000000..c85a63cc59 --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/rgl_rendermode.cpp @@ -0,0 +1,722 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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 "rdp.h" +#include "rgl.h" + +#include + +void rglRenderMode(rglRenderChunk_t & chunk) +{ + //int i; + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + if (RDP_GETOM_CYCLE_TYPE(chunk.rdpState.otherModes) < 2) { + glDepthMask(RDP_GETOM_Z_UPDATE_EN(chunk.rdpState.otherModes)? GL_TRUE:GL_FALSE); + if (RDP_GETOM_Z_COMPARE_EN(chunk.rdpState.otherModes)) + glDepthFunc(GL_LESS); + else + glDepthFunc(GL_ALWAYS); + } else { + glDepthMask(GL_FALSE); + glDepthFunc(GL_ALWAYS); + } + + + // if (RDP_GETOM_Z_MODE(chunk.rdpState.otherModes) & 1) { + // glEnable( GL_POLYGON_OFFSET_FILL ); + // switch(RDP_GETOM_Z_MODE(chunk.rdpState.otherModes)) { + // case 3: + // glPolygonOffset( -3, -300 ); + // break; + // default: + // // FIXME tune this value + // //glPolygonOffset( -3.0f, -3.0f ); + // glPolygonOffset( -3, -40 ); + // break; + // } + // //glDepthMask(GL_FALSE); + // } else { + // glDisable( GL_POLYGON_OFFSET_FILL ); + // } +} + + + +struct rglCombiner_t { + rdpCombineModes_t combineModes; + rdpOtherModes_t otherModes; + rglShader_t * shader; +#ifndef RGL_EXACT_BLEND + GLuint srcBlend, dstBlend; +#endif + int format; +}; +#define RGL_MAX_COMBINERS 128 +static int rglNbCombiners; +static rglCombiner_t rglCombiners[RGL_MAX_COMBINERS]; + +void rglClearCombiners() +{ + int i; + for (i=0; i= 2) return 0; + if (cycle == 1 && ( + RDP_GETCM_SUB_A_RGB1(state.combineModes)==2 || + RDP_GETCM_SUB_B_RGB1(state.combineModes)==2 || + RDP_GETCM_MUL_RGB1(state.combineModes)==2 || + RDP_GETCM_MUL_RGB1(state.combineModes)==9 || + RDP_GETCM_ADD_RGB1(state.combineModes)==2 || + RDP_GETCM_SUB_A_A1(state.combineModes)==2 || + RDP_GETCM_SUB_B_A1(state.combineModes)==2 || + RDP_GETCM_MUL_A1(state.combineModes)==2 || + RDP_GETCM_ADD_A1(state.combineModes)==2)) + return 1; + if ( + (RDP_GETOM_CVG_TIMES_ALPHA(state.otherModes) && + !RDP_GETOM_ALPHA_CVG_SELECT(state.otherModes)) || + + RDP_GETCM_SUB_A_RGB0(state.combineModes)==1 || + RDP_GETCM_SUB_B_RGB0(state.combineModes)==1 || + RDP_GETCM_MUL_RGB0(state.combineModes)==1 || + RDP_GETCM_MUL_RGB0(state.combineModes)==8 || + RDP_GETCM_ADD_RGB0(state.combineModes)==1 || + RDP_GETCM_SUB_A_A0(state.combineModes)==1 || + RDP_GETCM_SUB_B_A0(state.combineModes)==1 || + RDP_GETCM_MUL_A0(state.combineModes)==1 || + RDP_GETCM_ADD_A0(state.combineModes)==1) + + return 1; + + return 0; +} +int rglT2Usage(rdpState_t & state) +{ + //return 1; + int cycle = RDP_GETOM_CYCLE_TYPE(state.otherModes); + if (cycle >= 2) return 0; + if (cycle == 1 && ( + RDP_GETCM_SUB_A_RGB1(state.combineModes)==1 || + RDP_GETCM_SUB_B_RGB1(state.combineModes)==1 || + RDP_GETCM_MUL_RGB1(state.combineModes)==1 || + RDP_GETCM_MUL_RGB1(state.combineModes)==8 || + RDP_GETCM_ADD_RGB1(state.combineModes)==1 || + RDP_GETCM_SUB_A_A1(state.combineModes)==1 || + RDP_GETCM_SUB_B_A1(state.combineModes)==1 || + RDP_GETCM_MUL_A1(state.combineModes)==1 || + RDP_GETCM_ADD_A1(state.combineModes)==1)) + return 1; + + if ( + RDP_GETCM_SUB_A_RGB0(state.combineModes)==2 || + RDP_GETCM_SUB_B_RGB0(state.combineModes)==2 || + RDP_GETCM_MUL_RGB0(state.combineModes)==2 || + RDP_GETCM_MUL_RGB0(state.combineModes)==9 || + RDP_GETCM_ADD_RGB0(state.combineModes)==2 || + RDP_GETCM_SUB_A_A0(state.combineModes)==2 || + RDP_GETCM_SUB_B_A0(state.combineModes)==2 || + RDP_GETCM_MUL_A0(state.combineModes)==2 || + RDP_GETCM_ADD_A0(state.combineModes)==2) + + return 1; + + return 0; +} + + +void rglSetCombiner(rglRenderChunk_t & chunk, int format) +{ + static char _1ma[64]; + static char t1[64]; + static char t1a[64]; + static char t2[64]; + static char t2a[64]; + static char prim_lod_frac[64]; + + static const char *saRGB[] = { + "c", t1, t2, "p/*PRIM*/", + "gl_Color", "e", "1.0/*NOISE*/", "1.0", + "0.0", "0.0", "0.0", "0.0", + "0.0", "0.0", "0.0", "0.0" + }; + + static const char *mRGB[] = { + "c", t1, t2, "p/*PRIM*/", + "gl_Color/*SHADE*/","e", "0.0/*SCALE*/", "c.a/*COMBINED_A*/", + "t1.a/*TEXEL0_A*/", "t2.a/*TEXEL1_A*/", "p.a/*PRIM_A*/", "gl_Color.a/*SHADEA*/", + "e.a/*ENV_ALPHA*/", "0.5/*LOD_FRACTION*/","0.5/*PRIM_LOD_FRAC*/","k5/*K5*/", + "0.0", "0.0", "0.0", "0.0", + "0.0", "0.0", "0.0", "0.0", + "0.0", "0.0", "0.0", "0.0", + "0.0", "0.0", "0.0", "0.0" + }; + + static const char *aRGB[] = { + "c", t1, t2, "p/*PRIM*/", + "gl_Color/*SHADE*/","e/*ENV*/", "1.0", "0.0", + }; + + static const char *saA[] = { + "c.a", t1a, t2a, "p.a/*PRIM*/", + "gl_Color.a", "e.a", "1.0", "0.0", + }; + + static const char *sbA[] = { + "c.a", t1a, t2a, "p.a/*PRIM*/", + "gl_Color.a", "e.a", "1.0", "0.0", + }; + + static const char *mA[] = { + "0.5/*LOD_FRACTION*/", t1a, t2a, "p.a/*PRIM*/", + "gl_Color.a/*SHADE*/", "e.a", prim_lod_frac, "0.0", + }; + + static const char *aA[] = { + "c.a", t1a, t2a, "p.a/*PRIM*/", + "gl_Color.a/*SHADE*/", "e.a", "1.0", "0.0", + }; + + const static char * bRGB[] = + { "c/*PREV*/", "f", "b", "fog/*FOG*/" }; + const static char * bA[2][4] = + { {"c.a/*PREVA*/", "fog.a/*FOGA*/", "gl_Color.a/*SHADEA*/", "0.0/*ZERO*/"}, + {_1ma/*"(1.0-c.a/ *PREVA)"*/, "0.0/*f.a*//*FRAGA*/", "1.0", "0.0"}}; // need clamping on 1-alpha ? + + + rdpState_t & state = chunk.rdpState; + static rglCombiner_t * c; + uint32_t cycle = RDP_GETOM_CYCLE_TYPE(state.otherModes); + int i; //, fmt, size; + char * p; + const char * alphaTest; + const char * alphaTest2; + const char * write; + static char src[4*4096]; + + float env[4]; + env[0] = RDP_GETC32_R(state.envColor)/255.0f; + env[1] = RDP_GETC32_G(state.envColor)/255.0f; + env[2] = RDP_GETC32_B(state.envColor)/255.0f; + env[3] = RDP_GETC32_A(state.envColor)/255.0f; + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, env); + + env[0] = RDP_GETC32_R(state.blendColor)/255.0f; + env[1] = RDP_GETC32_G(state.blendColor)/255.0f; + env[2] = RDP_GETC32_B(state.blendColor)/255.0f; + env[3] = RDP_GETC32_A(state.blendColor)/255.0f; + glLightfv(GL_LIGHT0, GL_AMBIENT, env); + + env[0] = RDP_GETC32_R(state.fogColor)/255.0f; + env[1] = RDP_GETC32_G(state.fogColor)/255.0f; + env[2] = RDP_GETC32_B(state.fogColor)/255.0f; + env[3] = RDP_GETC32_A(state.fogColor)/255.0f; + glLightfv(GL_LIGHT0, GL_DIFFUSE, env); + + glActiveTextureARB(GL_TEXTURE1_ARB); + env[0] = state.k5/255.0f; + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, env); + if (cycle == RDP_CYCLE_TYPE_FILL) { + if (0/*fb_size == 3*/) { // FIXME + env[0] = RDP_GETC32_R(state.fillColor)/255.0f; + env[1] = RDP_GETC32_G(state.fillColor)/255.0f; + env[2] = RDP_GETC32_B(state.fillColor)/255.0f; + env[3] = RDP_GETC32_A(state.fillColor)/255.0f; + } else { + env[0] = RDP_GETC16_R(state.fillColor)/31.0f; + env[1] = RDP_GETC16_G(state.fillColor)/31.0f; + env[2] = RDP_GETC16_B(state.fillColor)/31.0f; + env[3] = RDP_GETC16_A(state.fillColor); + } + } else { + env[0] = RDP_GETC32_R(state.primColor)/255.0f; + env[1] = RDP_GETC32_G(state.primColor)/255.0f; + env[2] = RDP_GETC32_B(state.primColor)/255.0f; + env[3] = RDP_GETC32_A(state.primColor)/255.0f; + } + glLightfv(GL_LIGHT0, GL_SPECULAR, env); + glActiveTextureARB(GL_TEXTURE0_ARB); + rglAssert(glGetError() == GL_NO_ERROR); + + // if (c && rglNbCombiners && + // RDP_GETOM_CYCLE_TYPE(c->otherModes) == cycle && + // (RDP_GETOM_CYCLE_TYPE(c->otherModes) >= 2 || + // (!memcmp(&c->combineModes, &state.combineModes, sizeof(rdpCombineModes_t)) && + // !memcmp(&c->otherModes, &state.otherModes, sizeof(rdpOtherModes_t))))) { + // return; + // } + + for (i=0; iformat == format && + RDP_GETOM_CYCLE_TYPE(c->otherModes) == cycle && + (RDP_GETOM_CYCLE_TYPE(c->otherModes) >= 2 || + (!memcmp(&c->combineModes, &state.combineModes, sizeof(rdpCombineModes_t)) + && !memcmp(&c->otherModes, &state.otherModes, sizeof(rdpOtherModes_t)) + ))) { +#ifdef RDP_DEBUG + chunk.shader = c->shader; +#endif + rglUseShader(c->shader); + goto ok; + } + } + + if (rglNbCombiners == RGL_MAX_COMBINERS) + rglClearCombiners(); + + c = rglCombiners + rglNbCombiners++; + c->otherModes = state.otherModes; + c->combineModes = state.combineModes; + c->format = format; +#ifndef RGL_EXACT_BLEND + c->srcBlend = GL_ONE; + c->dstBlend = GL_ZERO; +#endif + + switch (format & RGL_COMB_FMT) { +case RGL_COMB_FMT_RGBA: + write = "gl_FragColor = c;"; + break; +case RGL_COMB_FMT_I: + write = "gl_FragColor = vec4(c[0]);"; + break; +case RGL_COMB_FMT_DEPTH: + write = "gl_FragDepth = c[0];"; + break; + } + + if (cycle == RDP_CYCLE_TYPE_FILL) { + sprintf( + src, + "void main() \n" + "{ \n" + //" c = gl_TextureEnvColor[1];\n" + " vec4 c = gl_LightSource[0].specular;\n" + " %s\n" + "} \n", + write); + c->shader = rglCreateShader( + "void main() \n" + "{ \n" + " gl_Position = ftransform(); \n" + " gl_FrontColor = gl_Color; \n" + " gl_BackColor = gl_Color; \n" + " gl_TexCoord[0] = gl_MultiTexCoord0; \n" + "} \n" + , + src + ); +#ifdef RDP_DEBUG + chunk.shader = c->shader; +#endif + rglUseShader(c->shader); + goto ok; + } + + alphaTest = ""; + alphaTest2 = ""; + + if (//cycle < 2 && // CHECK THIS + RDP_GETOM_CVG_TIMES_ALPHA(chunk.rdpState.otherModes) + //&& rglT1Usage(chunk.rdpState) + ) { + if (RDP_GETOM_ALPHA_CVG_SELECT(chunk.rdpState.otherModes)) + alphaTest = "if (c.a < 0.5) discard; \n"; + else + alphaTest = "if (t1.a < 0.5) discard; \n"; + alphaTest2 = "if (c.a < 0.5) discard; \n"; + } + else if (RDP_GETOM_ALPHA_COMPARE_EN(chunk.rdpState.otherModes) && + !RDP_GETOM_ALPHA_CVG_SELECT(chunk.rdpState.otherModes)) { + if (RDP_GETC32_A(chunk.rdpState.blendColor) > 0) { + alphaTest = "if (c.a < b.a) discard; \n"; + alphaTest2 = + " vec4 b = gl_LightSource[0].ambient; \n" + " if (c.a < b.a) discard; \n"; + //alphaTest2 = "if (c.a < 0.5) discard; \n"; + } else { + alphaTest = "if (c.a == 0.0) discard; \n"; + alphaTest2 = "if (c.a == 0.0) discard; \n"; + } + } + + if (cycle == RDP_CYCLE_TYPE_COPY) { + sprintf( + src, + "uniform sampler2D texture0; \n" + " \n" + "void main() \n" + "{ \n" + " vec4 c = texture2D(texture0, vec2(gl_TexCoord[0])); \n" + " %s" + " %s\n" + "} \n", + alphaTest2, + write + ); + c->shader = rglCreateShader( + "void main() \n" + "{ \n" + " gl_Position = ftransform(); \n" + " gl_FrontColor = gl_Color; \n" + " gl_BackColor = gl_Color; \n" + " gl_TexCoord[0] = gl_MultiTexCoord0; \n" + "} \n" + , + src + ); +#ifdef RDP_DEBUG + chunk.shader = c->shader; +#endif + rglUseShader(c->shader); + goto ok; + } + + + p = src; + p += + sprintf(p, + "uniform sampler2D texture0; \n" + "uniform sampler2D texture2; \n" +#ifdef RGL_EXACT_BLEND + "uniform sampler2D texture1; \n" +#endif + " \n" + "void main() \n" + "{ \n" + "vec4 c = vec4(0,0,0,0);\n" + "vec4 e = gl_TextureEnvColor[0];\n" + "float k5 = gl_TextureEnvColor[1][0];\n" + "vec4 p = gl_LightSource[0].specular;\n" +#ifdef RGL_EXACT_BLEND + "vec4 f = texture2D(texture1, vec2(gl_FragCoord.x/(2048.0*gl_TexCoord[1].x), gl_FragCoord.y/(2048.0*gl_TexCoord[1].y))); \n" +#endif + "vec4 fog = gl_LightSource[0].diffuse; \n" + "vec4 b = gl_LightSource[0].ambient; \n"); + + switch (format & RGL_COMB_IN0) { +case 0: + p += + sprintf(p, + "vec4 t1 = texture2D(texture0, vec2(gl_TexCoord[0]));\n"); + break; +case RGL_COMB_IN0_DEPTH: + p += + sprintf(p, + "vec4 t1 = vec4(texture2D(texture0, vec2(gl_TexCoord[0]))[0]);\n"); + break; + } + switch (format & RGL_COMB_IN1) { +case 0: + p += + sprintf(p, + "vec4 t2 = texture2D(texture2, vec2(gl_TexCoord[2]));\n"); + break; +case RGL_COMB_IN1_DEPTH: + p += + sprintf(p, + "vec4 t2 = vec4(texture2D(texture2, vec2(gl_TexCoord[2]))[0]);\n"); + break; + } + + const char * comb, * comb2; + comb2 = 0; + // switch (RDP_GETOM_CVG_DEST(state.otherModes)) + // { + // case 3: + // comb = "c = clamp(vec4((vec3(%s) - vec3(%s)) * vec3(%s) + vec3(%s), (%s - %s) * %s + %s), 0.0, 1.0);\n"; + // break; + // case 2: + // comb = "c = vec4((vec3(%s) - vec3(%s)) * vec3(%s) + vec3(%s), (%s - %s) * %s + %s);\n"; + // //comb = "c = vec4((vec3(%s) - vec3(%s)) * vec3(%s) + vec3(%s), t1.a*((%s - %s) * %s + %s));\n"; + // break; + // case 0: + // //comb2 = "c = vec4((vec3(%s) - vec3(%s)) * vec3(%s) + vec3(%s), t1.a);\n"; + // case 1: + // comb = "c = vec4((vec3(%s) - vec3(%s)) * vec3(%s) + vec3(%s), (%s - %s) * %s + %s);\n"; + // break; + // } + comb = "c = clamp(vec4((vec3(%s) - vec3(%s)) * vec3(%s) + vec3(%s), (%s - %s) * %s + %s), 0.0, 1.0);\n"; + strcpy(prim_lod_frac, "0.5/*PRIM_LOD_FRAC*/"); + strcpy(t1, "t1"); + strcpy(t1a, "t1.a"); + if (format & RGL_COMB_TILE7) { + strcpy(t2, "t1"); + strcpy(t2a, "t1.a"); + } else { + strcpy(t2, "t2"); + strcpy(t2a, "t2.a"); + } + p += + sprintf(p, + comb + , + saRGB[RDP_GETCM_SUB_A_RGB0(state.combineModes)], + saRGB[RDP_GETCM_SUB_B_RGB0(state.combineModes)], + mRGB[RDP_GETCM_MUL_RGB0(state.combineModes)], + aRGB[RDP_GETCM_ADD_RGB0(state.combineModes)], + saA[RDP_GETCM_SUB_A_A0(state.combineModes)], + sbA[RDP_GETCM_SUB_B_A0(state.combineModes)], + mA[RDP_GETCM_MUL_A0(state.combineModes)], + aA[RDP_GETCM_ADD_A0(state.combineModes)] + ); + + if (cycle == RDP_CYCLE_TYPE_2) { + if (!(format & RGL_COMB_TILE7)) { + strcpy(t1, "t2"); + strcpy(t1a, "t2.a"); + strcpy(t2, "t1"); + strcpy(t2a, "t1.a"); + } + //strcpy(prim_lod_frac, "0.0/*PRIM_LOD_FRAC*/"); + // if (!RDP_GETOM_ALPHA_CVG_SELECT(chunk.rdpState.otherModes)) + // p += + // sprintf(p, " c.a = t1.a; \n"); + + p += + sprintf(p, + comb2? comb2 : comb + , + saRGB[RDP_GETCM_SUB_A_RGB1(state.combineModes)], + saRGB[RDP_GETCM_SUB_B_RGB1(state.combineModes)], + mRGB[RDP_GETCM_MUL_RGB1(state.combineModes)], + aRGB[RDP_GETCM_ADD_RGB1(state.combineModes)], + saA[RDP_GETCM_SUB_A_A1(state.combineModes)], + sbA[RDP_GETCM_SUB_B_A1(state.combineModes)], + mA[RDP_GETCM_MUL_A1(state.combineModes)], + aA[RDP_GETCM_ADD_A1(state.combineModes)] + ); + } + + // if (!RDP_GETOM_CVG_TIMES_ALPHA(state.otherModes)) + // p += sprintf(p, "c.a = t1.a; \n"); + + p += sprintf(p, "%s", alphaTest); + + + const char * blender; + blender = "c = vec4(float(%s)*vec3(%s) + float(%s)*vec3(%s), 1.0); \n"; +#ifdef RGL_EXACT_BLEND + const char * noblender = "c.a = 1.0;\n"; +#endif + + int m1b, m1a, m2b, m2a; + + //LOG("New combiner / blender :\n%s", rglCombiner2String(state)); + + if (cycle == RDP_CYCLE_TYPE_2) { + if (RDP_GETOM_FORCE_BLEND(state.otherModes)) { +#ifndef RGL_EXACT_BLEND + if (RDP_GETOM_BLEND_M1A_0(state.otherModes) != 1 && + RDP_GETOM_BLEND_M2A_0(state.otherModes) != 1) { +#endif + sprintf(_1ma, "(1.0 - %s)", bA[0][RDP_GETOM_BLEND_M1B_0(state.otherModes)]); + p += + sprintf( + p, + "c = vec4(float(%s)*vec3(%s) + float(%s)*vec3(%s), c.a); \n" + ,bA[0][RDP_GETOM_BLEND_M1B_0(state.otherModes)], + bRGB[RDP_GETOM_BLEND_M1A_0(state.otherModes)], + bA[1][RDP_GETOM_BLEND_M2B_0(state.otherModes)], + bRGB[RDP_GETOM_BLEND_M2A_0(state.otherModes)] + ); +#ifndef RGL_EXACT_BLEND + } else { + LOG("Blender error : fragment in cycle 1\n%s", rglCombiner2String(state)); + } +#endif + + m1b = RDP_GETOM_BLEND_M1B_1(state.otherModes); + m1a = RDP_GETOM_BLEND_M1A_1(state.otherModes); + m2b = RDP_GETOM_BLEND_M2B_1(state.otherModes); + m2a = RDP_GETOM_BLEND_M2A_1(state.otherModes); + } else { + m1b = RDP_GETOM_BLEND_M1B_0(state.otherModes); + m1a = RDP_GETOM_BLEND_M1A_0(state.otherModes); + m2b = RDP_GETOM_BLEND_M2B_0(state.otherModes); + m2a = RDP_GETOM_BLEND_M2A_0(state.otherModes); + } + } else { + m1b = RDP_GETOM_BLEND_M1B_0(state.otherModes); + m1a = RDP_GETOM_BLEND_M1A_0(state.otherModes); + m2b = RDP_GETOM_BLEND_M2B_0(state.otherModes); + m2a = RDP_GETOM_BLEND_M2A_0(state.otherModes); + } + + if (RDP_GETOM_FORCE_BLEND(state.otherModes) || cycle == RDP_CYCLE_TYPE_2) { +#ifndef RGL_EXACT_BLEND + if (m1a == 1 || m2a == 1) { + if (/*(m1a != 1 || m1b == 3) &&*/ (m2a == 1 || m2b == 3)) { + int src = GL_ZERO, dst = GL_ONE; + const char * alpha = "c.a"; + switch (m1b) { +case 0: // c.a + src = GL_SRC_ALPHA; + break; +case 1: // fog.a + src = GL_SRC_ALPHA; + alpha = "fog.a"; + // LOGERROR("Unsupported src alpha : FOG\n"); + // LOGERROR(rglCombiner2String(state)); + break; +case 2: // shade.a + src = GL_SRC_ALPHA; + alpha = "gl_Color.a"; + // LOGERROR("Unsupported src alpha : SHADE\n"); + // LOGERROR(rglCombiner2String(state)); + break; +case 3: // 0 + src = GL_ZERO; + break; + } + switch (m1a) { +case 0: // c + if (m1b != 0 /* c.a */) + p += sprintf( + p, "c.a = %s; \n", alpha); + break; +case 1: // f + LOGERROR("Unsupported src color : FRAG\n"); + LOGERROR("%s", rglCombiner2String(state)); + break; +case 2: // b + p += sprintf( + p, "c = vec4(vec3(b), %s); \n", alpha); + break; +case 3: // fog + p += sprintf( + p, "c = vec4(vec3(fog), %s); \n", alpha); + break; + } + switch (m2b) { +case 0: + switch (m1b) { +case 3: + dst = GL_ONE; + break; +default: + dst = GL_ONE_MINUS_SRC_ALPHA; + break; + } + break; +case 1: + dst = GL_DST_ALPHA; + break; +case 2: + dst = GL_ONE; + break; +case 3: + dst = GL_ZERO; + break; + } + + c->srcBlend = src; + c->dstBlend = dst; + } else { + LOGERROR("Unsuported blender :\n"); + LOGERROR("%s", rglCombiner2String(state)); + } + } + else +#endif + { + sprintf(_1ma, "(1.0 - %s)", bA[0][m1b]); + p += + sprintf(p, blender, bA[0][m1b], bRGB[m1a], bA[1][m2b], bRGB[m2a]); + } + } else { +#ifdef RGL_EXACT_BLEND + p += + sprintf(p, + noblender + ); +#endif + } + + p += + sprintf( + p, + "%s \n" + "} \n" + ,write + ); + + rglAssert(p < src+sizeof(src)); + +#ifdef RGL_EXACT_BLEND + //printf("Creating combiner : \n%s", src); +#endif + + c->shader = rglCreateShader( + "void main() \n" + "{ \n" + " gl_Position = ftransform(); \n" + " gl_FrontColor = gl_Color; \n" + " gl_BackColor = gl_FrontColor; \n" + " gl_TexCoord[0] = gl_MultiTexCoord0; \n" +#ifdef RGL_EXACT_BLEND + " gl_TexCoord[1] = gl_MultiTexCoord1; \n" +#endif + " gl_TexCoord[2] = gl_MultiTexCoord2; \n" + "} \n" + , + src); + +#ifdef RDP_DEBUG + chunk.shader = c->shader; +#endif + rglUseShader(c->shader); + rglAssert(glGetError() == GL_NO_ERROR); + + int location; + location = glGetUniformLocationARB(c->shader->prog, "texture0"); + glUniform1iARB(location, 0); +#ifdef RGL_EXACT_BLEND + location = glGetUniformLocationARB(c->shader->prog, "texture1"); + glUniform1iARB(location, 1); +#endif + location = glGetUniformLocationARB(c->shader->prog, "texture2"); + glUniform1iARB(location, 2); + rglAssert(glGetError() == GL_NO_ERROR); + +ok:; +#ifndef RGL_EXACT_BLEND + if ((format & RGL_COMB_FMT) == RGL_COMB_FMT_DEPTH || + (c->srcBlend == GL_ONE && c->dstBlend == GL_ZERO)) + glDisable(GL_BLEND); + else { + glEnable(GL_BLEND); + if ((format & RGL_COMB_FMT) == RGL_COMB_FMT_RGBA) + glBlendFuncSeparate(c->srcBlend, c->dstBlend, GL_ZERO, GL_ONE); + else + glBlendFunc(c->srcBlend, c->dstBlend); + } +#endif +} diff --git a/libmupen64plus/mupen64plus-video-z64/src/rgl_settings.cpp b/libmupen64plus/mupen64plus-video-z64/src/rgl_settings.cpp new file mode 100644 index 0000000000..65d9ea49db --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/rgl_settings.cpp @@ -0,0 +1,71 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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 "rdp.h" +#include "rgl.h" + +extern ptr_ConfigOpenSection ConfigOpenSection; +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; + +char rgl_cwd[512]; + +int rglReadSettings() +{ + + m64p_handle videoGeneralSection; + m64p_handle videoZ64Section; + if (ConfigOpenSection("Video-General", &videoGeneralSection) != M64ERR_SUCCESS || + ConfigOpenSection("Video-Z64", &videoZ64Section) != M64ERR_SUCCESS) + { + rdp_log(M64MSG_ERROR, "Could not open configuration"); + return false; + } + + ConfigSetDefaultBool(videoGeneralSection, "Fullscreen", false, "Use fullscreen mode if True, or windowed mode if False"); + ConfigSetDefaultBool(videoZ64Section, "HiResFB", true, "High resolution framebuffer"); + ConfigSetDefaultBool(videoZ64Section, "FBInfo", true, "Use framebuffer info"); + ConfigSetDefaultBool(videoZ64Section, "Threaded", false, "Run RDP on thread"); + ConfigSetDefaultBool(videoZ64Section, "Async", false, "Run RDP asynchronously"); + ConfigSetDefaultBool(videoZ64Section, "NoNpotFbos", false, "Don't use NPOT FBOs (may be needed for older graphics cards)"); + + rglSettings.resX = ConfigGetParamInt(videoGeneralSection, "ScreenWidth"); + rglSettings.resY = ConfigGetParamInt(videoGeneralSection, "ScreenHeight"); + rglSettings.fsResX = ConfigGetParamInt(videoGeneralSection, "ScreenWidth"); + rglSettings.fsResY = ConfigGetParamInt(videoGeneralSection, "ScreenHeight"); + rglSettings.fullscreen = ConfigGetParamBool(videoGeneralSection, "Fullscreen"); + rglSettings.hiresFb = ConfigGetParamBool(videoZ64Section, "HiResFB"); + rglSettings.fbInfo = ConfigGetParamBool(videoZ64Section, "FBInfo"); + rglSettings.threaded = ConfigGetParamBool(videoZ64Section, "Threaded"); + rglSettings.async = ConfigGetParamBool(videoZ64Section, "Async"); + rglSettings.noNpotFbos = ConfigGetParamBool(videoZ64Section, "NoNpotFbos"); + + return true; +} diff --git a/libmupen64plus/mupen64plus-video-z64/src/rgl_tiles.cpp b/libmupen64plus/mupen64plus-video-z64/src/rgl_tiles.cpp new file mode 100644 index 0000000000..bca1554c2c --- /dev/null +++ b/libmupen64plus/mupen64plus-video-z64/src/rgl_tiles.cpp @@ -0,0 +1,676 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * 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 "rdp.h" +#include "rgl.h" + +#include + +rglTextureHead_t freeTextures; +rglTextureHead_t texturesByCrc[256]; +rglTextureHead_t texturesByUsage; + +void rglTouchTMEM() +{ + rglTexCacheCounter++; + if (!rglTexCacheCounter) { + // shouldn't happen too often but let's do things correctly for the hell of it ;) + rglResetTextureCache(); + } +} + +inline int crc8(uint32_t crc) +{ + uint8_t res; + res = crc^(crc>>8)^(crc>>16)^(crc>>24); + return res; +} + +void rglDeleteTexture(rglTexture_t * tex) +{ + //LOG("deleting texture %x\n", tex); + glDeleteTextures(1, &tex->id); + if (tex->zid) + glDeleteTextures(1, &tex->zid); + rglAssert(glGetError() == GL_NO_ERROR); + tex->id = tex->zid = 0; + CIRCLEQ_REMOVE(&texturesByUsage, tex, byUsage); + CIRCLEQ_REMOVE(&texturesByCrc[crc8(tex->crc)], tex, byCrc); + CIRCLEQ_INSERT_TAIL(rglTexture_t, &freeTextures, tex, byUsage); +} + +rglTexture_t * rglNewTexture(uint32_t crc) +{ + rglTexture_t * res; + + if (CIRCLEQ_EMPTY(&freeTextures)) + rglDeleteTexture(CIRCLEQ_FIRST(&texturesByUsage)); + + res = CIRCLEQ_FIRST(&freeTextures); + //LOG("new texture %x %x crc %x\n", res, crc, crc8(crc)); + CIRCLEQ_REMOVE(&freeTextures, res, byUsage); + CIRCLEQ_INSERT_TAIL(rglTexture_t, &texturesByUsage, res, byUsage); + CIRCLEQ_INSERT_TAIL(rglTexture_t, &texturesByCrc[crc8(crc)], res, byCrc); + + res->wt = res->ws = res->filter = 0; + + return res; +} + +void rglInitTextureCache() +{ + int i; + // initialize textures lists + CIRCLEQ_INIT(rglTexture_t, &freeTextures); + CIRCLEQ_INIT(rglTexture_t, &texturesByUsage); + for (i=0; i<256; i++) + CIRCLEQ_INIT(rglTexture_t, &texturesByCrc[i]); + for (i=0; i>2)+1; + int cliph = ((tile.th - tile.tl) >>2)+1; + int indirect = 1; + uint8_t * from = rdpTmem; + int ow, oh; + + // if (recth && cliph == recth+1) // hack for Mario Party (not necessary if we handle filter for texrect) + // cliph = recth; + + // if (tile.ms && tile.mask_s && (2<> tile.size; + //if (tile.mask_s && (1<>2)+1; // FIXME why not cliph ??? + //tile.h = (tile.th >>2)+1; + // if (tile.h <= 0) + // tile.h = (tile.th >>2)+1; + // FIXME remove test on mt ? + if (tile.mask_t && ((1<>2)) tile.h <<= 1; + // } + } + + // if (!tile.mask_t && !tile.ct/* && !tile.mt*/) + // tile.h = (0x1000-tile.tmem)/line; + + // if (tile.sl && !tile.mask_s) { + // printf("shifting sl %d\n", tile.sl); + // tile.tmem += tile.sl << tile.format >> 1; + // tile.tmem &= 0xfff; + // tile.sl = 0; + // } + // if (tile.tl && !tile.mask_t) { + // printf("shifting tl %d\n", tile.tl); + // tile.tmem += tile.tl * line; + // tile.tmem &= 0xfff; + // tile.tl = 0; + // } + + if (recth && tile.h == 1) + // +1 for yoshi + tile.h = recth+1; + + if (/*tile.h == 1 || */tile.w*tile.h << tile.size >> 1 > 0x1000-tile.tmem) { + DUMP("fixing tile size from %dx%d to ", tile.w, tile.h); + //tile.w = (line << 3) >> tile.size + 2; + //tile.h = 1; while (tile.h<(tile.th>>2)) tile.h <<= 1; + tile.h = (0x1000-tile.tmem)/line; + DUMP("%dx%d\n", tile.w, tile.h); + } + + // this is a warkaround for a bug in pj64 rsp plugin + // now fixed + if (0&&recth && /*tile.line == 8 && */tile.h == 1) { + //LOG("direct\n"); + tile.w = rdpTiWidth << rdpTiSize >> tile.size; + tile.h = recth; + from = gfx.RDRAM + rdpTiAddress; + if (recth > 1 || rdpTiWidth > 1) + line = rdpTiWidth << rdpTiSize >> 1; + indirect = 0; + } + + { + int fromLine, stop, fromFormat, fromSize; + uint32_t address = rdpGetTmemOrigin(tile.tmem, &fromLine, &stop, &fromFormat, &fromSize); + DUMP("tmem %x rdram %x\n", tile.tmem, address); + if (address != (uint32_t)~0) { + rglRenderBuffer_t * buffer; + if (!fromLine) fromLine = line; + if (!tile.mask_t) + tile.h = (stop-tile.tmem)/line; + rtile.hiresBuffer = 0; + //while (0) { + CIRCLEQ_FOREACH(rglRenderBuffer_t, buffer, &rBufferHead, link) { + //if (buffer->flags & RGL_RB_DEPTH) continue; + if (buffer->area.xh != 8192) + buffer->addressStop = buffer->addressStart + buffer->line * ((buffer->area.yl >>2)+1); + + // conservative + // if (address + tile.h * line > buffer->addressStart && + // address < buffer->addressStop) + if (address >= buffer->addressStart/* + buffer->line * ((buffer->area.yh >>2)+1)*/ && // oops cannot use yh, might not be initialized + address + tile.h * line <= buffer->addressStop) + DUMP("check %x --> %x with %x --> %x (%x %x %d %x)\n", + address, address + tile.h * line, + buffer->addressStart, buffer->addressStop, + fromLine, buffer->line, tile.h, line); + + // TODO store real address stop, it's not necessarily the same as + // address + tile.h * line + // conservative + // if (address + tile.h * line > buffer->addressStart && + // address < buffer->addressStop && + // more strict (better for LEGO racer) + // general solution would be : find all candidates, pick the one that covers + // the biggest area + if ((!rtile.hiresBuffer || buffer->addressStart > rtile.hiresBuffer->addressStart) && + address >= buffer->addressStart/* + buffer->line * ((buffer->area.yh >>2)+1)*/ && // oops cannot use yh, might not be initialized + address + tile.h * line <= buffer->addressStop && + (tile.h <= 1 || fromLine == buffer->line)) { + DUMP("texture buffer at %x %d x %d %d %d fmt %d fromfmt %d\n", + buffer->addressStart, tile.w, tile.h, + fromLine, buffer->line, tile.format, fromFormat); + + rtile.hiresBuffer = buffer; + rtile.hiresAddress = address; + + break; + } + } + + if (rtile.hiresBuffer) { + // FIXME current buffer could be a depth buffer, in this case + // we want the texture rendered as depth too + rtile.hiresBuffer->flags &= ~RGL_RB_DEPTH; + //rglRenderChunks(rtile.hiresBuffer); + } + + if (rglSettings.hiresFb && rtile.hiresBuffer) { + memcpy(&rtile, &tile, sizeof(tile)); + return; + } + + if (rtile.hiresBuffer) { + LOG("updating rdram %x\n", address); + rglFramebuffer2Rdram(*rtile.hiresBuffer, address, address + tile.h * line); + line = fromLine; + from = gfx.RDRAM + address; + indirect = 0; + } + + } + } + rtile.hiresBuffer = 0; + + if (tile.w > 1024) tile.w = 1024; + if (tile.h > 1024) tile.h = 1024; + + ow = tile.w; oh = tile.h; // save w/h before making it a power of 2 + { + int w=1, h=1; + while (w < tile.w) w*=2; + while (h < tile.h) h*=2; + tile.w = rtile.w = w; + tile.h = rtile.h = h; + } + + memcpy(&rtile, &tile, sizeof(tile)); + rtile.line = line; + + // NOTE more general solutions would involve subdividing the geometry + // or writing clamping/mirroring in glsl + int badmirror_s = + tile.mask_s && tile.cs && tile.ms && (clipw/2) < (1< (1< (1<>2) << tile.size >> 1; + // tile.sh -= tile.sl; + // tile.sl = 0; + ws = GL_CLAMP_TO_EDGE; + } + if (tile.ms && !badmirror_s) + ws = ((!tile.mask_s || tile.cs) && !badclamp_s)? +GL_MIRROR_CLAMP_TO_EDGE_EXT : GL_MIRRORED_REPEAT; + + wt = GL_REPEAT; + //wt = GL_CLAMP_TO_EDGE; + if ((!tile.mask_t || tile.ct) && !badclamp_t) { + // tile.tmem += (tile.tl>>2) * line; + // tile.th -= tile.tl; + // tile.tl = 0; + wt = GL_CLAMP_TO_EDGE; + } + if (tile.mt && !badmirror_t) + wt = ((!tile.mask_t || tile.ct) && !badclamp_t)? +GL_MIRROR_CLAMP_TO_EDGE_EXT : GL_MIRRORED_REPEAT; + +#if 1 + if ((npot_s||npot_t) && ws != GL_CLAMP_TO_EDGE) { + //LOG("Fixup npot clamp s\n"); + ws = GL_CLAMP_TO_EDGE; + } + if ((npot_t||npot_s) && wt != GL_CLAMP_TO_EDGE) { + //LOG("Fixup npot clamp t\n"); + wt = GL_CLAMP_TO_EDGE; + } +#else + // ws = GL_CLAMP_TO_EDGE; + // wt = GL_CLAMP_TO_EDGE; +#endif + + rtile.ws = ws; + rtile.wt = wt; + + rglAssert(!(tile.tmem & ~ 0xfff)); + if (rglTexCache[tile.tmem].counter == rglTexCacheCounter && + rglTexCache[tile.tmem].tex->fmt == tile.format && + rglTexCache[tile.tmem].tex->w == tile.w + && + rglTexCache[tile.tmem].tex->h == tile.h + // rglTexCache[tile.tmem].tex->h > (tile.th>>2) + ) { + tex = rglTexCache[tile.tmem].tex; + goto ok; + } + + // printf("tile #%d fmt %s sz %d w %d mask %d %dx%d (%d %d)\n", &tile-rdpTiles, rdpImageFormats[tile.format], tile.size, line, tile.mask_s, (tile.sh - tile.sl >>2)+1, (tile.th - tile.tl >>2)+1, tile.sl>>2, tile.tl>>2); + + //rglAssert(tile.w == (tile.sh - tile.sl >>2)+1); + + { + int h, i, j, x, y; + int palette = 0; + uint32_t crc = 0; + rglTextureHead_t * list; + +#if 1 + if (tile.format == RDP_FORMAT_CI || + (tile.size <= 1 && RDP_GETOM_EN_TLUT(rdpState.otherModes))) { + // tlut crc + h = tile.size? 256:16; + if (tile.size == 0) palette = (tile.palette<<4)&0xff; + for (i=0; i>3)|(crc<<(32-3)))+(rdpTlut[(i+palette)*4]); + } + + for (y=0; y>2); x++) + crc = ((crc>>3)|(crc<<(32-3)))+(*p++); + } + + list = texturesByCrc + crc8(crc); + CIRCLEQ_FOREACH(rglTexture_t, tex, list, byCrc) { + //LOG("comparing %x with %x\n", tex->crc, crc); + if (tex->crc == crc && + tex->fmt == tile.format && + tex->clipw >= clipw && + tex->cliph >= cliph && + tex->w == tile.w && + tex->h >= tile.h) { + CIRCLEQ_REMOVE(&texturesByUsage, tex, byUsage); + CIRCLEQ_INSERT_TAIL(rglTexture_t, &texturesByUsage, tex, byUsage); + goto ok2; + } + // if (tex->crc == crc) + // LOG("Same CRC %x !\n", crc); + } +#endif + + tex = rglNewTexture(crc); + tex->fmt = tile.format; + tex->w = tile.w; + tex->h = tile.h; + tex->clipw = clipw; + tex->cliph = cliph; + tex->crc = crc; + glGenTextures(1, &tex->id); + rglAssert(glGetError() == GL_NO_ERROR); + + + glBindTexture(GL_TEXTURE_2D, tex->id); + rglAssert(glGetError() == GL_NO_ERROR); + uint8_t * ptr; + GLuint packed = 0; + GLuint glfmt = 0, glpixfmt = 0; + + ptr = rglTmpTex2; + +#define XOR_SWAP_BYTE 3 +#define XOR_SWAP_WORD 2 +#define XOR_SWAP_DWORD 2 + // ugly but it works ... + if (tile.cs || !tile.mask_s) ow = tile.w; + if (tile.ct || !tile.mask_t) oh = tile.h; +#define CLAMP \ + int ci = i; \ + int cj = j; \ + if ((tile.cs || !tile.mask_s) && ci >= clipw) ci = clipw-1; \ + if ((tile.ct || !tile.mask_t) && cj >= cliph) cj = cliph-1; \ + + switch (tile.size) { + case 3: + for (j=0; j>4)|(a<<4); + } + break; + } + from = ptr; + + i = tile.format; + + // in Tom Clancy, they do this, using I texture with TLUT enabled + if (i != RDP_FORMAT_CI && tile.size <= 1 && RDP_GETOM_EN_TLUT(rdpState.otherModes)) { + LOG("fixing %s-%d tile to CI\n", rdpImageFormats[i], tile.size); + i = RDP_FORMAT_CI; + } + + if (tile.size <= 1 && i == RDP_FORMAT_RGBA) { + LOG("fixing RGBA tile to I\n"); + i = RDP_FORMAT_I; + } + + switch (i) { + case RDP_FORMAT_CI: { + if (!RDP_GETOM_TLUT_TYPE(rdpState.otherModes)) { + glfmt = GL_RGBA; + packed = GL_UNSIGNED_SHORT_5_5_5_1; + } else { + glfmt = GL_RGBA; + glpixfmt = GL_LUMINANCE_ALPHA; + //glfmt = GL_LUMINANCE_ALPHA; + packed = GL_UNSIGNED_BYTE; + } + switch (tile.size) { + case 0: + ptr = rglTmpTex; + for (i=0; i>4) + palette/* ^ WORD_ADDR_XOR*/)*4]; + if (RDP_GETOM_TLUT_TYPE(rdpState.otherModes)) { + a = (a>>8)|(a<<8); + b = (b>>8)|(b<<8); + } + *(uint16_t *)&ptr[i*4] = a; + *(uint16_t *)&ptr[i*4+2] = b; + } + break; + case 1: + ptr = rglTmpTex; + //rdpTlut[palette] = 0; + for (i=0; i>8)|(a<<8); + *(uint16_t *)&ptr[i*2] = a; + } + break; + } + break; + } + case RDP_FORMAT_RGBA: { + glfmt = GL_RGBA; + switch (tile.size) { + case 2: + //packed = GL_UNSIGNED_SHORT_4_4_4_4_REV; + packed = GL_UNSIGNED_SHORT_5_5_5_1; + break; + case 3: + packed = GL_UNSIGNED_INT_8_8_8_8; + break; + } + break; + } + case RDP_FORMAT_IA: { + glfmt = GL_RGBA; + glpixfmt = GL_LUMINANCE_ALPHA; + //if (tile.size == 0) line *= 2; + switch (tile.size) { + case 0: { + packed = GL_UNSIGNED_BYTE; + ptr = rglTmpTex; + for (i=0; i> 5; + int8_t b = (from[i]&0x10) >> 4; + ptr[i*4+2] = (a<<5) | (a<<2) | (a>>1); + ptr[i*4+3] = -b; + a = (from[i]&0xe) >> 1; + b = (from[i]&0x1); + ptr[i*4+0] = (a<<5) | (a<<2) | (a>>1); + ptr[i*4+1] = -b; + } + break; + } + case 1: { + packed = GL_UNSIGNED_BYTE; + ptr = rglTmpTex; + for (i=0; i>4); + ptr[i*2] = a | (a>>4); + a = from[i]&0x0F; + a = a | (a<<4); + ptr[i*2+1] = a; + } + break; + } + case 2: + packed = GL_UNSIGNED_BYTE; + ptr = rglTmpTex; + for (i=0; i>4); + a = from[i]&0x0F; + ptr[i*2] = a | (a<<4); + } + break; + } + case 1: { + packed = GL_UNSIGNED_BYTE; + break; + } + } + break; + } + } + + if (packed) { + DUMP("loading texture %dx%d fmt %s size %x (%x %x %x %p)\n", tile.w, tile.h, rdpImageFormats[tile.format], tile.size, glfmt, glpixfmt, packed, ptr); + // printf("cycle type = %d\n", chunk.rdpState.otherModes.cycle_type); + if (!glpixfmt) + glpixfmt = glfmt; + rglAssert(glGetError() == GL_NO_ERROR); + glTexImage2D(GL_TEXTURE_2D, 0, glfmt, tile.w, tile.h, 0, glpixfmt, packed, + ptr); + rglAssert(glGetError() == GL_NO_ERROR); + + +#if 0 + if (1||RDP_GETOM_CYCLE_TYPE(rdpState.otherModes) == RDP_CYCLE_TYPE_COPY) { + uint32_t * pixels = (uint32_t *) malloc(tile.w*tile.h*4); + // 0x1902 is another constant meaning GL_DEPTH_COMPONENT + // (but isn't defined in gl's headers !!) + if (1/*fmt != GL_DEPTH_COMPONENT && fmt != 0x1902*/) { + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + ilTexImage(tile.w, tile.h, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, pixels); + } else { + glGetTexImage(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, pixels); + int i; + for (i=0; i + +#define DACRATE_NTSC (48681812) +#define DACRATE_PAL (49656530) +#define DACRATE_MPAL (48628316) + +#define SP_INTERRUPT 0x1 +#define SI_INTERRUPT 0x2 +#define AI_INTERRUPT 0x4 +#define VI_INTERRUPT 0x8 +#define PI_INTERRUPT 0x10 +#define DP_INTERRUPT 0x20 + +#define SP_STATUS_HALT 0x0001 +#define SP_STATUS_BROKE 0x0002 +#define SP_STATUS_DMABUSY 0x0004 +#define SP_STATUS_DMAFULL 0x0008 +#define SP_STATUS_IOFULL 0x0010 +#define SP_STATUS_SSTEP 0x0020 +#define SP_STATUS_INTR_BREAK 0x0040 +#define SP_STATUS_SIGNAL0 0x0080 +#define SP_STATUS_SIGNAL1 0x0100 +#define SP_STATUS_SIGNAL2 0x0200 +#define SP_STATUS_SIGNAL3 0x0400 +#define SP_STATUS_SIGNAL4 0x0800 +#define SP_STATUS_SIGNAL5 0x1000 +#define SP_STATUS_SIGNAL6 0x2000 +#define SP_STATUS_SIGNAL7 0x4000 + +#define DP_STATUS_XBUS_DMA 0x01 +#define DP_STATUS_FREEZE 0x02 +#define DP_STATUS_FLUSH 0x04 +#define DP_STATUS_START_GCLK 0x008 +#define DP_STATUS_TMEM_BUSY 0x010 +#define DP_STATUS_PIPE_BUSY 0x020 +#define DP_STATUS_CMD_BUSY 0x040 +#define DP_STATUS_CBUF_READY 0x080 +#define DP_STATUS_DMA_BUSY 0x100 +#define DP_STATUS_END_VALID 0x200 +#define DP_STATUS_START_VALID 0x400 + +#define R4300i_SP_Intr 1 + + +#define LSB_FIRST 1 // TODO : check for platform +#ifdef LSB_FIRST + #define BYTE_ADDR_XOR 3 + #define WORD_ADDR_XOR 1 + #define BYTE4_XOR_BE(a) ((a) ^ 3) /* read/write a byte to a 32-bit space */ +#else + #define BYTE_ADDR_XOR 0 + #define WORD_ADDR_XOR 0 + #define BYTE4_XOR_BE(a) (a) +#endif + + +typedef uint64_t UINT64; +typedef int64_t INT64; +typedef uint32_t UINT32; +typedef int32_t INT32; +typedef uint16_t UINT16; +typedef int16_t INT16; +typedef uint8_t UINT8; +typedef int8_t INT8; +typedef unsigned int offs_t; +#endif +