pax_global_header00006660000000000000000000000064146450732440014523gustar00rootroot0000000000000052 comment=fcf00779f08a9503ef30d26422f6b0350684820d mupen64plus-video-rice-src-2.6.0/000077500000000000000000000000001464507324400165435ustar00rootroot00000000000000mupen64plus-video-rice-src-2.6.0/.gitattributes000066400000000000000000000007661464507324400214470ustar00rootroot00000000000000* text=auto # normal text files *.6 text AUTHORS text *.c text *.cfg text *.cht text *.conf text COPYING text *.cpp text *.def text *-license text *.h text *.html text *.ini text INSTALL text LICENSES text Makefile text *.py text README text RELEASE text *.S text *.sh text *.txt text *.ver text # windows specific text files *.sln text eol=crlf *.vcproj text eol=crlf *.vcxproj text eol=crlf *.vcxproj.filters text eol=crlf # binary files *.gz binary *.ttf binary cursor.tex binary font.tex binary mupen64plus-video-rice-src-2.6.0/.github/000077500000000000000000000000001464507324400201035ustar00rootroot00000000000000mupen64plus-video-rice-src-2.6.0/.github/workflows/000077500000000000000000000000001464507324400221405ustar00rootroot00000000000000mupen64plus-video-rice-src-2.6.0/.github/workflows/build.yml000066400000000000000000000121701464507324400237630ustar00rootroot00000000000000name: Rice on: push: paths-ignore: - '.{gitattributes,gitignore,travis.yml}' - '*.md,appveyor.yml,README' pull_request: paths-ignore: - '.{gitattributes,gitignore,travis.yml}' - '*.md,appveyor.yml,README' workflow_dispatch: jobs: Linux: strategy: fail-fast: false matrix: include: - cc: GCC arch: x64 - cc: GCC arch: x86 - cc: Clang arch: x64 - cc: Clang arch: x86 name: Linux / ${{ matrix.cc }} / ${{ matrix.arch }} runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - name: Get build dependencies and arrange the environment run: | git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12" export BUILD_DEPS="libgl1-mesa-dev libpng-dev libsdl1.2-dev libsdl2-dev zlib1g-dev" ./../mupen64plus-core/.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }} - name: Build and related stuff, backup binaries run: | export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12" export PATH="$(pwd)/../mupen64plus-core/.github/workflows/scripts:${PATH}" export CONFIG_OVERRIDE="SDL_CONFIG="sdl-config"" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} export CONFIG_OVERRIDE="SDL_CONFIG="sdl2-config"" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg - name: Upload artifact if: matrix.cc == 'GCC' uses: actions/upload-artifact@v4 with: name: ${{ env.PKG_NAME }} path: pkg/*.tar.gz MSYS2: strategy: fail-fast: false matrix: include: - cc: GCC arch: x64 cross: x86_64 env: MINGW64 - cc: GCC arch: x86 cross: i686 env: MINGW32 name: Windows / MSYS2 ${{ matrix.cc }} / ${{ matrix.arch }} runs-on: windows-2022 defaults: run: shell: msys2 {0} steps: - uses: actions/checkout@v4 - uses: msys2/setup-msys2@v2 with: msystem: ${{ matrix.env }} update: true install: >- git libtool make mingw-w64-${{ matrix.cross }}-gcc mingw-w64-${{ matrix.cross }}-toolchain mingw-w64-${{ matrix.cross }}-libpng mingw-w64-${{ matrix.cross }}-ntldd mingw-w64-${{ matrix.cross }}-SDL2 mingw-w64-${{ matrix.cross }}-zlib - name: Build and related stuff, backup binaries run: | git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core ./../mupen64plus-core/.github/workflows/scripts/ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} - name: Backup dependencies, etc... run: | ./../mupen64plus-core/.github/workflows/scripts/ci_backup_mingw_deps.sh ${{ matrix.env }} - name: Upload artifact uses: actions/upload-artifact@v4 with: name: ${{ env.PKG_NAME }} path: pkg/* MSVC: strategy: fail-fast: false matrix: include: - toolset: v143 arch: x64 vs: 2022 - toolset: v141_xp arch: x86 vs: 2019 name: Windows / MSVC with ${{ matrix.toolset }} / ${{ matrix.arch }} runs-on: windows-${{ matrix.vs }} defaults: run: shell: cmd steps: - uses: actions/checkout@v4 - uses: microsoft/setup-msbuild@v2 - name: Build and related stuff, backup binaries run: | git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ..\mupen64plus-core set TOOLSET=${{ matrix.toolset }} .\..\mupen64plus-core\.github\workflows\scripts\ci_msvc_build.cmd ${{ matrix.arch }} - name: Backup dependencies, etc... run: | .\..\mupen64plus-core\.github\workflows\scripts\ci_backup_msvc_deps.cmd ${{ matrix.arch }} libpng16.dll SDL2.dll - name: Upload artifact uses: actions/upload-artifact@v4 with: name: ${{ env.PKG_NAME }} path: pkg/* Nightly-build: runs-on: ubuntu-latest if: github.ref_name == 'master' needs: [Linux, MSYS2, MSVC] steps: - uses: actions/checkout@v4 - name: Download artifacts uses: actions/download-artifact@v4 with: path: binaries - name: Get some tools run: | git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core sudo apt-get update sudo apt-get -y install hashdeep - name: Creating new artifacts and update nightly-build run: | ./../mupen64plus-core/.github/workflows/scripts/ci_nightly_artifacts.sh - name: Nightly-build uses: ncipollo/release-action@v1 with: prerelease: true allowUpdates: true removeArtifacts: true replacesArtifacts: false tag: nightly-build artifacts: pkg/* mupen64plus-video-rice-src-2.6.0/.github/workflows/schedule.yml000066400000000000000000000121721464507324400244620ustar00rootroot00000000000000name: Rice - Scheduled on: schedule: - cron: '20 14 21 * *' jobs: Linux: strategy: fail-fast: false matrix: include: - cc: GCC arch: x64 - cc: GCC arch: x86 - cc: Clang arch: x64 - cc: Clang arch: x86 name: Linux / ${{ matrix.cc }} / ${{ matrix.arch }} runs-on: ubuntu-22.04 if: github.repository == 'mupen64plus/mupen64plus-video-rice' steps: - uses: actions/checkout@v4 - name: Get build dependencies and arrange the environment run: | git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12" export BUILD_DEPS="libgl1-mesa-dev libpng-dev libsdl1.2-dev libsdl2-dev zlib1g-dev" ./../mupen64plus-core/.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }} - name: Build and related stuff, backup binaries run: | export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12" export PATH="$(pwd)/../mupen64plus-core/.github/workflows/scripts:${PATH}" export CONFIG_OVERRIDE="SDL_CONFIG="sdl-config"" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} export CONFIG_OVERRIDE="SDL_CONFIG="sdl2-config"" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg - name: Upload artifact if: matrix.cc == 'GCC' uses: actions/upload-artifact@v4 with: name: ${{ env.PKG_NAME }} path: pkg/*.tar.gz MSYS2: strategy: fail-fast: false matrix: include: - cc: GCC arch: x64 cross: x86_64 env: MINGW64 - cc: GCC arch: x86 cross: i686 env: MINGW32 name: Windows / MSYS2 ${{ matrix.cc }} / ${{ matrix.arch }} runs-on: windows-2022 if: github.repository == 'mupen64plus/mupen64plus-video-rice' defaults: run: shell: msys2 {0} steps: - uses: actions/checkout@v4 - uses: msys2/setup-msys2@v2 with: msystem: ${{ matrix.env }} update: true install: >- git libtool make mingw-w64-${{ matrix.cross }}-gcc mingw-w64-${{ matrix.cross }}-toolchain mingw-w64-${{ matrix.cross }}-libpng mingw-w64-${{ matrix.cross }}-ntldd mingw-w64-${{ matrix.cross }}-SDL2 mingw-w64-${{ matrix.cross }}-zlib - name: Build and related stuff, backup binaries run: | git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core ./../mupen64plus-core/.github/workflows/scripts/ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} - name: Backup dependencies, etc... run: | ./../mupen64plus-core/.github/workflows/scripts/ci_backup_mingw_deps.sh ${{ matrix.env }} - name: Upload artifact uses: actions/upload-artifact@v4 with: name: ${{ env.PKG_NAME }} path: pkg/* MSVC: strategy: fail-fast: false matrix: include: - toolset: v143 arch: x64 vs: 2022 - toolset: v141_xp arch: x86 vs: 2019 name: Windows / MSVC with ${{ matrix.toolset }} / ${{ matrix.arch }} runs-on: windows-${{ matrix.vs }} if: github.repository == 'mupen64plus/mupen64plus-video-rice' defaults: run: shell: cmd steps: - uses: actions/checkout@v4 - uses: microsoft/setup-msbuild@v2 - name: Build and related stuff, backup binaries run: | git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ..\mupen64plus-core set TOOLSET=${{ matrix.toolset }} .\..\mupen64plus-core\.github\workflows\scripts\ci_msvc_build.cmd ${{ matrix.arch }} - name: Backup dependencies, etc... run: | .\..\mupen64plus-core\.github\workflows\scripts\ci_backup_msvc_deps.cmd ${{ matrix.arch }} libpng16.dll SDL2.dll - name: Upload artifact uses: actions/upload-artifact@v4 with: name: ${{ env.PKG_NAME }} path: pkg/* Nightly-build: runs-on: ubuntu-latest if: github.ref_name == 'master' needs: [Linux, MSYS2, MSVC] steps: - uses: actions/checkout@v4 - name: Download artifacts uses: actions/download-artifact@v4 with: path: binaries - name: Get some tools run: | git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core sudo apt-get update sudo apt-get -y install hashdeep - name: Creating new artifacts and update nightly-build run: | ./../mupen64plus-core/.github/workflows/scripts/ci_nightly_artifacts.sh - name: Nightly-build uses: ncipollo/release-action@v1 with: prerelease: true allowUpdates: true removeArtifacts: true replacesArtifacts: false tag: nightly-build artifacts: pkg/* mupen64plus-video-rice-src-2.6.0/.gitignore000066400000000000000000000001001464507324400205220ustar00rootroot00000000000000/projects/unix/_obj*/ /projects/unix/mupen64plus-video-rice*.so mupen64plus-video-rice-src-2.6.0/.travis.yml000066400000000000000000000016441464507324400206610ustar00rootroot00000000000000sudo: false dist: trusty language: cpp compiler: - gcc - clang addons: apt: packages: - git - libsdl1.2-dev - libsdl2-dev - libgl1-mesa-dev - libpng-dev - pkg-config before_install: - git clone --depth=1 --branch=master git://github.com/mupen64plus/mupen64plus-core.git deps/mupen64plus-core env: - NO_ASM=0 - NO_ASM=1 script: - make -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 clean && LDFLAGS="-Wl,--no-add-needed -Wl,--no-undefined" OPTFLAGS="-O2" make SDL_CONFIG=sdl-config CC="${CC}" CXX="${CXX}" -j$(nproc) -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 all - make -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 clean && LDFLAGS="-Wl,--no-add-needed -Wl,--no-undefined" OPTFLAGS="-O2" make SDL_CONFIG=sdl2-config CC="${CC}" CXX="${CXX}" -j$(nproc) -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 all mupen64plus-video-rice-src-2.6.0/INSTALL000066400000000000000000000015201464507324400175720ustar00rootroot00000000000000Mupen64Plus-Video-Rice INSTALL ------------------------------ This text file was written to explain the installation process of the Mupen64Plus-Video-Rice module. If this module is part of a Mupen64Plus source code bundle, the user should run the "m64p_install.sh" script in the root of the unzipped bundle to install all of the included modules in the bundle. If this module is a standalone source code release, you should build the library from source code and install it via the makefile, like this: $ cd projects/unix $ make all $ sudo make install If you want to build the Mupen64Plus-Video-Rice module for installation in a home folder for a single user, you may build it like this (replacing with your desired local installation path): $ cd projects/unix $ make all $ make install LIBDIR= SHAREDIR= mupen64plus-video-rice-src-2.6.0/LICENSES000066400000000000000000000457441464507324400177110ustar00rootroot00000000000000Mupen64Plus-video-rice LICENSE ------------------------------ Mupen64Plus-video-rice is licensed under the GNU General Public License version 2. The authors of Mupen64Plus-video-rice are: * Richard Goedeken (Richard42) * Sven Eckelmann (ecsv) * John Chadwick (NMN) * James Hood (Ebenblues) * Scott Gorman (okaygo) * Scott Knauert (Tillin9) * Jesse Dean (DarkJezter) * Louai Al-Khanji (slougi) * Bob Forder (orbitaldecay) * Jason Espinosa (hasone) * Dorian Fevrier (Narann) * Riley Labrecque (rlabrecque) * Fayvel Victor * Gillou68310 * krnlyng * Lioncash * littleguy77 * Metricity * HyperHacker * and others. Mupen64Plus-video-rice is based on the Rice Video plugin, which is GPL-licensed and was originally written by: * Rice1964 * Mudlord GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 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 Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. mupen64plus-video-rice-src-2.6.0/README000066400000000000000000000070521464507324400174270ustar00rootroot00000000000000=============================================================================== ------------------------------------------------------------------------------- Mupen64plus-video-rice README v2.5 ------------------------------------------------------------------------------- =============================================================================== The latest version of this document can be found online at: https://mupen64plus.org/wiki/index.php/HighResolutionTextures ------------------------------------------------------------------------------- ABOUT ------------------------------------------------------------------------------- Mupen64Plus's Rice Video plugin supports a very nice feature which allows the user to replace all of the original textures used for 3D rendering in a game with high-resolution replacement textures drawn by graphic artists. ------------------------------------------------------------------------------- Enable Hi-Res Texture Loading in Rice Video ------------------------------------------------------------------------------- In order to begin using the hi-resolution texture feature, you must enable it by editing the Mupen64Plus config file. One option is to find the file and edit it directly with a text editor. On Linux or OSX, this is located at: "~/.config/ mupen64plus/", and on Windows it is in the "Application Data" sub-folder of your user folder. On Windows XP and prior, this is "C:\Documents and Settings\ \Application Data\Mupen64Plus\", while on Windows Vista and newer this is "C:\Users\\AppData\Mupen64Plus". You should find a section in this file labeled [Video-Rice], and within this section is a parameter called LoadHiResTextures. Set this to True to enable searching for and loading high- resolution textures. Another option to enable this feature is to use the --set option with the Mupen64Plus command-line user interface. To do this, run a game with a command similar to this: ./mupen64plus --set Video-Rice[LoadHiResTextures]=True --saveoptions m64p_test_rom.v64 ------------------------------------------------------------------------------- Installing Hi-Res Texture Files ------------------------------------------------------------------------------- To install a high-resolution texture pack for a game, all that you need to do is unzip the archive and put the extracted directory full of images into the right place. On Linux and OSX, this is usually "/home//.local/share/ mupen64plus/hires_texture". On Windows it is in the "Application Data" sub- folder of your user folder. On Windows XP and prior, this is "C:\Documents and Settings\\Application Data\Mupen64Plus\hires_texture", while on Windows Vista and newer this is "C:\Users\\AppData\Mupen64Plus\ hires_texture". If this directory doesn't exist, create it and copy the hi-res texture directory inside. The folder containing hi-res textures must be named exactly the same as the ROM's name in the header of the ROM file. Usually this name is short with all capital letters, like "MARIOKART64" or "SMASH BROTHERS". The command-line UI prints out this ROM name when running a game, right after the Goodname and before the MD5. ------------------------------------------------------------------------------- Running ------------------------------------------------------------------------------- After setup, just run the game as usual. If using the command-line UI, you should see a line printed out which says: Video: Texture loading option is enabled. Finding all hires textures mupen64plus-video-rice-src-2.6.0/RELEASE000066400000000000000000000236351464507324400175570ustar00rootroot00000000000000Mupen64Plus-Video-Rice RELEASE ------------------------------ ----------------------------------------------- # Mupen64Plus-Video-Rice v2.6.0 - July 14, 2024 ## Merged PRs * [110](https://github.com/mupen64plus/mupen64plus-video-rice/pull/110): CI/CD: Update to generic scripts, independent schedule, etc * [108](https://github.com/mupen64plus/mupen64plus-video-rice/pull/108): CI/CD: Fixes Ubuntu i386 builds, among other changes * [106](https://github.com/mupen64plus/mupen64plus-video-rice/pull/106): CI/CD: Integrate scheduled builds and other... * [104](https://github.com/mupen64plus/mupen64plus-video-rice/pull/104): CI/CD: Update MSVC * [103](https://github.com/mupen64plus/mupen64plus-video-rice/pull/103): CI/CD: Update * [100](https://github.com/mupen64plus/mupen64plus-video-rice/pull/100): CI/CD: Implement GitHub Actions and public nightly builds * [99](https://github.com/mupen64plus/mupen64plus-video-rice/pull/99): Add RISC-V Support * [96](https://github.com/mupen64plus/mupen64plus-video-rice/pull/96): build: Allow out of tree builds. * [95](https://github.com/mupen64plus/mupen64plus-video-rice/pull/95): Add fix for PAL & JPN roms of Mystical Ninja * [92](https://github.com/mupen64plus/mupen64plus-video-rice/pull/92): Allow non-default compilers without resorting to symbolic links * [91](https://github.com/mupen64plus/mupen64plus-video-rice/pull/91): Allow to set custom platform toolset from commands * [90](https://github.com/mupen64plus/mupen64plus-video-rice/pull/90): Add build support for aarch64 * [89](https://github.com/mupen64plus/mupen64plus-video-rice/pull/89): AppVeyor with artifact packaging * [87](https://github.com/mupen64plus/mupen64plus-video-rice/pull/87): Changes to have more generic project files * [84](https://github.com/mupen64plus/mupen64plus-video-rice/pull/84): Add ppc64le support * [83](https://github.com/mupen64plus/mupen64plus-video-rice/pull/83): Drop C++ 'register' specifier. ## Closed Issues * [109](https://github.com/mupen64plus/mupen64plus-video-rice/issues/109): Use `GL_NUM_EXTENSIONS` and `glGetStringi` to check OpenGL extensions * [102](https://github.com/mupen64plus/mupen64plus-video-rice/issues/102): Depth issue with ANGLE * [94](https://github.com/mupen64plus/mupen64plus-video-rice/issues/94): Mystical Ninja PAL & NTSC-JP versions need options in RiceVideoLinux.ini * [85](https://github.com/mupen64plus/mupen64plus-video-rice/issues/85): build: Unable to build on aarch64 ## Top Contributors (2 or more commits) 1. Jj0YzL5nvJ 2. richard42 3. Gillou68310 --------------------------------------------------- # Mupen64Plus-Video-Rice v2.5.9 - February 10, 2019 ## Merged PRs * [82](https://github.com/mupen64plus/mupen64plus-video-rice/pull/82): Remove trailing space on parameter description. * [81](https://github.com/mupen64plus/mupen64plus-video-rice/pull/81): Remove unused reference to ConfigSaveFile * [78](https://github.com/mupen64plus/mupen64plus-video-rice/pull/78): Update homepage links * [77](https://github.com/mupen64plus/mupen64plus-video-rice/pull/77): Use faster container based Travis CI * [65](https://github.com/mupen64plus/mupen64plus-video-rice/pull/65): Use Ubuntu Trusty as base system for Travis CI * [58](https://github.com/mupen64plus/mupen64plus-video-rice/pull/58): Added x64 configuration to VisualStudio2013 project file * [56](https://github.com/mupen64plus/mupen64plus-video-rice/pull/56): Remove unnecessary OpenBSD warning. * [31](https://github.com/mupen64plus/mupen64plus-video-rice/pull/31): [WIP] Color Combiner Refactoring ## Closed Issues * [51](https://github.com/mupen64plus/mupen64plus-video-rice/issues/51): HarvestMoon 64 - Screen is cropped to approx 1/4 of expected size * [64](https://github.com/mupen64plus/mupen64plus-video-rice/issues/64): Everything renders with the same textures * [41](https://github.com/mupen64plus/mupen64plus-video-rice/issues/41): Black screen on real OpenGL ES device * [27](https://github.com/mupen64plus/mupen64plus-video-rice/issues/27): Remove pgl prefix for gl ones investigation * [61](https://github.com/mupen64plus/mupen64plus-video-rice/issues/61): naming / version conflict * [66](https://github.com/mupen64plus/mupen64plus-video-rice/issues/66): Broken compilation with GLES headers * [45](https://github.com/mupen64plus/mupen64plus-video-rice/issues/45): Possible memory leak in texture SSB * [28](https://github.com/mupen64plus/mupen64plus-video-rice/issues/28): Flashing textures in Zelda * [60](https://github.com/mupen64plus/mupen64plus-video-rice/issues/60): Dump and load audio. * [57](https://github.com/mupen64plus/mupen64plus-video-rice/issues/57): Remove processDList() from code Mupen64Plus-Video-Rice v2.5 - April 26, 2015 -------------------------------------------- - Add hack-fix to show last heart and map arrows in Zelda OoT & MM. - Lots of code cleanup, removal of deprecated code, and simplifications - Modernize OpenGL interfaces, remove code for supporting very old opengl versions - Graphics fixes for: fog, RDP InsertMatrix - fix for INI file loading under Windows - minor OpenGL ES fixes - add config option to force polygon offset values (fixes artifacts on certains games / renderers) - bugfix: crash if RiceVideoLinux.ini not found Mupen64Plus-Video-Rice v2.0 - July 4, 2013 ------------------------------------------ - support for resizable video window - add support to build and run with OpenGL ES 2.0 - improve hi-resolution texture loading support - fix texture CRC calculation for non-x86 (or NO_ASM) platforms - support to build against SDL2 - Project files for Visual Studio 2012 - Makefile changes - add support for PowerPC and MinGW32 builds - add cross-compiling support to build Win32 executables (MXE) under Linux Mupen64Plus-Video-Rice v1.99.5 - March 10, 2012 ----------------------------------------------- - Hires texture loading: support for 8-bit PNG images - New config option for forcing vertical sync - Check OpenGL attributes after creating video window and report any that failed to set - Updated video plugin for new Mupen64plus 2.0 API versioning scheme - Update to Video API version 2.1.0. - Bugfix: hi-res textures: Scale highres textures by precalculated scaleShift exponent - Bugfix: dont call CoreVideo_Init() inside of the InitializeGFX() function. This will fix some front-end use cases - Bugfix: Fix z coordinate in 3d line rendering - Bugfix: double infinite loop in GetValidTmemInfoIndex - Bugfix: Perfect Dark randomly crashes due to divide-by-zero error - Bugfix: crash in loading Celda 2009 hi-res texture pack for Zelda Ocarina of Time - makefile fixes, improvements, and code cleanups Mupen64Plus-Video-Rice v1.99.4 - November 22, 2010 -------------------------------------------------- - new feature: anisotropic filtering - new feature: trilinear filtering - new feature: mipmaps - cleaned up FindScaleFactor function based upon r45 of the 1964 repo - bugfix: buffer overrun (and crash) when reading vendor string info on some opengl implementations - API change for reading the video buffer: new interface is more flexible and avoids some potential problems - support for anti-aliasing (GL_MULTISAMPLE) - makefile fixes, improvements, and code cleanups Mupen64Plus-Video-Rice v1.99.3 - February 13, 2010 -------------------------------------------------- - sync with core<-->plugin API change for RomOpen() - Changed default ScreenUpdateSetting to 1 for Linux, and 4 for Windows - use custom opengl extension function pointer typedefs, to avoid compilation errors with some drivers including hosed gl.h headers - merged some changes from Tillin9 commits in r1142-rice-video-gtk-refactor branch, to be more lenient in hi-res texture loading - bugfix: hi-res textures did not work in Windows - bugfix: #329: remove some deprecated types and a function call to prevent build errors with libpng 1.4 - bugfix: fixed mirroring bugs in Rice Video hi-resolution texture loading, based on Tillin9 rev 1337 in r1142-rice-video-gtk-refactor branch - bugfix: in ConvertImage.cpp none of the 4-bit conversion functions could handle 1-pixel wide textures - Makefile improvements: - added OS type GNU/kFreeBSD Mupen64Plus-Video-Rice v1.99.2 - January 6, 2010 -------------------------------------------------- - bugfix: fix fragment program combiner for Intel drivers in Win32, by ensuring that program does not allocate unused temp vars or call TEX commands for texture units that are not enabled - new feature: compile-time option for opengl debugging by calling glGetError after each opengl command (except inside of glBegin/glEnd) - portability: use ALIGN() for aligned data member declarations in header files as well as the definitions in CPP files - portability: refactor opengl code to use VidExt_GL_GetProc() for all opengl functions newer than v1.1, so that this will work in Windows - portability: Abstracted directory-handling code with new osal_files* source code - portability: replaced unix gettimeofday() function calls with SDL_GetTicks() - new feature: added MSVC8 project file, fixed minor incompatibilities with VC compiler - Makefile improvements: - throw error if OS/CPU not supported - use DESTDIR in install/uninstall paths - Allow user-specified CC/CXX/LD paths - use C++ compiler to link instead of LD, because the compiler knows where the standard C++ libs are - OSX hack for inline assembly code: mismatch between function names with-w/o preceding underscores Mupen64Plus-Video-Rice v1.99.1 - December 14, 2009 -------------------------------------------------- - Converted to new Mupen64Plus 2.0 API - Major code cleanup, removed all non-standard data types - Refactored build system to separate source and object files - added NO_ASM build option - removed some unused configuration parameters - bugfix: handle fullscreen video mode properly: start up in this mode instead of always starting in windowed and needing the core to switch to fullscreen - bugfix #209: setjmp/longjmp fixes in the BMP writer and PNG reader - bugfix: eliminated duplicate 'Found ROM ...' messages mupen64plus-video-rice-src-2.6.0/appveyor.yml000066400000000000000000000017641464507324400211430ustar00rootroot00000000000000version: 1.0.{build} image: Visual Studio 2022 skip_tags: true skip_commits: files: - '**/*.md' - .github/ - data/* - .gitattributes - .gitignore - .travis.yml - README configuration: - Release platform: - Win32 - x64 before_build: - git tag --delete nightly-build - git clone --depth 1 https://github.com/mupen64plus/mupen64plus-win32-deps.git ..\mupen64plus-win32-deps - git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ..\mupen64plus-core build_script: - msbuild projects\msvc\mupen64plus-video-rice.vcxproj /p:Configuration=%configuration%;Platform=%platform% after_build: - ps: $env:rev1 = git describe --tags - set rev2=%platform% - if "%rev2%"=="Win32" set rev2=x86 - set filepkg=mupen64plus-video-rice_v%rev1%_%rev2% - cd projects\msvc\%platform%\%configuration% - copy *.dll ..\..\..\..\data - cd ..\..\..\..\data - 7z a -t7z ..\build\%filepkg%.7z * artifacts: - path: build\$(filepkg).7z name: $(filepkg) mupen64plus-video-rice-src-2.6.0/data/000077500000000000000000000000001464507324400174545ustar00rootroot00000000000000mupen64plus-video-rice-src-2.6.0/data/RiceVideoLinux.ini000066400000000000000000000552331464507324400230560ustar00rootroot00000000000000{e2f35d53f1899760-4a} Name=Wave Race 64 SE FastTextureCRC=2 FrameBufferEmulation=4 {b09d00f82318296b-4a} Name=CITY TOUR GP IncTexRectEdge {542540b304c04073-45} Name=Cruis'n USA {faf1b9fb8986f86b-45} Name=LT DUCK DODGERS {231f2836cf569700-45} Name=KEN GRIFFEY SLUGFEST {5b05a00a65df3776-50} Name=DAFFY DUCK STARRING {ec939031ef09c20f-45} Name=OFFROAD {378f8f658dd21318-44} Name=RTL WLS2000 {a2eca9b98ee4aa17-45} Name=Rush 2049 {54ddbcae4a83ff15-50} Name=Taz Express {e07359beb8edb089-45} Name=TOP GEAR RALLY 2 {aaccfabcefd814b8-45} Name=BASSMASTERS2000 {696b64f4951075c5-4a} Name=BattlePhoenix64 FastLoadTile {cec4d4558ac75377-45} Name=BATTLEZONE ForceScreenClear=2 {45f48871680a4184-4a} Name=DDR DISNEY D MUSEUM FastLoadTile {181a33df44e0d45f-45} Name=NASCAR 2000 PrimaryDepthHack {437f1c551c834991-4a} Name=TOUKON ROAD2 {4707dec0d372dfa2-4a} Name=PUZZLEBOBBLE64 {421886079fbc2ea1-45} Name=EXCITEBIKE64 FastTextureCRC=1 RenderToTexture=3 {9803f7728ba95665-45} Name=STAR WARS EP1 RACER ZHack {afe66a73c7e91741-4a} Name=MICKEY USA FastTextureCRC=1 AlternativeTxtSizeMethod=1 FrameBufferEmulation=3 RenderToTexture=3 {955f5df3693dfe8a-45} Name=CASTLEVANIA FrameBufferEmulation=1 {9aaae9c2aa705d47-45} Name=BANJO TOOIE {0693bfa4d1df0cbf-45} Name=Banjo-Kazooie FrameBufferEmulation=8 RenderToTexture=4 ScreenUpdateSetting=4 {ff2b5a632623028b-45} Name=SUPER MARIO 64 AlternativeTxtSizeMethod=1 {b655503e52da922e-45} Name=Mario Kart 64 FastTextureCRC=1 FrameBufferEmulation=3 RenderToTexture=3 {ec4ba2664fd9ad2e-45} Name=Rogue Squadron FrameBufferEmulation=2 {3863c01c26893887-45} Name=CASTLEVANIA2 {5cb6f92ad7a2e285-45} Name=MULTI RACING ForceScreenClear=2 {9c33b2d5edcabcca-50} Name=BUCK BUMBLE {9b98023de281a3d4-45} Name=Battle for Naboo {15cc9daf883d721a-45} Name=Indiana Jones {452fefaef1307ef9-45} Name=FIGHTER DESTINY2 {c33022a6884483f0-45} Name=Dual heroes USA {fc06d8d3a8a23ab4-50} Name=MTM64 {71d10ea66ed0853d-45} Name=SPIDERMAN {9deaf4dbc0823e33-45} Name=SNOWBOARD KIDS {b71170ec2bd71676-45} Name=THE LEGEND OF ZELDA FrameBufferEmulation=3 RenderToTexture=3 {b49f03462c823703-45} Name=Kirby64 {0aff1ce6710d1cce-50} Name=NEWTETRIS IncTexRectEdge {1c9651c8faaafc78-45} Name=Pilot Wings64 {3afc8a4ff22d91f7-50} Name=South Park Rally {7ebc10dd51b300f9-50} Name=V8: SECOND OFFENSE FrameBufferEmulation=3 RenderToTexture=3 {a819f4edcc0419bf-45} Name=Beetle Adventure Rac Texture1Hack {fc9ddf9889c10666-45} Name=HARVESTMOON64 {73f0868a4be545cd-45} Name=Bust A Move 2 FastLoadTile TexRectScaleHack {2ecf221e13c8aa42-45} Name=BRUNSWICKBOWLING {21cbbcfc6b3c9072-45} Name=Mystical Ninja FastLoadTile FrameBufferEmulation=1 {be0f36f51d69f12b-50} Name=Mystical Ninja FastLoadTile FrameBufferEmulation=0 {8b162c83aecda256-4a} Name=Ganbare Goemon FastLoadTile FrameBufferEmulation=0 {80205766e148e328-4a} Name=SUPERROBOTSPIRITS {4f5aa9e623ead2ba-45} Name=AIDYN_CHRONICLES {0b15d45cf1c20c47-45} Name=Extreme G 2 PrimaryDepthHack {0be1d56046eded8b-50} Name=Rayman 2 FastTextureCRC=1 {1c635453f0dea203-45} Name=ZELDA MAJORA'S MASK FrameBufferEmulation=3 RenderToTexture=3 {67cf7503aa3fa956-4a} Name=OgreBattle64 FrameBufferEmulation=3 RenderToTexture=3 {3ae5ee653c737ded-45} Name=PAPER MARIO FrameBufferEmulation=3 RenderToTexture=3 ScreenUpdateSetting=4 {7e260025cec37e2a-45} Name=RIDGE RACER 64 {4fcf0150bdb30cf3-45} Name=MarioTennis AccurateTextureMapping=1 FastTextureCRC=1 AlternativeTxtSizeMethod=1 FrameBufferEmulation=4 RenderToTexture=4 {5c52381956966e58-45} Name=MS. PAC-MAN MM {d0b4b8cd2d353288-45} Name=JET FORCE GEMINI FrameBufferEmulation=1 {db0e7e142cb1c536-4a} Name=EVANGELION AccurateTextureMapping=1 FastTextureCRC=1 {cc60f4ddc034a63c-45} Name=Perfect Dark {85e05e0c3edd67a1-45} Name=ROCKETROBOTONWHEELS FastTextureCRC=1 {8438e2bfafea48ef-45} Name=Silicon Valley AlternativeTxtSizeMethod=1 RenderToTexture=3 {0c28d5b12abca74b-4a} Name=SIM CITY 2000 {325e9b7280d928b7-45} Name=GAUNTLET LEGENDS FrameBufferEmulation=1 {0d4302e49dfcfcd2-45} Name=Diddy Kong Racing {22c04e2085d119b1-45} Name=TONY HAWK PRO SKATER {b2bb524c6b0fabce-45} Name=ARMYMENAIRCOMBAT IncTexRectEdge {b6ce09347a51c8ce-45} Name=SMASH BROTHERS {50acc7302d070477-45} Name=CONKER BFD FrameBufferEmulation=3 RenderToTexture=4 {a5b118aaeb6adb07-45} Name=Resident Evil II ForceScreenClear=1 {d150bcdca31afd09-45} Name=GOLDENEYE ZHack FrameBufferEmulation=1 ScreenUpdateSetting=4 {e8d83723ec7c8e6b-45} Name=YOSHI STORY FrameBufferEmulation=3 RenderToTexture=3 {78d90eb3f9c90330-45} Name=F-ZERO X {3603165ab0377bbc-50} Name=BOMBERMAN64E {0390a59064980831-45} Name=WRESTLEMANIA 2000 {6d208ebd1c5ec398-4a} Name=DOUBUTSUNOMORI {96fa0e65a7f9dd30-50} Name=WAVE RACE 64 VIWidth=320 VIHeight=240 {72e270fcaae7ff08-50} Name=Silicon Valley {bbe8e07eaa11e449-50} Name=Rogue Squadron {38a59bd089541a1c-50} Name=Top Gear Overdrive {f4791f15e5c8ed8e-50} Name=VIGILANTE 8 {7b5bf45be8ee6b59-50} Name=WWF: Attitude {485f9493302e0f5c-50} Name=SMASH BROTHERS {36f03ca0d2c5c1bc-50} Name=SUPER MARIO 64 FastTextureCRC=1 {8616b80c815ad85f-45} Name=Madden NFL 2000 {a475a233594450b8-50} Name=WWF War Zone RenderToTexture=3 {a526899f09b48705-50} Name=TONY HAWK SKATEBOARD {84ea4ed8b4f1b245-50} Name=SHADOWGATE64 {bfe514d6c1bc6da7-50} Name=TARZAN {4a831839290cb515-45} Name=RAZOR FREESTYLE {4d675728da3743cc-45} Name=NIGHTMARE CREATURES {9940307f7652cf52-4a} Name=LASTLEGION UX {782706acb8fcaddf-50} Name=WORLD DRIVER CHAMP FullTMEM=1 {f336411da9ee63af-45} Name=ZELDA MASTER QUEST {614b2f496a14e504-45} Name=WAVE RACE 64 {b1cc3f73f9924844-50} Name=Banjo-Kazooie {e74bc5a2b2cb1967-50} Name=CASTLEVANIA2 FastTextureCRC=1 {b609608a50e1ac94-45} Name=JET FORCE GEMINI AccurateTextureMapping=1 FastTextureCRC=1 RenderToTexture=3 {b3d9f590f0dc0e9d-45} Name=POKEMON STADIUM FrameBufferEmulation=3 RenderToTexture=3 {a059e913b0ca930e-45} Name=WORMS ARMAGEDDON {d7d81095d20d1035-45} Name=Stunt Racer 64 FullTMEM=1 {bfea58ec69717cad-45} Name=DONKEY KONG 64 EmulateClear=2 {40064b4efbbc491b-45} Name=WWF No Mercy {d68cbe33126918ec-45} Name=WCW MAYHEM {bd193e2c5eee1351-45} Name=WCWvs.NWO:World Tour FrameBufferEmulation=4 ScreenUpdateSetting=4 {b960be713cfbdb1d-45} Name=WCWvs.NWO:World Tour FrameBufferEmulation=1 ScreenUpdateSetting=4 {ab96e5dee77a3baf-45} Name=WCW / nWo REVENGE ScreenUpdateSetting=4 {253ffd588daa2ed9-50} Name=1080 SNOWBOARDING {47cfa352fc3bc14e-50} Name=NFL QBC '99 {497df9d35b132469-50} Name=YOSHI STORY FrameBufferEmulation=3 RenderToTexture=3 {af29ab1928cd1bc7-50} Name=PAPER MARIO {7d1d6172d2bd1999-58} Name=HSV ADVENTURE RACING Texture1Hack {ad84d7df036642ae-50} Name=ALL STAR TENNIS '99 {b4fb88b01d4b1e44-50} Name=BASS HUNTER 64 {d3dd3f71efa0d672-20} Name=Bike Race by NaN ForceScreenClear=2 {16d3794d331b50e8-45} Name=BEAST WARS US {d0483cfb9ff6288d-50} Name=CHARLIE BLAST'S {e89d2b491cc8ccc6-50} Name=EARTHWORM JIM 3D {3421cfdc7835d69d-50} Name=Centre Court Tennis UseCIWidthAndRatio=1 {9531740f95dba6d8-50} Name=DAIKATANA {b3c83ccca405c40e-50} Name=F1 WORLD GRAND PRIX {9d127b27ff7938dd-50} Name=Holy Magic Century {98da8b41580f8a24-50} Name=MISCHIEF MAKERS {f10bfd20871dcff5-50} Name=RAT ATTACK {7bc5212d8cc5e48f-50} Name=WORMS N64 {9bbfc5f3e2330f16-45} Name=Rayman 2 FastTextureCRC=1 {118a08497e959464-45} Name=Turok 2: Seeds of Ev AccurateTextureMapping=1 {4e2d0ff0f4aa0f34-45} Name=CARMAGEDDON64 FastTextureCRC=1 {ababd40d1ea9a2b5-45} Name=D K DISPLAY {32d9b51f1b48a93b-45} Name=Armorines Project S. {b46e28958fd56ab7-45} Name=Command&Conquer {9addd0dea72582e7-50} Name=MICKEY USA PAL {75d474fcab78029a-45} Name=PPG CHEMICAL X {b5707f1afdb9b700-45} Name=THPS3 {6a0571ea474821e4-45} Name=VIGILANTE 8 FullTMEM=2 RenderToTexture=3 {e7dda46ae7f4e2e3-45} Name=BATTLETANX {47e2a4753d960860-45} Name=BATTLETANXGA {ca243cf0cc7b23c5-45} Name=CLAYFIGHTER 63 {cbc7ef32203feac3-45} Name=Fighting Force {1a103ea89db637e9-45} Name=Doom64 {ff016e8e48f9b4cc-45} Name=Glover AccurateTextureMapping=1 {3f14532151632d99-45} Name=NEWTETRIS VIWidth=400 VIHeight=300 {a35ecf42df34139a-50} Name=STARCRAFT 64 NormalAlphaBlender=2 UseCIWidthAndRatio=1 RenderToTexture=3 {ac47477a23ecee44-44} Name=PUZZLE LEAGUE N64 VIWidth=320 VIHeight=240 FrameBufferEmulation=4 RenderToTexture=3 {fd04dc82f4822dcf-45} Name=A Bug's Life {f628fef7c3acf2c3-45} Name=WAR GODS {3f22456b565c0ef0-45} Name=W.G. 3DHOCKEY {59389d5a10e7aa97-45} Name=W.G 3D Hockey 98 {329dc9bb80aa7d11-45} Name=TWISTED EDGE {3e7450a1cd2225cf-45} Name=Toy Story 2 FrameBufferEmulation=2 {3d9b2662e8b111fe-45} Name=TOP GEAR RALLY ScreenUpdateSetting=2 {beda1f3cbae0a402-45} Name=TETRISPHERE IncTexRectEdge {5bf3e8a2d987dcc9-45} Name=SUPERMAN {c8615eab9675faa2-45} Name=PENNY RACERS {669464dcd9f02f57-4a} Name=ONEGAI MONSTER {1a5ac4d45eb225f4-45} Name=NITRO64 {eeb0255fdbc12762-45} Name=NBA LIVE 2000 {ada552424ebf6fae-45} Name=GOEMONS GREAT ADV {c59b41e6e31d0169-45} Name=OgreBattle64 {e5522da955b6261d-45} Name=FLYING DRAGON FastLoadTile {d6fd4644088278e3-45} Name=BOMBERMAN HERO {b42f2fff9a1461d1-45} Name=Cruis'n USA {5c7e4d2622468718-45} Name=Shadow of the Empire DisableObjBG=1 ScreenUpdateSetting=4 {63cff584dc7eee08-45} Name=KNIFE EDGE {9fd8224237b6e0af-45} Name=Bust A Move '99 FastLoadTile {a43c70efc99a4a4d-4a} Name=TOUKON ROAD {b3c83ccca405c40e-45} Name=F1 WORLD GRAND PRIX {8e8fc9c7de5d1442-45} Name=HOT WHEELS TURBO {36cee20de6291dd4-4a} Name=HYBRID HEAVEN JP {374cff6dfd63b7b1-4a} Name=抬薪?64 {180e1599a5e66612-45} Name=THPS2 {7ff0da0488e6180d-45} Name=DUKE NUKEM ZERO HOUR {7a6882ae8d383f9a-45} Name=F1 POLE POSITION 64 {6e86c107decc7557-50} Name=F1 WORLD GRAND PRIX2 {5858a99e18b672af-45} Name=MarioParty2 {d929387cce47826e-45} Name=MarioParty3 FastTextureCRC=1 TexRectScaleHack {9207384145e067a1-45} Name=POLARISSNOCROSS TexRectScaleHack DisableAlphaBlender=1 {31e0d6ed13601368-45} Name=RUSH 2 {0d7ddff78f0152ed-00} Name=Shufflepuck 64 {ac3363d79d21b60c-4a} Name=Bass Rush {fab428e3e1284a00-50} Name=Bust A Move 3 DX {20186b2a66f4bc6a-45} Name=S.F. RUSH IncTexRectEdge {4d7a545e9507e690-45} Name=All-Star Baseball '0 {30a61376f396d63e-45} Name=FIFA 99 FastTextureCRC=1 {996e30b6b2d23eb6-4a} Name=霓状虞2 硕厣驾棉 {049805d8119b7392-4a} Name=霓状虞3 伤蘩上罶OS! {4cca08f927434636-45} Name=Killer Instinct Gold ForceScreenClear=1 {ac0443c321c0792d-45} Name=MK_MYTHOLOGIES {b9019507ab3202ab-4a} Name=CUSTOMROBOV2 {582ba5a441987523-45} Name=DARK RIFT EmulateClear=1 {c18944202bcf8612-45} Name=BATMAN BEYOND RETURN {b4737e23376b3bd6-45} Name=BOMBERMAN64U2 AccurateTextureMapping=1 FastTextureCRC=1 {bf2ff236f2128931-4a} Name=64逝汤?~幂忌愿扛~ {ec7c7fc26f80e085-50} Name=MYSTICAL NINJA2 SG {33ddbf4e849d4c66-45} Name=Tigger's Honey Hunt {dd5a6f39a7ec9366-45} Name=WCW BACKSTAGE {8c1168f44ee42ee3-4a} Name=Ultraman Battle JAPA {aff7a346d091750f-45} Name=CruisnExotica ForceScreenClear=1 FrameBufferEmulation=2 {e1a49e51e88475eb-4a} Name=KING HILL 64 {f002cc8e81de8b7f-45} Name=Top Gear Hyper Bike {54edd74d7d28f974-45} Name=Shadow of the Empire FrameBufferEmulation=3 ScreenUpdateSetting=3 {6c7450f00b827b24-45} Name=ROAD RASH 64 AccurateTextureMapping=1 {6a6d63bdba541f5d-45} Name=World Cup 98 {9516943beb5e0af9-50} Name=TWINE UseCIWidthAndRatio=1 {95351208def11005-45} Name=BIOFREAKS {abd8f7d146043b29-45} Name=Asteroids Hyper 64 {0588f752b7ca8f8b-45} Name=Fighter's Destiny {a2dc9ac4621b50f1-45} Name=GT64 IncTexRectEdge {ea406a09100abe8a-45} Name=LEGORacers FrameBufferEmulation=2 {87b4694e90e218fe-45} Name=NBA HANGTIME FastLoadTile FullTMEM=1 {47b512cae44efa71-45} Name=POKEMON SNAP FastTextureCRC=1 RenderToTexture=3 {1a1d75c2ff9bc1f8-50} Name=SNOWBOARD KIDS2 {f85c032635912b80-45} Name=Mission Impossible {f18b591b459ba2ec-45} Name=AERO FIGHTERS ASSAUL {20d568510dcd5fca-4a} Name=Banjo-Kazooie {eeea74f73eb1d8f0-4a} Name=F3 坛撞杉谳2 AccurateTextureMapping=1 FastTextureCRC=1 {6d8d76286c9779b3-45} Name=Monaco Grand Prix {821157036dd02f89-45} Name=POKEMON STADIUM 2 FrameBufferEmulation=3 {b8a5ed9403e97386-45} Name=Starshot {127edc3ec91c6ce2-45} Name=Gex 3 Deep Cover Gec {98ae2b8dbf2537d7-45} Name=NAGANO OLYMPICS {6b7e8094e462cc60-4a} Name=PUYO PUYO SUN 64 {f34791760ec13320-45} Name=SCARS VIWidth=320 VIHeight=240 FullTMEM=1 {2d16e69f37407ee9-4a} Name=TROUBLE MAKERS {8ad56680c1cadec3-45} Name=Waialae Country Club {20f9b837efb38ba5-45} Name=Twintris {9dae5305c1e0d8ea-45} Name=XENAWARRIORPRINCESS {f179a589ef977e66-45} Name=Turok 3: Shadow of O {3d8ea87371c5c53a-45} Name=RALLY CHALLENGE RenderToTexture=3 {9cf75b9fa008fed2-45} Name=Quake ForceScreenClear=1 {a7233ec41a68b140-45} Name=All Star Baseball 99 {d025c427c1992d8c-50} Name=AIR BOARDER 64 {941a95b6af49c863-4a} Name=DRACULA MOKUSHIROKU {2907d2674c7796f6-4a} Name=SMASH BROTHERS {c73b072011013b5e-45} Name=ITF 2000 {4fd5ea30f60b6231-45} Name=NFL BLITZ SPECIAL ED {80cd41d712b9a9ac-45} Name=Top Gear Overdrive {2b0996e84e4d24dc-45} Name=WHEEL OF FORTUNE {3e46beae4b4671cc-45} Name=AEROGAUGE {ec620158f18b10e3-58} Name=CARMAGEDDON64 {d245a2fd473d4aa7-45} Name=extremeg {74d7fe891be2afca-45} Name=GEX: ENTER THE GECKO {6064256986f5a3b9-45} Name=JEOPARDY! {bcb516e6888b65c9-45} Name=Iggy's Reckin' Balls {32272d1318910ec7-45} Name=Wipeout 64 {14979eef7d2c3bc0-45} Name=Tonic Trouble {163ed509b968b23a-45} Name=PIAZZA STRIKEZONE {f4d47d41e22f481b-45} Name=MORTAL KOMBAT 4 {4f47294f7a70cb30-4a} Name=KAKUTOU DENSHOU {6910969c8d48eaf5-4a} Name=64 OHZUMOU FastLoadTile {1462a21e0f9090e7-50} Name=Turok: Rage Wars {f6290781c1cf3fe0-45} Name=NBA JAM 99 {cab7f1645537a271-50} Name=CASTLEVANIA {5991f1c35abcd265-45} Name=FIFA Soccer 64 {dce23ae1e85cb64f-4a} Name=Eltail {514423656f34d3eb-4a} Name=Blastdozer {e48c53cdf9fc8a61-45} Name=Chameleon Twist2 ScreenUpdateSetting=4 {56ab73a29adb33da-45} Name=DUKE NUKEM {657e647c05d34819-45} Name=Blast Corps {e167f6a51fbd1fda-4a} Name=DERBYSTALLION 64 {92f738eb46a20e19-45} Name=Madden NFL 2001 ScreenUpdateSetting=4 {d4a34b66b7808a67-45} Name=MarioGolf64 FrameBufferEmulation=4 RenderToTexture=4 {83c871d5cf3f2d82-50} Name=BLUES BROTHERS 2000 {134d9d76fe3f23da-45} Name=DR.MARIO 64 FastTextureCRC=2 TexRectScaleHack FrameBufferEmulation=7 RenderToTexture=3 {f815d0a743aa8922-45} Name=STARFOX64 {a284e5de8711160f-45} Name=DESTRUCT DERBY {7e652928771862a0-45} Name=MarioParty FastTextureCRC=1 ScreenUpdateSetting=4 {c8fe8d30f6b52ece-45} Name=WORLD DRIVER CHAMP {d94dbbc80b435fcc-45} Name=Quest 64 {4fb5a8ce03d5217f-45} Name=Wetrix AccurateTextureMapping=1 FastTextureCRC=1 {436b4bfea7291d08-45} Name=TRIPLE PLAY 2000 {77eb3c7f0a038189-45} Name=HERCULES {b7a4ff08b653f401-45} Name=Big Mountain 2000 {d66abc75c92b5578-4a} Name=纷恫孤 64垒貌擂 {65973ce4bec1b105-4a} Name=Wonder Project J2 {78957423fd58dc80-45} Name=NASCAR 99 PrimaryDepthHack {b6730fb234fc7529-45} Name=ARMYMEN SARGE 2 {1cfb9046446dd54c-45} Name=GOLDEN NUGGET 64 {8074f13d5aed3d19-50} Name=Donald Duck Quack At FastTextureCRC=1 {cdb8580bd291b2b7-50} Name=Body Harvest ScreenUpdateSetting=2 {4dd12fd7c432ed1f-45} Name=Bottom of the 9th VIWidth=320 VIHeight=240 {c2b1f7bf8e14bfae-4a} Name=霓状虞 携律静诓痉 {405127a8e856b0b9-4a} Name=霓状虞3 伤蘩上罶OS! {26f7fc68bc8c6549-50} Name=G.A.S.P!!Fighters'NE {978d9fab66a7ea95-00} Name=Kings of Porn Vol 01 {4c5eb3e4c95cc41a-45} Name=MGAH VOL1 {2f96deac7ff8cbb2-50} Name=NBA PRO 98 {a55f70280e6909b5-50} Name=Monaco GP Racing 2 {420c2a397de790b7-45} Name=RAINBOW SIX {5d0ef1d379a52e05-45} Name=hey you, pikachu {d44a7da4f981fa8b-45} Name=Manic Miner 64 {231b1c14259ef43e-00} Name=(C) DATEL D&D NU10:0 {0cf10110c1d8513d-45} Name=Mia Hamm Soccer 64 {bbdd9849bcaeb7f7-45} Name=NUCLEARSTRIKE64 {25d625395ec7838c-50} Name=MADDEN NFL 99 {bf882810ca884843-45} Name=HYBRID HEAVEN USA {7a4636e49b8fde82-45} Name=INDY RACING 2000 {d04eabe3d20d0483-45} Name=NFL QBC 2000 {6960bfac62e1beea-45} Name=CHOPPER_ATTACK {707ae874d4ae9362-50} Name=ROADSTERS TROPHY {c463275fe52a4162-45} Name=I S S 64 ScreenUpdateSetting=3 {43f1a8bd622dafb1-45} Name=QUAKE II ForceScreenClear=2 {127341ec5fde31eb-4a} Name=THE MASK OF MUJURA DisableObjBG=1 {c26661e3e5a21386-58} Name=MO WORLD LEAGUE SOCC {5a211daa9abecb91-45} Name=SUPER BOWLING {e2a2bb4bb2bbf38b-00} Name=Puzzle Master 64 {9e5abd88bfdf1fe8-50} Name=NFL QBC 2000 {48a90cc04bd3608e-45} Name=South Park: Chef's L TexRectScaleHack FullTMEM=1 AlternativeTxtSizeMethod=1 {4b45d50895ccaaff-4a} Name=TETRIS64 {5a53206462800250-45} Name=Chameleon Twist {493336f51bd2f9db-45} Name=DeadlyArts {c7c4eb0c32e99c0c-4a} Name=WILD CHOPPERS {57062c866d89fd8d-45} Name=Army Men Sarge {a18efce89183739f-45} Name=CyberTiger {010c339eba14038c-45} Name=Forsaken {36fecce375bc8f39-45} Name=YOSHI STORY {1d5bce9c83e25163-00} Name= {e98889b5e84bfcb1-50} Name=Hydro Thunder {6e84e4bab0fe8ebb-45} Name=PAPERBOY {ec4716df47a9a2be-50} Name=MYSTICAL NINJA2 SG {532a11638fa89fa2-4a} Name=PERFECT STRIKER2 {2d56d52850aed5e4-4a} Name=棉葚沧沧无 ScreenUpdateSetting=2 {fbabf721e8a78a6a-50} Name=Jeremy McGrath Super {0df1702fff87415c-45} Name=TUROK_DINOSAUR_HUNTE {efc64654bb478ee1-45} Name=All-Star Baseball 20 {e8603e5e95d4b54a-4a} Name=徊樊呈剔籍撤 {cd0d702fc9c56c17-50} Name=TUROK_DINOSAUR_HUNTE {db4d6b0b82e67196-45} Name=ROADSTERS TROPHY {aea23b699f4ef1b7-45} Name=THE LEGEND OF ZELDA {3890053c8221bfc8-45} Name=V-RALLY {5b8b6b91a4850b78-45} Name=SMASH BROTHERS {89638313763c5b26-45} Name=MADDEN 64 {a93af3830dd401a9-45} Name=MortalKombatTrilogy {29b4b7ea572cc9ba-45} Name=READY 2 RUMBLE {5e6c6384fa4a9e94-4a} Name=TETRIS64 {c45db2418667721b-45} Name=Lamborghini 64 {5007706bfe21d629-45} Name=MACE {865877637b0eb85f-4a} Name=POKEMON STADIUM 2 FrameBufferEmulation=3 RenderToTexture=3 {d0f2f9989cf0d903-50} Name=Virtual Pool 64 ScreenUpdateSetting=3 {f311e83524277999-4a} Name=浇?啦据蔬睫倮尴 TexRectScaleHack {2dac77289a13dcc3-44} Name=Racing Simulation 2 FastLoadTile {d8526891efeadb73-45} Name=NBA Courtside 2 {3754838eb44857cd-45} Name=I.S.S.2000 {f336411da9ee63af-50} Name=THE LEGEND OF ZELDA FrameBufferEmulation=7 {0000000000000000-00} Name= {decd1acbf21d29cf-45} Name=FIFA: RTWC 98 ScreenUpdateSetting=2 {6930669c804af280-50} Name=MarioParty {79c712671d78723b-50} Name=IT&F SUMMERGAMES {f49e624b9b1db299-50} Name=quarterback_club_98 {8725c27e23e31aef-45} Name=OLYMPIC HOCKEY {f0ed310ed54972c3-50} Name=FIFA: RTWC 98 {51a69801849d21fc-50} Name=FIFA 99 {dbe5388cd7277cb3-50} Name=ECW Hardcore Revolut {2ce9cbf412ed92b3-50} Name=STARFOX64 {796690e4053f249f-50} Name=MAGICAL TETRIS {7e9598edacdc4282-45} Name=WIN BACK {ba8bb7de9dbdf652-45} Name=MADDEN NFL 99 {604167c53c455f0f-50} Name=MarioParty3 TexRectScaleHack {d057e9625d5ac17f-50} Name=MarioGolf64 FrameBufferEmulation=3 RenderToTexture=3 {396d17c9d17947ea-50} Name=BANJO TOOIE {185bf98d7b49daec-45} Name=NBA IN THE ZONE 2000 {9c9094082dd8d4da-45} Name=Knockout Kings 2000 UseCIWidthAndRatio=1 RenderToTexture=3 {fb4e4f2bfe11c543-50} Name=TOM AND JERRY {dadf3a4daefc9875-50} Name=RUGRATSTREASUREHUNT {02c608eea6d5c26b-50} Name=PGA European Tour Go {94ad4c21243b1abe-45} Name=CHOPPER_ATTACK {4716b67578bfda7a-45} Name=MAGICAL TETRIS {350c85f11279e0ac-45} Name=MICROMACHINES64TURBO {e183c35a87e312d7-45} Name=monopoly {168bc185af2296df-4a} Name=64 档睫映 2 {fbb1ab739360ca9c-45} Name=PENNY RACERS {e4f99fc27dfe4b26-45} Name=RAMPAGE {99d7e0fc546c3165-45} Name=KNIFE EDGE {0ca3d88317c15285-00} Name=YOSHI BOOT EMU {8d3bda777c0d2b16-4a} Name=裁拗辰股习嫁嫁 {986c006081a30526-4a} Name=VIOLENCEKILLER {cd0c011cfab7d322-4a} Name=睫百 霞蕲陈恫棉菥� {222ee09cb0f16e20-4a} Name=SUPER SPEED RACE 64 {dccda73ba0524e46-4a} Name=MARIO STORY {1e82cccc838ae896-4a} Name=习嫁纬鄢稢LASSIC {20b93bd8166440cc-4a} Name=羌罗�64 {3b4b5574b5bcaef4-4a} Name=PACHINKO365NICHI {ad5b4934269d2e50-4a} Name=PAWAFURU PUROYAKYU4 {da4329d2c0772bac-4a} Name=PAWAFURU PUROYAKYU5 {b7205eb7fdfdfeb3-4a} Name=PAWAFURU PUROYAKYU6 {547fd2f3f9ac11c1-50} Name=Premier Manager 64 {3b5966d6075ca2d7-4a} Name=RockMan Dash {ff04fc84e93c25b1-4a} Name=缴无矾睫 ScreenUpdateSetting=4 {c1a7caff37858568-4a} Name=STARFOX64 {87a91f0fa6afc1bf-45} Name=Re-Volt {5db998df78098458-4a} Name=BANGAIOH IncTexRectEdge {8824ae7e5aa3409d-4a} Name=BioHazard II {c4085c048b79fd4a-4a} Name=兽傲 踢圳截莞� 64 FrameBufferEmulation=2 ScreenUpdateSetting=3 {9c167989a0f689f1-4a} Name=DEZAEMON3D {819b9b3911ad33d5-4a} Name=锤侥匕袵2 PrimaryDepthHack {66e8703ee8ba3844-4a} Name=HEIWA 蔬凛� 馨倌�64 RenderToTexture=3 {f5d919afcc2302b7-4a} Name=G1STABLE {ac90989adf13c3f0-4a} Name=县瞪太乃甙 {0f692b27777a0aad-4a} Name=Robopon64 FrameBufferEmulation=3 RenderToTexture=3 {339521e9bdaffb13-45} Name=Ready to Rumble {f480fe3f7e5fc1a7-45} Name=NBA SHOWTIME {56a48bb9af762b5b-4a} Name=休琶蘩虾薤淋百霓 FastLoadTile FullTMEM=1 {69025b840295de57-4a} Name=Top Gear Hyper Bike {e6849c48f9496e4c-4a} Name=Getter Love!! {b157ae0937562a18-4a} Name=MASTERS'98 {f127177deb836b6c-00} Name=Test Program {93b8a075b521a34c-00} Name= {321536813f64eb2a-00} Name= {e04dda1e8d69bf22-00} Name=Test Program {0ab5b39a056166bc-44} Name=HEXEN {6805ed0d5e510215-4a} Name=床撼删菽陛霓丨敖 {c851318f45f53a4f-44} Name=WWF: Attitude {8ef08d6dcfc308d0-50} Name=WWF No Mercy {dbe6647cdb24b955-50} Name=Blast Corps {ce97680354fad4e0-45} Name=SHADOWGATE64 {324b8eac2673b4e7-45} Name=ROBOTRON-64 {424a5554fb5f98e4-4a} Name=J LEAGUE LIVE 64 {d218739cc10dae24-4a} Name=BEETLE ADVENTURE JP Texture1Hack {614ab6a10b9414d0-50} Name=Beetle Adventure Rac Texture1Hack {5cc0c180f45e06ea-45} Name=MLB FEATURING K G JR FastLoadTile {be98b9cdc8a52410-50} Name=MLB FEATURING K G JR FastLoadTile AlternativeTxtSizeMethod=1 {1e93f3833d2272cb-50} Name=CRUIS'N WORLD UseCIWidthAndRatio=2 {80064660720e5f30-50} Name=Lode Runner 3D ScreenUpdateSetting=1 {140efa7505d1b3c9-44} Name=Holy Magic Century {3e269b97040047f8-50} Name=Killer Instinct Gold {2bc6673d5031d031-4a} Name=LET'S SMASH {87a9c3c94c341058-4a} Name=MARIOKART64 {b8a588e6183f4bb1-50} Name=TWISTED EDGE {30dcef8261246a80-45} Name=BLADES OF STEEL '99 {b01a15d04ba15cfe-45} Name=DAIKATANA {bae28f9e7007278b-45} Name=KILLER INSTINCT GOLD ForceScreenClear=1 {61f1ba1ff1541c2c-41} Name=1080 SNOWBOARDING FastTextureCRC=2 ScreenUpdateSetting=2 {e08b138c460e7095-45} Name=BASS HUNTER 64 {8b24b3824d243ee7-45} Name=VIRTUALCHESS {9369a7da7cf7acd8-00} Name= {4986248e52de1c2e-00} Name= {74ab4cb4299a0207-50} Name=SUPERMAN {1ed568f51eba497e-45} Name=BOMBERMAN64U {f558c10e96683efb-45} Name=Mega Man 64 {dab629518c3cef9d-45} Name=NAMCOMUSEUM64 {60a73e50960e30e1-50} Name=Cruis'n USA {9723feeb34da74ff-45} Name=SPACE INVADERS {0e4016ac1a075dcf-45} Name=CAL SPEED {e8960e1e6b82284e-45} Name=CHARLIE BLAST'S {a00b78ba34db210f-45} Name=STARFOX64 {e740d45311b01975-45} Name=Diddy Kong Racing {134c3f03a7e79e31-45} Name=TWINE {ccffc42d215affc8-50} Name=AIDYN_CHRONICLES {91e285e16d76504e-45} Name=ALL STAR TENNIS '99 {df1850253aaed657-45} Name=Lode Runner 3D {71458cfac0f9e7bb-45} Name=MICKEY USA mupen64plus-video-rice-src-2.6.0/projects/000077500000000000000000000000001464507324400203745ustar00rootroot00000000000000mupen64plus-video-rice-src-2.6.0/projects/msvc/000077500000000000000000000000001464507324400213445ustar00rootroot00000000000000mupen64plus-video-rice-src-2.6.0/projects/msvc/mupen64plus-video-rice.vcxproj000066400000000000000000000354431464507324400272200ustar00rootroot00000000000000 Debug Win32 Debug x64 Release Win32 Release x64 {7D4AFF6A-B7D9-4C25-975A-038B8079098E} mupen64plusvideorice $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) $(LatestTargetPlatformVersion) $(WindowsTargetPlatformVersion) $(DefaultPlatformToolset) DynamicLibrary MultiByte true $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ DynamicLibrary MultiByte true $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ DynamicLibrary MultiByte $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ DynamicLibrary MultiByte $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ Disabled ..\..\src;..\..\..\mupen64plus-core\src\api;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\opengl\include;%(AdditionalIncludeDirectories) WIN32;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Level3 user32.lib;gdi32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x86\SDL2.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x86\libpng16.lib;%(AdditionalDependencies) true Windows Disabled ..\..\src;..\..\..\mupen64plus-core\src\api;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\opengl\include;%(AdditionalIncludeDirectories) WIN32;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;NO_ASM;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Level3 user32.lib;gdi32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x64\SDL2.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x64\libpng16.lib;%(AdditionalDependencies) true Windows ..\..\src;..\..\..\mupen64plus-core\src\api;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\opengl\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) MultiThreadedDLL Level3 MaxSpeed true true user32.lib;gdi32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x86\SDL2.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x86\libpng16.lib;%(AdditionalDependencies) true Windows true true ..\..\src;..\..\..\mupen64plus-core\src\api;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\opengl\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;NO_ASM;%(PreprocessorDefinitions) MultiThreadedDLL Level3 MaxSpeed true true user32.lib;gdi32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x64\SDL2.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x64\libpng16.lib;%(AdditionalDependencies) true Windows true true mupen64plus-video-rice-src-2.6.0/projects/unix/000077500000000000000000000000001464507324400213575ustar00rootroot00000000000000mupen64plus-video-rice-src-2.6.0/projects/unix/Makefile000077500000000000000000000330111464507324400230200ustar00rootroot00000000000000#/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # * Mupen64plus-video-rice - Makefile * # * Mupen64Plus homepage: https://mupen64plus.org/ * # * Copyright (C) 2007-2009 Richard Goedeken * # * Copyright (C) 2007-2008 DarkJeztr Tillin9 * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU General Public License as published by * # * the Free Software Foundation; either version 2 of the License, or * # * (at your option) any later version. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU General Public License for more details. * # * * # * You should have received a copy of the GNU General Public License * # * along with this program; if not, write to the * # * Free Software Foundation, Inc., * # * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ # Makefile for RiceVideo plugin in Mupen64Plus # detect operating system UNAME ?= $(shell uname -s) OS := NONE ifeq ("$(UNAME)","Linux") OS = LINUX SO_EXTENSION = so SHARED = -shared endif ifeq ("$(UNAME)","linux") OS = LINUX SO_EXTENSION = so SHARED = -shared endif ifneq ("$(filter GNU hurd,$(UNAME))","") OS = LINUX SO_EXTENSION = so SHARED = -shared endif ifeq ("$(UNAME)","Darwin") OS = OSX SO_EXTENSION = dylib SHARED = -bundle PIC = 1 # force PIC under OSX endif ifeq ("$(UNAME)","FreeBSD") OS = FREEBSD SO_EXTENSION = so SHARED = -shared endif ifeq ("$(UNAME)","OpenBSD") OS = FREEBSD SO_EXTENSION = so SHARED = -shared 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 'https://github.com/mupen64plus/mupen64plus-core/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 ppc64le powerpc64le,$(HOST_CPU))","") CPU := PPC ARCH_DETECTED := 64BITS BIG_ENDIAN := 0 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 ifneq ("$(filter aarch64,$(HOST_CPU))","") CPU := AARCH ARCH_DETECTED := 64BITS PIC ?= 1 NO_ASM := 1 endif ifneq ("$(filter riscv64,$(HOST_CPU))","") CPU := RISCV64 ARCH_DETECTED := 64BITS PIC ?= 1 NO_ASM := 1 $(warning Architecture "$(HOST_CPU)" not officially supported.) endif ifeq ("$(CPU)","NONE") $(error CPU type "$(HOST_CPU)" not supported. Please file bug report at 'https://github.com/mupen64plus/mupen64plus-core/issues') endif SRCDIR = ../../src OBJDIR = _obj$(POSTFIX) # base CFLAGS, LDLIBS, and LDFLAGS OPTFLAGS ?= -O3 -flto WARNFLAGS ?= -Wall CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -ffast-math -fno-strict-aliasing -fvisibility=hidden -I$(SRCDIR) CXXFLAGS += -fvisibility-inlines-hidden LDFLAGS += $(SHARED) ifeq ($(CPU), X86) CFLAGS += -msse endif # Since we are building a shared library, we must compile with -fPIC on some architectures # On 32-bit x86 systems we do not want to use -fPIC because we don't have to and it has a big performance penalty on this arch ifeq ($(PIC), 1) CFLAGS += -fPIC else CFLAGS += -fno-PIC endif ifeq ($(BIG_ENDIAN), 1) CFLAGS += -DM64P_BIG_ENDIAN endif # tweak flags for 32-bit build on 64-bit system ifeq ($(ARCH_DETECTED), 64BITS_32) ifeq ($(OS), FREEBSD) $(error Do not use the BITS=32 option with FreeBSD, use -m32 and -m elf_i386) endif ifneq ($(OS), OSX) ifeq ($(OS), MINGW) LDFLAGS += -Wl,-m,i386pe else CFLAGS += -m32 LDFLAGS += -Wl,-m,elf_i386 endif endif endif ifeq ($(ARCH_DETECTED), 64BITS) ifeq ($(OS), MINGW) LDFLAGS += -Wl,-m,i386pep endif endif # set special flags per-system ifeq ($(OS), LINUX) LDLIBS += -ldl # only export api symbols LDFLAGS += -Wl,-version-script,$(SRCDIR)/video_api_export.ver endif ifeq ($(OS), OSX) OSX_SDK_PATH = $(shell xcrun --sdk macosx --show-sdk-path) ifeq ($(CPU), X86) ifeq ($(ARCH_DETECTED), 64BITS) CFLAGS += -pipe -arch x86_64 -mmacosx-version-min=10.9 -isysroot $(OSX_SDK_PATH) -stdlib=libc++ LDFLAGS += -bundle LDLIBS += -ldl else CFLAGS += -pipe -mmmx -msse -fomit-frame-pointer -arch i686 -mmacosx-version-min=10.9 -isysroot $(OSX_SDK_PATH) LDFLAGS += -bundle LDLIBS += -ldl endif endif endif # test for essential build dependencies ifeq ($(origin PKG_CONFIG), undefined) PKG_CONFIG = $(CROSS_COMPILE)pkg-config ifeq ($(shell which $(PKG_CONFIG) 2>/dev/null),) $(error $(PKG_CONFIG) not found) endif endif ifeq ($(origin LIBPNG_CFLAGS) $(origin LIBPNG_LDLIBS), undefined undefined) ifeq ($(shell $(PKG_CONFIG) --modversion libpng 2>/dev/null),) $(error No libpng development libraries found!) endif LIBPNG_CFLAGS += $(shell $(PKG_CONFIG) --cflags libpng) LIBPNG_LDLIBS += $(shell $(PKG_CONFIG) --libs libpng) endif CFLAGS += $(LIBPNG_CFLAGS) LDLIBS += $(LIBPNG_LDLIBS) # search for OpenGL libraries ifeq ($(VC), 1) GL_CFLAGS += -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/vmcs_host/linux GL_LDLIBS += -L/opt/vc/lib -lEGL -lbcm_host -lvcos -lvchiq_arm USE_GLES=1 endif ifeq ($(USE_GLES), 1) CFLAGS += -DUSE_GLES GL_LDLIBS += -lGLESv2 endif 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)sdl2-config ifeq ($(shell which $(SDL_CONFIG) 2>/dev/null),) SDL_CONFIG = $(CROSS_COMPILE)sdl-config ifeq ($(shell which $(SDL_CONFIG) 2>/dev/null),) $(error No SDL development libraries found!) else $(warning Using SDL 1.2 libraries) endif endif SDL_CFLAGS += $(shell $(SDL_CONFIG) --cflags) SDL_LDLIBS += $(shell $(SDL_CONFIG) --libs) endif CFLAGS += $(SDL_CFLAGS) LDLIBS += $(SDL_LDLIBS) # set mupen64plus core API header path ifneq ("$(APIDIR)","") CFLAGS += "-I$(APIDIR)" else TRYDIR = ../../../mupen64plus-core/src/api ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","") CFLAGS += -I$(TRYDIR) else TRYDIR = /usr/local/include/mupen64plus ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","") CFLAGS += -I$(TRYDIR) else TRYDIR = /usr/include/mupen64plus ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","") CFLAGS += -I$(TRYDIR) else $(error Mupen64Plus API header files not found! Use makefile parameter APIDIR to force a location.) endif endif endif endif # reduced compile output when running make without V=1 ifneq ($(findstring $(MAKEFLAGS),s),s) ifndef V Q_CC = @echo ' CC '$@; Q_CXX = @echo ' CXX '$@; Q_LD = @echo ' LD '$@; endif endif # set base program pointers and flags CC = $(CROSS_COMPILE)gcc CXX = $(CROSS_COMPILE)g++ RM ?= rm -f INSTALL ?= install MKDIR ?= mkdir -p COMPILE.c = $(Q_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c COMPILE.cc = $(Q_CXX)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c LINK.o = $(Q_LD)$(CXX) $(CXXFLAGS) $(LDFLAGS) $(TARGET_ARCH) # set special flags for given Makefile parameters ifeq ($(DEBUG),1) CFLAGS += -g INSTALL_STRIP_FLAG ?= else ifneq ($(OS),OSX) INSTALL_STRIP_FLAG ?= -s endif endif ifeq ($(NO_ASM), 1) CFLAGS += -DNO_ASM endif # set installation options ifeq ($(PREFIX),) PREFIX := /usr/local endif ifeq ($(SHAREDIR),) SHAREDIR := $(PREFIX)/share/mupen64plus endif ifeq ($(LIBDIR),) LIBDIR := $(PREFIX)/lib endif ifeq ($(PLUGINDIR),) PLUGINDIR := $(LIBDIR)/mupen64plus endif # list of source files to compile SOURCE = \ $(SRCDIR)/liblinux/BMGImage.c \ $(SRCDIR)/liblinux/BMGUtils.cpp \ $(SRCDIR)/liblinux/bmp.c \ $(SRCDIR)/liblinux/pngrw.c \ $(SRCDIR)/Blender.cpp \ $(SRCDIR)/Combiner.cpp \ $(SRCDIR)/Config.cpp \ $(SRCDIR)/ConvertImage.cpp \ $(SRCDIR)/ConvertImage16.cpp \ $(SRCDIR)/Debugger.cpp \ $(SRCDIR)/DeviceBuilder.cpp \ $(SRCDIR)/FrameBuffer.cpp \ $(SRCDIR)/GraphicsContext.cpp \ $(SRCDIR)/OGLCombiner.cpp \ $(SRCDIR)/OGLExtensions.cpp \ $(SRCDIR)/OGLGraphicsContext.cpp \ $(SRCDIR)/OGLRender.cpp \ $(SRCDIR)/OGLRenderExt.cpp \ $(SRCDIR)/OGLTexture.cpp \ $(SRCDIR)/Render.cpp \ $(SRCDIR)/RenderBase.cpp \ $(SRCDIR)/RenderExt.cpp \ $(SRCDIR)/RenderTexture.cpp \ $(SRCDIR)/RSP_Parser.cpp \ $(SRCDIR)/RSP_S2DEX.cpp \ $(SRCDIR)/Texture.cpp \ $(SRCDIR)/TextureFilters.cpp \ $(SRCDIR)/TextureFilters_2xsai.cpp \ $(SRCDIR)/TextureFilters_hq2x.cpp \ $(SRCDIR)/TextureFilters_hq4x.cpp \ $(SRCDIR)/TextureManager.cpp \ $(SRCDIR)/VectorMath.cpp \ $(SRCDIR)/Video.cpp ifeq ($(OS),MINGW) SOURCE += \ $(SRCDIR)/osal_dynamiclib_win32.c \ $(SRCDIR)/osal_files_win32.c else SOURCE += \ $(SRCDIR)/osal_dynamiclib_unix.c \ $(SRCDIR)/osal_files_unix.c endif # generate a list of object files build, make a temporary directory for them OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(filter %.c, $(SOURCE))) OBJECTS += $(patsubst $(SRCDIR)/%.cpp, $(OBJDIR)/%.o, $(filter %.cpp, $(SOURCE))) OBJDIRS = $(dir $(OBJECTS)) $(shell $(MKDIR) $(OBJDIRS)) # build targets TARGET = mupen64plus-video-rice$(POSTFIX).$(SO_EXTENSION) targets: @echo "Mupen64plus-video-rice N64 Graphics plugin makefile. " @echo " Targets:" @echo " all == Build Mupen64plus-video-rice plugin" @echo " clean == remove object files" @echo " rebuild == clean and re-build all" @echo " install == Install Mupen64Plus-video-rice plugin" @echo " uninstall == Uninstall Mupen64Plus-video-rice plugin" @echo " Options:" @echo " BITS=32 == build 32-bit binaries on 64-bit machine" @echo " NO_ASM=1 == build without inline assembly code (x86 MMX/SSE)" @echo " USE_GLES=1 == build against GLESv2 instead of OpenGL" @echo " VC=1 == build against Broadcom Videocore GLESv2" @echo " APIDIR=path == path to find Mupen64Plus Core headers" @echo " OPTFLAGS=flag == compiler optimization (default: -O3 -flto)" @echo " WARNFLAGS=flag == compiler warning levels (default: -Wall)" @echo " PIC=(1|0) == Force enable/disable of position independent code" @echo " POSTFIX=name == String added to the name of the the build (default: '')" @echo " Install Options:" @echo " PREFIX=path == install/uninstall prefix (default: /usr/local)" @echo " SHAREDIR=path == path to install shared data files (default: PREFIX/share/mupen64plus)" @echo " LIBDIR=path == library prefix (default: PREFIX/lib)" @echo " PLUGINDIR=path == path to install plugin libraries (default: LIBDIR/mupen64plus)" @echo " DESTDIR=path == path to prepend to all installation paths (only for packagers)" @echo " Debugging Options:" @echo " DEBUG=1 == add debugging symbols" @echo " V=1 == show verbose compiler output" all: $(TARGET) install: $(TARGET) $(INSTALL) -d "$(DESTDIR)$(PLUGINDIR)" $(INSTALL) -m 0644 $(INSTALL_STRIP_FLAG) $(TARGET) "$(DESTDIR)$(PLUGINDIR)" $(INSTALL) -d "$(DESTDIR)$(SHAREDIR)" $(INSTALL) -m 0644 "$(SRCDIR)/../data/RiceVideoLinux.ini" "$(DESTDIR)$(SHAREDIR)" uninstall: $(RM) "$(DESTDIR)$(PLUGINDIR)/$(TARGET)" $(RM) "$(DESTDIR)$(SHAREDIR)/RiceVideoLinux.ini" clean: $(RM) -r $(OBJDIR) $(TARGET) rebuild: clean all # build dependency files CFLAGS += -MD -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 mupen64plus-video-rice-src-2.6.0/src/000077500000000000000000000000001464507324400173325ustar00rootroot00000000000000mupen64plus-video-rice-src-2.6.0/src/Blender.cpp000066400000000000000000000362671464507324400214270ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Blender.h" #include "Config.h" #include "RSP_Parser.h" #include "Render.h" #include "RenderBase.h" #include "osal_preproc.h" #include "typedefs.h" const char * sc_szBlClr[4] = { "In", "Mem", "Bl", "Fog" }; const char * sc_szBlA1[4] = { "AIn", "AFog", "AShade", "0" }; const char * sc_szBlA2[4] = { "1-A", "AMem", "1", "0" }; //======================================================================== void CBlender::InitBlenderMode(void) // Set Alpha Blender mode { //1. Z_COMPARE -- Enable / Disable Zbuffer compare // 1 - Enable ZBuffer // 0 - Disable ZBuffer //2. Z_UPDATE -- Enable / Disable Zbuffer update // 1 - Enable ZBuffer writeable // 0 - Zbuffer not writeable //3. AA_EN and IM_RD -- Anti-Alias // AA_EN - Enable anti-aliase // AA_EN | IM_RD - Reduced anti-aliase // IM_RD - ?? // - - Disable anti-aliase //4. ZMode // #define ZMODE_OPA 0 -- Usually used with Z_COMPARE and Z_UPDATE // or used without neither Z_COMPARE or Z_UPDATE // if used with Z_COMPARE and Z_UPDATE, then this is // the regular ZBuffer mode, with compare and update // #define ZMODE_INTER 0x400 // #define ZMODE_XLU 0x800 -- Usually used with Z_COMPARE, but not with Z_UPDATE // Do only compare, no zbuffer update. // Not output if the z value is the same // #define ZMODE_DEC 0xc00 -- Usually used with Z_COMPARE, but not with Z_UPDATE // Do only compare, no update, but because this is // decal mode, so image should be updated even // the z value is the same as compared. CRender *render = CRender::g_pRender; // Alpha Blender Modes /* 6. FORCE_BL - Alpha blending at blender stage 1 - Enable alpha blending at blender 0 - Disable alpha blending at blender Alpha blending at blender is usually used to render XLU surface if enabled, then use the blending setting of C1 and C2 7. ALPHA_CVG_SEL - Output full alpha from the color combiner, usually not used together with FORCE_BL. If it is used together with FORCE_BL, then ignore this 8. CVG_X_ALPHA - Before output the color from color combiner, mod it with alpha 9. TEX_EDGE - Ignore this 10.CLR_ON_CVG - Used with XLU surfaces, ignore it 11.CVG_DST #define CVG_DST_CLAMP 0 - Usually used with OPA surface #define CVG_DST_WRAP 0x100 - Usually used with XLU surface or OPA line #define CVG_DST_FULL 0x200 - ? #define CVG_DST_SAVE 0x300 - ? Possible Blending Inputs: In - Input from color combiner Mem - Input from current frame buffer Fog - Fog generator BL - Blender Possible Blending Factors: A-IN - Alpha from color combiner A-MEM - Alpha from current frame buffer (1-A) - A-FOG - Alpha of fog color A-SHADE - Alpha of shade 1 - 1 0 - 0 */ #define BLEND_NOOP 0x0000 #define BLEND_NOOP5 0xcc48 // Fog * 0 + Mem * 1 #define BLEND_NOOP4 0xcc08 // Fog * 0 + In * 1 #define BLEND_FOG_ASHADE 0xc800 #define BLEND_FOG_3 0xc000 // Fog * AIn + In * 1-A #define BLEND_FOG_MEM 0xc440 // Fog * AFog + Mem * 1-A #define BLEND_FOG_APRIM 0xc400 // Fog * AFog + In * 1-A #define BLEND_BLENDCOLOR 0x8c88 #define BLEND_BI_AFOG 0x8400 // Bl * AFog + In * 1-A #define BLEND_BI_AIN 0x8040 // Bl * AIn + Mem * 1-A #define BLEND_MEM 0x4c40 // Mem*0 + Mem*(1-0)?! #define BLEND_FOG_MEM_3 0x44c0 // Mem * AFog + Fog * 1-A #define BLEND_NOOP3 0x0c48 // In * 0 + Mem * 1 #define BLEND_PASS 0x0c08 // In * 0 + In * 1 #define BLEND_FOG_MEM_IN_MEM 0x0440 // In * AFog + Mem * 1-A #define BLEND_FOG_MEM_FOG_MEM 0x04c0 // In * AFog + Fog * 1-A #define BLEND_OPA 0x0044 // In * AIn + Mem * AMem #define BLEND_XLU 0x0040 #define BLEND_MEM_ALPHA_IN 0x4044 // Mem * AIn + Mem * AMem uint32 blendmode_1 = (uint32)( gRDP.otherMode.blender & 0xcccc ); uint32 blendmode_2 = (uint32)( gRDP.otherMode.blender & 0x3333 ); uint32 cycletype = gRDP.otherMode.cycle_type; switch( cycletype ) { case CYCLE_TYPE_FILL: //BlendFunc(BLEND_ONE, BLEND_ZERO); //Enable(); Disable(); break; case CYCLE_TYPE_COPY: //Disable(); BlendFunc(BLEND_ONE, BLEND_ZERO); Enable(); break; case CYCLE_TYPE_2: if( gRDP.otherMode.force_bl && gRDP.otherMode.z_cmp ) { BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); Enable(); break; } /* if( gRDP.otherMode.alpha_cvg_sel && gRDP.otherMode.cvg_x_alpha==0 ) { BlendFunc(BLEND_ONE, BLEND_ZERO); Enable(); break; } */ switch( blendmode_1+blendmode_2 ) { case BLEND_PASS+(BLEND_PASS>>2): // In * 0 + In * 1 case BLEND_FOG_APRIM+(BLEND_PASS>>2): BlendFunc(BLEND_ONE, BLEND_ZERO); if( gRDP.otherMode.alpha_cvg_sel ) { Enable(); } else { Disable(); } render->SetAlphaTestEnable( ((gRDP.otherModeL >> RSP_SETOTHERMODE_SHIFT_ALPHACOMPARE) & 0x3)==1 ? TRUE : FALSE); break; case BLEND_PASS+(BLEND_OPA>>2): // 0x0c19 // Cycle1: In * 0 + In * 1 // Cycle2: In * AIn + Mem * AMem if( gRDP.otherMode.cvg_x_alpha && gRDP.otherMode.alpha_cvg_sel ) { BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); Enable(); } else { BlendFunc(BLEND_ONE, BLEND_ZERO); Enable(); } break; case BLEND_PASS + (BLEND_XLU>>2): // 0x0c18 // Cycle1: In * 0 + In * 1 // Cycle2: In * AIn + Mem * 1-A case BLEND_FOG_ASHADE + (BLEND_XLU>>2): //Cycle1: Fog * AShade + In * 1-A //Cycle2: In * AIn + Mem * 1-A case BLEND_FOG_APRIM + (BLEND_XLU>>2): //Cycle1: Fog * AFog + In * 1-A //Cycle2: In * AIn + Mem * 1-A //case BLEND_FOG_MEM_FOG_MEM + (BLEND_OPA>>2): //Cycle1: In * AFog + Fog * 1-A //Cycle2: In * AIn + Mem * AMem case BLEND_FOG_MEM_FOG_MEM + (BLEND_PASS>>2): //Cycle1: In * AFog + Fog * 1-A //Cycle2: In * 0 + In * 1 case BLEND_XLU + (BLEND_XLU>>2): //Cycle1: Fog * AFog + In * 1-A //Cycle2: In * AIn + Mem * 1-A case BLEND_BI_AFOG + (BLEND_XLU>>2): //Cycle1: Bl * AFog + In * 1-A //Cycle2: In * AIn + Mem * 1-A case BLEND_XLU + (BLEND_FOG_MEM_IN_MEM>>2): //Cycle1: In * AIn + Mem * 1-A //Cycle2: In * AFog + Mem * 1-A case BLEND_PASS + (BLEND_FOG_MEM_IN_MEM>>2): //Cycle1: In * 0 + In * 1 //Cycle2: In * AFog + Mem * 1-A BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); Enable(); break; case BLEND_FOG_MEM_FOG_MEM + (BLEND_OPA>>2): //Cycle1: In * AFog + Fog * 1-A //Cycle2: In * AIn + Mem * AMem BlendFunc(BLEND_ONE, BLEND_ZERO); Enable(); break; case BLEND_FOG_APRIM + (BLEND_OPA>>2): // For Golden Eye //Cycle1: Fog * AFog + In * 1-A //Cycle2: In * AIn + Mem * AMem case BLEND_FOG_ASHADE + (BLEND_OPA>>2): //Cycle1: Fog * AShade + In * 1-A //Cycle2: In * AIn + Mem * AMem case BLEND_BI_AFOG + (BLEND_OPA>>2): //Cycle1: Bl * AFog + In * 1-A //Cycle2: In * AIn + Mem * 1-AMem case BLEND_FOG_ASHADE + (BLEND_NOOP>>2): //Cycle1: Fog * AShade + In * 1-A //Cycle2: In * AIn + In * 1-A case BLEND_NOOP + (BLEND_OPA>>2): //Cycle1: In * AIn + In * 1-A //Cycle2: In * AIn + Mem * AMem case BLEND_NOOP4 + (BLEND_NOOP>>2): //Cycle1: Fog * AIn + In * 1-A //Cycle2: In * 0 + In * 1 case BLEND_FOG_ASHADE+(BLEND_PASS>>2): //Cycle1: Fog * AShade + In * 1-A //Cycle2: In * 0 + In * 1 case BLEND_FOG_3+(BLEND_PASS>>2): BlendFunc(BLEND_ONE, BLEND_ZERO); Enable(); break; case BLEND_FOG_ASHADE+0x0301: // c800 - Cycle1: Fog * AShade + In * 1-A // 0301 - Cycle2: In * 0 + In * AMem BlendFunc(BLEND_SRCALPHA, BLEND_ZERO); Enable(); break; case 0x0c08+0x1111: // 0c08 - Cycle1: In * 0 + In * 1 // 1111 - Cycle2: Mem * AFog + Mem * AMem BlendFunc(BLEND_ZERO, BLEND_DESTALPHA); Enable(); break; default: #ifdef DEBUGGER if( pauseAtNext ) { uint32 dwM1A_1 = (gRDP.otherMode.blender>>14) & 0x3; uint32 dwM1B_1 = (gRDP.otherMode.blender>>10) & 0x3; uint32 dwM2A_1 = (gRDP.otherMode.blender>>6) & 0x3; uint32 dwM2B_1 = (gRDP.otherMode.blender>>2) & 0x3; uint32 dwM1A_2 = (gRDP.otherMode.blender>>12) & 0x3; uint32 dwM1B_2 = (gRDP.otherMode.blender>>8) & 0x3; uint32 dwM2A_2 = (gRDP.otherMode.blender>>4) & 0x3; uint32 dwM2B_2 = (gRDP.otherMode.blender ) & 0x3; TRACE0("Unknown Blender Mode: 2 cycle"); DebuggerAppendMsg( "\tblender:\t\t%04x - Cycle1:\t%s * %s + %s * %s\n\t\t%04x - Cycle2:\t%s * %s + %s * %s", blendmode_1, sc_szBlClr[dwM1A_1], sc_szBlA1[dwM1B_1], sc_szBlClr[dwM2A_1], sc_szBlA2[dwM2B_1], blendmode_2, sc_szBlClr[dwM1A_2], sc_szBlA1[dwM1B_2], sc_szBlClr[dwM2A_2], sc_szBlA2[dwM2B_2]); } #endif if( blendmode_2 == (BLEND_PASS>>2) ) { BlendFunc(BLEND_ONE, BLEND_ZERO); } else { BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); } Enable(); break; } break; default: // 1/2 Cycle or Copy if( gRDP.otherMode.force_bl && gRDP.otherMode.z_cmp && blendmode_1 != BLEND_FOG_ASHADE ) { BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); Enable(); break; } if( gRDP.otherMode.force_bl && options.enableHackForGames == HACK_FOR_COMMANDCONQUER ) { BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); Enable(); break; } switch ( blendmode_1 ) //switch ( blendmode_2<<2 ) { case BLEND_XLU: // IN * A_IN + MEM * (1-A_IN) case BLEND_BI_AIN: // Bl * AIn + Mem * 1-A case BLEND_FOG_MEM: // c440 - Cycle1: Fog * AFog + Mem * 1-A case BLEND_FOG_MEM_IN_MEM: // c440 - Cycle1: In * AFog + Mem * 1-A case BLEND_BLENDCOLOR: //Bl * 0 + Bl * 1 case 0x00c0: //In * AIn + Fog * 1-A BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); Enable(); break; case BLEND_MEM_ALPHA_IN: // Mem * AIn + Mem * AMem BlendFunc(BLEND_ZERO, BLEND_DESTALPHA); Enable(); break; case BLEND_PASS: // IN * 0 + IN * 1 BlendFunc(BLEND_ONE, BLEND_ZERO); if( gRDP.otherMode.alpha_cvg_sel ) { Enable(); } else { Disable(); } break; case BLEND_OPA: // IN * A_IN + MEM * A_MEM if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS ) { BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); } else { BlendFunc(BLEND_ONE, BLEND_ZERO); } Enable(); break; case BLEND_NOOP: // IN * A_IN + IN * (1 - A_IN) case BLEND_FOG_ASHADE: // Fog * AShade + In * 1-A case BLEND_FOG_MEM_3: // Mem * AFog + Fog * 1-A case BLEND_BI_AFOG: // Bl * AFog + In * 1-A BlendFunc(BLEND_ONE, BLEND_ZERO); Enable(); break; case BLEND_FOG_APRIM: // Fog * AFog + In * 1-A BlendFunc(BLEND_INVSRCALPHA, BLEND_ZERO); Enable(); break; case BLEND_NOOP3: // In * 0 + Mem * 1 case BLEND_NOOP5: // Fog * 0 + Mem * 1 BlendFunc(BLEND_ZERO, BLEND_ONE); Enable(); break; case BLEND_MEM: // Mem * 0 + Mem * 1-A // WaveRace BlendFunc(BLEND_ZERO, BLEND_ONE); Enable(); break; default: #ifdef DEBUGGER if( pauseAtNext ) { uint32 dwM1A_1 = (gRDP.otherMode.blender>>14) & 0x3; uint32 dwM1B_1 = (gRDP.otherMode.blender>>10) & 0x3; uint32 dwM2A_1 = (gRDP.otherMode.blender>>6) & 0x3; uint32 dwM2B_1 = (gRDP.otherMode.blender>>2) & 0x3; uint32 dwM1A_2 = (gRDP.otherMode.blender>>12) & 0x3; uint32 dwM1B_2 = (gRDP.otherMode.blender>>8) & 0x3; uint32 dwM2A_2 = (gRDP.otherMode.blender>>4) & 0x3; uint32 dwM2B_2 = (gRDP.otherMode.blender ) & 0x3; TRACE0("Unknown Blender Mode: 1 cycle"); DebuggerAppendMsg( "\tblender:\t\t%04x - Cycle1:\t%s * %s + %s * %s\n\t\t\tCycle2:\t%s * %s + %s * %s", blendmode_1, sc_szBlClr[dwM1A_1], sc_szBlA1[dwM1B_1], sc_szBlClr[dwM2A_1], sc_szBlA2[dwM2B_1], sc_szBlClr[dwM1A_2], sc_szBlA1[dwM1B_2], sc_szBlClr[dwM2A_2], sc_szBlA2[dwM2B_2]); } #endif BlendFunc(BLEND_SRCALPHA, BLEND_INVSRCALPHA); Enable(); render->SetAlphaTestEnable(TRUE); break; } } } mupen64plus-video-rice-src-2.6.0/src/Blender.h000066400000000000000000000032331464507324400210570ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _BLENDER_H_ #define _BLENDER_H_ #include "typedefs.h" class CRender; class CBlender { public: virtual ~CBlender() {} virtual void InitBlenderMode(void); virtual void NormalAlphaBlender(void)=0; virtual void DisableAlphaBlender(void)=0; virtual void BlendFunc(uint32 srcFunc, uint32 desFunc)=0; virtual void Enable()=0; virtual void Disable()=0; protected: CBlender(CRender *pRender) : m_pRender(pRender) {} CRender *m_pRender; }; typedef enum _BLEND { BLEND_ZERO = 1, BLEND_ONE = 2, BLEND_SRCCOLOR = 3, BLEND_INVSRCCOLOR = 4, BLEND_SRCALPHA = 5, BLEND_INVSRCALPHA = 6, BLEND_DESTALPHA = 7, BLEND_INVDESTALPHA = 8, BLEND_DESTCOLOR = 9, BLEND_INVDESTCOLOR = 10, BLEND_SRCALPHASAT = 11, BLEND_BOTHSRCALPHA = 12, BLEND_BOTHINVSRCALPHA = 13, BLEND_BLENDFACTOR = 14, BLEND_INVBLENDFACTOR = 15, BLEND_FORCE_DWORD = 0x7fffffff } BLEND; #endif mupen64plus-video-rice-src-2.6.0/src/COLOR.h000066400000000000000000000054221464507324400203640ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - COLOR.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Rice1964 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef XCOLOR_H #define XCOLOR_H typedef struct _COLORVALUE { float r; float g; float b; float a; } COLORVALUE; typedef struct XCOLOR { float r, g, b, a; #ifdef __cplusplus public: XCOLOR() { } XCOLOR( unsigned int argb ); XCOLOR( const float * ); XCOLOR( const COLORVALUE& ); XCOLOR( float r, float g, float b, float a ); // casting operator unsigned int () const; operator float* (); operator const float* () const; operator COLORVALUE* (); operator const COLORVALUE* () const; operator COLORVALUE& (); operator const COLORVALUE& () const; // assignment operators XCOLOR& operator += ( const XCOLOR& ); XCOLOR& operator -= ( const XCOLOR& ); XCOLOR& operator *= ( float ); XCOLOR& operator /= ( float ); // unary operators XCOLOR operator + () const; XCOLOR operator - () const; // binary operators XCOLOR operator + ( const XCOLOR& ) const; XCOLOR operator - ( const XCOLOR& ) const; XCOLOR operator * ( float ) const; XCOLOR operator / ( float ) const; friend XCOLOR operator * (float, const XCOLOR& ); bool operator == ( const XCOLOR& ) const; bool operator != ( const XCOLOR& ) const; #endif //__cplusplus } XCOLOR; #endif mupen64plus-video-rice-src-2.6.0/src/CSortedList.h000066400000000000000000000067411464507324400217120ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _SORTED_LIST_H_ #define _SORTED_LIST_H_ #include template class CSortedList { private: Key *keys; Element *elements; int curSize; int maxSize; public: CSortedList(int size=1000) { maxSize = size; curSize = 0; keys = new Key[size]; elements = new Element[size]; } ~CSortedList() { delete [] keys; delete [] elements; } int size() { return curSize; } void clear() { curSize = 0; } void add(Key key, Element ele) { int i = find(key); if( i >= 0 ) { elements[i] = ele; return; } if( curSize == maxSize ) { // Need to increase maxSize Key *oldkeys = keys; Element *oldelements = elements; int oldmaxsize = maxSize; maxSize *= 2; keys = new Key[maxSize]; elements = new Element[maxSize]; std::memcpy(keys,oldkeys,oldmaxsize*sizeof(Key)); std::memcpy(elements,oldelements,oldmaxsize*sizeof(Element)); } for( i=0; i key ) { // Found the spot break; } } for( int j=curSize; j>i; j-- ) { keys[j] = keys[j-1]; elements[j] = elements[j-1]; } keys[i] = key; elements[i] = ele; curSize++; } Element operator[](int index) { if( index >= curSize ) index = curSize-1; else if( index < 0 ) index = 0; return elements[index]; } Element get(Key key) { int index = Find(key); return this->operator[](index); } // Binary search int find(Key key) { if( curSize <= 0 ) return -1; int dwMin = 0; int dwMax = curSize - 1; int index = -1; int dwRange; int dwIndex; while (true) { dwRange = dwMax - dwMin; dwIndex = dwMin + (dwRange/2); if( keys[dwIndex] == key ) { index = dwIndex; break; } // If the range is 0, and we didn't match above, then it must be unmatched if (dwRange == 0) break; // If lower, check from min..index // If higher, check from index..max if (key < keys[dwIndex]) { // Lower dwMax = dwIndex; } else { // Higher dwMin = dwIndex + 1; } } return index; } }; #endif mupen64plus-video-rice-src-2.6.0/src/Combiner.cpp000066400000000000000000000154611464507324400216030ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Combiner.h" #include "Config.h" #include "RSP_Parser.h" #include "RenderBase.h" //static BOOL g_bHiliteRGBAHack = FALSE; #ifdef DEBUGGER const char *constStrs[] = { "MUX_0", "MUX_1", "MUX_COMBINED", "MUX_TEXEL0", "MUX_TEXEL1", "MUX_PRIM", "MUX_SHADE", "MUX_ENV", "MUX_COMBALPHA", "MUX_T0_ALPHA", "MUX_T1_ALPHA", "MUX_PRIM_ALPHA", "MUX_SHADE_ALPHA", "MUX_ENV_ALPHA", "MUX_LODFRAC", "MUX_PRIMLODFRAC", "MUX_K5", "MUX_UNK", }; const char *cycleTypeStrs[] = { "1 Cycle", "2 Cycle", "Copy Mode", "Fill Mode" }; const char* constStr(uint32 op) { if(op<=MUX_UNK) return constStrs[op]; else return "Invalid-Const"; } #endif void swap(uint8 &a, uint8 &b) { uint8 c=a; a=b; b=c; } //======================================================================== const CColorCombiner::SourceIndex CColorCombiner::color_indices[8] = { CS_COLOR_A0 , CS_COLOR_B0 , CS_COLOR_C0 , CS_COLOR_D0 , CS_COLOR_A1 , CS_COLOR_B1 , CS_COLOR_C1 , CS_COLOR_D1 }; const CColorCombiner::SourceIndex CColorCombiner::alpha_indices[8] = { CS_ALPHA_A0 , CS_ALPHA_B0 , CS_ALPHA_C0 , CS_ALPHA_D0 , CS_ALPHA_A1 , CS_ALPHA_B1 , CS_ALPHA_C1 , CS_ALPHA_D1 }; void CColorCombiner::InitCombinerMode(void) { if( currentRomOptions.bNormalCombiner ) { DisableCombiner(); } else if( gRDP.otherMode.cycle_type == CYCLE_TYPE_COPY ) { InitCombinerCycleCopy(); m_bCycleChanged = true; } else if ( gRDP.otherMode.cycle_type == CYCLE_TYPE_FILL ) //else if ( gRDP.otherMode.cycle_type == CYCLE_TYPE_FILL && gRSP.ucode != 5 ) //hack { InitCombinerCycleFill(); m_bCycleChanged = true; } else { InitCombinerCycle12(); m_bCycleChanged = false; } } bool bConkerHideShadow=false; // rgb0 = (A0 - B0) * C0 + D0 // rgb1 = (A1 - B1) * C1 + D1 // alpha0 = (a0 - b0) * c0 + d0 // alpha1 = (a1 - b1) * c1 + d1 void CColorCombiner::SetCombineMode(uint32 dwMux0, uint32 dwMux1) { // Cycle 1 m_sources[CS_COLOR_A0] = (uint8)((dwMux0 >> 20) & 0xF); m_sources[CS_COLOR_B0] = (uint8)((dwMux1 >> 28) & 0xF); m_sources[CS_COLOR_C0] = (uint8)((dwMux0 >> 15) & 0x1F); m_sources[CS_COLOR_D0] = (uint8)((dwMux1 >> 15) & 0x7); m_sources[CS_ALPHA_A0] = (uint8)((dwMux0 >> 12) & 0x7); m_sources[CS_ALPHA_B0] = (uint8)((dwMux1 >> 12) & 0x7); m_sources[CS_ALPHA_C0] = (uint8)((dwMux0 >> 9) & 0x7); m_sources[CS_ALPHA_D0] = (uint8)((dwMux1 >> 9) & 0x7); //Cycle 2 m_sources[CS_COLOR_A1] = (uint8)((dwMux0 >> 5) & 0xF); m_sources[CS_COLOR_B1] = (uint8)((dwMux1 >> 24) & 0xF); m_sources[CS_COLOR_C1] = (uint8)((dwMux0 >> 0) & 0x1F); m_sources[CS_COLOR_D1] = (uint8)((dwMux1 >> 6) & 0x7); m_sources[CS_ALPHA_A1] = (uint8)((dwMux1 >> 21) & 0x7); m_sources[CS_ALPHA_B1] = (uint8)((dwMux1 >> 3) & 0x7); m_sources[CS_ALPHA_C1] = (uint8)((dwMux1 >> 18) & 0x7); m_sources[CS_ALPHA_D1] = (uint8)((dwMux1 >> 0) & 0x7); m_combineMode1 = dwMux0; m_combineMode2 = dwMux1; // Look what is used in this combine mode. // TODO: We should be able to remove this part in the futur and let the // plugin reproduce the N64 behavior to keep the code clean and avoid // unnecessary optimizations. m_bTex0Enabled = false; m_bTex1Enabled = false; m_bLODFracEnabled = false; for( int i = 0; i < 8; i++ ) { switch( color_indices[i] ) { case CCMUX_TEXEL0: case CCMUX_TEXEL0_ALPHA: m_bTex0Enabled = true; break; case CCMUX_TEXEL1: case CCMUX_TEXEL1_ALPHA: m_bTex1Enabled = true; break; case CCMUX_LOD_FRACTION: m_bLODFracEnabled = true; break; default: break; } switch( alpha_indices[i] ) { case ACMUX_TEXEL0: m_bTex0Enabled = true; break; case ACMUX_TEXEL1: m_bTex1Enabled = true; break; case ACMUX_LOD_FRACTION: m_bLODFracEnabled = true; break; default: break; } } m_bTexelsEnable = m_bTex0Enabled || m_bTex1Enabled; // Hacks if( options.enableHackForGames == HACK_FOR_TOPGEARRALLY ) { //Mux=0x00317e025ffef3fa Used in TOP GEAR RALLY //Color0: (PRIM - ENV) * TEXEL1 + ENV //Color1: (COMBINED - 0) * TEXEL1 + 0 //Alpha0: (0 - 0) * 0 + TEXEL0 //Alpha1: (0 - 0) * 0 + TEXEL1 if( dwMux1 == 0x5ffef3fa || dwMux0 == 0x00317e02 ) { // The texts m_sources[CS_ALPHA_D1] = ACMUX_COMBINED; m_sources[CS_COLOR_C1] = CCMUX_TEXEL0; } } if( options.enableHackForGames == HACK_FOR_CONKER ) { // Conker's shadow, to disable the shadow //Mux=0x00ffe9ff Used in CONKER BFD //Color0: (0 - 0) * 0 + SHADE //Color1: (0 - 0) * 0 + SHADE //Alpha0: (1 - TEXEL0) * SHADE + 0 //Alpha1: (1 - TEXEL0) * SHADE + 0 if( dwMux1 == 0xffd21f0f && dwMux0 == 0x00ffe9ff ) { bConkerHideShadow = true; } else { bConkerHideShadow = false; } } } mupen64plus-video-rice-src-2.6.0/src/Combiner.h000066400000000000000000000052551464507324400212500ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _COMBINER_H_ #define _COMBINER_H_ #include "typedefs.h" #include "CombinerDefs.h" #include "CSortedList.h" class CRender; extern const char* cycleTypeStrs[]; class CColorCombiner { friend class CRender; public: virtual ~CColorCombiner() {}; virtual void InitCombinerMode(void); virtual bool Initialize(void)=0; virtual void CleanUp(void) {}; virtual void SetCombineMode(uint32 dwMux0, uint32 dwMux1); virtual void InitCombinerBlenderForSimpleTextureDraw(uint32 tile=0)=0; virtual void DisableCombiner(void)=0; bool m_bLODFracEnabled; // TODO: Find a way to remove that. protected: CColorCombiner(CRender *pRender) : m_combineMode1(0),m_combineMode2(0),m_bTex0Enabled(false),m_bTex1Enabled(false),m_bTexelsEnable(false), m_bCycleChanged(false),m_pRender(pRender) { for(int i=0; i<16; i++) { m_sources[i] = -1; } } virtual void InitCombinerCycleCopy(void)=0; virtual void InitCombinerCycleFill(void)=0; virtual void InitCombinerCycle12(void)=0; enum SourceIndex { CS_COLOR_A0 = 0, // index for Color A, cycle 1 CS_COLOR_B0, CS_COLOR_C0, CS_COLOR_D0, CS_ALPHA_A0, // index for Alpha A,cycle 1 CS_ALPHA_B0, CS_ALPHA_C0, CS_ALPHA_D0, CS_COLOR_A1, // index for Color A, cycle 2 CS_COLOR_B1, CS_COLOR_C1, CS_COLOR_D1, CS_ALPHA_A1, // index for Alpha A, cycle 2 CS_ALPHA_B1, CS_ALPHA_C1, CS_ALPHA_D1 }; uint8 m_sources[16]; uint32 m_combineMode1; uint32 m_combineMode2; bool m_bTex0Enabled; bool m_bTex1Enabled; bool m_bTexelsEnable; bool m_bCycleChanged; // A flag will be set if cycle is changed to FILL or COPY CRender *m_pRender; private: static const SourceIndex color_indices[8]; static const SourceIndex alpha_indices[8]; }; void swap(uint8 &a, uint8 &b); #endif mupen64plus-video-rice-src-2.6.0/src/CombinerDefs.h000066400000000000000000000117471464507324400220550ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _COMBINER_DEFS_H_ #define _COMBINER_DEFS_H_ #include "typedefs.h" #define MUX_MASK 0x1F #define MUX_MASK_WITH_ALPHA 0x5F #define MUX_MASK_WITH_NEG 0x3F #define MUX_MASK_WITH_COMP 0x9F enum { MUX_0 = 0, MUX_1, MUX_COMBINED, MUX_TEXEL0, MUX_TEXEL1, MUX_PRIM, MUX_SHADE, MUX_ENV, MUX_COMBALPHA, MUX_T0_ALPHA, MUX_T1_ALPHA, MUX_PRIM_ALPHA, MUX_SHADE_ALPHA, MUX_ENV_ALPHA, MUX_LODFRAC, MUX_PRIMLODFRAC, MUX_K5, MUX_UNK, //Use this if you want to factor to be set to 0 // Don't change value of these three flags, then need to be within 1 uint8 MUX_NEG = 0x20, //Support by NVidia register combiner MUX_ALPHAREPLICATE = 0x40, MUX_COMPLEMENT = 0x80, MUX_FORCE_0 = 0xFE, MUX_ERR = 0xFF, }; #define CCMUX_COMBINED 0 #define CCMUX_TEXEL0 1 #define CCMUX_TEXEL1 2 #define CCMUX_PRIMITIVE 3 #define CCMUX_SHADE 4 #define CCMUX_ENVIRONMENT 5 #define CCMUX_CENTER 6 #define CCMUX_SCALE 6 #define CCMUX_COMBINED_ALPHA 7 #define CCMUX_TEXEL0_ALPHA 8 #define CCMUX_TEXEL1_ALPHA 9 #define CCMUX_PRIMITIVE_ALPHA 10 #define CCMUX_SHADE_ALPHA 11 #define CCMUX_ENV_ALPHA 12 #define CCMUX_LOD_FRACTION 13 #define CCMUX_PRIM_LOD_FRAC 14 #define CCMUX_NOISE 7 #define CCMUX_K4 7 #define CCMUX_K5 15 #define CCMUX_1 6 #define CCMUX_0 31 #define ACMUX_COMBINED 0 #define ACMUX_TEXEL0 1 #define ACMUX_TEXEL1 2 #define ACMUX_PRIMITIVE 3 #define ACMUX_SHADE 4 #define ACMUX_ENVIRONMENT 5 #define ACMUX_LOD_FRACTION 0 #define ACMUX_PRIM_LOD_FRAC 6 #define ACMUX_1 6 #define ACMUX_0 7 #define CVG_DST_CLAMP 0 #define CVG_DST_WRAP 1 #define CVG_DST_FULL 2 #define CVG_DST_SAVE 3 enum CombinerFormatType { CM_FMT_TYPE_NOT_USED, CM_FMT_TYPE_D, // = A can mapped to SEL(arg1) CM_FMT_TYPE_A_MOD_C, // = A*C can mapped to MOD(arg1,arg2) CM_FMT_TYPE_A_ADD_D, // = A+D can mapped to ADD(arg1,arg2) CM_FMT_TYPE_A_SUB_B, // = A-B can mapped to SUB(arg1,arg2) CM_FMT_TYPE_A_MOD_C_ADD_D, // = A*C+D can mapped to MULTIPLYADD(arg1,arg2,arg0) CM_FMT_TYPE_A_LERP_B_C, // = (A-B)*C+B can mapped to LERP(arg1,arg2,arg0) // or mapped to BLENDALPHA(arg1,arg2) if C is // alpha channel or DIF, TEX, FAC, CUR CM_FMT_TYPE_A_SUB_B_ADD_D, // = A-B+C can not map very well in 1 stage CM_FMT_TYPE_A_SUB_B_MOD_C, // = (A-B)*C can not map very well in 1 stage CM_FMT_TYPE_A_ADD_B_MOD_C, // = (A+B)*C can not map very well in 1 stage CM_FMT_TYPE_A_B_C_D, // = (A-B)*C+D can not map very well in 1 stage CM_FMT_TYPE_A_B_C_A, // = (A-B)*C+D can not map very well in 1 stage // Don't use these two types in default functions CM_FMT_TYPE_AB_ADD_CD, // = A*B+C*D Use by nvidia video cards CM_FMT_TYPE_AB_SUB_CD, // = A*B-C*D Use by nvidia video cards CM_FMT_TYPE_AB_ADD_C, // = A*B+C Use by ATI video cards CM_FMT_TYPE_AB_SUB_C, // = A*B-C Use by ATI video cards CM_FMT_TYPE_NOT_CHECKED = 0xFF, }; typedef enum { ENABLE_BOTH, DISABLE_ALPHA, DISABLE_COLOR, DISABLE_BOTH, COLOR_ONE, ALPHA_ONE, } BlendingFunc; typedef enum { COLOR_CHANNEL, ALPHA_CHANNEL, } CombineChannel; typedef struct { uint8 a; uint8 b; uint8 c; uint8 d; } N64CombinerType; #define CONST_FLAG4(a,b,c,d) (a|(b<<8)|(c<<16)|(d<<24)) //(A-B)*C+D #define CONST_MOD(a,b) (a|(b<<16)) //A*B #define CONST_SEL(a) (a<<24) //=D #define CONST_ADD(a,b) (a|b<<24) //A+D #define CONST_SUB(a,b) (a|b<<8) //A-B #define CONST_MULADD(a,b,c) (a|b<<16|c<<24) //A*C+D #define G_CCMUX_TEXEL1 2 #define G_ACMUX_TEXEL1 2 #define NOTUSED MUX_0 enum { TEX_0=0, TEX_1=1}; typedef struct { uint32 op; uint32 Arg1; uint32 Arg2; uint32 Arg0; } StageOperate; #endif mupen64plus-video-rice-src-2.6.0/src/Config.cpp000066400000000000000000001620271464507324400212530ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #define M64P_PLUGIN_PROTOTYPES 1 #include "Config.h" #include "Debugger.h" #include "DeviceBuilder.h" #include "RenderBase.h" #include "Texture.h" #include "TextureManager.h" #include "Video.h" #include "m64p_config.h" #include "m64p_plugin.h" #include "m64p_types.h" #include "osal_preproc.h" #define INI_FILE "RiceVideoLinux.ini" static m64p_handle l_ConfigVideoRice = NULL; static m64p_handle l_ConfigVideoGeneral = NULL; static int FindIniEntry(uint32 dwCRC1, uint32 dwCRC2, uint8 nCountryID, char* szName, int PrintInfo); const char *frameBufferSettings[] = { "None (default)", "Hide Framebuffer Effects", "Basic Framebuffer", "Basic & Write Back", "Write Back & Reload", "Write Back Every Frame", "With Emulator", "Basic Framebuffer & With Emulator", "With Emulator Read Only", "With Emulator Write Only", }; const char *frameBufferWriteBackControlSettings[] = { "Every Frame (default)", "Every 2 Frames", "Every 3 Frames", "Every 4 Frames", "Every 5 Frames", "Every 6 Frames", "Every 7 Frames", "Every 8 Frames", }; const char *renderToTextureSettings[] = { "None (default)", "Hide Render-to-texture Effects", "Basic Render-to-texture", "Basic & Write Back", "Write Back & Reload", }; const char *screenUpdateSettings[] = { "At VI origin update", "At VI origin change", "At CI change", "At the 1st CI change", "At the 1st drawing", "Before clear the screen", "At VI origin update after screen is drawn (default)", }; WindowSettingStruct windowSetting; GlobalOptions options; RomOptions defaultRomOptions; RomOptions currentRomOptions; FrameBufferOptions frameBufferOptions; std::vector IniSections; bool bIniIsChanged = false; char szIniFileName[300]; SettingInfo TextureQualitySettings[] = { {"Default", FORCE_DEFAULT_FILTER}, {"32-bit Texture", FORCE_POINT_FILTER}, {"16-bit Texture", FORCE_LINEAR_FILTER}, }; SettingInfo ForceTextureFilterSettings[] = { {"N64 Default Texture Filter", FORCE_DEFAULT_FILTER}, {"Force Nearest Filter (faster, low quality)", FORCE_POINT_FILTER}, {"Force Linear Filter (slower, better quality)", FORCE_LINEAR_FILTER}, }; SettingInfo TextureEnhancementSettings[] = { {"N64 original texture (No enhancement)", TEXTURE_NO_ENHANCEMENT}, {"2x (Double the texture size)", TEXTURE_2X_ENHANCEMENT}, {"2xSaI", TEXTURE_2XSAI_ENHANCEMENT}, {"hq2x", TEXTURE_HQ2X_ENHANCEMENT}, {"lq2x", TEXTURE_LQ2X_ENHANCEMENT}, {"hq4x", TEXTURE_HQ4X_ENHANCEMENT}, {"Sharpen", TEXTURE_SHARPEN_ENHANCEMENT}, {"Sharpen More", TEXTURE_SHARPEN_MORE_ENHANCEMENT}, }; SettingInfo TextureEnhancementControlSettings[] = { {"Normal", TEXTURE_ENHANCEMENT_NORMAL}, {"Smooth", TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1}, {"Less smooth", TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2}, {"2xSaI smooth", TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3}, {"Less 2xSaI smooth", TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4}, }; SettingInfo colorQualitySettings[] = { {"16-bit", TEXTURE_FMT_A4R4G4B4}, {"32-bit (def)", TEXTURE_FMT_A8R8G8B8}, }; const char* strDXDeviceDescs[] = { "HAL", "REF" }; SettingInfo openGLDepthBufferSettings[] = { {"16-bit (def)", 16}, {"32-bit", 32}, }; SettingInfo OnScreenDisplaySettings[] = { {"Display Nothing", ONSCREEN_DISPLAY_NOTHING}, {"Display DList Per Second", ONSCREEN_DISPLAY_DLIST_PER_SECOND}, {"Display Frame Per Second", ONSCREEN_DISPLAY_FRAME_PER_SECOND}, {"Display Debug Information Only", ONSCREEN_DISPLAY_DEBUG_INFORMATION_ONLY}, {"Display Messages From CPU Core Only", ONSCREEN_DISPLAY_TEXT_FROM_CORE_ONLY}, {"Display DList Per Second With Core Msgs", ONSCREEN_DISPLAY_DLIST_PER_SECOND_WITH_CORE_MSG}, {"Display Frame Per Second With Core Msgs", ONSCREEN_DISPLAY_FRAME_PER_SECOND_WITH_CORE_MSG}, {"Display Debug Information With Core Msgs", ONSCREEN_DISPLAY_DEBUG_INFORMATION_WITH_CORE_MSG}, }; void GenerateFrameBufferOptions(void) { if( CDeviceBuilder::GetGeneralDeviceType() == OGL_DEVICE ) { // OpenGL does not support much yet if( currentRomOptions.N64FrameBufferEmuType != FRM_BUF_NONE ) currentRomOptions.N64FrameBufferEmuType = FRM_BUF_IGNORE; if( currentRomOptions.N64RenderToTextureEmuType != TXT_BUF_NONE ) currentRomOptions.N64RenderToTextureEmuType = TXT_BUF_IGNORE; } frameBufferOptions.bUpdateCIInfo = false; frameBufferOptions.bCheckBackBufs = false; frameBufferOptions.bWriteBackBufToRDRAM = false; frameBufferOptions.bLoadBackBufFromRDRAM = false; frameBufferOptions.bIgnore = true; frameBufferOptions.bSupportRenderTextures = false; frameBufferOptions.bCheckRenderTextures = false; frameBufferOptions.bRenderTextureWriteBack = false; frameBufferOptions.bLoadRDRAMIntoRenderTexture = false; frameBufferOptions.bProcessCPUWrite = false; frameBufferOptions.bProcessCPURead = false; frameBufferOptions.bAtEachFrameUpdate = false; frameBufferOptions.bIgnoreRenderTextureIfHeightUnknown = false; switch( currentRomOptions.N64FrameBufferEmuType ) { case FRM_BUF_NONE: break; case FRM_BUF_COMPLETE: frameBufferOptions.bAtEachFrameUpdate = true; frameBufferOptions.bProcessCPUWrite = true; frameBufferOptions.bProcessCPURead = true; frameBufferOptions.bUpdateCIInfo = true; break; case FRM_BUF_WRITEBACK_AND_RELOAD: frameBufferOptions.bLoadBackBufFromRDRAM = true; case FRM_BUF_BASIC_AND_WRITEBACK: frameBufferOptions.bWriteBackBufToRDRAM = true; case FRM_BUF_BASIC: frameBufferOptions.bCheckBackBufs = true; case FRM_BUF_IGNORE: frameBufferOptions.bUpdateCIInfo = true; break; case FRM_BUF_BASIC_AND_WITH_EMULATOR: // Banjo Kazooie frameBufferOptions.bCheckBackBufs = true; case FRM_BUF_WITH_EMULATOR: frameBufferOptions.bUpdateCIInfo = true; frameBufferOptions.bProcessCPUWrite = true; frameBufferOptions.bProcessCPURead = true; break; case FRM_BUF_WITH_EMULATOR_READ_ONLY: frameBufferOptions.bUpdateCIInfo = true; frameBufferOptions.bProcessCPURead = true; break; case FRM_BUF_WITH_EMULATOR_WRITE_ONLY: frameBufferOptions.bUpdateCIInfo = true; frameBufferOptions.bProcessCPUWrite = true; break; } switch( currentRomOptions.N64RenderToTextureEmuType ) { case TXT_BUF_NONE: frameBufferOptions.bSupportRenderTextures = false; break; case TXT_BUF_WRITE_BACK_AND_RELOAD: frameBufferOptions.bLoadRDRAMIntoRenderTexture = true; case TXT_BUF_WRITE_BACK: frameBufferOptions.bRenderTextureWriteBack = true; case TXT_BUF_NORMAL: frameBufferOptions.bCheckRenderTextures = true; frameBufferOptions.bIgnore = false; case TXT_BUF_IGNORE: frameBufferOptions.bUpdateCIInfo = true; frameBufferOptions.bSupportRenderTextures = true; break; } if( currentRomOptions.screenUpdateSetting >= SCREEN_UPDATE_AT_CI_CHANGE ) { frameBufferOptions.bUpdateCIInfo = true; } } BOOL InitConfiguration(void) { if (ConfigOpenSection("Video-General", &l_ConfigVideoGeneral) != M64ERR_SUCCESS) { DebugMessage(M64MSG_ERROR, "Unable to open Video-General configuration section"); return FALSE; } if (ConfigOpenSection("Video-Rice", &l_ConfigVideoRice) != M64ERR_SUCCESS) { DebugMessage(M64MSG_ERROR, "Unable to open Video-Rice configuration section"); return FALSE; } /* Ensure versionning is present */ int ConfigParamsVersion; if (ConfigGetParameter(l_ConfigVideoRice, "Version", M64TYPE_INT, &ConfigParamsVersion, sizeof(int)) != M64ERR_SUCCESS) { DebugMessage(M64MSG_WARNING, "No version number in 'Rice-Video' config section. Setting defaults."); ConfigParamsVersion = 0; // zero to ensure updates will be applied } /* Update config parameters */ if (ConfigParamsVersion < CONFIG_PARAM_VERSION) { DebugMessage(M64MSG_WARNING, "Old parameter config version detected : %d, updating to %d;", ConfigParamsVersion, CONFIG_PARAM_VERSION); if (ConfigParamsVersion == 0) /* From v0 to v1: Remove OGL_TNT2_DEVICE and NVIDIA_OGL device, Remove force fog method option */ { int oldOglDevice; if (ConfigGetParameter(l_ConfigVideoRice, "OpenGLRenderSetting", M64TYPE_INT, &oldOglDevice, sizeof(int)) == M64ERR_SUCCESS) { /* OGL_1.1 was 1, OGL_1.2 was 2, OGL_1.3 was 3, OGL_1.4 was 4, OGL_1.4_V2 was 5, OGL_TNT2_DEVICE was 6, NVIDIA_OGL was 7 but doesnt exist anymore: Put to auto*/ if ((oldOglDevice == 1) || (oldOglDevice == 2) || (oldOglDevice == 3) || (oldOglDevice == 4) || (oldOglDevice == 5) || (oldOglDevice == 6) || (oldOglDevice == 7)) { oldOglDevice = 0; // auto } else if (oldOglDevice >= 8) /* OGL_FRAGMENT_PROGRAM (was 8+) is now 1*/ { oldOglDevice = 1; } ConfigSetParameter(l_ConfigVideoRice, "OpenGLRenderSetting", M64TYPE_INT, &oldOglDevice); ConfigSetParameterHelp(l_ConfigVideoRice, "OpenGLRenderSetting", "OpenGL level to support (0=auto, 1=OGL_FRAGMENT_PROGRAM)"); } int fogMethod; if (ConfigGetParameter(l_ConfigVideoRice, "FogMethod", M64TYPE_INT, &fogMethod, sizeof(int)) == M64ERR_SUCCESS) { if ( fogMethod > 1 ) // if FogMethod was "Force Fog" { fogMethod = 1; ConfigSetParameter(l_ConfigVideoRice, "FogMethod", M64TYPE_INT, &fogMethod); } ConfigSetParameterHelp(l_ConfigVideoRice, "FogMethod", "Enable, Disable fog generation (0=Disable, 1=Enable)"); } ConfigParamsVersion = 1; } // place others update stuff here and increment "ConfigParamsVersion" and CONFIG_PARAM_VERSION each time. } /* Set default config parameters */ ConfigSetDefaultBool(l_ConfigVideoGeneral, "Fullscreen", 0, "Use fullscreen mode if True, or windowed mode if False"); ConfigSetDefaultInt(l_ConfigVideoGeneral, "ScreenWidth", 640, "Width of output window or fullscreen width"); ConfigSetDefaultInt(l_ConfigVideoGeneral, "ScreenHeight", 480, "Height of output window or fullscreen height"); ConfigSetDefaultBool(l_ConfigVideoGeneral, "VerticalSync", 0, "If true, activate the SDL_GL_SWAP_CONTROL attribute"); ConfigSetDefaultInt(l_ConfigVideoRice, "Version", CONFIG_PARAM_VERSION, "Mupen64Plus Rice Video Plugin config parameter version number"); ConfigSetDefaultInt(l_ConfigVideoRice, "FrameBufferSetting", FRM_BUF_NONE, "Frame Buffer Emulation (0=ROM default, 1=disable)"); ConfigSetDefaultInt(l_ConfigVideoRice, "FrameBufferWriteBackControl", FRM_BUF_WRITEBACK_NORMAL, "Frequency to write back the frame buffer (0=every frame, 1=every other frame, etc)"); ConfigSetDefaultInt(l_ConfigVideoRice, "RenderToTexture", TXT_BUF_NONE, "Render-to-texture emulation (0=none, 1=ignore, 2=normal, 3=write back, 4=write back and reload)"); ConfigSetDefaultInt(l_ConfigVideoRice, "ScreenUpdateSetting", SCREEN_UPDATE_AT_1ST_CI_CHANGE, "Control when the screen will be updated (0=ROM default, 1=VI origin update, 2=VI origin change, 3=CI change, 4=first CI change, 5=first primitive draw, 6=before screen clear, 7=after screen drawn)"); // SCREEN_UPDATE_AT_VI_UPDATE_AND_DRAWN ConfigSetDefaultBool(l_ConfigVideoRice, "NormalAlphaBlender", FALSE, "Force to use normal alpha blender"); ConfigSetDefaultBool(l_ConfigVideoRice, "FastTextureLoading", FALSE, "Use a faster algorithm to speed up texture loading and CRC computation"); ConfigSetDefaultBool(l_ConfigVideoRice, "AccurateTextureMapping", TRUE, "Use different texture coordinate clamping code"); ConfigSetDefaultBool(l_ConfigVideoRice, "InN64Resolution", FALSE, "Force emulated frame buffers to be in N64 native resolution"); ConfigSetDefaultBool(l_ConfigVideoRice, "SaveVRAM", FALSE, "Try to reduce Video RAM usage (should never be used)"); ConfigSetDefaultBool(l_ConfigVideoRice, "DoubleSizeForSmallTxtrBuf", FALSE, "Enable this option to have better render-to-texture quality"); ConfigSetDefaultBool(l_ConfigVideoRice, "DefaultCombinerDisable", FALSE, "Force to use normal color combiner"); ConfigSetDefaultBool(l_ConfigVideoRice, "EnableHacks", TRUE, "Enable game-specific settings from INI file"); ConfigSetDefaultBool(l_ConfigVideoRice, "WinFrameMode", FALSE, "If enabled, graphics will be drawn in WinFrame mode instead of solid and texture mode"); ConfigSetDefaultBool(l_ConfigVideoRice, "FullTMEMEmulation", FALSE, "N64 Texture Memory Full Emulation (may fix some games, may break others)"); ConfigSetDefaultBool(l_ConfigVideoRice, "OpenGLVertexClipper", FALSE, "Enable vertex clipper for fog operations"); ConfigSetDefaultBool(l_ConfigVideoRice, "EnableSSE", TRUE, "Enable/Disable SSE optimizations for capable CPUs"); ConfigSetDefaultBool(l_ConfigVideoRice, "SkipFrame", FALSE, "If this option is enabled, the plugin will skip every other frame"); ConfigSetDefaultBool(l_ConfigVideoRice, "TexRectOnly", FALSE, "If enabled, texture enhancement will be done only for TxtRect ucode"); ConfigSetDefaultBool(l_ConfigVideoRice, "SmallTextureOnly", FALSE, "If enabled, texture enhancement will be done only for textures width+height<=128"); ConfigSetDefaultBool(l_ConfigVideoRice, "LoadHiResCRCOnly", TRUE, "Select hi-resolution textures based only on the CRC and ignore format+size information (Glide64 compatibility)"); ConfigSetDefaultBool(l_ConfigVideoRice, "LoadHiResTextures", FALSE, "Enable hi-resolution texture file loading"); ConfigSetDefaultBool(l_ConfigVideoRice, "DumpTexturesToFiles", FALSE, "Enable texture dumping"); ConfigSetDefaultBool(l_ConfigVideoRice, "ShowFPS", FALSE, "Display On-screen FPS"); ConfigSetDefaultInt(l_ConfigVideoRice, "Mipmapping", 2, "Use Mipmapping? 0=no, 1=nearest, 2=bilinear, 3=trilinear"); ConfigSetDefaultInt(l_ConfigVideoRice, "FogMethod", 1, "Enable, Disable fog generation (0=Disable, 1=Enable)"); ConfigSetDefaultInt(l_ConfigVideoRice, "ForceTextureFilter", 0, "Force to use texture filtering or not (0=auto: n64 choose, 1=force no filtering, 2=force filtering)"); ConfigSetDefaultInt(l_ConfigVideoRice, "TextureEnhancement", 0, "Primary texture enhancement filter (0=None, 1=2X, 2=2XSAI, 3=HQ2X, 4=LQ2X, 5=HQ4X, 6=Sharpen, 7=Sharpen More, 8=External, 9=Mirrored)"); ConfigSetDefaultInt(l_ConfigVideoRice, "TextureEnhancementControl", 0, "Secondary texture enhancement filter (0 = none, 1-4 = filtered)"); ConfigSetDefaultInt(l_ConfigVideoRice, "TextureQuality", TXT_QUALITY_DEFAULT, "Color bit depth to use for textures (0=default, 1=32 bits, 2=16 bits)"); ConfigSetDefaultInt(l_ConfigVideoRice, "OpenGLDepthBufferSetting", 16, "Z-buffer depth (only 16 or 32)"); ConfigSetDefaultInt(l_ConfigVideoRice, "MultiSampling", 0, "Enable/Disable MultiSampling (0=off, 2,4,8,16=quality)"); ConfigSetDefaultInt(l_ConfigVideoRice, "ColorQuality", TEXTURE_FMT_A8R8G8B8, "Color bit depth for rendering window (0=32 bits, 1=16 bits)"); ConfigSetDefaultInt(l_ConfigVideoRice, "OpenGLRenderSetting", OGL_DEVICE, "OpenGL level to support (0=auto, 1=OGL_FRAGMENT_PROGRAM)"); ConfigSetDefaultInt(l_ConfigVideoRice, "AnisotropicFiltering", 0, "Enable/Disable Anisotropic Filtering for Mipmapping (0=no filtering, 2-16=quality). This is uneffective if Mipmapping is 0. If the given value is to high to be supported by your graphic card, the value will be the highest value your graphic card can support. Better result with Trilinear filtering"); ConfigSetDefaultBool(l_ConfigVideoRice, "ForcePolygonOffset", FALSE, "If true, use polygon offset values specified below"); ConfigSetDefaultFloat(l_ConfigVideoRice, "PolygonOffsetFactor", 0.0f, "Specifies a scale factor that is used to create a variable depth offset for each polygon"); ConfigSetDefaultFloat(l_ConfigVideoRice, "PolygonOffsetUnits", 0.0f, "Is multiplied by an implementation-specific value to create a constant depth offset"); return TRUE; } bool isMMXSupported() { int IsMMXSupported = 0; #if !defined(__GNUC__) && !defined(NO_ASM) __asm { mov eax,1 // CPUID level 1 cpuid // EDX = feature flag and edx,0x800000 // test bit 23 of feature flag mov IsMMXSupported,edx // != 0 if MMX is supported } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) return true; #elif !defined(NO_ASM) // GCC assumed asm volatile ( "push %%ebx \n" "mov $1, %%eax \n" // CPUID level 1 "cpuid \n" // EDX = feature flag "and $0x800000, %%edx \n" // test bit 23 of feature flag "pop %%ebx \n" : "=d"(IsMMXSupported) : : "memory", "cc", "eax", "ecx" ); #endif if (IsMMXSupported != 0) return true; else return false; } bool isSSESupported() { int SSESupport = 0; // And finally, check the CPUID for Streaming SIMD Extensions support. #if !defined(__GNUC__) && !defined(NO_ASM) _asm { mov eax, 1 // Put a "1" in eax to tell CPUID to get the feature bits cpuid // Perform CPUID (puts processor feature info into EDX) and edx, 02000000h // Test bit 25, for Streaming SIMD Extensions existence. mov SSESupport, edx // SIMD Extensions). Set return value to 1 to indicate, } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) return true; #elif !defined(NO_ASM) // GCC assumed asm volatile ( "push %%ebx \n" "mov $1, %%eax \n" // Put a "1" in eax to tell CPUID to get the feature bits "cpuid \n" // Perform CPUID (puts processor feature info into EDX) "and $0x02000000, %%edx \n" // Test bit 25, for Streaming SIMD Extensions existence. "pop %%ebx \n" : "=d"(SSESupport) : : "memory", "cc", "eax", "ecx" ); # endif if (SSESupport != 0) return true; else return false; } static void ReadConfiguration(void) { windowSetting.bDisplayFullscreen = ConfigGetParamBool(l_ConfigVideoGeneral, "Fullscreen"); windowSetting.uDisplayWidth = ConfigGetParamInt(l_ConfigVideoGeneral, "ScreenWidth"); windowSetting.uDisplayHeight = ConfigGetParamInt(l_ConfigVideoGeneral, "ScreenHeight"); windowSetting.bVerticalSync = ConfigGetParamBool(l_ConfigVideoGeneral, "VerticalSync"); defaultRomOptions.N64FrameBufferEmuType = ConfigGetParamInt(l_ConfigVideoRice, "FrameBufferSetting"); defaultRomOptions.N64FrameBufferWriteBackControl = ConfigGetParamInt(l_ConfigVideoRice, "FrameBufferWriteBackControl"); defaultRomOptions.N64RenderToTextureEmuType = ConfigGetParamInt(l_ConfigVideoRice, "RenderToTexture"); defaultRomOptions.screenUpdateSetting = ConfigGetParamInt(l_ConfigVideoRice, "screenUpdateSetting"); defaultRomOptions.bNormalBlender = ConfigGetParamBool(l_ConfigVideoRice, "NormalAlphaBlender"); defaultRomOptions.bFastTexCRC = ConfigGetParamBool(l_ConfigVideoRice, "FastTextureLoading"); defaultRomOptions.bAccurateTextureMapping = ConfigGetParamBool(l_ConfigVideoRice, "AccurateTextureMapping"); defaultRomOptions.bInN64Resolution = ConfigGetParamBool(l_ConfigVideoRice, "InN64Resolution"); defaultRomOptions.bSaveVRAM = ConfigGetParamBool(l_ConfigVideoRice, "SaveVRAM"); defaultRomOptions.bDoubleSizeForSmallTxtrBuf = ConfigGetParamBool(l_ConfigVideoRice, "DoubleSizeForSmallTxtrBuf"); defaultRomOptions.bNormalCombiner = ConfigGetParamBool(l_ConfigVideoRice, "DefaultCombinerDisable"); options.bEnableHacks = ConfigGetParamBool(l_ConfigVideoRice, "EnableHacks"); options.bWinFrameMode = ConfigGetParamBool(l_ConfigVideoRice, "WinFrameMode"); options.bFullTMEM = ConfigGetParamBool(l_ConfigVideoRice, "FullTMEMEmulation"); options.bOGLVertexClipper = ConfigGetParamBool(l_ConfigVideoRice, "OpenGLVertexClipper"); options.bEnableSSE = ConfigGetParamBool(l_ConfigVideoRice, "EnableSSE"); options.bSkipFrame = ConfigGetParamBool(l_ConfigVideoRice, "SkipFrame"); options.bTexRectOnly = ConfigGetParamBool(l_ConfigVideoRice, "TexRectOnly"); options.bSmallTextureOnly = ConfigGetParamBool(l_ConfigVideoRice, "SmallTextureOnly"); options.bLoadHiResTextures = ConfigGetParamBool(l_ConfigVideoRice, "LoadHiResTextures"); options.bLoadHiResCRCOnly = ConfigGetParamBool(l_ConfigVideoRice, "LoadHiResCRCOnly"); options.bDumpTexturesToFiles = ConfigGetParamBool(l_ConfigVideoRice, "DumpTexturesToFiles"); options.bShowFPS = ConfigGetParamBool(l_ConfigVideoRice, "ShowFPS"); options.mipmapping = ConfigGetParamInt(l_ConfigVideoRice, "Mipmapping"); options.fogMethod = ConfigGetParamInt(l_ConfigVideoRice, "FogMethod"); options.forceTextureFilter = ConfigGetParamInt(l_ConfigVideoRice, "ForceTextureFilter"); options.textureEnhancement = ConfigGetParamInt(l_ConfigVideoRice, "TextureEnhancement"); options.textureEnhancementControl = ConfigGetParamInt(l_ConfigVideoRice, "TextureEnhancementControl"); options.textureQuality = ConfigGetParamInt(l_ConfigVideoRice, "TextureQuality"); options.OpenglDepthBufferSetting = ConfigGetParamInt(l_ConfigVideoRice, "OpenGLDepthBufferSetting"); options.multiSampling = ConfigGetParamInt(l_ConfigVideoRice, "MultiSampling"); options.colorQuality = ConfigGetParamInt(l_ConfigVideoRice, "ColorQuality"); options.OpenglRenderSetting = ConfigGetParamInt(l_ConfigVideoRice, "OpenGLRenderSetting"); options.anisotropicFiltering = ConfigGetParamInt(l_ConfigVideoRice, "AnisotropicFiltering"); options.bForcePolygonOffset = ConfigGetParamBool(l_ConfigVideoRice, "ForcePolygonOffset"); options.polygonOffsetFactor = ConfigGetParamFloat(l_ConfigVideoRice, "PolygonOffsetFactor"); options.polygonOffsetUnits = ConfigGetParamFloat(l_ConfigVideoRice, "PolygonOffsetUnits"); CDeviceBuilder::SelectDeviceType((SupportedDeviceType)options.OpenglRenderSetting); status.isMMXSupported = isMMXSupported(); status.isSSESupported = isSSESupported(); status.isSSEEnabled = status.isSSESupported && options.bEnableSSE; #if !defined(NO_ASM) if( status.isSSEEnabled ) { ProcessVertexData = ProcessVertexDataSSE; DebugMessage(M64MSG_INFO, "SSE processing enabled."); } else #endif { ProcessVertexData = ProcessVertexDataNoSSE; DebugMessage(M64MSG_INFO, "Disabled SSE processing."); } } BOOL LoadConfiguration(void) { IniSections.clear(); bIniIsChanged = false; strcpy(szIniFileName, INI_FILE); if (!ReadIniFile()) { DebugMessage(M64MSG_ERROR, "Unable to read ini file from disk"); return FALSE; } if (l_ConfigVideoGeneral == NULL || l_ConfigVideoRice == NULL) { DebugMessage(M64MSG_ERROR, "Rice Video configuration sections are not open!"); return FALSE; } // Read config parameters from core config API and set up internal variables ReadConfiguration(); return TRUE; } void GenerateCurrentRomOptions() { currentRomOptions.N64FrameBufferEmuType =g_curRomInfo.dwFrameBufferOption; currentRomOptions.N64FrameBufferWriteBackControl =defaultRomOptions.N64FrameBufferWriteBackControl; currentRomOptions.N64RenderToTextureEmuType =g_curRomInfo.dwRenderToTextureOption; currentRomOptions.screenUpdateSetting =g_curRomInfo.dwScreenUpdateSetting; currentRomOptions.bNormalCombiner =g_curRomInfo.dwNormalCombiner; currentRomOptions.bNormalBlender =g_curRomInfo.dwNormalBlender; currentRomOptions.bFastTexCRC =g_curRomInfo.dwFastTextureCRC; currentRomOptions.bAccurateTextureMapping =g_curRomInfo.dwAccurateTextureMapping; options.enableHackForGames = NO_HACK_FOR_GAME; if ((strncmp((char*)g_curRomInfo.szGameName, "BANJO TOOIE", 11) == 0)) { options.enableHackForGames = HACK_FOR_BANJO_TOOIE; } else if ((strncmp((char*)g_curRomInfo.szGameName, "DR.MARIO", 8) == 0)) { options.enableHackForGames = HACK_FOR_DR_MARIO; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "Pilot", 5) == 0)) { options.enableHackForGames = HACK_FOR_PILOT_WINGS; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "YOSHI", 5) == 0)) { options.enableHackForGames = HACK_FOR_YOSHI; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "NITRO", 5) == 0)) { options.enableHackForGames = HACK_FOR_NITRO; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "TONY HAWK", 9) == 0)) { options.enableHackForGames = HACK_FOR_TONYHAWK; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "THPS", 4) == 0)) { options.enableHackForGames = HACK_FOR_TONYHAWK; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "SPIDERMAN", 9) == 0)) { options.enableHackForGames = HACK_FOR_TONYHAWK; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "NASCAR", 6) == 0)) { options.enableHackForGames = HACK_FOR_NASCAR; } else if ((strstr((char*)g_curRomInfo.szGameName, "ZELDA") != 0) && (strstr((char*)g_curRomInfo.szGameName, "MASK") != 0)) { options.enableHackForGames = HACK_FOR_ZELDA_MM; } else if ((strstr((char*)g_curRomInfo.szGameName, "ZELDA") != 0)) { options.enableHackForGames = HACK_FOR_ZELDA; } else if ((strstr((char*)g_curRomInfo.szGameName, "Ogre") != 0)) { options.enableHackForGames = HACK_FOR_OGRE_BATTLE; } else if ((strstr((char*)g_curRomInfo.szGameName, "TWINE") != 0)) { options.enableHackForGames = HACK_FOR_TWINE; } else if ((strstr((char*)g_curRomInfo.szGameName, "Squadron") != 0)) { options.enableHackForGames = HACK_FOR_ROGUE_SQUADRON; } else if ((strstr((char*)g_curRomInfo.szGameName, "Baseball") != 0) && (strstr((char*)g_curRomInfo.szGameName, "Star") != 0)) { options.enableHackForGames = HACK_FOR_ALL_STAR_BASEBALL; } else if ((strstr((char*)g_curRomInfo.szGameName, "Tigger") != 0) && (strstr((char*)g_curRomInfo.szGameName, "Honey") != 0)) { options.enableHackForGames = HACK_FOR_TIGER_HONEY_HUNT; } else if ((strstr((char*)g_curRomInfo.szGameName, "Bust") != 0) && (strstr((char*)g_curRomInfo.szGameName, "Move") != 0)) { options.enableHackForGames = HACK_FOR_BUST_A_MOVE; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MarioTennis",11) == 0)) { options.enableHackForGames = HACK_FOR_MARIO_TENNIS; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "SUPER BOWLING",13) == 0)) { options.enableHackForGames = HACK_FOR_SUPER_BOWLING; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "CONKER",6) == 0)) { options.enableHackForGames = HACK_FOR_CONKER; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MK_MYTHOLOGIES",14) == 0)) { options.enableHackForGames = HACK_REVERSE_Y_COOR; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "Fighting Force",14) == 0)) { options.enableHackForGames = HACK_REVERSE_XY_COOR; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "GOLDENEYE",9) == 0)) { options.enableHackForGames = HACK_FOR_GOLDEN_EYE; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "F-ZERO",6) == 0)) { options.enableHackForGames = HACK_FOR_FZERO; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "Command&Conquer",15) == 0)) { options.enableHackForGames = HACK_FOR_COMMANDCONQUER; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "READY 2 RUMBLE",14) == 0)) { options.enableHackForGames = HACK_FOR_RUMBLE; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "READY to RUMBLE",15) == 0)) { options.enableHackForGames = HACK_FOR_RUMBLE; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "South Park Rally",16) == 0)) { options.enableHackForGames = HACK_FOR_SOUTH_PARK_RALLY; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "Extreme G 2",11) == 0)) { options.enableHackForGames = HACK_FOR_EXTREME_G2; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MarioGolf64",11) == 0)) { options.enableHackForGames = HACK_FOR_MARIO_GOLF; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MLB FEATURING",13) == 0)) { options.enableHackForGames = HACK_FOR_MLB; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "POLARISSNOCROSS",15) == 0)) { options.enableHackForGames = HACK_FOR_POLARISSNOCROSS; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "TOP GEAR RALLY",14) == 0)) { options.enableHackForGames = HACK_FOR_TOPGEARRALLY; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "DUKE NUKEM",10) == 0)) { options.enableHackForGames = HACK_FOR_DUKE_NUKEM; } else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MARIOKART64",11) == 0)) { options.enableHackForGames = HACK_FOR_MARIO_KART; } if (options.enableHackForGames != NO_HACK_FOR_GAME) DebugMessage(M64MSG_INFO, "Enabled hacks for game: '%s'", g_curRomInfo.szGameName); if( currentRomOptions.N64FrameBufferEmuType == 0 ) currentRomOptions.N64FrameBufferEmuType = defaultRomOptions.N64FrameBufferEmuType; else currentRomOptions.N64FrameBufferEmuType--; if( currentRomOptions.N64RenderToTextureEmuType == 0 ) currentRomOptions.N64RenderToTextureEmuType = defaultRomOptions.N64RenderToTextureEmuType; else currentRomOptions.N64RenderToTextureEmuType--; if( currentRomOptions.screenUpdateSetting == 0 ) currentRomOptions.screenUpdateSetting = defaultRomOptions.screenUpdateSetting; if( currentRomOptions.bNormalCombiner == 0 ) currentRomOptions.bNormalCombiner = defaultRomOptions.bNormalCombiner; else currentRomOptions.bNormalCombiner--; if( currentRomOptions.bNormalBlender == 0 ) currentRomOptions.bNormalBlender = defaultRomOptions.bNormalBlender; else currentRomOptions.bNormalBlender--; if( currentRomOptions.bFastTexCRC == 0 ) currentRomOptions.bFastTexCRC = defaultRomOptions.bFastTexCRC; else currentRomOptions.bFastTexCRC--; if( currentRomOptions.bAccurateTextureMapping == 0 ) currentRomOptions.bAccurateTextureMapping = defaultRomOptions.bAccurateTextureMapping; else currentRomOptions.bAccurateTextureMapping--; options.bUseFullTMEM = ((options.bFullTMEM && (g_curRomInfo.dwFullTMEM == 0)) || g_curRomInfo.dwFullTMEM == 2); GenerateFrameBufferOptions(); if( options.enableHackForGames == HACK_FOR_MARIO_GOLF || options.enableHackForGames == HACK_FOR_MARIO_TENNIS ) { frameBufferOptions.bIgnoreRenderTextureIfHeightUnknown = true; } } void Ini_GetRomOptions(LPGAMESETTING pGameSetting) { int i; i = FindIniEntry(pGameSetting->romheader.dwCRC1, pGameSetting->romheader.dwCRC2, pGameSetting->romheader.nCountryID, (char*)pGameSetting->szGameName, 1); pGameSetting->bDisableTextureCRC = IniSections[i].bDisableTextureCRC; pGameSetting->bDisableCulling = IniSections[i].bDisableCulling; pGameSetting->bIncTexRectEdge = IniSections[i].bIncTexRectEdge; pGameSetting->bZHack = IniSections[i].bZHack; pGameSetting->bTextureScaleHack = IniSections[i].bTextureScaleHack; pGameSetting->bPrimaryDepthHack = IniSections[i].bPrimaryDepthHack; pGameSetting->bTexture1Hack = IniSections[i].bTexture1Hack; pGameSetting->bFastLoadTile = IniSections[i].bFastLoadTile; pGameSetting->bUseSmallerTexture = IniSections[i].bUseSmallerTexture; pGameSetting->VIWidth = IniSections[i].VIWidth; pGameSetting->VIHeight = IniSections[i].VIHeight; pGameSetting->UseCIWidthAndRatio = IniSections[i].UseCIWidthAndRatio; pGameSetting->dwFullTMEM = IniSections[i].dwFullTMEM; pGameSetting->bTxtSizeMethod2 = IniSections[i].bTxtSizeMethod2; pGameSetting->bEnableTxtLOD = IniSections[i].bEnableTxtLOD; pGameSetting->dwFastTextureCRC = IniSections[i].dwFastTextureCRC; pGameSetting->bEmulateClear = IniSections[i].bEmulateClear; pGameSetting->bForceScreenClear = IniSections[i].bForceScreenClear; pGameSetting->dwAccurateTextureMapping = IniSections[i].dwAccurateTextureMapping; pGameSetting->dwNormalBlender = IniSections[i].dwNormalBlender; pGameSetting->bDisableBlender = IniSections[i].bDisableBlender; pGameSetting->dwNormalCombiner = IniSections[i].dwNormalCombiner; pGameSetting->bForceDepthBuffer = IniSections[i].bForceDepthBuffer; pGameSetting->bDisableObjBG = IniSections[i].bDisableObjBG; pGameSetting->dwFrameBufferOption = IniSections[i].dwFrameBufferOption; pGameSetting->dwRenderToTextureOption = IniSections[i].dwRenderToTextureOption; pGameSetting->dwScreenUpdateSetting = IniSections[i].dwScreenUpdateSetting; } void Ini_StoreRomOptions(LPGAMESETTING pGameSetting) { int i; i = FindIniEntry(pGameSetting->romheader.dwCRC1, pGameSetting->romheader.dwCRC2, pGameSetting->romheader.nCountryID, (char*)pGameSetting->szGameName, 0); if( IniSections[i].bDisableTextureCRC !=pGameSetting->bDisableTextureCRC ) { IniSections[i].bDisableTextureCRC =pGameSetting->bDisableTextureCRC ; bIniIsChanged=true; } if( IniSections[i].bDisableCulling !=pGameSetting->bDisableCulling ) { IniSections[i].bDisableCulling =pGameSetting->bDisableCulling ; bIniIsChanged=true; } if( IniSections[i].dwFastTextureCRC !=pGameSetting->dwFastTextureCRC ) { IniSections[i].dwFastTextureCRC =pGameSetting->dwFastTextureCRC ; bIniIsChanged=true; } if( IniSections[i].bEmulateClear !=pGameSetting->bEmulateClear ) { IniSections[i].bEmulateClear =pGameSetting->bEmulateClear ; bIniIsChanged=true; } if( IniSections[i].dwNormalBlender !=pGameSetting->dwNormalBlender ) { IniSections[i].dwNormalBlender =pGameSetting->dwNormalBlender ; bIniIsChanged=true; } if( IniSections[i].bDisableBlender !=pGameSetting->bDisableBlender ) { IniSections[i].bDisableBlender =pGameSetting->bDisableBlender ; bIniIsChanged=true; } if( IniSections[i].bForceScreenClear !=pGameSetting->bForceScreenClear ) { IniSections[i].bForceScreenClear =pGameSetting->bForceScreenClear ; bIniIsChanged=true; } if( IniSections[i].dwAccurateTextureMapping !=pGameSetting->dwAccurateTextureMapping ) { IniSections[i].dwAccurateTextureMapping =pGameSetting->dwAccurateTextureMapping ; bIniIsChanged=true; } if( IniSections[i].dwNormalCombiner !=pGameSetting->dwNormalCombiner ) { IniSections[i].dwNormalCombiner =pGameSetting->dwNormalCombiner ; bIniIsChanged=true; } if( IniSections[i].bForceDepthBuffer !=pGameSetting->bForceDepthBuffer ) { IniSections[i].bForceDepthBuffer =pGameSetting->bForceDepthBuffer ; bIniIsChanged=true; } if( IniSections[i].bDisableObjBG !=pGameSetting->bDisableObjBG ) { IniSections[i].bDisableObjBG =pGameSetting->bDisableObjBG ; bIniIsChanged=true; } if( IniSections[i].dwFrameBufferOption !=pGameSetting->dwFrameBufferOption ) { IniSections[i].dwFrameBufferOption =pGameSetting->dwFrameBufferOption ; bIniIsChanged=true; } if( IniSections[i].dwRenderToTextureOption !=pGameSetting->dwRenderToTextureOption ) { IniSections[i].dwRenderToTextureOption =pGameSetting->dwRenderToTextureOption ; bIniIsChanged=true; } if( IniSections[i].dwScreenUpdateSetting !=pGameSetting->dwScreenUpdateSetting ) { IniSections[i].dwScreenUpdateSetting =pGameSetting->dwScreenUpdateSetting ; bIniIsChanged=true; } if( IniSections[i].bIncTexRectEdge != pGameSetting->bIncTexRectEdge ) { IniSections[i].bIncTexRectEdge =pGameSetting->bIncTexRectEdge; bIniIsChanged=true; } if( IniSections[i].bZHack != pGameSetting->bZHack ) { IniSections[i].bZHack =pGameSetting->bZHack; bIniIsChanged=true; } if( IniSections[i].bTextureScaleHack != pGameSetting->bTextureScaleHack ) { IniSections[i].bTextureScaleHack =pGameSetting->bTextureScaleHack; bIniIsChanged=true; } if( IniSections[i].bPrimaryDepthHack != pGameSetting->bPrimaryDepthHack ) { IniSections[i].bPrimaryDepthHack =pGameSetting->bPrimaryDepthHack; bIniIsChanged=true; } if( IniSections[i].bTexture1Hack != pGameSetting->bTexture1Hack ) { IniSections[i].bTexture1Hack =pGameSetting->bTexture1Hack; bIniIsChanged=true; } if( IniSections[i].bFastLoadTile != pGameSetting->bFastLoadTile ) { IniSections[i].bFastLoadTile =pGameSetting->bFastLoadTile; bIniIsChanged=true; } if( IniSections[i].bUseSmallerTexture != pGameSetting->bUseSmallerTexture ) { IniSections[i].bUseSmallerTexture =pGameSetting->bUseSmallerTexture; bIniIsChanged=true; } if( IniSections[i].VIWidth != pGameSetting->VIWidth ) { IniSections[i].VIWidth =pGameSetting->VIWidth; bIniIsChanged=true; } if( IniSections[i].VIHeight != pGameSetting->VIHeight ) { IniSections[i].VIHeight =pGameSetting->VIHeight; bIniIsChanged=true; } if( IniSections[i].UseCIWidthAndRatio != pGameSetting->UseCIWidthAndRatio ) { IniSections[i].UseCIWidthAndRatio =pGameSetting->UseCIWidthAndRatio; bIniIsChanged=true; } if( IniSections[i].dwFullTMEM != pGameSetting->dwFullTMEM ) { IniSections[i].dwFullTMEM =pGameSetting->dwFullTMEM; bIniIsChanged=true; } if( IniSections[i].bTxtSizeMethod2 != pGameSetting->bTxtSizeMethod2 ) { IniSections[i].bTxtSizeMethod2 =pGameSetting->bTxtSizeMethod2; bIniIsChanged=true; } if( IniSections[i].bEnableTxtLOD != pGameSetting->bEnableTxtLOD ) { IniSections[i].bEnableTxtLOD =pGameSetting->bEnableTxtLOD; bIniIsChanged=true; } if( bIniIsChanged ) { WriteIniFile(); TRACE0("Rom option is changed and saved"); } } std::ifstream& getline( std::ifstream &is, char *str ); char * left(const char * src, int nchars) { static char dst[300]; strncpy(dst,src,nchars); dst[nchars]=0; return dst; } char * right(const char *src, int nchars) { static char dst[300]; int srclen = strlen(src); if (nchars >= srclen) { strcpy(dst, src); } else { strncpy(dst, src + srclen - nchars, nchars); dst[nchars]=0; } return dst; } char * tidy(char * s) { char * p = s + strlen(s); p--; while (p >= s && (*p == ' ' || *p == '\r' || *p == '\n') ) { *p = 0; p--; } return s; } BOOL ReadIniFile() { std::ifstream inifile; char readinfo[100]; const char *ini_filepath = ConfigGetSharedDataFilepath(szIniFileName); DebugMessage(M64MSG_VERBOSE, "Reading .ini file: %s", szIniFileName); if (ini_filepath == NULL) { DebugMessage(M64MSG_ERROR, "Could not find .ini file: %s", szIniFileName); return FALSE; } inifile.open(ini_filepath); if (inifile.fail()) { DebugMessage(M64MSG_ERROR, "Could not open .ini file: %s", szIniFileName); return FALSE; } while (getline(inifile,readinfo)/*&§ionno<999*/) { tidy(readinfo); if (readinfo[0] == '/') continue; if (strlen(readinfo) > 0) { if (readinfo[0] == '{') //if a section heading { section newsection; readinfo[strlen(readinfo)-1]='\0'; strcpy(newsection.crccheck, readinfo+1); newsection.bDisableTextureCRC = FALSE; newsection.bDisableCulling = FALSE; newsection.bIncTexRectEdge = FALSE; newsection.bZHack = FALSE; newsection.bTextureScaleHack = FALSE; newsection.bFastLoadTile = FALSE; newsection.bUseSmallerTexture = FALSE; newsection.bPrimaryDepthHack = FALSE; newsection.bTexture1Hack = FALSE; newsection.bDisableObjBG = FALSE; newsection.VIWidth = -1; newsection.VIHeight = -1; newsection.UseCIWidthAndRatio = NOT_USE_CI_WIDTH_AND_RATIO; newsection.dwFullTMEM = 0; newsection.bTxtSizeMethod2 = FALSE; newsection.bEnableTxtLOD = FALSE; newsection.bEmulateClear = FALSE; newsection.bForceScreenClear = FALSE; newsection.bDisableBlender = FALSE; newsection.bForceDepthBuffer = FALSE; newsection.dwFastTextureCRC = 0; newsection.dwAccurateTextureMapping = 0; newsection.dwNormalBlender = 0; newsection.dwNormalCombiner = 0; newsection.dwFrameBufferOption = 0; newsection.dwRenderToTextureOption = 0; newsection.dwScreenUpdateSetting = 0; IniSections.push_back(newsection); } else { int sectionno = IniSections.size() - 1; if (strcasecmp(left(readinfo,4), "Name")==0) strcpy(IniSections[sectionno].name,right(readinfo,strlen(readinfo)-5)); if (strcasecmp(left(readinfo,17), "DisableTextureCRC")==0) IniSections[sectionno].bDisableTextureCRC=true; if (strcasecmp(left(readinfo,14), "DisableCulling")==0) IniSections[sectionno].bDisableCulling=true; if (strcasecmp(left(readinfo,16), "PrimaryDepthHack")==0) IniSections[sectionno].bPrimaryDepthHack=true; if (strcasecmp(left(readinfo,12), "Texture1Hack")==0) IniSections[sectionno].bTexture1Hack=true; if (strcasecmp(left(readinfo,12), "FastLoadTile")==0) IniSections[sectionno].bFastLoadTile=true; if (strcasecmp(left(readinfo,17), "UseSmallerTexture")==0) IniSections[sectionno].bUseSmallerTexture=true; if (strcasecmp(left(readinfo,14), "IncTexRectEdge")==0) IniSections[sectionno].bIncTexRectEdge=true; if (strcasecmp(left(readinfo,5), "ZHack")==0) IniSections[sectionno].bZHack=true; if (strcasecmp(left(readinfo,16), "TexRectScaleHack")==0) IniSections[sectionno].bTextureScaleHack=true; if (strcasecmp(left(readinfo,7), "VIWidth")==0) IniSections[sectionno].VIWidth = strtol(right(readinfo,3),NULL,10); if (strcasecmp(left(readinfo,8), "VIHeight")==0) IniSections[sectionno].VIHeight = strtol(right(readinfo,3),NULL,10); if (strcasecmp(left(readinfo,18), "UseCIWidthAndRatio")==0) IniSections[sectionno].UseCIWidthAndRatio = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,8), "FullTMEM")==0) IniSections[sectionno].dwFullTMEM = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,24), "AlternativeTxtSizeMethod")==0) IniSections[sectionno].bTxtSizeMethod2 = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,12), "EnableTxtLOD")==0) IniSections[sectionno].bEnableTxtLOD = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,12), "DisableObjBG")==0) IniSections[sectionno].bDisableObjBG = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,16), "ForceScreenClear")==0) IniSections[sectionno].bForceScreenClear = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,22), "AccurateTextureMapping")==0) IniSections[sectionno].dwAccurateTextureMapping = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,14), "FastTextureCRC")==0) IniSections[sectionno].dwFastTextureCRC = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,12), "EmulateClear")==0) IniSections[sectionno].bEmulateClear = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,18), "NormalAlphaBlender")==0) IniSections[sectionno].dwNormalBlender = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,19), "DisableAlphaBlender")==0) IniSections[sectionno].bDisableBlender = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,19), "NormalColorCombiner")==0) IniSections[sectionno].dwNormalCombiner = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,16), "ForceDepthBuffer")==0) IniSections[sectionno].bForceDepthBuffer = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,20), "FrameBufferEmulation")==0) IniSections[sectionno].dwFrameBufferOption = strtol(readinfo+21,NULL,10); if (strcasecmp(left(readinfo,15), "RenderToTexture")==0) IniSections[sectionno].dwRenderToTextureOption = strtol(right(readinfo,1),NULL,10); if (strcasecmp(left(readinfo,19), "ScreenUpdateSetting")==0) IniSections[sectionno].dwScreenUpdateSetting = strtol(right(readinfo,1),NULL,10); } } } inifile.close(); return TRUE; } //read a line from the ini file std::ifstream & getline(std::ifstream & is, char *str) { char buf[100]; is.getline(buf,100); strcpy( str,buf); return is; } void WriteIniFile() { uint32 i; FILE * fhIn; FILE * fhOut; /* get path to game-hack INI file and read it */ const char *ini_filepath = ConfigGetSharedDataFilepath(szIniFileName); if (ini_filepath == NULL) return; fhIn = fopen(ini_filepath, "r"); if (fhIn == NULL) return; fseek(fhIn, 0L, SEEK_END); long filelen = ftell(fhIn); fseek(fhIn, 0L, SEEK_SET); char *chIniData = (char *) malloc(filelen + 1); if (chIniData == NULL) { fclose(fhIn); return; } long bytesread = fread(chIniData, 1, filelen, fhIn); fclose(fhIn); if (bytesread != filelen) { free(chIniData); return; } chIniData[filelen] = 0; /* now try to open the file for writing */ fhOut = fopen(ini_filepath, "w"); if (fhOut == NULL) { free(chIniData); return; } // Mark all sections and needing to be written for (i = 0; i < IniSections.size(); i++) { IniSections[i].bOutput = false; } char *thisline = chIniData; while ((thisline - chIniData) < filelen) { char *nextline = strchr(thisline, '\n'); if (nextline == NULL) nextline = thisline + strlen(thisline) + 1; else nextline++; if (thisline[0] == '{') { BOOL bFound = FALSE; // Start of section tidy((char*) thisline); thisline[strlen(thisline) - 1] = '\0'; for (i = 0; i < IniSections.size(); i++) { if (IniSections[i].bOutput) continue; if (strcasecmp((char*) thisline + 1, IniSections[i].crccheck) == 0) { // Output this CRC OutputSectionDetails(i, fhOut); IniSections[i].bOutput = true; bFound = TRUE; break; } } if (!bFound) { // Do what? This should never happen, unless the user // replaces the inifile while game is running! } } else if (thisline[0] == '/') { // Comment fputs((char*) thisline, fhOut); } thisline = nextline; } // Input buffer done- process any new entries! for (i = 0; i < IniSections.size(); i++) { // Skip any that have not been done. if (IniSections[i].bOutput) continue; // Output this CRC OutputSectionDetails(i, fhOut); IniSections[i].bOutput = true; } fclose(fhOut); free(chIniData); bIniIsChanged = false; } void OutputSectionDetails(uint32 i, FILE * fh) { fprintf(fh, "{%s}\n", IniSections[i].crccheck); fprintf(fh, "Name=%s\n", IniSections[i].name); //fprintf(fh, "UCode=%d\n", IniSections[i].ucode); // Tri-state variables if (IniSections[i].dwAccurateTextureMapping != 0) fprintf(fh, "AccurateTextureMapping=%d\n", IniSections[i].dwAccurateTextureMapping); if (IniSections[i].dwFastTextureCRC != 0) fprintf(fh, "FastTextureCRC=%d\n", IniSections[i].dwFastTextureCRC); if (IniSections[i].dwNormalBlender != 0) fprintf(fh, "NormalAlphaBlender=%d\n", IniSections[i].dwNormalBlender); if (IniSections[i].dwNormalCombiner != 0) fprintf(fh, "NormalColorCombiner=%d\n", IniSections[i].dwNormalCombiner); // Normal bi-state variables if (IniSections[i].bDisableTextureCRC) fprintf(fh, "DisableTextureCRC\n"); if (IniSections[i].bDisableCulling) fprintf(fh, "DisableCulling\n"); if (IniSections[i].bPrimaryDepthHack) fprintf(fh, "PrimaryDepthHack\n"); if (IniSections[i].bTexture1Hack) fprintf(fh, "Texture1Hack\n"); if (IniSections[i].bFastLoadTile) fprintf(fh, "FastLoadTile\n"); if (IniSections[i].bUseSmallerTexture) fprintf(fh, "UseSmallerTexture\n"); if (IniSections[i].bIncTexRectEdge) fprintf(fh, "IncTexRectEdge\n"); if (IniSections[i].bZHack) fprintf(fh, "ZHack\n"); if (IniSections[i].bTextureScaleHack) fprintf(fh, "TexRectScaleHack\n"); if (IniSections[i].VIWidth > 0) fprintf(fh, "VIWidth=%d\n", IniSections[i].VIWidth); if (IniSections[i].VIHeight > 0) fprintf(fh, "VIHeight=%d\n", IniSections[i].VIHeight); if (IniSections[i].UseCIWidthAndRatio > 0) fprintf(fh, "UseCIWidthAndRatio=%d\n", IniSections[i].UseCIWidthAndRatio); if (IniSections[i].dwFullTMEM > 0) fprintf(fh, "FullTMEM=%d\n", IniSections[i].dwFullTMEM); if (IniSections[i].bTxtSizeMethod2 != FALSE ) fprintf(fh, "AlternativeTxtSizeMethod=%d\n", IniSections[i].bTxtSizeMethod2); if (IniSections[i].bEnableTxtLOD != FALSE ) fprintf(fh, "EnableTxtLOD=%d\n", IniSections[i].bEnableTxtLOD); if (IniSections[i].bDisableObjBG != 0 ) fprintf(fh, "DisableObjBG=%d\n", IniSections[i].bDisableObjBG); if (IniSections[i].bForceScreenClear != 0) fprintf(fh, "ForceScreenClear=%d\n", IniSections[i].bForceScreenClear); if (IniSections[i].bEmulateClear != 0) fprintf(fh, "EmulateClear=%d\n", IniSections[i].bEmulateClear); if (IniSections[i].bDisableBlender != 0) fprintf(fh, "DisableAlphaBlender=%d\n", IniSections[i].bDisableBlender); if (IniSections[i].bForceDepthBuffer != 0) fprintf(fh, "ForceDepthBuffer=%d\n", IniSections[i].bForceDepthBuffer); if (IniSections[i].dwFrameBufferOption != 0) fprintf(fh, "FrameBufferEmulation=%d\n", IniSections[i].dwFrameBufferOption); if (IniSections[i].dwRenderToTextureOption != 0) fprintf(fh, "RenderToTexture=%d\n", IniSections[i].dwRenderToTextureOption); if (IniSections[i].dwScreenUpdateSetting != 0) fprintf(fh, "ScreenUpdateSetting=%d\n", IniSections[i].dwScreenUpdateSetting); fprintf(fh, "\n"); // Spacer } // Find the entry corresponding to the specified rom. // If the rom is not found, a new entry is created // The resulting value is returned void __cdecl DebuggerAppendMsg (const char * Message, ...); static int FindIniEntry(uint32 dwCRC1, uint32 dwCRC2, uint8 nCountryID, char* szName, int PrintInfo) { uint32 i; unsigned char szCRC[50+1]; // Generate the CRC-ID for this rom: sprintf((char*)szCRC, "%08x%08x-%02x", (unsigned int)dwCRC1, (unsigned int)dwCRC2, nCountryID); for (i = 0; i < IniSections.size(); i++) { if (strcasecmp((char*)szCRC, IniSections[i].crccheck) == 0) { if (PrintInfo) DebugMessage(M64MSG_INFO, "Found ROM '%s', CRC %s", IniSections[i].name, szCRC); return i; } } // Add new entry!!! section newsection; if (PrintInfo) DebugMessage(M64MSG_INFO, "ROM (CRC %s) not found in INI file", szCRC); strcpy(newsection.crccheck, (char*)szCRC); strncpy(newsection.name, szName, 50); newsection.bDisableTextureCRC = FALSE; newsection.bDisableCulling = FALSE; newsection.bIncTexRectEdge = FALSE; newsection.bZHack = FALSE; newsection.bTextureScaleHack = FALSE; newsection.bFastLoadTile = FALSE; newsection.bUseSmallerTexture = FALSE; newsection.bPrimaryDepthHack = FALSE; newsection.bTexture1Hack = FALSE; newsection.bDisableObjBG = FALSE; newsection.VIWidth = -1; newsection.VIHeight = -1; newsection.UseCIWidthAndRatio = NOT_USE_CI_WIDTH_AND_RATIO; newsection.dwFullTMEM = 0; newsection.bTxtSizeMethod2 = FALSE; newsection.bEnableTxtLOD = FALSE; newsection.bEmulateClear = FALSE; newsection.bForceScreenClear = FALSE; newsection.bDisableBlender = FALSE; newsection.bForceDepthBuffer = FALSE; newsection.dwFastTextureCRC = 0; newsection.dwAccurateTextureMapping = 0; newsection.dwNormalBlender = 0; newsection.dwNormalCombiner = 0; newsection.dwFrameBufferOption = 0; newsection.dwRenderToTextureOption = 0; newsection.dwScreenUpdateSetting = 0; IniSections.push_back(newsection); bIniIsChanged = true; // Flag to indicate we should be updated return IniSections.size()-1; // -1 takes into account increment } GameSetting g_curRomInfo; void ROM_GetRomNameFromHeader(unsigned char * szName, ROMHeader * pHdr) { unsigned char * p; memcpy(szName, pHdr->szName, 20); szName[20] = '\0'; p = szName + (strlen((char*)szName) -1); // -1 to skip null while (p >= szName && *p == ' ') { *p = 0; p--; } } uint32 CountryCodeToTVSystem(uint32 countryCode) { uint32 system; switch(countryCode) { /* Demo */ case 0: system = TV_SYSTEM_NTSC; break; case '7': system = TV_SYSTEM_NTSC; break; case 0x41: system = TV_SYSTEM_NTSC; break; /* Germany */ case 0x44: system = TV_SYSTEM_PAL; break; /* USA */ case 0x45: system = TV_SYSTEM_NTSC; break; /* France */ case 0x46: system = TV_SYSTEM_PAL; break; /* Italy */ case 'I': system = TV_SYSTEM_PAL; break; /* Japan */ case 0x4A: system = TV_SYSTEM_NTSC; break; /* Europe - PAL */ case 0x50: system = TV_SYSTEM_PAL; break; case 'S': /* Spain */ system = TV_SYSTEM_PAL; break; /* Australia */ case 0x55: system = TV_SYSTEM_PAL; break; case 0x58: system = TV_SYSTEM_PAL; break; /* Australia */ case 0x59: system = TV_SYSTEM_PAL; break; case 0x20: case 0x21: case 0x38: case 0x70: system = TV_SYSTEM_PAL; break; /* ??? */ default: system = TV_SYSTEM_PAL; break; } return system; } mupen64plus-video-rice-src-2.6.0/src/Config.h000066400000000000000000000252621464507324400207170ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _RICE_CONFIG_H_ #define _RICE_CONFIG_H_ #include #include "osal_preproc.h" #include "typedefs.h" #define CONFIG_PARAM_VERSION 1 typedef enum { OGL_DEVICE, OGL_FRAGMENT_PROGRAM, } SupportedDeviceType; enum { FRM_BUF_NONE, FRM_BUF_IGNORE, FRM_BUF_BASIC, FRM_BUF_BASIC_AND_WRITEBACK, FRM_BUF_WRITEBACK_AND_RELOAD, FRM_BUF_COMPLETE, FRM_BUF_WITH_EMULATOR, FRM_BUF_BASIC_AND_WITH_EMULATOR, FRM_BUF_WITH_EMULATOR_READ_ONLY, FRM_BUF_WITH_EMULATOR_WRITE_ONLY, }; enum { FRM_BUF_WRITEBACK_NORMAL, FRM_BUF_WRITEBACK_1_2, FRM_BUF_WRITEBACK_1_3, FRM_BUF_WRITEBACK_1_4, FRM_BUF_WRITEBACK_1_5, FRM_BUF_WRITEBACK_1_6, FRM_BUF_WRITEBACK_1_7, FRM_BUF_WRITEBACK_1_8, }; enum { TXT_BUF_NONE, TXT_BUF_IGNORE, TXT_BUF_NORMAL, TXT_BUF_WRITE_BACK, TXT_BUF_WRITE_BACK_AND_RELOAD, }; enum { TXT_QUALITY_DEFAULT, TXT_QUALITY_32BIT, TXT_QUALITY_16BIT, }; enum { FORCE_DEFAULT_FILTER, FORCE_POINT_FILTER, FORCE_LINEAR_FILTER, }; enum { TEXTURE_NO_MIPMAP = 0, TEXTURE_NO_FILTER, TEXTURE_BILINEAR_FILTER, TEXTURE_TRILINEAR_FILTER, }; enum { TEXTURE_NO_ENHANCEMENT, TEXTURE_2X_ENHANCEMENT, TEXTURE_2XSAI_ENHANCEMENT, TEXTURE_HQ2X_ENHANCEMENT, TEXTURE_LQ2X_ENHANCEMENT, TEXTURE_HQ4X_ENHANCEMENT, TEXTURE_SHARPEN_ENHANCEMENT, TEXTURE_SHARPEN_MORE_ENHANCEMENT, TEXTURE_EXTERNAL, TEXTURE_MIRRORED, }; enum { TEXTURE_ENHANCEMENT_NORMAL, TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1, TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2, TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3, TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4, }; enum { SCREEN_UPDATE_DEFAULT = 0, SCREEN_UPDATE_AT_VI_UPDATE = 1, SCREEN_UPDATE_AT_VI_CHANGE = 2, SCREEN_UPDATE_AT_CI_CHANGE = 3, SCREEN_UPDATE_AT_1ST_CI_CHANGE = 4, SCREEN_UPDATE_AT_1ST_PRIMITIVE = 5, SCREEN_UPDATE_BEFORE_SCREEN_CLEAR = 6, SCREEN_UPDATE_AT_VI_UPDATE_AND_DRAWN = 7, // Update screen at VI origin is updated and the screen has been drawn }; enum { ONSCREEN_DISPLAY_NOTHING = 0, ONSCREEN_DISPLAY_DLIST_PER_SECOND, ONSCREEN_DISPLAY_FRAME_PER_SECOND, ONSCREEN_DISPLAY_DEBUG_INFORMATION_ONLY, ONSCREEN_DISPLAY_TEXT_FROM_CORE_ONLY, ONSCREEN_DISPLAY_DLIST_PER_SECOND_WITH_CORE_MSG, ONSCREEN_DISPLAY_FRAME_PER_SECOND_WITH_CORE_MSG, ONSCREEN_DISPLAY_DEBUG_INFORMATION_WITH_CORE_MSG, }; enum HACK_FOR_GAMES { NO_HACK_FOR_GAME, HACK_FOR_BANJO_TOOIE, HACK_FOR_DR_MARIO, HACK_FOR_ZELDA, HACK_FOR_MARIO_TENNIS, HACK_FOR_BANJO, HACK_FOR_PD, HACK_FOR_GE, HACK_FOR_PILOT_WINGS, HACK_FOR_YOSHI, HACK_FOR_NITRO, HACK_FOR_TONYHAWK, HACK_FOR_NASCAR, HACK_FOR_SUPER_BOWLING, HACK_FOR_CONKER, HACK_FOR_ALL_STAR_BASEBALL, HACK_FOR_TIGER_HONEY_HUNT, HACK_REVERSE_XY_COOR, HACK_REVERSE_Y_COOR, HACK_FOR_GOLDEN_EYE, HACK_FOR_FZERO, HACK_FOR_COMMANDCONQUER, HACK_FOR_RUMBLE, HACK_FOR_SOUTH_PARK_RALLY, HACK_FOR_BUST_A_MOVE, HACK_FOR_OGRE_BATTLE, HACK_FOR_TWINE, HACK_FOR_EXTREME_G2, HACK_FOR_ROGUE_SQUADRON, HACK_FOR_MARIO_GOLF, HACK_FOR_MLB, HACK_FOR_POLARISSNOCROSS, HACK_FOR_TOPGEARRALLY, HACK_FOR_DUKE_NUKEM, HACK_FOR_ZELDA_MM, HACK_FOR_MARIO_KART, }; enum { NOT_USE_CI_WIDTH_AND_RATIO, USE_CI_WIDTH_AND_RATIO_FOR_NTSC, USE_CI_WIDTH_AND_RATIO_FOR_PAL, }; typedef struct { BOOL bEnableHacks; BOOL bWinFrameMode; BOOL bOGLVertexClipper; BOOL bEnableSSE; BOOL bSkipFrame; BOOL bFullTMEM; BOOL bUseFullTMEM; BOOL bShowFPS; uint32 mipmapping; uint32 fogMethod; uint32 forceTextureFilter; uint32 textureEnhancement; uint32 textureEnhancementControl; uint32 textureQuality; uint32 anisotropicFiltering; uint32 multiSampling; BOOL bTexRectOnly; BOOL bSmallTextureOnly; BOOL bDumpTexturesToFiles; BOOL bLoadHiResTextures; BOOL bLoadHiResCRCOnly; int OpenglDepthBufferSetting; int OpenglRenderSetting; uint32 colorQuality; // Polygon Offset Settings // These can be used to eliminate stitching artifacts in textures and shadows, which are typically only a problem // in mobile/embedded platforms (e.g. Android), where chipsets are inconsistent in their implementation of // glPolygonOffset. The float settings (factor and units) are typically set to the same value, and are ignored if // bForcePolygonOffset is False. The float settings (factor and units) are found through trial and error and may be // positive or negative. Mario's shadow in Super Mario 64 is a good test case when tuning this value. If the shadow // flickers, use a larger magnitude for the float settings. Do not use a larger value than necessary to eliminate // artifacts. As a guideline, typical values for mobile chipsets circa 2012-2014 are positive or negative values in // the range 0.001 to 2. BOOL bForcePolygonOffset; float polygonOffsetFactor; float polygonOffsetUnits; HACK_FOR_GAMES enableHackForGames; } GlobalOptions; typedef struct { bool bUpdateCIInfo; bool bCheckBackBufs; // Check texture again against the recent backbuffer addresses bool bWriteBackBufToRDRAM; // If a recent backbuffer is used, write its content back to RDRAM bool bLoadBackBufFromRDRAM; // Load content from RDRAM and draw into backbuffer bool bIgnore; // Ignore all rendering into texture buffers bool bSupportRenderTextures; // Support render-to-texture bool bCheckRenderTextures; // Check texture again against the the last render_texture addresses bool bRenderTextureWriteBack; // Write back render_texture into RDRAM bool bLoadRDRAMIntoRenderTexture; // Load RDRAM content and render into render_texture bool bAtEachFrameUpdate; // Reload and write back at each frame buffer and CI update bool bProcessCPUWrite; bool bProcessCPURead; bool bFillRectNextTextureBuffer; bool bIgnoreRenderTextureIfHeightUnknown; //bool bFillColor; } FrameBufferOptions; typedef struct { uint32 N64FrameBufferEmuType; uint32 N64FrameBufferWriteBackControl; uint32 N64RenderToTextureEmuType; uint32 screenUpdateSetting; BOOL bNormalCombiner; BOOL bNormalBlender; BOOL bFastTexCRC; BOOL bAccurateTextureMapping; BOOL bInN64Resolution; BOOL bDoubleSizeForSmallTxtrBuf; BOOL bSaveVRAM; } RomOptions; typedef struct IniSection { bool bOutput; char crccheck[50]; char name[50]; // Options with changeable default values uint32 dwNormalCombiner; uint32 dwNormalBlender; uint32 dwFastTextureCRC; uint32 dwAccurateTextureMapping; uint32 dwFrameBufferOption; uint32 dwRenderToTextureOption; uint32 dwScreenUpdateSetting; // Options with FALSE as default values BOOL bDisableBlender; BOOL bForceScreenClear; BOOL bEmulateClear; BOOL bForceDepthBuffer; // Less useful options BOOL bDisableObjBG; BOOL bDisableTextureCRC; BOOL bIncTexRectEdge; BOOL bZHack; BOOL bTextureScaleHack; BOOL bFastLoadTile; BOOL bUseSmallerTexture; BOOL bPrimaryDepthHack; BOOL bTexture1Hack; BOOL bDisableCulling; int VIWidth; int VIHeight; uint32 UseCIWidthAndRatio; uint32 dwFullTMEM; BOOL bTxtSizeMethod2; BOOL bEnableTxtLOD; } section; struct ROMHeader { uint8 x1, x2, x3, x4; uint32 dwClockRate; uint32 dwBootAddressOffset; uint32 dwRelease; uint32 dwCRC1; uint32 dwCRC2; uint64 qwUnknown1; char szName[20]; uint32 dwUnknown2; uint16 wUnknown3; uint8 nUnknown4; uint8 nManufacturer; uint16 wCartID; s8 nCountryID; uint8 nUnknown5; }; typedef struct { // Other info from the rom. This is for convenience unsigned char szGameName[50+1]; s8 nCountryID; // Copy of the ROM header ROMHeader romheader; // With changeable default values uint32 dwNormalCombiner; uint32 dwNormalBlender; uint32 dwAccurateTextureMapping; uint32 dwFastTextureCRC; uint32 dwFrameBufferOption; uint32 dwRenderToTextureOption; uint32 dwScreenUpdateSetting; // With FALSE as its default values BOOL bForceScreenClear; BOOL bEmulateClear; BOOL bForceDepthBuffer; BOOL bDisableBlender; // Less useful options BOOL bDisableObjBG; BOOL bDisableTextureCRC; BOOL bIncTexRectEdge; BOOL bZHack; BOOL bTextureScaleHack; BOOL bFastLoadTile; BOOL bUseSmallerTexture; BOOL bPrimaryDepthHack; BOOL bTexture1Hack; BOOL bDisableCulling; int VIWidth; int VIHeight; uint32 UseCIWidthAndRatio; uint32 dwFullTMEM; BOOL bTxtSizeMethod2; BOOL bEnableTxtLOD; } GameSetting, *LPGAMESETTING; typedef struct { s8 nCountryID; char* szName; uint32 nTvType; } CountryIDInfo; #define TV_SYSTEM_NTSC 1 #define TV_SYSTEM_PAL 0 extern GlobalOptions options; extern FrameBufferOptions frameBufferOptions; extern RomOptions defaultRomOptions; extern RomOptions currentRomOptions; extern const CountryIDInfo g_CountryCodeInfo[]; extern GameSetting g_curRomInfo; extern bool bIniIsChanged; extern char szIniFileName[300]; extern BOOL InitConfiguration(void); extern BOOL LoadConfiguration(void); extern void WriteIniFile(); extern BOOL ReadIniFile(); extern void OutputSectionDetails(uint32 i, FILE * fh); extern void GenerateCurrentRomOptions(); extern void Ini_GetRomOptions(LPGAMESETTING pGameSetting); extern void Ini_StoreRomOptions(LPGAMESETTING pGameSetting); extern uint32 CountryCodeToTVSystem(uint32 countryCode); extern void ROM_GetRomNameFromHeader(unsigned char * szName, ROMHeader * pHdr); #endif mupen64plus-video-rice-src-2.6.0/src/ConvertImage.cpp000066400000000000000000001274711464507324400224350ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "Config.h" #include "ConvertImage.h" #include "RSP_Parser.h" #include "RenderBase.h" #include "Texture.h" #include "TextureManager.h" ConvertFunction gConvertFunctions_FullTMEM[ 8 ][ 4 ] = { // 4bpp 8bpp 16bpp 32bpp { Convert4b, Convert8b, Convert16b, ConvertRGBA32 }, // RGBA { NULL, NULL, ConvertYUV, NULL }, // YUV { Convert4b, Convert8b, NULL, NULL }, // CI { Convert4b, Convert8b, Convert16b, NULL }, // IA { Convert4b, Convert8b, Convert16b, NULL }, // I { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL } // ? }; ConvertFunction gConvertFunctions[ 8 ][ 4 ] = { // 4bpp 8bpp 16bpp 32bpp { ConvertCI4, ConvertCI8, ConvertRGBA16, ConvertRGBA32 }, // RGBA { NULL, NULL, ConvertYUV, NULL }, // YUV { ConvertCI4, ConvertCI8, NULL, NULL }, // CI { ConvertIA4, ConvertIA8, ConvertIA16, NULL }, // IA { ConvertI4, ConvertI8, ConvertIA16, NULL }, // I { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL } // ? }; ConvertFunction gConvertTlutFunctions[ 8 ][ 4 ] = { // 4bpp 8bpp 16bpp 32bpp { ConvertCI4, ConvertCI8, ConvertRGBA16, ConvertRGBA32 }, // RGBA { NULL, NULL, ConvertYUV, NULL }, // YUV { ConvertCI4, ConvertCI8, NULL, NULL }, // CI { ConvertCI4, ConvertCI8, ConvertIA16, NULL }, // IA { ConvertCI4, ConvertCI8, ConvertIA16, NULL }, // I { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL } // ? }; extern bool conkerSwapHack; // Super Mario 64, Zelda OOT void ConvertRGBA16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; // Copy of the base pointer uint8 * pByteSrc = (uint8 *)(tinfo.pPhysicalAddress); if (!pTexture->StartUpdate(&dInfo)) return; // is only setted if the texture is swapped uint32 nFiddle = 0x2; for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if (tinfo.bSwapped) // Super Smash Bros N64 logo { if (y&1) nFiddle = 0x2 | 0x4; // only odd lines are swapped else nFiddle = 0x2; } // dwDst points to start of destination row uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); // DWordOffset points to the current dword we're looking at // (process 2 pixels at a time). May be a problem if we don't start on even pixel uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint16 w = *(uint16 *)&pByteSrc[dwWordOffset ^ nFiddle]; dwDst[x] = Convert555ToRGBA(w); // Increment word offset to point to the next two pixels dwWordOffset += 2; } } pTexture->EndUpdate(&dInfo); } // N64 32 bit textures are in R8G8B8A8 format. On little endian processors, // components are reverted during transfer to GPU. So RGBA is send as ABGR // which is not supported. We need to convert RGBA to ARGB (A8R8G8B8) because // ARGB will be BGRA on GPU. void ConvertRGBA32(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; if( options.bUseFullTMEM ) { Tile &tile = gRDP.tiles[tinfo.tileNo]; uint32 *pWordSrc; if( tinfo.tileNo >= 0 ) { pWordSrc = (uint32*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); uint32 nFiddle = ( y&1 )? 0x2 : 0; int idx = tile.dwLine*4*y; for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) { uint32 w = pWordSrc[idx^nFiddle]; uint8* psw = (uint8*)&w; uint8* pdw = (uint8*)&dwDst[x]; pdw[0] = psw[2]; // Blue pdw[1] = psw[1]; // Green pdw[2] = psw[0]; // Red pdw[3] = psw[3]; // Alpha } } } } else { // Copy of the base pointer uint8 * pByteSrc = (uint8 *)tinfo.pPhysicalAddress; // is only setted if the texture is swapped uint32 nFiddle = 0x0; for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { // non swapped: Banjo Tooie Title screen // swapped: Super Smash Bros N64 logo if (tinfo.bSwapped) { if (y&1) nFiddle = 0x8; // only odd lines are swapped else nFiddle = 0x0; } // dwDst points to start of destination row uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); // offset in byte to the start of the current row uint32 byteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 4); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint32 dw = *(uint32 *)&pByteSrc[byteOffset^nFiddle]; dwDst[x] = RGBA_TO_ARGB(dw); // move to the next pixel byteOffset += 4; } } } pTexture->EndUpdate(&dInfo); } // E.g. Dear Mario text // Copy, Score etc void ConvertIA4(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); #ifdef DEBUGGER if (((long long)pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); #endif if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; // For odd lines, swap words too if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; // This may not work if X is not even? uint32 dwByteOffset = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad/2); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ nFiddle]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = OneToEight[(b & 0x10) >> 4]; } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // Do two pixels at a time uint8 b = pSrc[dwByteOffset ^ nFiddle]; // Even *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = OneToEight[(b & 0x10) >> 4]; // Odd *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; *pDst++ = OneToEight[(b & 0x01) ]; dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + (y * dInfo.lPitch); // This may not work if X is not even? uint32 dwByteOffset = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad/2); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ 0x3]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = OneToEight[(b & 0x10) >> 4]; } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // Do two pixels at a time uint8 b = pSrc[dwByteOffset ^ 0x3]; // Even *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; *pDst++ = OneToEight[(b & 0x10) >> 4]; // Odd *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; *pDst++ = OneToEight[(b & 0x01) ]; dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } // E.g Mario's head textures void ConvertIA8(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); #ifdef DEBUGGER if (((long long)pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); #endif if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { // For odd lines, swap words too if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; // Points to current byte uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; uint8 I = FourToEight[(b & 0xf0)>>4]; *pDst++ = I; *pDst++ = I; *pDst++ = I; *pDst++ = FourToEight[(b & 0x0f) ]; dwByteOffset++; } } } else { const uint8* FourToEightArray = &FourToEight[0]; for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; // Points to current byte uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[(dwByteOffset++) ^ 0x3]; uint8 I = *(FourToEightArray+(b>>4)); *pDst++ = I; *pDst++ = I; *pDst++ = I; *pDst++ = *(FourToEightArray+(b&0xF)); } } } pTexture->EndUpdate(&dInfo); } // E.g. camera's clouds, shadows void ConvertIA16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; if ((y%2) == 0) nFiddle = 0x2; else nFiddle = 0x4 | 0x2; // Points to current word uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint16 w = *(uint16 *)&pByteSrc[dwWordOffset^nFiddle]; *pDst++ = (uint8)(w >> 8); *pDst++ = (uint8)(w >> 8); *pDst++ = (uint8)(w >> 8); *pDst++ = (uint8)(w & 0xFF); dwWordOffset += 2; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; // Points to current word uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint16 w = *(uint16 *)&pByteSrc[dwWordOffset^0x2]; *pDst++ = (uint8)(w >> 8); *pDst++ = (uint8)(w >> 8); *pDst++ = (uint8)(w >> 8); *pDst++ = (uint8)(w & 0xFF); dwWordOffset += 2; } } } pTexture->EndUpdate(&dInfo); } // Used by MarioKart void ConvertI4(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); #ifdef DEBUGGER if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); #endif if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; // Might not work with non-even starting X uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); // For odd lines, swap words too if( !conkerSwapHack || (y&4) == 0 ) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; } else { if ((y%2) == 1) nFiddle = 0x3; else nFiddle = 0x7; } if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ nFiddle]; *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // two pixels at a time uint8 b = pSrc[dwByteOffset ^ nFiddle]; // Even *pDst++ = FourToEight[(b & 0xF0)>>4]; // Other implementations seem to or in (b&0xF0)>>4 *pDst++ = FourToEight[(b & 0xF0)>>4]; // why? *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; // Odd *pDst++ = FourToEight[(b & 0x0F)]; *pDst++ = FourToEight[(b & 0x0F)]; *pDst++ = FourToEight[(b & 0x0F)]; *pDst++ = FourToEight[(b & 0x0F)]; dwByteOffset++; } } conkerSwapHack = false; } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; // Might not work with non-even starting X uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ 0x3]; *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // two pixels at a time uint8 b = pSrc[dwByteOffset ^ 0x3]; // Even *pDst++ = FourToEight[(b & 0xF0)>>4]; // Other implementations seem to or in (b&0xF0)>>4 *pDst++ = FourToEight[(b & 0xF0)>>4]; // why? *pDst++ = FourToEight[(b & 0xF0)>>4]; *pDst++ = FourToEight[(b & 0xF0)>>4]; // Odd *pDst++ = FourToEight[(b & 0x0F)]; *pDst++ = FourToEight[(b & 0x0F)]; *pDst++ = FourToEight[(b & 0x0F)]; *pDst++ = FourToEight[(b & 0x0F)]; dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } // Used by MarioKart void ConvertI8(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; long long pSrc = (long long) tinfo.pPhysicalAddress; if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = *(uint8*)((pSrc+dwByteOffset)^nFiddle); *pDst++ = b; *pDst++ = b; *pDst++ = b; *pDst++ = b; // Alpha not 255? dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = *(uint8*)((pSrc+dwByteOffset)^0x3); *pDst++ = b; *pDst++ = b; *pDst++ = b; *pDst++ = b; // Alpha not 255? dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } //***************************************************************************** // Convert CI4 images. We need to switch on the palette type //***************************************************************************** void ConvertCI4( CTexture * p_texture, const TxtrInfo & tinfo ) { if ( tinfo.TLutFmt == TLUT_FMT_RGBA16 ) { ConvertCI4_RGBA16( p_texture, tinfo ); } else if ( tinfo.TLutFmt == TLUT_FMT_IA16 ) { ConvertCI4_IA16( p_texture, tinfo ); } } //***************************************************************************** // Convert CI8 images. We need to switch on the palette type //***************************************************************************** void ConvertCI8( CTexture * p_texture, const TxtrInfo & tinfo ) { if ( tinfo.TLutFmt == TLUT_FMT_RGBA16 ) { ConvertCI8_RGBA16( p_texture, tinfo ); } else if ( tinfo.TLutFmt == TLUT_FMT_IA16 ) { ConvertCI8_IA16( p_texture, tinfo ); } } // Used by Starfox intro void ConvertCI4_RGBA16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ nFiddle]; uint8 bhi = (b&0xf0)>>4; *pDst = Convert555ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { *pDst |= 0xFF000000; } } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // two at a time uint8 b = pSrc[dwByteOffset ^ nFiddle]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = Convert555ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = Convert555ToRGBA(pPal[blo^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { pDst[0] |= 0xFF000000; pDst[1] |= 0xFF000000; } pDst+=2; dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ 0x3]; uint8 bhi = (b&0xf0)>>4; *pDst = Convert555ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { *pDst |= 0xFF000000; } } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // two at a time uint8 b = pSrc[dwByteOffset ^ 0x3]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = Convert555ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = Convert555ToRGBA(pPal[blo^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { pDst[0] |= 0xFF000000; pDst[1] |= 0xFF000000; } pDst+=2; dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } // Used by Starfox intro void ConvertCI4_IA16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); #ifdef DEBUGGER if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); #endif uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ nFiddle]; uint8 bhi = (b&0xf0)>>4; *pDst = ConvertIA16ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) *pDst |= 0xFF000000; } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // two at a time uint8 b = pSrc[dwByteOffset ^ nFiddle]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = ConvertIA16ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = ConvertIA16ToRGBA(pPal[blo^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { pDst[0] |= 0xFF000000; pDst[1] |= 0xFF000000; } pDst+=2; dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pSrc[dwByteOffset ^ 0x3]; uint8 bhi = (b&0xf0)>>4; *pDst = ConvertIA16ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) *pDst |= 0xFF000000; } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { // two pixels at a time uint8 b = pSrc[dwByteOffset ^ 0x3]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = ConvertIA16ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = ConvertIA16ToRGBA(pPal[blo^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { pDst[0] |= 0xFF000000; pDst[1] |= 0xFF000000; } pDst+=2; dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } // Used by MarioKart for Cars etc void ConvertCI8_RGBA16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); #ifdef DEBUGGER if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); #endif uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; *pDst++ = Convert555ToRGBA(pPal[b^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { *(pDst-1) |= 0xFF000000; } dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); int dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ 0x3]; *pDst++ = Convert555ToRGBA(pPal[b^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { *(pDst-1) |= 0xFF000000; } dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } // Used by MarioKart for Cars etc void ConvertCI8_IA16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); #ifdef DEBUGGER if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); #endif uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; *pDst++ = ConvertIA16ToRGBA(pPal[b^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { *(pDst-1) |= 0xFF000000; } dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ 0x3]; *pDst++ = ConvertIA16ToRGBA(pPal[b^1]); // Remember palette is in different endian order! if( bIgnoreAlpha ) { *(pDst-1) |= 0xFF000000; } dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } void ConvertYUV(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; uint32 x, y; uint32 nFiddle; if( options.bUseFullTMEM ) { Tile &tile = gRDP.tiles[tinfo.tileNo]; uint16 * pSrc; if( tinfo.tileNo >= 0 ) pSrc = (uint16*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; else pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; for (y = 0; y < tinfo.HeightToLoad; y++) { nFiddle = ( y&1 )? 0x4 : 0; int dwWordOffset = tinfo.tileNo>=0? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); for (x = 0; x < tinfo.WidthToLoad/2; x++) { int y0 = *(uint8*)&pByteSrc[(dwWordOffset+1)^nFiddle]; int y1 = *(uint8*)&pByteSrc[(dwWordOffset+3)^nFiddle]; int u0 = *(uint8*)&pByteSrc[(dwWordOffset )^nFiddle]; int v0 = *(uint8*)&pByteSrc[(dwWordOffset+2)^nFiddle]; dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0); dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0); dwWordOffset += 4; } } } else { uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; if (tinfo.bSwapped) { for (y = 0; y < tinfo.HeightToLoad; y++) { if ((y&1) == 0) nFiddle = 0x3; else nFiddle = 0x7; // dwDst points to start of destination row uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); // DWordOffset points to the current dword we're looking at // (process 2 pixels at a time). May be a problem if we don't start on even pixel uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (x = 0; x < tinfo.WidthToLoad/2; x++) { int y0 = *(uint8*)&pByteSrc[(dwWordOffset+2)^nFiddle]; int v0 = *(uint8*)&pByteSrc[(dwWordOffset+1)^nFiddle]; int y1 = *(uint8*)&pByteSrc[(dwWordOffset )^nFiddle]; int u0 = *(uint8*)&pByteSrc[(dwWordOffset+3)^nFiddle]; dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0); dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0); dwWordOffset += 4; } } } else { for (y = 0; y < tinfo.HeightToLoad; y++) { // dwDst points to start of destination row uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); uint32 dwByteOffset = y * 32; for (x = 0; x < tinfo.WidthToLoad/2; x++) { int y0 = *(uint8*)&pByteSrc[(dwByteOffset+2)]; int v0 = *(uint8*)&pByteSrc[(dwByteOffset+1)]; int y1 = *(uint8*)&pByteSrc[(dwByteOffset )]; int u0 = *(uint8*)&pByteSrc[(dwByteOffset+3)]; dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0); dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0); // Increment word offset to point to the next two pixels dwByteOffset += 4; } } } } pTexture->EndUpdate(&dInfo); } uint32 ConvertYUV16ToR8G8B8(int Y, int U, int V) { /* int R = int(g_convc0 *(Y-16) + g_convc1 * V); int G = int(g_convc0 *(Y-16) + g_convc2 * U - g_convc3 * V); int B = int(g_convc0 *(Y-16) + g_convc4 * U); */ Y += 80; int R = int(Y + (1.370705f * (V-128))); int G = int(Y - (0.698001f * (V-128)) - (0.337633f * (U-128))); int B = int(Y + (1.732446f * (U-128))); R = R < 0 ? 0 : (R>255 ? 255 : R); G = G < 0 ? 0 : (G>255 ? 255 : G); B = B < 0 ? 0 : (B>255 ? 255 : B); return COLOR_RGBA(R, G, B, 0xFF); } // Used by Starfox intro void Convert4b(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); if( tinfo.Format <= TXT_FMT_CI ) bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); Tile &tile = gRDP.tiles[tinfo.tileNo]; uint8 *pByteSrc = tinfo.tileNo >= 0 ? (uint8*)&g_Tmem.g_Tmem64bit[tile.dwTMem] : (uint8*)(tinfo.pPhysicalAddress); for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 nFiddle; if( tinfo.tileNo < 0 ) { if (tinfo.bSwapped) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; } else { nFiddle = 3; } } else { nFiddle = ( y&1 )? 0x4 : 0; } uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); int idx = tinfo.tileNo>=0 ? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); if (tinfo.WidthToLoad == 1) { // corner case uint8 b = pByteSrc[idx^nFiddle]; uint8 bhi = (b&0xf0)>>4; if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) ) { if( tinfo.TLutFmt == TLUT_FMT_IA16 ) { if( tinfo.tileNo>=0 ) *pDst = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); else *pDst = ConvertIA16ToRGBA(pPal[bhi^1]); } else { if( tinfo.tileNo>=0 ) *pDst = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); else *pDst = Convert555ToRGBA(pPal[bhi^1]); } } else if( tinfo.Format == TXT_FMT_IA ) *pDst = ConvertIA4ToRGBA(b>>4); else // if( tinfo.Format == TXT_FMT_I ) *pDst = ConvertI4ToRGBA(b>>4); if( bIgnoreAlpha ) *pDst |= 0xFF000000; } else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2, idx++) { // two pixels at a time uint8 b = pByteSrc[idx^nFiddle]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) ) { if( tinfo.TLutFmt == TLUT_FMT_IA16 ) { if( tinfo.tileNo>=0 ) { pDst[0] = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); pDst[1] = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(blo<<2)]); } else { pDst[0] = ConvertIA16ToRGBA(pPal[bhi^1]); pDst[1] = ConvertIA16ToRGBA(pPal[blo^1]); } } else { if( tinfo.tileNo>=0 ) { pDst[0] = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); pDst[1] = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(blo<<2)]); } else { pDst[0] = Convert555ToRGBA(pPal[bhi^1]); pDst[1] = Convert555ToRGBA(pPal[blo^1]); } } } else if( tinfo.Format == TXT_FMT_IA ) { pDst[0] = ConvertIA4ToRGBA(b>>4); pDst[1] = ConvertIA4ToRGBA(b&0xF); } else // if( tinfo.Format == TXT_FMT_I ) { pDst[0] = ConvertI4ToRGBA(b>>4); pDst[1] = ConvertI4ToRGBA(b&0xF); } if( bIgnoreAlpha ) { pDst[0] |= 0xFF000000; pDst[1] |= 0xFF000000; } pDst+=2; } } pTexture->EndUpdate(&dInfo); } void Convert8b(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); if( tinfo.Format <= TXT_FMT_CI ) bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); Tile &tile = gRDP.tiles[tinfo.tileNo]; uint8 *pByteSrc; if( tinfo.tileNo >= 0 ) { pByteSrc = (uint8*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; } else { pByteSrc = (uint8*)(tinfo.pPhysicalAddress); } for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 nFiddle; if( tinfo.tileNo < 0 ) { if (tinfo.bSwapped) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; } else { nFiddle = 3; } } else { nFiddle = ( y&1 )? 0x4 : 0; } int idx = tinfo.tileNo>=0? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) { uint8 b = pByteSrc[idx^nFiddle]; if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) ) { if( tinfo.TLutFmt == TLUT_FMT_IA16 ) { if( tinfo.tileNo>=0 ) *pDst = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+(b<<2)]); else *pDst = ConvertIA16ToRGBA(pPal[b^1]); } else { if( tinfo.tileNo>=0 ) *pDst = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+(b<<2)]); else *pDst = Convert555ToRGBA(pPal[b^1]); } } else if( tinfo.Format == TXT_FMT_IA ) { uint8 I = FourToEight[(b & 0xf0)>>4]; uint8 * pByteDst = (uint8*)pDst; pByteDst[0] = I; pByteDst[1] = I; pByteDst[2] = I; pByteDst[3] = FourToEight[(b & 0x0f) ]; } else // if( tinfo.Format == TXT_FMT_I ) { uint8 * pByteDst = (uint8*)pDst; pByteDst[0] = b; pByteDst[1] = b; pByteDst[2] = b; pByteDst[3] = b; } if( bIgnoreAlpha ) { *pDst |= 0xFF000000; } pDst++; } } pTexture->EndUpdate(&dInfo); } void Convert16b(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; Tile &tile = gRDP.tiles[tinfo.tileNo]; uint16 *pWordSrc; if( tinfo.tileNo >= 0 ) pWordSrc = (uint16*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; else pWordSrc = (uint16*)(tinfo.pPhysicalAddress); for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); uint32 nFiddle; if( tinfo.tileNo < 0 ) { if (tinfo.bSwapped) { if ((y&1) == 0) nFiddle = 0x1; else nFiddle = 0x3; } else { nFiddle = 0x1; } } else { nFiddle = ( y&1 )? 0x2 : 0; } int idx = tinfo.tileNo>=0? tile.dwLine*4*y : (((y+tinfo.TopToLoad) * tinfo.Pitch)>>1) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) { uint16 w = pWordSrc[idx^nFiddle]; uint16 w2 = tinfo.tileNo>=0? ((w>>8)|(w<<8)) : w; if( tinfo.Format == TXT_FMT_RGBA ) { dwDst[x] = Convert555ToRGBA(w2); } else if( tinfo.Format == TXT_FMT_YUV ) { } else if( tinfo.Format >= TXT_FMT_IA ) { uint8 * pByteDst = (uint8*)&dwDst[x]; *pByteDst++ = (uint8)(w2 >> 8); *pByteDst++ = (uint8)(w2 >> 8); *pByteDst++ = (uint8)(w2 >> 8); *pByteDst++ = (uint8)(w2 & 0xFF); } } } pTexture->EndUpdate(&dInfo); } mupen64plus-video-rice-src-2.6.0/src/ConvertImage.h000066400000000000000000000222301464507324400220650ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __CONVERTIMAGE_H__ #define __CONVERTIMAGE_H__ #include "Texture.h" #include "TextureManager.h" #include "typedefs.h" class CTexture; class TxtrInfo; static const uint8 OneToEight[2] = { 0x00, // 0 -> 00 00 00 00 0xff // 1 -> 11 11 11 11 }; static const uint8 OneToFour[2] = { 0x00, // 0 -> 00 00 0x0f // 1 -> 11 11 }; static const uint8 TwoToEight[4] = { 0x00, // 00 -> 00 00 00 00 0x55, // 01 -> 01 01 01 01 0xaa, // 10 -> 10 10 10 10 0xff // 11 -> 11 11 11 11 }; static const uint8 TwoToFour[4] = { 0x0, // 00 -> 00 00 0x5, // 01 -> 01 01 0xa, // 10 -> 10 10 0xf // 11 -> 11 11 }; static const uint8 ThreeToEight[8] = { 0x00, // 000 -> 00 00 00 00 0x24, // 001 -> 00 10 01 00 0x49, // 010 -> 01 00 10 01 0x6d, // 011 -> 01 10 11 01 0x92, // 100 -> 10 01 00 10 0xb6, // 101 -> 10 11 01 10 0xdb, // 110 -> 11 01 10 11 0xff // 111 -> 11 11 11 11 }; static const uint8 ThreeToFour[8] = { 0x0, // 000 -> 00 00 00 00 0x2, // 001 -> 00 10 01 00 0x4, // 010 -> 01 00 10 01 0x6, // 011 -> 01 10 11 01 0x9, // 100 -> 10 01 00 10 0xb, // 101 -> 10 11 01 10 0xd, // 110 -> 11 01 10 11 0xf // 111 -> 11 11 11 11 }; static const uint8 FourToEight[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; static const uint16 FourToSixteen[16] = { 0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888, 0x9999, 0xaaaa, 0xbbbb, 0xcccc, 0xdddd, 0xeeee, 0xffff }; static const uint8 FiveToEight[32] = { 0x00, // 00000 -> 00000000 0x08, // 00001 -> 00001000 0x10, // 00010 -> 00010000 0x18, // 00011 -> 00011000 0x21, // 00100 -> 00100001 0x29, // 00101 -> 00101001 0x31, // 00110 -> 00110001 0x39, // 00111 -> 00111001 0x42, // 01000 -> 01000010 0x4a, // 01001 -> 01001010 0x52, // 01010 -> 01010010 0x5a, // 01011 -> 01011010 0x63, // 01100 -> 01100011 0x6b, // 01101 -> 01101011 0x73, // 01110 -> 01110011 0x7b, // 01111 -> 01111011 0x84, // 10000 -> 10000100 0x8c, // 10001 -> 10001100 0x94, // 10010 -> 10010100 0x9c, // 10011 -> 10011100 0xa5, // 10100 -> 10100101 0xad, // 10101 -> 10101101 0xb5, // 10110 -> 10110101 0xbd, // 10111 -> 10111101 0xc6, // 11000 -> 11000110 0xce, // 11001 -> 11001110 0xd6, // 11010 -> 11010110 0xde, // 11011 -> 11011110 0xe7, // 11100 -> 11100111 0xef, // 11101 -> 11101111 0xf7, // 11110 -> 11110111 0xff // 11111 -> 11111111 }; #define RGBA5551_RedMask (0xF800) #define RGBA5551_GreenMask (0x07C0) #define RGBA5551_BlueMask (0x003E) #define RGBA5551_AlphaMask (0x0001) #define RGBA5551_RedShift 11 #define RGBA5551_GreenShift 6 #define RGBA5551_BlueShift 1 #define RGBA5551_AlphaShift 0 #define RGBA565_RedMask (0xF800) #define RGBA565_GreenMask (0x07E0) #define RGBA565_BlueMask (0x001F) #define RGBA565_RedShift 11 #define RGBA565_GreenShift 5 #define RGBA565_BlueShift 0 inline uint16 ConvertRGBTo555(uint8 red, uint8 grn, uint8 blu) { return (uint16)(((uint16)(red >> 3) << RGBA5551_RedShift) | ((uint16)(grn >> 3) << RGBA5551_GreenShift) | ((uint16)(blu >> 3) << RGBA5551_BlueShift) | ((uint16)(1) << RGBA5551_AlphaShift)); } inline uint16 ConvertRGBTo565(uint8 red, uint8 grn, uint8 blu) { return (uint16)(((uint16)(red >> 3) << RGBA565_RedShift) | ((uint16)(grn >> 2) << RGBA565_GreenShift) | ((uint16)(blu >> 3) << RGBA565_BlueShift)); } inline uint16 Convert555To565(uint16 w555) { // Probably a faster method by fudging the low bits.. uint8 red = FiveToEight[(w555&RGBA5551_RedMask) >> RGBA5551_RedShift]; uint8 grn = FiveToEight[(w555&RGBA5551_GreenMask)>> RGBA5551_GreenShift]; uint8 blu = FiveToEight[(w555&RGBA5551_BlueMask) >> RGBA5551_BlueShift]; return ConvertRGBTo565(red, grn, blu); } #define R4G4B4A4_MAKE(r,g,b,a) ((uint16)(((a) << 12) | ((r)<< 8) | ((g)<<4) | (b))) inline uint32 Convert555ToRGBA(uint16 w555) { uint32 dwRed = FiveToEight[(w555&RGBA5551_RedMask) >> RGBA5551_RedShift]; uint32 dwGreen = FiveToEight[(w555&RGBA5551_GreenMask)>> RGBA5551_GreenShift]; uint32 dwBlue = FiveToEight[(w555&RGBA5551_BlueMask) >> RGBA5551_BlueShift]; uint32 dwAlpha = (w555&RGBA5551_AlphaMask) ? 0xFF : 0x00; return COLOR_RGBA(dwRed, dwGreen, dwBlue, dwAlpha); } inline uint16 Convert555ToR4G4B4A4(uint16 w555) { uint8 dwRed = ((w555&RGBA5551_RedMask) >> RGBA5551_RedShift)>>1; uint8 dwGreen = ((w555&RGBA5551_GreenMask)>> RGBA5551_GreenShift)>>1; uint8 dwBlue = ((w555&RGBA5551_BlueMask) >> RGBA5551_BlueShift)>>1; uint8 dwAlpha = (w555&RGBA5551_AlphaMask) ? 0xF : 0x0; return R4G4B4A4_MAKE(dwRed, dwGreen, dwBlue, dwAlpha); } inline uint32 ConvertIA4ToRGBA(uint8 IA4) { uint32 I = ThreeToEight[(IA4 & 0x0F) >> 1]; uint32 A = OneToEight[(IA4 & 0x01)]; return COLOR_RGBA(I, I, I, A); } inline uint16 ConvertIA4ToR4G4B4A4(uint8 IA4) { uint32 I = ThreeToFour[(IA4 & 0x0F) >> 1]; uint32 A = OneToFour[(IA4 & 0x01)]; return R4G4B4A4_MAKE(I, I, I, A); } inline uint32 ConvertI4ToRGBA(uint8 I4) { uint32 I = FourToEight[I4 & 0x0F]; return COLOR_RGBA(I, I, I, I); } inline uint16 ConvertI4ToR4G4B4A4(uint8 I4) { return FourToSixteen[I4 & 0x0F]; } inline uint32 ConvertIA16ToRGBA(uint16 wIA) { uint32 dwIntensity = (wIA >> 8) & 0xFF; uint32 dwAlpha = (wIA ) & 0xFF; return COLOR_RGBA(dwIntensity, dwIntensity, dwIntensity, dwAlpha); } inline uint16 ConvertIA16ToR4G4B4A4(uint16 wIA) { uint16 dwIntensity = (wIA >> 12) & 0x0F; uint16 dwAlpha = (wIA >> 4) & 0x0F; return R4G4B4A4_MAKE(dwIntensity, dwIntensity, dwIntensity, dwAlpha); } extern int g_convk0,g_convk1,g_convk2,g_convk3,g_convk4,g_convk5; extern float g_convc0,g_convc1,g_convc2,g_convc3,g_convc4,g_convc5; uint32 ConvertYUV16ToR8G8B8(int Y, int U, int V); uint16 ConvertYUV16ToR4G4B4(int Y, int U, int V); typedef void ( * ConvertFunction )( CTexture * p_texture, const TxtrInfo & ti ); void ConvertRGBA16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertRGBA32(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertIA4(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertIA8(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertIA16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertI4(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertI8(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI4( CTexture *pTexture, const TxtrInfo & ti ); void ConvertCI8( CTexture *pTexture, const TxtrInfo & ti ); void ConvertCI4_RGBA16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI4_IA16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI8_RGBA16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI8_IA16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertYUV(CTexture *pTexture, const TxtrInfo &tinfo); // 16 a4r4g4b4 void ConvertRGBA16_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertRGBA32_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertIA4_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertIA8_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertIA16_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertI4_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertI8_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI4_16( CTexture *pTexture, const TxtrInfo & ti ); void ConvertCI8_16( CTexture *pTexture, const TxtrInfo & ti ); void ConvertCI4_RGBA16_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI4_IA16_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI8_RGBA16_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertCI8_IA16_16(CTexture *pTexture, const TxtrInfo &tinfo); void ConvertYUV_16(CTexture *pTexture, const TxtrInfo &tinfo); void Convert4b(CTexture *pTexture, const TxtrInfo &tinfo); void Convert8b(CTexture *pTexture, const TxtrInfo &tinfo); void Convert16b(CTexture *pTexture, const TxtrInfo &tinfo); void Convert4b_16(CTexture *pTexture, const TxtrInfo &tinfo); void Convert8b_16(CTexture *pTexture, const TxtrInfo &tinfo); void Convert16b_16(CTexture *pTexture, const TxtrInfo &tinfo); #endif mupen64plus-video-rice-src-2.6.0/src/ConvertImage16.cpp000066400000000000000000001130221464507324400225670ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "Config.h" #include "ConvertImage.h" #include "RSP_Parser.h" #include "RenderBase.h" #include "Texture.h" #include "TextureManager.h" #include "typedefs.h" // Still to be swapped: // IA16 ConvertFunction gConvertFunctions_16_FullTMEM[ 8 ][ 4 ] = { // 4bpp 8bpp 16bpp 32bpp { Convert4b_16, Convert8b_16, Convert16b_16, ConvertRGBA32_16 }, // RGBA { NULL, NULL, ConvertYUV_16, NULL }, // YUV { Convert4b_16, Convert8b_16, NULL, NULL }, // CI { Convert4b_16, Convert8b_16, Convert16b_16, NULL }, // IA { Convert4b_16, Convert8b_16, Convert16b_16, NULL }, // I { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL } // ? }; ConvertFunction gConvertFunctions_16[ 8 ][ 4 ] = { // 4bpp 8bpp 16bpp 32bpp { ConvertCI4_16, ConvertCI8_16, ConvertRGBA16_16, ConvertRGBA32_16 }, // RGBA { NULL, NULL, ConvertYUV_16, NULL }, // YUV { ConvertCI4_16, ConvertCI8_16, NULL, NULL }, // CI { ConvertIA4_16, ConvertIA8_16, ConvertIA16_16, NULL }, // IA { ConvertI4_16, ConvertI8_16, ConvertRGBA16_16, NULL }, // I { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL } // ? }; ConvertFunction gConvertTlutFunctions_16[ 8 ][ 4 ] = { // 4bpp 8bpp 16bpp 32bpp { ConvertCI4_16, ConvertCI8_16, ConvertRGBA16_16, ConvertRGBA32_16 }, // RGBA { NULL, NULL, ConvertYUV_16, NULL }, // YUV { ConvertCI4_16, ConvertCI8_16, NULL, NULL }, // CI { ConvertCI4_16, ConvertCI8_16, ConvertIA16_16, NULL }, // IA { ConvertCI4_16, ConvertCI8_16, ConvertRGBA16_16, NULL }, // I { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL }, // ? { NULL, NULL, NULL, NULL } // ? }; extern bool conkerSwapHack; void ConvertRGBA16_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 x, y; uint32 nFiddle; // Copy of the base pointer uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x2; else nFiddle = 0x2 | 0x4; // dwDst points to start of destination row uint16 * wDst = (uint16 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); // DWordOffset points to the current dword we're looking at // (process 2 pixels at a time). May be a problem if we don't start on even pixel uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (x = 0; x < tinfo.WidthToLoad; x++) { uint16 w = *(uint16 *)&pByteSrc[dwWordOffset ^ nFiddle]; wDst[x] = Convert555ToR4G4B4A4(w); // Increment word offset to point to the next two pixels dwWordOffset += 2; } } } else { for (y = 0; y < tinfo.HeightToLoad; y++) { // dwDst points to start of destination row uint16 * wDst = (uint16 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); // DWordOffset points to the current dword we're looking at // (process 2 pixels at a time). May be a problem if we don't start on even pixel uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (x = 0; x < tinfo.WidthToLoad; x++) { uint16 w = *(uint16 *)&pByteSrc[dwWordOffset ^ 0x2]; wDst[x] = Convert555ToR4G4B4A4(w); // Increment word offset to point to the next two pixels dwWordOffset += 2; } } } pTexture->EndUpdate(&dInfo); } void ConvertRGBA32_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 * pSrc = (uint32*)(tinfo.pPhysicalAddress); if (!pTexture->StartUpdate(&dInfo)) return; if( options.bUseFullTMEM ) { Tile &tile = gRDP.tiles[tinfo.tileNo]; uint32 *pWordSrc; if( tinfo.tileNo >= 0 ) { pWordSrc = (uint32*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 * dwDst = (uint16 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); uint32 nFiddle = ( y&1 )? 0x2 : 0; int idx = tile.dwLine*4*y; for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) { uint32 w = pWordSrc[idx^nFiddle]; uint8* psw = (uint8*)&w; dwDst[x] = R4G4B4A4_MAKE( (psw[0]>>4), (psw[1]>>4), (psw[2]>>4), (psw[3]>>4)); } } } } else { if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint8 *pS = (uint8 *)pSrc + (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { *pDst++ = R4G4B4A4_MAKE((pS[3]>>4), // Red (pS[2]>>4), // Green (pS[1]>>4), // Blue (pS[0]>>4)); // Alpha pS+=4; } } else { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint8 *pS = (uint8 *)pSrc + (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4); int n; n = 0; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { *pDst++ = R4G4B4A4_MAKE((pS[(n^0x8) + 3]>>4), // Red (pS[(n^0x8) + 2]>>4), // Green (pS[(n^0x8) + 1]>>4), // Blue (pS[(n^0x8) + 0]>>4)); // Alpha n += 4; } } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint8 *pS = (uint8 *)pSrc + (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { *pDst++ = R4G4B4A4_MAKE((pS[3]>>4), // Red (pS[2]>>4), // Green (pS[1]>>4), // Blue (pS[0]>>4)); // Alpha pS+=4; } } } } pTexture->EndUpdate(&dInfo); } // E.g. Dear Mario text // Copy, Score etc void ConvertIA4_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); // For odd lines, swap words too if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; // This may not work if X is not even? uint32 dwByteOffset = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad/2); // Do two pixels at a time for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; // Even *pDst++ = R4G4B4A4_MAKE(ThreeToFour[(b & 0xE0) >> 5], ThreeToFour[(b & 0xE0) >> 5], ThreeToFour[(b & 0xE0) >> 5], OneToFour[(b & 0x10) >> 4]); // Odd *pDst++ = R4G4B4A4_MAKE(ThreeToFour[(b & 0x0E) >> 1], ThreeToFour[(b & 0x0E) >> 1], ThreeToFour[(b & 0x0E) >> 1], OneToFour[(b & 0x01)] ); dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); // This may not work if X is not even? uint32 dwByteOffset = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad/2); // Do two pixels at a time for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ 0x3]; // Even *pDst++ = R4G4B4A4_MAKE(ThreeToFour[(b & 0xE0) >> 5], ThreeToFour[(b & 0xE0) >> 5], ThreeToFour[(b & 0xE0) >> 5], OneToFour[(b & 0x10) >> 4]); // Odd *pDst++ = R4G4B4A4_MAKE(ThreeToFour[(b & 0x0E) >> 1], ThreeToFour[(b & 0x0E) >> 1], ThreeToFour[(b & 0x0E) >> 1], OneToFour[(b & 0x01)] ); dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } // E.g Mario's head textures void ConvertIA8_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { // For odd lines, swap words too if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint16 *pDst = (uint16 *)((uint8*)dInfo.lpSurface + y * dInfo.lPitch); // Points to current byte uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; *pDst++ = R4G4B4A4_MAKE( ((b&0xf0)>>4),((b&0xf0)>>4),((b&0xf0)>>4),(b&0x0f)); dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); // Points to current byte uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ 0x3]; *pDst++ = R4G4B4A4_MAKE(((b&0xf0)>>4),((b&0xf0)>>4),((b&0xf0)>>4),(b&0x0f)); dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } // E.g. camera's clouds, shadows void ConvertIA16_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; if (!pTexture->StartUpdate(&dInfo)) return; for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); // Points to current word uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint16 w = *(uint16 *)&pByteSrc[dwWordOffset^0x2]; uint8 i = (uint8)(w >> 12); uint8 a = (uint8)(w & 0xFF); *pDst++ = R4G4B4A4_MAKE(i, i, i, (a>>4)); dwWordOffset += 2; } } pTexture->EndUpdate(&dInfo); } // Used by MarioKart void ConvertI4_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); // Might not work with non-even starting X uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); // For odd lines, swap words too if( !conkerSwapHack || (y&4) == 0 ) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; } else { if ((y%2) == 1) nFiddle = 0x3; else nFiddle = 0x7; } for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; // Even //*pDst++ = R4G4B4A4_MAKE(b>>4, b>>4, b>>4, b>>4); *pDst++ = FourToSixteen[(b & 0xF0)>>4]; // Odd //*pDst++ = R4G4B4A4_MAKE(b & 0x0f, b & 0x0f, b & 0x0f, b & 0x0f); *pDst++ = FourToSixteen[b & 0x0f]; dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; // Might not work with non-even starting X uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ 0x3]; // Even //*pDst++ = R4G4B4A4_MAKE(b>>4, b>>4, b>>4, b>>4); *pDst++ = FourToEight[(b & 0xF0)>>4]; // Odd //*pDst++ = R4G4B4A4_MAKE(b & 0x0f, b & 0x0f, b & 0x0f, b & 0x0f); *pDst++ = FourToEight[b & 0x0f]; dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } // Used by MarioKart void ConvertI8_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; long long pSrc = (long long) (tinfo.pPhysicalAddress); if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = *(uint8*)((pSrc+dwByteOffset)^nFiddle); *pDst++ = R4G4B4A4_MAKE(b>>4, b>>4, b>>4, b>>4); dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16*)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = *(uint8*)((pSrc+dwByteOffset)^0x3); *pDst++ = R4G4B4A4_MAKE(b>>4, b>>4, b>>4, b>>4); dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } // Used by Starfox intro void ConvertCI4_RGBA16_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); uint16 * pPal = (uint16 *)tinfo.PalAddress; if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint16 * pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = Convert555ToR4G4B4A4(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = Convert555ToR4G4B4A4(pPal[blo^1]); // Remember palette is in different endian order! pDst+=2; dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 * pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ 0x3]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = Convert555ToR4G4B4A4(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = Convert555ToR4G4B4A4(pPal[blo^1]); // Remember palette is in different endian order! pDst+=2; dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } //***************************************************************************** // Convert CI4 images. We need to switch on the palette type //***************************************************************************** void ConvertCI4_16( CTexture * p_texture, const TxtrInfo & tinfo ) { if ( tinfo.TLutFmt == TLUT_FMT_RGBA16 ) { ConvertCI4_RGBA16_16( p_texture, tinfo ); } else if ( tinfo.TLutFmt == TLUT_FMT_IA16 ) { ConvertCI4_IA16_16( p_texture, tinfo ); } } //***************************************************************************** // Convert CI8 images. We need to switch on the palette type //***************************************************************************** void ConvertCI8_16( CTexture * p_texture, const TxtrInfo & tinfo ) { if ( tinfo.TLutFmt == TLUT_FMT_RGBA16 ) { ConvertCI8_RGBA16_16( p_texture, tinfo ); } else if ( tinfo.TLutFmt == TLUT_FMT_IA16 ) { ConvertCI8_IA16_16( p_texture, tinfo ); } } // Used by Starfox intro void ConvertCI4_IA16_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); uint16 * pPal = (uint16 *)tinfo.PalAddress; if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint16 * pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = ConvertIA16ToR4G4B4A4(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = ConvertIA16ToR4G4B4A4(pPal[blo^1]); // Remember palette is in different endian order! pDst += 2; dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 * pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) { uint8 b = pSrc[dwByteOffset ^ 0x3]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); pDst[0] = ConvertIA16ToR4G4B4A4(pPal[bhi^1]); // Remember palette is in different endian order! pDst[1] = ConvertIA16ToR4G4B4A4(pPal[blo^1]); // Remember palette is in different endian order! pDst+=2; dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } // Used by MarioKart for Cars etc void ConvertCI8_RGBA16_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); uint16 * pPal = (uint16 *)tinfo.PalAddress; if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint16 *pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; *pDst++ = Convert555ToR4G4B4A4(pPal[b^1]); // Remember palette is in different endian order! dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ 0x3]; *pDst++ = Convert555ToR4G4B4A4(pPal[b^1]); // Remember palette is in different endian order! dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } // Used by MarioKart for Cars etc void ConvertCI8_IA16_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; uint32 nFiddle; uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); uint16 * pPal = (uint16 *)tinfo.PalAddress; if (!pTexture->StartUpdate(&dInfo)) return; if (tinfo.bSwapped) { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; uint16 *pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ nFiddle]; *pDst++ = ConvertIA16ToR4G4B4A4(pPal[b^1]); // Remember palette is in different endian order! dwByteOffset++; } } } else { for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 *pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++) { uint8 b = pSrc[dwByteOffset ^ 0x3]; *pDst++ = ConvertIA16ToR4G4B4A4(pPal[b^1]); // Remember palette is in different endian order! dwByteOffset++; } } } pTexture->EndUpdate(&dInfo); } void ConvertYUV_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; uint32 x, y; uint32 nFiddle; if( options.bUseFullTMEM ) { Tile &tile = gRDP.tiles[tinfo.tileNo]; uint16 * pSrc; if( tinfo.tileNo >= 0 ) pSrc = (uint16*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; else pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; for (y = 0; y < tinfo.HeightToLoad; y++) { nFiddle = ( y&1 )? 0x4 : 0; int dwWordOffset = tinfo.tileNo>=0? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); uint16 * wDst = (uint16 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); for (x = 0; x < tinfo.WidthToLoad/2; x++) { int y0 = *(uint8*)&pByteSrc[(dwWordOffset+1)^nFiddle]; int y1 = *(uint8*)&pByteSrc[(dwWordOffset+3)^nFiddle]; int u0 = *(uint8*)&pByteSrc[(dwWordOffset )^nFiddle]; int v0 = *(uint8*)&pByteSrc[(dwWordOffset+2)^nFiddle]; wDst[x*2+0] = ConvertYUV16ToR4G4B4(y0,u0,v0); wDst[x*2+1] = ConvertYUV16ToR4G4B4(y1,u0,v0); dwWordOffset += 4; } } } else { // Copy of the base pointer uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress); uint8 * pByteSrc = (uint8 *)pSrc; if (tinfo.bSwapped) { for (y = 0; y < tinfo.HeightToLoad; y++) { if ((y%2) == 0) nFiddle = 0x2; else nFiddle = 0x2 | 0x4; // dwDst points to start of destination row uint16 * wDst = (uint16 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); // DWordOffset points to the current dword we're looking at // (process 2 pixels at a time). May be a problem if we don't start on even pixel uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (x = 0; x < tinfo.WidthToLoad/2; x++) { uint32 y0 = *(uint8*)&pByteSrc[(dwWordOffset+1)^nFiddle]; uint32 y1 = *(uint8*)&pByteSrc[(dwWordOffset+3)^nFiddle]; uint32 u0 = *(uint8*)&pByteSrc[(dwWordOffset )^nFiddle]; uint32 v0 = *(uint8*)&pByteSrc[(dwWordOffset+2)^nFiddle]; wDst[x*2+0] = ConvertYUV16ToR4G4B4(y0,u0,v0); wDst[x*2+1] = ConvertYUV16ToR4G4B4(y1,u0,v0); dwWordOffset += 4; } } } else { for (y = 0; y < tinfo.HeightToLoad; y++) { // dwDst points to start of destination row uint16 * wDst = (uint16 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); // DWordOffset points to the current dword we're looking at // (process 2 pixels at a time). May be a problem if we don't start on even pixel uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); for (x = 0; x < tinfo.WidthToLoad/2; x++) { uint32 y0 = *(uint8*)&pByteSrc[(dwWordOffset+1)^3]; uint32 y1 = *(uint8*)&pByteSrc[(dwWordOffset+3)^3]; uint32 u0 = *(uint8*)&pByteSrc[(dwWordOffset )^3]; uint32 v0 = *(uint8*)&pByteSrc[(dwWordOffset+2)^3]; wDst[x*2+0] = ConvertYUV16ToR4G4B4(y0,u0,v0); wDst[x*2+1] = ConvertYUV16ToR4G4B4(y1,u0,v0); dwWordOffset += 4; } } } } pTexture->EndUpdate(&dInfo); } uint16 ConvertYUV16ToR4G4B4(int Y, int U, int V) { uint32 A=1; uint32 R1 = Y + g_convk0 * V; uint32 G1 = Y + g_convk1 * U + g_convk2 * V; uint32 B1 = Y + g_convk3 * U; uint32 R = (R1 - g_convk4) * g_convk5 + R1; uint32 G = (G1 - g_convk4) * g_convk5 + G1; uint32 B = (B1 - g_convk4) * g_convk5 + B1; return (uint16)R4G4B4A4_MAKE((R>>4), (G>>4), (B>>4), 0xF*A); } // Used by Starfox intro void Convert4b_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); if( tinfo.Format <= TXT_FMT_CI ) bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); Tile &tile = gRDP.tiles[tinfo.tileNo]; uint8 *pByteSrc = tinfo.tileNo >= 0 ? (uint8*)&g_Tmem.g_Tmem64bit[tile.dwTMem] : (uint8*)(tinfo.pPhysicalAddress); for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 * pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 nFiddle; if( tinfo.tileNo < 0 ) { if (tinfo.bSwapped) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; } else { nFiddle = 3; } } else { nFiddle = ( y&1 )? 0x4 : 0; } int idx = tinfo.tileNo>=0 ? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2, idx++) { uint8 b = pByteSrc[idx^nFiddle]; uint8 bhi = (b&0xf0)>>4; uint8 blo = (b&0x0f); if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) ) { if( tinfo.TLutFmt == TLUT_FMT_IA16 ) { if( tinfo.tileNo>=0 ) { pDst[0] = ConvertIA16ToR4G4B4A4(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); pDst[1] = ConvertIA16ToR4G4B4A4(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(blo<<2)]); } else { pDst[0] = ConvertIA16ToR4G4B4A4(pPal[bhi^1]); pDst[1] = ConvertIA16ToR4G4B4A4(pPal[blo^1]); } } else { if( tinfo.tileNo>=0 ) { pDst[0] = Convert555ToR4G4B4A4(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); pDst[1] = Convert555ToR4G4B4A4(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(blo<<2)]); } else { pDst[0] = Convert555ToR4G4B4A4(pPal[bhi^1]); pDst[1] = Convert555ToR4G4B4A4(pPal[blo^1]); } } } else if( tinfo.Format == TXT_FMT_IA ) { pDst[0] = ConvertIA4ToR4G4B4A4(b>>4); pDst[1] = ConvertIA4ToR4G4B4A4(b&0xF); } else //if( tinfo.Format == TXT_FMT_I ) { pDst[0] = ConvertI4ToR4G4B4A4(b>>4); pDst[1] = ConvertI4ToR4G4B4A4(b&0xF); } if( bIgnoreAlpha ) { pDst[0] |= 0xF000; pDst[1] |= 0xF000; } pDst+=2; } } pTexture->EndUpdate(&dInfo); } void Convert8b_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; uint16 * pPal = (uint16 *)tinfo.PalAddress; bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); if( tinfo.Format <= TXT_FMT_CI ) bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); Tile &tile = gRDP.tiles[tinfo.tileNo]; uint8 *pByteSrc; if( tinfo.tileNo >= 0 ) pByteSrc = (uint8*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; else pByteSrc = (uint8*)(tinfo.pPhysicalAddress); for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 * pDst = (uint16 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); uint32 nFiddle; if( tinfo.tileNo < 0 ) { if (tinfo.bSwapped) { if ((y%2) == 0) nFiddle = 0x3; else nFiddle = 0x7; } else { nFiddle = 3; } } else { nFiddle = ( y&1 )? 0x4 : 0; } int idx = tinfo.tileNo>=0? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) { uint8 b = pByteSrc[idx^nFiddle]; if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) ) { if( tinfo.TLutFmt == TLUT_FMT_IA16 ) { if( tinfo.tileNo>=0 ) *pDst = ConvertIA16ToR4G4B4A4(g_Tmem.g_Tmem16bit[0x400+(b<<2)]); else *pDst = ConvertIA16ToR4G4B4A4(pPal[b^1]); } else { if( tinfo.tileNo>=0 ) *pDst = Convert555ToR4G4B4A4(g_Tmem.g_Tmem16bit[0x400+(b<<2)]); else *pDst = Convert555ToR4G4B4A4(pPal[b^1]); } } else if( tinfo.Format == TXT_FMT_IA ) { *pDst = R4G4B4A4_MAKE( ((b&0xf0)>>4),((b&0xf0)>>4),((b&0xf0)>>4),(b&0x0f)); } else //if( tinfo.Format == TXT_FMT_I ) { *pDst = R4G4B4A4_MAKE(b>>4, b>>4, b>>4, b>>4); } if( bIgnoreAlpha ) { *pDst |= 0xFF000000; } pDst++; } } pTexture->EndUpdate(&dInfo); } void Convert16b_16(CTexture *pTexture, const TxtrInfo &tinfo) { DrawInfo dInfo; if (!pTexture->StartUpdate(&dInfo)) return; Tile &tile = gRDP.tiles[tinfo.tileNo]; uint16 *pWordSrc; if( tinfo.tileNo >= 0 ) pWordSrc = (uint16*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; else pWordSrc = (uint16*)(tinfo.pPhysicalAddress); for (uint32 y = 0; y < tinfo.HeightToLoad; y++) { uint16 * dwDst = (uint16 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); uint32 nFiddle; if( tinfo.tileNo < 0 ) { if (tinfo.bSwapped) { if ((y&1) == 0) nFiddle = 0x1; else nFiddle = 0x3; } else { nFiddle = 0x1; } } else { nFiddle = ( y&1 )? 0x2 : 0; } int idx = tinfo.tileNo>=0? tile.dwLine*4*y : (((y+tinfo.TopToLoad) * tinfo.Pitch)>>1) + tinfo.LeftToLoad; for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) { uint16 w = pWordSrc[idx^nFiddle]; uint16 w2 = tinfo.tileNo>=0? ((w>>8)|(w<<8)) : w; if( tinfo.Format == TXT_FMT_RGBA ) { dwDst[x] = Convert555ToR4G4B4A4(w2); } else if( tinfo.Format == TXT_FMT_YUV ) { } else if( tinfo.Format >= TXT_FMT_IA ) { uint8 i = (uint8)(w2 >> 12); uint8 a = (uint8)(w2 & 0xFF); dwDst[x] = R4G4B4A4_MAKE(i, i, i, (a>>4)); } } } pTexture->EndUpdate(&dInfo); } mupen64plus-video-rice-src-2.6.0/src/CritSect.h000066400000000000000000000023361464507324400212270ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if !defined(CRITSECT_H) #define CRITSECT_H #include class CCritSect { public: CCritSect() { cs = SDL_CreateMutex(); locked = 0; } ~CCritSect() { SDL_DestroyMutex(cs); } void Lock() { SDL_LockMutex(cs); locked = 1; } void Unlock() { locked = 0; SDL_UnlockMutex(cs); } bool IsLocked() { return (locked != 0); } protected: SDL_mutex *cs; int locked; }; #endif // !defined(CRITSECT_H) mupen64plus-video-rice-src-2.6.0/src/Debugger.cpp000066400000000000000000000535261464507324400215750ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define M64P_PLUGIN_PROTOTYPES 1 #include "m64p_plugin.h" #include "osal_preproc.h" #include "typedefs.h" #ifndef DEBUGGER void __cdecl DebuggerAppendMsg(const char * Message, ...) {} #else void DumpMatrix2(const Matrix &mtx, const char* prompt); bool debuggerWinOpened = false; bool debuggerDrawRenderTexture = false; int debuggerDrawRenderTextureNo = 0; bool logCombiners = false; bool logWarning = true; bool logTriangles = false; bool logMatrix = false; bool logVertex = false; bool logTextures = false; bool logTextureBuffer = false; bool logToScreen = true; bool logToFile = false; bool logUcodes = false; bool logMicrocode = false; bool logFog = false; bool logDetails = false; FILE *logFp = NULL; bool debuggerEnableTexture=true; bool debuggerEnableZBuffer=true; bool debuggerEnableCullFace=true; bool debuggerEnableTestTris=true; bool debuggerEnableAlphaTest=true; bool debuggerContinueWithUnknown=false; bool debuggerPause = false; bool pauseAtNext = true; int eventToPause = NEXT_FRAME; int debuggerPauseCount = 340; int countToPause = 1; bool debuggerDropCombiners=false; bool debuggerDropGeneralCombiners=false; bool debuggerDropDecodedMux=false; bool debuggerDropCombinerInfos=false; char msgBuf[0x20000+2]; bool msgBufUpdated = false; extern FiddledVtx * g_pVtxBase; uint32 CachedTexIndex = 0; const char* otherNexts[] = { "Frame", "Flush Tri", "TextRect", "Triangle", "Set CImg", "ObjTxt Cmd", "Obj BG", "Sprite2D", "FillRect", "DList", "Ucode", "Texture Buffer", "Matrix Cmd", "Vertex Cmd", "New Texture", "Set Texture", "Mux", "Set Light", "Set Mode Cmd", "Set Prim Color", "Texture Cmd", "Unknown Ops", "Scale Image", "LoadTlut", "Ucode Switching", }; int numberOfNextOthers = sizeof(otherNexts)/sizeof(char*); const char* thingsToDump[] = { "Cur Texture RGBA", "Cur+1 Texture RGBA", "Colors", "Memory At", "Mux", "Simple Mux", "Other Modes", "Texture #", "Tile #", "VI Regs", "Cur Txt to file", "Cur+1 Txt to file", "Cur Texture RGB", "Cur Texture Alpha", "Cur+1 Texture RGB", "Cur+1 Texture Alpha", "Light Info", "Tlut", "Obj Tlut", "Vertexes", "Cached Texture", "Next Texture", "Prev Texture", "Dlist At", "Matrix At", "Combined Matrix", "World Top Matrix", "Projection Matrix", "World Matrix #", "Frame Buffer in RDRAM", "BackBuffer", "TexBuffer #", }; int numberOfThingsToDump = sizeof(thingsToDump)/sizeof(char*); enum { DUMP_CUR_TEXTURE_RGBA, DUMP_CUR_1_TEXTURE_RGBA, DUMP_COLORS, DUMP_CONTENT_AT, DUMP_CUR_MUX, DUMP_SIMPLE_MUX, DUMP_OTHER_MODE, DUMP_TEXTURE_AT, DUMP_TILE_AT, DUMP_VI_REGS, DUMP_CUR_TEXTURE_TO_FILE, DUMP_CUR_1_TEXTURE_TO_FILE, DUMP_CUR_TEXTURE_RGB, DUMP_CUR_TEXTURE_ALPHA, DUMP_CUR_1_TEXTURE_RGB, DUMP_CUR_1_TEXTURE_ALPHA, DUMP_LIGHT, DUMP_TLUT, DUMP_OBJ_TLUT, DUMP_VERTEXES, DUMP_CACHED_TEX, DUMP_NEXT_TEX, DUMP_PREV_TEX, DUMP_DLIST_AT, DUMP_MATRIX_AT, DUMP_COMBINED_MATRIX, DUMP_WORLD_TOP_MATRIX, DUMP_PROJECTION_MATRIX, DUMP_WORLD_MATRIX_AT, DUMP_FRAME_BUFFER, DUMP_BACKBUFFER, DUMP_TEXBUFFER_AT, }; //--------------------------------------------------------------------- void DumpVIRegisters(void) { DebuggerAppendMsg("----VI Registers----\nSTATUS:\t%08X\nORIGIN:\t%08X\nWIDTH:\t%08X\n\ V_SYNC:\t%08X\nH_SYNC:\t%08X\nX_SCALE:\t%08X\nY_SCALE:\t%08X\n\ H_START:\t%08X\nV_START:\t%08X\nVI Width=%f(x %f), VI Height=%f(x %f)\n\n", *g_GraphicsInfo.VI_STATUS_REG, *g_GraphicsInfo.VI_ORIGIN_REG, *g_GraphicsInfo.VI_WIDTH_REG, *g_GraphicsInfo.VI_V_SYNC_REG, *g_GraphicsInfo.VI_H_SYNC_REG, *g_GraphicsInfo.VI_X_SCALE_REG, *g_GraphicsInfo.VI_Y_SCALE_REG, *g_GraphicsInfo.VI_H_START_REG, *g_GraphicsInfo.VI_V_START_REG, windowSetting.fViWidth,windowSetting.fMultX, windowSetting.fViHeight,windowSetting.fMultY); DebuggerAppendMsg("Scissor: x0=%d y0=%d x1=%d y1=%d mode=%d", gRDP.scissor.left, gRDP.scissor.top, gRDP.scissor.right, gRDP.scissor.bottom, gRDP.scissor.mode); DebuggerAppendMsg("Effective scissor: x0=%d y0=%d x1=%d y1=%d", gRSP.real_clip_scissor_left, gRSP.real_clip_scissor_top, gRSP.real_clip_scissor_right, gRSP.real_clip_scissor_bottom); DebuggerAppendMsg("Clipping: (%d) left=%f top=%f right=%f bottom=%f", gRSP.clip_ratio_posx, gRSP.real_clip_ratio_negx , gRSP.real_clip_ratio_negy, gRSP.real_clip_ratio_posx, gRSP.real_clip_ratio_posy); DebuggerAppendMsg("Viewport: left=%d top=%d right=%d bottom=%d", gRSP.nVPLeftN, gRSP.nVPTopN , gRSP.nVPRightN, gRSP.nVPBottomN); DebuggerAppendMsg("Current CImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_CI.dwAddr, pszImgFormat[g_CI.dwFormat], pszImgSize[g_CI.dwSize], g_CI.dwWidth); DebuggerAppendMsg("Current ZImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_ZI.dwAddr, pszImgFormat[g_ZI.dwFormat], pszImgSize[g_ZI.dwSize], g_ZI.dwWidth); } void DumpVertexArray(void) { DebuggerAppendMsg("----Vertexes----\n"); try { for( int i=0; i<32; i++ ) { FiddledVtx &v = g_pVtxBase[i]; DebuggerAppendMsg("[%d] x=%d,y=%d,z=%d -- r=%d,g=%d,b=%d,a=%d\n", i, v.x, v.y, v.z, v.rgba.r, v.rgba.g, v.rgba.b, v.rgba.a); DebuggerAppendMsg("\tx=%f,y=%f,z=%f,rhw=%f\n", g_vecProjected[i].x, g_vecProjected[i].y, g_vecProjected[i].z, g_vecProjected[i].w); } } catch(...) { DebuggerAppendMsg("Invalid memory pointer of vertex array\n"); } } void DumpHex(uint32 rdramAddr, int count); uint32 StrToHex(char *HexStr); void DumpTileInfo(uint32 dwTile) { const char *pszOnOff[2] = {"Off", "On"}; DebuggerAppendMsg("Tile: %d\nFmt: %s/%s Line:%d (Pitch %d) TMem:0x%04x Palette:%d\n", dwTile, pszImgFormat[gRDP.tiles[dwTile].dwFormat], pszImgSize[gRDP.tiles[dwTile].dwSize], gRDP.tiles[dwTile].dwLine, gRDP.tiles[dwTile].dwPitch, gRDP.tiles[dwTile].dwTMem, gRDP.tiles[dwTile].dwPalette); DebuggerAppendMsg("S: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x\n", pszOnOff[gRDP.tiles[dwTile].bClampS],pszOnOff[gRDP.tiles[dwTile].bMirrorS], gRDP.tiles[dwTile].dwMaskS, gRDP.tiles[dwTile].dwShiftS); DebuggerAppendMsg("T: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x\n", pszOnOff[gRDP.tiles[dwTile].bClampT],pszOnOff[gRDP.tiles[dwTile].bMirrorT], gRDP.tiles[dwTile].dwMaskT, gRDP.tiles[dwTile].dwShiftT); DebuggerAppendMsg("(%d,%d) -> (%d,%d), hilite [%d, %d]\n", gRDP.tiles[dwTile].sl, gRDP.tiles[dwTile].tl, gRDP.tiles[dwTile].sh, gRDP.tiles[dwTile].th, gRDP.tiles[dwTile].hilite_sl,gRDP.tiles[dwTile].hilite_tl); } void DumpTexture(int tex, TextureChannel channel = TXT_RGB ) { CRender::GetRender()->DrawTexture(tex, channel); } void DumpRenderTexture(int tex=-1) { debuggerDrawRenderTextureNo = tex; debuggerDrawRenderTexture = true; } void DumpTextureToFile(int tex, TextureChannel channel = TXT_RGB) { CRender::GetRender()->SaveTextureToFile(tex, channel,false); } void DumpTlut(uint16* palAddr) { for( uint32 i=0; i<0x100; i+=8 ) { DebuggerAppendMsg("0x%4X 0x%4X 0x%4X 0x%4X 0x%4X 0x%4X 0x%4X 0x%4X ", g_wRDPTlut[i], g_wRDPTlut[i+1], g_wRDPTlut[i+2], g_wRDPTlut[i+2], g_wRDPTlut[i+4], g_wRDPTlut[i+5], g_wRDPTlut[i+6], g_wRDPTlut[i+7]); } } extern char ucodeNames_GBI1[256]; extern char ucodeNames_GBI2[256]; void DumpDlistAt(uint32 dwPC) { uint32 word0, word1, opcode; char *name; switch( gRSP.ucode ) { case 2: case 10: //case 8: name=ucodeNames_GBI2; break; default: name=ucodeNames_GBI1; } DebuggerAppendMsg("\n\n"); //if( dwPC>100 ) dwPC -= 40; for( uint32 i=0; i<20; i++) { word0 = g_pRDRAMu32[(dwPC>>2)+0]; word1 = g_pRDRAMu32[(dwPC>>2)+1]; opcode = word0>>24; DebuggerAppendMsg("%08X: %08X, %08X - %s", dwPC, word0, word1, name[opcode] ); dwPC+=8; } DebuggerAppendMsg("\n\n"); } void DumpMatrixAt(uint32 dwPC) { Matrix mat; const float fRecip = 1.0f / 65536.0f; for (uint32 dwI = 0; dwI < 4; dwI++) { for (uint32 dwJ = 0; dwJ < 4; dwJ++) { int nDataHi = *(short *)(g_pRDRAMu8 + ((dwPC+(dwI<<3)+(dwJ<<1) )^0x2)); int nDataLo = *(uint16 *)(g_pRDRAMu8 + ((dwPC+(dwI<<3)+(dwJ<<1) + 32)^0x2)); mat.m[dwI][dwJ] = (float)((nDataHi << 16) | nDataLo) * fRecip; } } TRACE0("Dump Matrix in Memory"); DebuggerAppendMsg( " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n", mat.m[0][0], mat.m[0][1], mat.m[0][2], mat.m[0][3], mat.m[1][0], mat.m[1][1], mat.m[1][2], mat.m[1][3], mat.m[2][0], mat.m[2][1], mat.m[2][2], mat.m[2][3], mat.m[3][0], mat.m[3][1], mat.m[3][2], mat.m[3][3]); } // High static const char *alphadithertypes[4] = {"Pattern", "NotPattern", "Noise", "Disable"}; static const char *rgbdithertype[4] = {"MagicSQ", "Bayer", "Noise", "Disable"}; static const char *convtype[8] = {"Conv", "?", "?", "?", "?", "FiltConv", "Filt", "?"}; static const char *filtertype[4] = {"Point", "?", "Bilinear", "Average"}; static const char *cycletype[4] = {"1Cycle", "2Cycle", "Copy", "Fill"}; static const char *alphacomptype[4] = {"None", "Threshold", "?", "Dither"}; static const char * szCvgDstMode[4] = { "Clamp", "Wrap", "Full", "Save" }; static const char * szZMode[4] = { "Opa", "Inter", "XLU", "Decal" }; static const char * szZSrcSel[2] = { "Pixel", "Primitive" }; static const char * sc_szBlClr[4] = { "In", "Mem", "Bl", "Fog" }; static const char * sc_szBlA1[4] = { "AIn", "AFog", "AShade", "0" }; static const char * sc_szBlA2[4] = { "1-A", "AMem", "1", "0" }; void DumpOtherMode() { uint16 blender = gRDP.otherMode.blender; RDP_BlenderSetting &bl = *(RDP_BlenderSetting*)(&(blender)); DebuggerAppendMsg( "Other Modes"); DebuggerAppendMsg( "\talpha_compare:\t%s", alphacomptype[ gRDP.otherMode.alpha_compare ]); DebuggerAppendMsg( "\tdepth_source:\t%s", szZSrcSel[ gRDP.otherMode.depth_source ]); DebuggerAppendMsg( "\taa_en:\t\t%d", gRDP.otherMode.aa_en ); DebuggerAppendMsg( "\tz_cmp:\t\t%d", gRDP.otherMode.z_cmp ); DebuggerAppendMsg( "\tz_upd:\t\t%d", gRDP.otherMode.z_upd ); DebuggerAppendMsg( "\tim_rd:\t\t%d", gRDP.otherMode.im_rd ); DebuggerAppendMsg( "\tclr_on_cvg:\t%d", gRDP.otherMode.clr_on_cvg ); DebuggerAppendMsg( "\tcvg_dst:\t\t%s", szCvgDstMode[ gRDP.otherMode.cvg_dst ] ); DebuggerAppendMsg( "\tzmode:\t\t%s", szZMode[ gRDP.otherMode.zmode ] ); DebuggerAppendMsg( "\tcvg_x_alpha:\t%d", gRDP.otherMode.cvg_x_alpha ); DebuggerAppendMsg( "\talpha_cvg_sel:\t%d", gRDP.otherMode.alpha_cvg_sel ); DebuggerAppendMsg( "\tforce_bl:\t\t%d", gRDP.otherMode.force_bl ); DebuggerAppendMsg( "\ttex_edge:\t\t%d", gRDP.otherMode.tex_edge ); DebuggerAppendMsg( "\tblender:\t\t%04x - Cycle1:\t%s * %s + %s * %s\n\t\t\tCycle2:\t%s * %s + %s * %s", gRDP.otherMode.blender, sc_szBlClr[bl.c1_m1a], sc_szBlA1[bl.c1_m1b], sc_szBlClr[bl.c1_m2a], sc_szBlA2[bl.c1_m2b], sc_szBlClr[bl.c2_m1a], sc_szBlA1[bl.c2_m1b], sc_szBlClr[bl.c2_m2a], sc_szBlA2[bl.c2_m2b]); DebuggerAppendMsg( "\tblend_mask:\t%d", gRDP.otherMode.blend_mask ); DebuggerAppendMsg( "\talpha_dither:\t%s", alphadithertypes[ gRDP.otherMode.alpha_dither ] ); DebuggerAppendMsg( "\trgb_dither:\t\t%s", rgbdithertype[ gRDP.otherMode.rgb_dither ] ); DebuggerAppendMsg( "\tcomb_key:\t%s", gRDP.otherMode.key_en ? "Key" : "None" ); DebuggerAppendMsg( "\ttext_conv:\t\t%s", convtype[ gRDP.otherMode.text_conv ] ); DebuggerAppendMsg( "\ttext_filt:\t\t%s", filtertype[ gRDP.otherMode.text_filt ] ); DebuggerAppendMsg( "\ttext_tlut:\t\t%s", textluttype[ gRDP.otherMode.text_tlut ] ); DebuggerAppendMsg( "\ttext_lod:\t\t%s", gRDP.otherMode.text_lod ? "Yes": "No" ); DebuggerAppendMsg( "\ttext_detail:\t\t%s", gRDP.otherMode.text_detail ? "Yes": "No" ); DebuggerAppendMsg( "\ttext_sharpen:\t\t%s", gRDP.otherMode.text_sharpen ? "Yes": "No" ); DebuggerAppendMsg( "\ttext_persp:\t%s", gRDP.otherMode.text_persp ? "On" : "Off" ); DebuggerAppendMsg( "\tcycle_type:\t%s", cycletype[ gRDP.otherMode.cycle_type ] ); DebuggerAppendMsg( "\tpipeline:\t\t%s", gRDP.otherMode.atomic_prim ? "1Primitive" : "NPrimitive" ); DebuggerAppendMsg("\n\nSP render flags:"); DebuggerAppendMsg("\tCull mode: %s%s", gRSP.bCullFront?"Cull Front":"", gRSP.bCullBack?" Cull Back":""); DebuggerAppendMsg("\tShade mode: %d", gRSP.shadeMode); DebuggerAppendMsg("\tFog: %s", gRSP.bFogEnabled?"enabled":"disabled"); DebuggerAppendMsg("\tZbuffer in SP: %s", gRSP.bZBufferEnabled?"enabled":"disabled"); DebuggerAppendMsg("\tLighting: %s", gRSP.bLightingEnable?"enabled":"disabled"); DebuggerAppendMsg("\\Number of lights: %d", gRSPnumLights); DebuggerAppendMsg("\tTexture Gen: %s", gRSP.bTextureGen?"enabled":"disabled"); DebuggerAppendMsg("\tTexture Gen Linear: %s", (gRDP.geometryMode & G_TEXTURE_GEN_LINEAR)?"enabled":"disabled"); } void DumpCachedTexture(uint32 index) { TxtrCacheEntry *p = gTextureManager.GetCachedTexture(index); if( p != NULL ) { char filename[80]; sprintf(filename,"\\Texture%d_rgb", index); CRender::GetRender()->SaveTextureToFile(*(p->pTexture), filename, TXT_RGB); DebuggerAppendMsg("Display cached texture #%d of %d\n", index, gTextureManager.GetNumOfCachedTexture()); DebuggerAppendMsg("W:%d, H:%d, RealW:%d, RealH:%d, D3DW:%d, D3DH: %d", p->ti.WidthToCreate, p->ti.HeightToCreate, p->ti.WidthToLoad, p->ti.HeightToLoad, p->pTexture->m_dwCreatedTextureWidth, p->pTexture->m_dwCreatedTextureHeight); } else { DebuggerAppendMsg("No cached texture at index = %d\n", index); } } extern uint32 gObjTlutAddr; void DumpInfo(int thingToDump) { switch(thingToDump) { case DUMP_COLORS: DebuggerAppendMsg("----Colors----\nPrim Color:\t%08X\nEnv Color:\t%08X\n" "Fill Color:\t%08X\nFog Color:\t%08X\n" "Prim Depth:\t%f\nPrim LOD Frac:\t%08X\n", GetPrimitiveColor(), GetEnvColor(), gRDP.fillColor, CRender::GetRender()->GetFogColor(), GetPrimitiveDepth(), GetLODFrac()); break; case DUMP_CUR_MUX: CRender::GetRender()->m_pColorCombiner->DisplayMuxString(); break; case DUMP_LIGHT: DebuggerAppendMsg("----Light Colors----\nNumber of Lights: %d\n",GetNumLights()); for( uint32 i=0; im_pColorCombiner->DisplaySimpleMuxString(); break; case DUMP_OTHER_MODE: DumpOtherMode(); break; case DUMP_FRAME_BUFFER: CRender::GetRender()->DrawFrameBuffer(true); break; case DUMP_CONTENT_AT: { } break; case DUMP_DLIST_AT: { } break; case DUMP_MATRIX_AT: { } break; case DUMP_NEXT_TEX: CachedTexIndex++; if( CachedTexIndex >= gTextureManager.GetNumOfCachedTexture() ) { CachedTexIndex = 0; } DumpCachedTexture(CachedTexIndex); break; case DUMP_PREV_TEX: CachedTexIndex--; if( CachedTexIndex < 0 || CachedTexIndex >= gTextureManager.GetNumOfCachedTexture() ) CachedTexIndex = 0; DumpCachedTexture(CachedTexIndex); break; case DUMP_CACHED_TEX: DumpCachedTexture(CachedTexIndex); break; case DUMP_TEXBUFFER_AT: { } break; case DUMP_COMBINED_MATRIX: DumpMatrix2(gRSPworldProject,"Combined Matrix"); break; case DUMP_WORLD_TOP_MATRIX: DumpMatrix2(gRSP.modelviewMtxs[gRSP.modelViewMtxTop],"World Top Matrix"); break; case DUMP_WORLD_MATRIX_AT: { } break; case DUMP_PROJECTION_MATRIX: DumpMatrix2(gRSP.projectionMtxs[gRSP.projectionMtxTop],"Projection Top Matrix"); break; } } void SetLogToFile(bool log) { if( log ) { if( logFp == NULL ) { logFp = fopen("\\RiceVideo.log", "at"); } } else { if( logFp != NULL ) { fclose(logFp); logFp = NULL; } } } void __cdecl DebuggerAppendMsg(const char * Message, ...) { if( !logToScreen && !logToFile ) return; char Msg[5000]; va_list ap; va_start( ap, Message ); vsprintf( Msg, Message, ap ); va_end( ap ); if( Msg[strlen(Msg)-1]!='\n' ) strcat(Msg,"\n"); if( logToScreen ) { DebugMessage(M64MSG_INFO, "Rice Debug: %s", Msg); } if( logToFile ) { fprintf(logFp, "%s\n", Msg); } } void DebuggerPause() { while( debuggerPause ) { if( debuggerDrawRenderTexture ) { g_pFrameBufferManager->DisplayRenderTexture(debuggerDrawRenderTextureNo); debuggerDrawRenderTexture = false; } usleep(100 * 1000); debuggerPause = false; } } void __cdecl LOG_UCODE(const char* szFormat, ...) { if( logUcodes) { char Msg[400]; va_list va; va_start(va, szFormat); vsprintf( Msg, szFormat, va ); va_end(va); DebuggerAppendMsg("%s\n", Msg); } } void DumpHex(uint32 rdramAddr, int count) { rdramAddr &= 0xFFFFFFF0; uint32 *ptr = (uint32 *)((rdramAddr&(g_dwRamSize-1))+g_pRDRAMu8); for( int i=0; i<(count+3)/4; i++) { DebuggerAppendMsg("%08X: %08X, %08X, %08X, %08X\n", rdramAddr+i*16, ptr[i*4], ptr[i*4+1], ptr[i*4+2], ptr[i*4+3]); } DebuggerAppendMsg("\n"); } uint32 StrToHex(char *HexStr) { uint32 temp = 0; for(uint32 k = 0; k < strlen(HexStr); k++) { if(HexStr[k] <= '9' && HexStr[k] >= '0') { temp = temp << 4; temp += HexStr[k] - '0'; } else if(HexStr[k] <= 'F' && HexStr[k] >= 'A') { temp = temp << 4; temp += HexStr[k] - 'A' + 10; } else if(HexStr[k] <= 'f' && HexStr[k] >= 'a') { temp = temp << 4; temp += HexStr[k] - 'a' + 10; } else { return(temp); } } return(temp); } void DEBUGGER_PAUSE_COUNT_N(uint32 val) { if (eventToPause == (int)val) { if(debuggerPauseCount>0) debuggerPauseCount--; if(debuggerPauseCount==0) { CGraphicsContext::Get()->UpdateFrame(); debuggerPause = true; } } } void DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(uint32 val) { if(eventToPause == (int)val) { if(debuggerPauseCount>0) debuggerPauseCount--; if(debuggerPauseCount==0) { debuggerPauseCount = countToPause; debuggerPause = true; } } } void DumpMatrix2(const Matrix &mat, const char* prompt) { DebuggerAppendMsg(prompt); DebuggerAppendMsg( " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\n", mat.m[0][0], mat.m[0][1], mat.m[0][2], mat.m[0][3], mat.m[1][0], mat.m[1][1], mat.m[1][2], mat.m[1][3], mat.m[2][0], mat.m[2][1], mat.m[2][2], mat.m[2][3], mat.m[3][0], mat.m[3][1], mat.m[3][2], mat.m[3][3]); } void DumpMatrix(const Matrix &mat, const char* prompt) { if( pauseAtNext && logMatrix ) { DumpMatrix2(mat, prompt); } } #endif mupen64plus-video-rice-src-2.6.0/src/Debugger.h000066400000000000000000000173221464507324400212340ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if !defined(DEBUGGER_H) #define DEBUGGER_H #if defined(__GNUC__) #define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos))) #else #define ATTR_FMT(fmtpos, attrpos) #endif #include "typedefs.h" #if defined(DEBUGGER) // Debugger.h : header file // ///////////////////////////////////////////////////////////////////////////// // CDebugger dialog extern bool debuggerWinOpened; extern bool logCombiners; extern bool logTriangles; extern bool logVertex; extern bool logWarning; extern bool logTextures; extern bool logTextureBuffer; extern bool logMatrix; extern bool logToScreen; extern bool logToFile; extern bool logUcodes; extern bool logMicrocode; extern bool logFog; extern bool logDetails; extern bool debuggerEnableTexture; extern bool debuggerEnableZBuffer; extern bool debuggerEnableCullFace; extern bool debuggerEnableTestTris; extern bool debuggerEnableAlphaTest; extern bool debuggerContinueWithUnknown; extern bool debuggerPause; extern bool pauseAtNext; extern int eventToPause; extern int debuggerPauseCount; extern int countToPause; extern bool debuggerDropCombiners; extern bool debuggerDropGeneralCombiners; extern bool debuggerDropDecodedMux; extern bool debuggerDropCombinerInfos; enum { NEXT_FRAME, NEXT_FLUSH_TRI, NEXT_TEXTRECT, NEXT_TRIANGLE, NEXT_SET_CIMG, NEXT_OBJ_TXT_CMD, NEXT_OBJ_BG, NEXT_SPRITE_2D, NEXT_FILLRECT, NEXT_DLIST, NEXT_UCODE, NEXT_RENDER_TEXTURE, NEXT_MATRIX_CMD, NEXT_VERTEX_CMD, NEXT_NEW_TEXTURE, NEXT_SET_TEXTURE, NEXT_MUX, NEXT_SET_LIGHT, NEXT_SET_MODE_CMD, NEXT_SET_PRIM_COLOR, NEXT_TEXTURE_CMD, NEXT_UNKNOWN_OP, NEXT_SCALE_IMG, NEXT_LOADTLUT, NEXT_SWITCH_UCODE, }; void DebuggerPause(); void __cdecl DebuggerAppendMsg(const char * Message, ...) ATTR_FMT(1,2); void DumpHex(uint32 rdramAddr, int count); void DumpMatrix(const Matrix &mtx, const char* prompt); //Some common used macros #define DEBUG_DUMP_VERTEXES(str, v0, v1, v2) \ if( (pauseAtNext && (eventToPause == NEXT_TRIANGLE || eventToPause == NEXT_FLUSH_TRI)) && logTriangles ) \ { \ DebuggerAppendMsg("%s:%d(%08X),%d(%08X),%d(%08X)\n", (str),\ (v0), GetVertexDiffuseColor((v0)), \ (v1), GetVertexDiffuseColor((v1)), \ (v2), GetVertexDiffuseColor((v2))); \ } #define DEBUGGER_IF(op) if(op) #define DEBUGGER_PAUSE(op) if(pauseAtNext && eventToPause == op){pauseAtNext = false;CGraphicsContext::Get()->UpdateFrame(); debuggerPause = true;} extern void DEBUGGER_PAUSE_COUNT_N(uint32 event); extern void DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(uint32 val); #define DebuggerPauseCountN DEBUGGER_PAUSE_COUNT_N #define DEBUGGER_PAUSE_AND_DUMP(op,dumpfuc) \ if(pauseAtNext && eventToPause == op) \ { pauseAtNext = false;debuggerPause = true; CGraphicsContext::Get()->UpdateFrame(); dumpfuc;} #define DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(op,dumpfuc) \ if(pauseAtNext && eventToPause == op) \ { pauseAtNext = false;debuggerPause = true; dumpfuc;} #define DEBUGGER_PAUSE_AND_DUMP_COUNT_N(op,dumpfuc) \ if(pauseAtNext && eventToPause == op) \ { if( debuggerPauseCount > 0 ) debuggerPauseCount--; if( debuggerPauseCount == 0 ){pauseAtNext = false;debuggerPause = true; CGraphicsContext::Get()->UpdateFrame(); dumpfuc;}} #define DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N(cond,dumpfuc) \ if(pauseAtNext && (cond) ) \ { if( debuggerPauseCount > 0 ) debuggerPauseCount--; if( debuggerPauseCount == 0 ){pauseAtNext = false;debuggerPause = true; CGraphicsContext::Get()->UpdateFrame(); dumpfuc;}} void RDP_NOIMPL_Real(const char* op,uint32,uint32) ; #define RSP_RDP_NOIMPL RDP_NOIMPL_Real #define DEBUGGER_IF_DUMP(cond, dumpfunc) {if(cond) {dumpfunc}} #define TXTRBUF_DUMP(dumpfunc) DEBUGGER_IF_DUMP((logTextureBuffer), dumpfunc) #define TXTRBUF_DETAIL_DUMP(dumpfunc) DEBUGGER_IF_DUMP((logTextureBuffer&&logDetails), dumpfunc) #define TXTRBUF_OR_CI_DUMP(dumpfunc) DEBUGGER_IF_DUMP((logTextureBuffer || (pauseAtNext && eventToPause == NEXT_SET_CIMG)), dumpfunc) #define TXTRBUF_OR_CI_DETAIL_DUMP(dumpfunc) DEBUGGER_IF_DUMP(((logTextureBuffer || (pauseAtNext && eventToPause == NEXT_SET_CIMG))&&logDetails), dumpfunc) #define VTX_DUMP(dumpfunc) DEBUGGER_IF_DUMP((logVertex && pauseAtNext), dumpfunc) #define TRI_DUMP(dumpfunc) DEBUGGER_IF_DUMP((logTriangles && pauseAtNext), dumpfunc) #define LIGHT_DUMP(dumpfunc) DEBUGGER_IF_DUMP((eventToPause == NEXT_SET_LIGHT && pauseAtNext), dumpfunc) #define WARNING(dumpfunc) DEBUGGER_IF_DUMP(logWarning, dumpfunc) #define FOG_DUMP(dumpfunc) DEBUGGER_IF_DUMP(logFog, dumpfunc) #define LOG_TEXTURE(dumpfunc) DEBUGGER_IF_DUMP((logTextures || (pauseAtNext && eventToPause==NEXT_TEXTURE_CMD) ), dumpfunc) #define DEBUGGER_ONLY_IF DEBUGGER_IF_DUMP #define DEBUGGER_ONLY(func) {func} #define TRACE0(arg0) {DebuggerAppendMsg(arg0);} #define TRACE1(arg0,arg1) {DebuggerAppendMsg(arg0,arg1);} #define TRACE2(arg0,arg1,arg2) {DebuggerAppendMsg(arg0,arg1,arg2);} #define TRACE3(arg0,arg1,arg2,arg3) {DebuggerAppendMsg(arg0,arg1,arg2,arg3);} #define TRACE4(arg0,arg1,arg2,arg3,arg4) {DebuggerAppendMsg(arg0,arg1,arg2,arg3,arg4);} #define TRACE5(arg0,arg1,arg2,arg3,arg4,arg5) {DebuggerAppendMsg(arg0,arg1,arg2,arg3,arg4,arg5);} #define DEBUG_TRIANGLE(dumpfunc) { if(pauseAtNext && eventToPause==NEXT_TRIANGLE ) { eventToPause = NEXT_FLUSH_TRI; debuggerPause = true; DEBUGGER_PAUSE(NEXT_FLUSH_TRI); dumpfunc} } #else #define DEBUG_DUMP_VERTEXES(str, v0, v1, v2) #define DEBUGGER_IF(op) #define DEBUGGER_PAUSE(op) #define DEBUGGER_PAUSE_COUNT_N(op) #define DEBUGGER_PAUSE_AND_DUMP(op,dumpfuc) #define DebuggerPauseCountN DEBUGGER_PAUSE_COUNT_N #define DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N(cond,dumpfuc) #define DEBUGGER_PAUSE_AND_DUMP_COUNT_N(op,dumpfuc) #define DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(op) #define DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(op,dumpfuc) #define RSP_RDP_NOIMPL(a,b,c) void __cdecl DebuggerAppendMsg(const char * Message, ...) ATTR_FMT(1,2); #define DumpHex(rdramAddr, count) #define DEBUGGER_IF_DUMP(cond, dumpfunc) #define TXTRBUF_DUMP(dumpfunc) #define TXTRBUF_DETAIL_DUMP(dumpfunc) #define TXTRBUF_OR_CI_DUMP(dumpfunc) #define TXTRBUF_OR_CI_DETAIL_DUMP(dumpfunc) #define VTX_DUMP(dumpfunc) #define TRI_DUMP(dumpfunc) #define LIGHT_DUMP(dumpfunc) #define WARNING(dumpfunc) #define FOG_DUMP(dumpfunc) #define LOG_TEXTURE(dumpfunc) #define DEBUGGER_ONLY_IF DEBUGGER_IF_DUMP #define DEBUGGER_ONLY(func) #define DumpMatrix(a,b) #define TRACE0(arg0) {} #define TRACE1(arg0,arg1) {} #define TRACE2(arg0,arg1,arg2) {} #define TRACE3(arg0,arg1,arg2,arg3) {} #define TRACE4(arg0,arg1,arg2,arg3,arg4) {} #define TRACE5(arg0,arg1,arg2,arg3,arg4,arg5) {} #define DEBUG_TRIANGLE(arg0) {} #endif #endif // !defined(DEBUGGER_H) mupen64plus-video-rice-src-2.6.0/src/DeviceBuilder.cpp000066400000000000000000000150011464507324400225410ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "Blender.h" #include "Combiner.h" #include "Debugger.h" #include "DeviceBuilder.h" #include "FrameBuffer.h" #include "GraphicsContext.h" #include "OGLCombiner.h" #include "OGLDebug.h" #include "OGLRender.h" #include "OGLGraphicsContext.h" #include "OGLTexture.h" #include "OGLExtensions.h" //======================================================================== CDeviceBuilder* CDeviceBuilder::m_pInstance = NULL; SupportedDeviceType CDeviceBuilder::m_deviceType = OGL_DEVICE; SupportedDeviceType CDeviceBuilder::m_deviceGeneralType = OGL_DEVICE; CDeviceBuilder* CDeviceBuilder::GetBuilder(void) { if( m_pInstance == NULL ) CreateBuilder(m_deviceType); return m_pInstance; } void CDeviceBuilder::SelectDeviceType(SupportedDeviceType type) { if( type != m_deviceType && m_pInstance != NULL ) { DeleteBuilder(); } CDeviceBuilder::m_deviceType = type; switch(type) { case OGL_DEVICE: case OGL_FRAGMENT_PROGRAM: CDeviceBuilder::m_deviceGeneralType = OGL_DEVICE; break; default: break; } } SupportedDeviceType CDeviceBuilder::GetDeviceType(void) { return CDeviceBuilder::m_deviceType; } SupportedDeviceType CDeviceBuilder::GetGeneralDeviceType(void) { return CDeviceBuilder::m_deviceGeneralType; } CDeviceBuilder* CDeviceBuilder::CreateBuilder(SupportedDeviceType type) { if( m_pInstance == NULL ) { switch( type ) { case OGL_DEVICE: case OGL_FRAGMENT_PROGRAM: m_pInstance = new OGLDeviceBuilder(); break; default: DebugMessage(M64MSG_ERROR, "CreateBuilder: unknown OGL device type"); exit(1); } SAFE_CHECK(m_pInstance); } return m_pInstance; } void CDeviceBuilder::DeleteBuilder(void) { delete m_pInstance; m_pInstance = NULL; } CDeviceBuilder::CDeviceBuilder() : m_pRender(NULL), m_pColorCombiner(NULL), m_pAlphaBlender(NULL) { } CDeviceBuilder::~CDeviceBuilder() { DeleteGraphicsContext(); DeleteRender(); DeleteColorCombiner(); DeleteAlphaBlender(); } void CDeviceBuilder::DeleteGraphicsContext(void) { if( !CGraphicsContext::IsNull() ) { delete CGraphicsContext::m_pGraphicsContext; CGraphicsContext::m_pGraphicsContext = NULL; } SAFE_DELETE(g_pFrameBufferManager); } void CDeviceBuilder::DeleteRender(void) { if( m_pRender != NULL ) { delete m_pRender; CRender::g_pRender = m_pRender = NULL; CRender::gRenderReferenceCount = 0; } } void CDeviceBuilder::DeleteColorCombiner(void) { if( m_pColorCombiner != NULL ) { delete m_pColorCombiner; m_pColorCombiner = NULL; } } void CDeviceBuilder::DeleteAlphaBlender(void) { if( m_pAlphaBlender != NULL ) { delete m_pAlphaBlender; m_pAlphaBlender = NULL; } } //======================================================================== CGraphicsContext * OGLDeviceBuilder::CreateGraphicsContext(void) { if( CGraphicsContext::IsNull() ) { CGraphicsContext::m_pGraphicsContext = new COGLGraphicsContext(); SAFE_CHECK(CGraphicsContext::m_pGraphicsContext); } g_pFrameBufferManager = new FrameBufferManager; return CGraphicsContext::m_pGraphicsContext; } CRender * OGLDeviceBuilder::CreateRender(void) { if( m_pRender == NULL ) { if( CGraphicsContext::IsNull() || !CGraphicsContext::Get()->IsReady() ) { DebugMessage(M64MSG_ERROR, "Can not create ColorCombiner before creating and initializing GraphicsContext"); m_pRender = NULL; SAFE_CHECK(m_pRender); } m_pRender = new OGLRender(); SAFE_CHECK(m_pRender); CRender::g_pRender = m_pRender; } return m_pRender; } CTexture * OGLDeviceBuilder::CreateTexture(uint32 dwWidth, uint32 dwHeight, TextureUsage usage) { COGLTexture *txtr = new COGLTexture(dwWidth, dwHeight, usage); if( txtr->m_pTexture == NULL ) { delete txtr; TRACE0("Cannot create new texture, out of video memory"); return NULL; } else return txtr; } CColorCombiner * OGLDeviceBuilder::CreateColorCombiner(CRender *pRender) { bool bColorCombinerFound = false; if( m_pColorCombiner == NULL ) { if( CGraphicsContext::Get() == NULL && CGraphicsContext::Get()->IsReady() ) { DebugMessage(M64MSG_ERROR, "Can not create ColorCombiner before creating and initializing GraphicsContext"); } else { m_deviceType = (SupportedDeviceType)options.OpenglRenderSetting; if( m_deviceType == OGL_DEVICE ) // Best fit { m_pColorCombiner = new COGLColorCombiner(pRender); bColorCombinerFound = true; DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: 2.1"); } else { switch(m_deviceType) { case OGL_FRAGMENT_PROGRAM: m_pColorCombiner = new COGLColorCombiner(pRender); bColorCombinerFound = true; DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: 2.1"); break; default: break; } } } if (!bColorCombinerFound) { DebugMessage(M64MSG_ERROR, "OpenGL Combiner: Can't find a valid OpenGL Combiner"); exit(1); } SAFE_CHECK(m_pColorCombiner); } return m_pColorCombiner; } CBlender * OGLDeviceBuilder::CreateAlphaBlender(CRender *pRender) { if( m_pAlphaBlender == NULL ) { m_pAlphaBlender = new COGLBlender(pRender); SAFE_CHECK(m_pAlphaBlender); } return m_pAlphaBlender; } mupen64plus-video-rice-src-2.6.0/src/DeviceBuilder.h000066400000000000000000000052101464507324400222070ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _DEVICE_BUILDER_H #define _DEVICE_BUILDER_H #include "Blender.h" #include "Combiner.h" #include "Config.h" #include "GraphicsContext.h" #include "Texture.h" #include "TextureManager.h" #include "typedefs.h" class CBlender; class CColorCombiner; class CGraphicsContext; class CRender; //======================================================================== class CDeviceBuilder { public: virtual CGraphicsContext * CreateGraphicsContext(void)=0; virtual CRender * CreateRender(void)=0; virtual CTexture * CreateTexture(uint32 dwWidth, uint32 dwHeight, TextureUsage usage = AS_NORMAL)=0; virtual CColorCombiner * CreateColorCombiner(CRender *pRender)=0; virtual CBlender * CreateAlphaBlender(CRender *pRender)=0; void DeleteGraphicsContext(void); void DeleteRender(void); void DeleteColorCombiner(void); void DeleteAlphaBlender(void); static void DeleteBuilder(void); static CDeviceBuilder* GetBuilder(void); static void SelectDeviceType(SupportedDeviceType type); static SupportedDeviceType GetDeviceType(void); static SupportedDeviceType GetGeneralDeviceType(void); static SupportedDeviceType m_deviceGeneralType; protected: CDeviceBuilder(); virtual ~CDeviceBuilder(); static CDeviceBuilder* CreateBuilder(SupportedDeviceType type); static SupportedDeviceType m_deviceType; static CDeviceBuilder* m_pInstance; CRender* m_pRender; CColorCombiner* m_pColorCombiner; CBlender* m_pAlphaBlender; }; class OGLDeviceBuilder : public CDeviceBuilder { friend class CDeviceBuilder; public: CGraphicsContext * CreateGraphicsContext(void); CRender * CreateRender(void); CTexture * CreateTexture(uint32 dwWidth, uint32 dwHeight, TextureUsage usage = AS_NORMAL); CColorCombiner * CreateColorCombiner(CRender *pRender); CBlender * CreateAlphaBlender(CRender *pRender); protected: OGLDeviceBuilder() {}; virtual ~OGLDeviceBuilder() {}; }; #endif mupen64plus-video-rice-src-2.6.0/src/ExtendedRender.h000066400000000000000000000042141464507324400224040ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _EXTENDED_RENDER_H_ #define _EXTENDED_RENDER_H_ #include "RSP_Parser.h" #include "RSP_S2DEX.h" // Define the render extension interface and provide empty implementation of // the render extension functions. // Real render can either implement or not implement these extended render functions // These extended render functions are in different groups: // - Group #1: Related to frame buffer // - Group #2: Related to 2D sprite // - Group #3: Related BG and ScaledBG class CExtendedRender { public: virtual ~CExtendedRender() {} virtual void DrawFrameBuffer(bool useVIreg=false, uint32 left=0, uint32 top=0, uint32 width=0, uint32 height=0) {}; virtual void LoadFrameBuffer(bool useVIreg=false, uint32 left=0, uint32 top=0, uint32 width=0, uint32 height=0) {}; virtual void LoadTxtrBufFromRDRAM(void) {}; virtual void LoadTxtrBufIntoTexture(void) {}; virtual void DrawSprite2D(Sprite2DInfo &info, uint32 ucode) {}; virtual void LoadSprite2D(Sprite2DInfo &info, uint32 ucode) {}; virtual void DrawSprite(uObjTxSprite &sprite, bool rectR = true) {}; virtual void DrawObjBG1CYC(uObjScaleBg &bg, bool scaled=true) {}; virtual void DrawObjBGCopy(uObjBg &info) {}; virtual void LoadObjBGCopy(uObjBg &info) {}; virtual void LoadObjBG1CYC(uObjScaleBg &info) {}; virtual void LoadObjSprite(uObjTxSprite &info, bool useTIAddr=false) {}; virtual void DrawText(const char* str, RECT *rect) {}; }; #endif mupen64plus-video-rice-src-2.6.0/src/FrameBuffer.cpp000066400000000000000000002177101464507324400222320ustar00rootroot00000000000000/* Copyright (C) 2005 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // =========================================================================== #include #include #include #include "Config.h" #include "ConvertImage.h" #include "Debugger.h" #include "DeviceBuilder.h" #include "FrameBuffer.h" #include "GraphicsContext.h" #include "RSP_Parser.h" #include "Render.h" #include "RenderBase.h" #include "UcodeDefs.h" #include "Video.h" #include "m64p_plugin.h" #undef min #undef max extern TMEMLoadMapInfo g_tmemLoadAddrMap[0x200]; // Totally 4KB TMEM; // 0 keeps the most recent CI info // 1 keeps the frame buffer CI info which is being displayed now // 2 keeps the older frame buffer CI info. This can be used if we are using triple buffer /* Overview of framebuffer implementation 1) Check if backbuffer has changed, via different detection techniques 2) If changed, we copy the GFX card's backbuffer to main RAM 3) This is slow due to the reading process, not the writing */ RecentCIInfo g_RecentCIInfo[5]; RecentCIInfo *g_uRecentCIInfoPtrs[5] = { &g_RecentCIInfo[0], &g_RecentCIInfo[1], &g_RecentCIInfo[2], &g_RecentCIInfo[3], &g_RecentCIInfo[4], }; int numOfRecentCIInfos = 5; RecentViOriginInfo g_RecentVIOriginInfo[5]; uint32 dwBackBufferSavedAtFrame=0; RenderTextureInfo gRenderTextureInfos[20]; int numOfTxtBufInfos = sizeof(gRenderTextureInfos)/sizeof(RenderTextureInfo); RenderTextureInfo *g_pRenderTextureInfo = NULL; FrameBufferManager* g_pFrameBufferManager = NULL; bool LastCIIsNewCI=false; FrameBufferManager::FrameBufferManager() : m_isRenderingToTexture(false), m_curRenderTextureIndex(-1), m_lastTextureBufferIndex(-1) { } FrameBufferManager::~FrameBufferManager() { } void FrameBufferManager::CloseUp() { for( int i=0; i=0x20?1:0; return ((r>>3)<>3)<>3)<>7); } uint16 ConvertRGBATo555(uint32 color32) { return (uint16)((((color32>>19)&0x1F)<>11)&0x1F)<>3)&0x1F)<>31)));; } void FrameBufferManager::UpdateRecentCIAddr(SetImgInfo &ciinfo) { if( ciinfo.dwAddr == g_uRecentCIInfoPtrs[0]->dwAddr ) return; RecentCIInfo *temp; int i; for( i=1; idwAddr ) { temp = g_uRecentCIInfoPtrs[i]; for( int j=i; j>0; j-- ) { g_uRecentCIInfoPtrs[j] = g_uRecentCIInfoPtrs[j-1]; } break; } } if( i >= numOfRecentCIInfos ) { temp = g_uRecentCIInfoPtrs[4]; g_uRecentCIInfoPtrs[4] = g_uRecentCIInfoPtrs[3]; g_uRecentCIInfoPtrs[3] = g_uRecentCIInfoPtrs[2]; g_uRecentCIInfoPtrs[2] = g_uRecentCIInfoPtrs[1]; g_uRecentCIInfoPtrs[1] = g_uRecentCIInfoPtrs[0]; temp->dwCopiedAtFrame = 0; temp->bCopied = false; } g_uRecentCIInfoPtrs[0] = temp; // Fix me here for Mario Tennis temp->dwLastWidth = windowSetting.uViWidth; temp->dwLastHeight = windowSetting.uViHeight; temp->dwFormat = ciinfo.dwFormat; temp->dwAddr = ciinfo.dwAddr; temp->dwSize = ciinfo.dwSize; temp->dwWidth = ciinfo.dwWidth; temp->dwHeight = gRDP.scissor.bottom; temp->dwMemSize = (temp->dwWidth*temp->dwHeight/2)<dwSize; temp->bCopied = false; temp->lastUsedFrame = status.gDlistCount; temp->lastSetAtUcode = status.gUcodeCount; } /************************************************************************/ /* Mark the ciinfo entry that the ciinfo is used by VI origin register */ /* in another word, this is a real frame buffer, not a fake frame buffer*/ /* Fake frame buffers are never really used by VI origin */ /************************************************************************/ void FrameBufferManager::SetAddrBeDisplayed(uint32 addr) { uint32 viwidth = *g_GraphicsInfo.VI_WIDTH_REG; addr &= (g_dwRamSize-1); int i; for( i=0; idwAddr+2*viwidth == addr ) { g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame = status.gDlistCount; } else if( addr >= g_uRecentCIInfoPtrs[i]->dwAddr && addr < g_uRecentCIInfoPtrs[i]->dwAddr+0x1000 ) { g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame = status.gDlistCount; } } for( i=0; idwAddr == 0 ) continue; if( g_uRecentCIInfoPtrs[i]->dwAddr == addr ) { if( status.gDlistCount-g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame < 20 ) //if( g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame != 0 ) { return true; } else { TXTRBUF_DUMP(TRACE0("This is a new buffer address, the addr is never a displayed buffer");); return false; } } } for( i=0; i addr && (g_RecentVIOriginInfo[i].addr - addr)%width == 0 && (g_RecentVIOriginInfo[i].addr - addr)/width <= 4) { if( status.gDlistCount-g_RecentVIOriginInfo[i].FrameCount < 20 ) //if( g_RecentVIOriginInfo[i].FrameCount != 0 ) { return true; } else { TXTRBUF_DUMP(DebuggerAppendMsg("This is a new buffer address, the addr is never a displayed buffer");); return false; } } } } if( status.gDlistCount > 20 ) return false; else { TXTRBUF_DUMP({DebuggerAppendMsg("This is a new buffer address, the addr is never a displayed buffer");}); return true; } } int FrameBufferManager::FindRecentCIInfoIndex(uint32 addr) { for( int i=0; idwAddr <= addr && addr < g_uRecentCIInfoPtrs[i]->dwAddr+g_uRecentCIInfoPtrs[i]->dwMemSize ) { return i; } } return -1; } bool FrameBufferManager::IsDIaRenderTexture() { // Knowing g_CI and g_ZI //if( g_CI.dwWidth ) bool foundSetScissor=false; bool foundFillRect=false; bool foundSetFillColor=false; bool foundSetCImg=false; uint32 newFillColor = 0; uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction for( int i=0; i<10; i++ ) { uint32 w0 = *(uint32 *)(g_pRDRAMu8 + dwPC + i*8); uint32 w1 = *(uint32 *)(g_pRDRAMu8 + dwPC + 4 + i*8); if( (w0>>24) == RDP_SETSCISSOR ) { foundSetScissor = true; continue; } if( (w0>>24) == RDP_SETFILLCOLOR ) { foundSetFillColor = true; newFillColor = w1; continue; } if( (w0>>24) == RDP_FILLRECT ) { uint32 x0 = ((w1>>12)&0xFFF)/4; uint32 y0 = ((w1>>0 )&0xFFF)/4; uint32 x1 = ((w0>>12)&0xFFF)/4; if( x0 == 0 && y0 == 0 ) { if( x1 == g_CI.dwWidth ) { foundFillRect = true; continue; } if(x1 == (unsigned int)(g_CI.dwWidth-1)) { foundFillRect = true; continue; } } } if( (w0>>24) == RDP_TEXRECT ) { break; } if( (w0>>24) == RDP_SETCIMG ) { foundSetCImg = true; break; } } /* bool foundSetScissor=false; bool foundFillRect=false; bool foundSetFillColor=false; bool foundSetCImg=false; bool foundTxtRect=false; int ucodeLength=10; uint32 newFillColor; */ if( foundFillRect ) { if( foundSetFillColor ) { if( newFillColor != 0xFFFCFFFC ) return true; // this is a render_texture else return false; } if( gRDP.fillColor != 0x00FFFFF7 ) return true; // this is a render_texture else return false; // this is a normal ZImg } else if( foundSetFillColor && newFillColor == 0xFFFCFFFC && foundSetCImg ) { return false; } else { return true; } if( !foundSetCImg ) return true; if( foundSetScissor ) return true; } int FrameBufferManager::CheckAddrInBackBuffers(uint32 addr, uint32 memsize, bool copyToRDRAM) { int r = FindRecentCIInfoIndex(addr); if( r >= 0 ) { // Also check if the address is overwritten by a recent render_texture //int t = CheckAddrInRenderTextures(addr,false); int t =-1; for( int i=0; i=gRenderTextureInfos[i].CI_Info.dwAddr && addr < gRenderTextureInfos[i].CI_Info.dwAddr+bufMemSize) { if( g_uRecentCIInfoPtrs[r]->lastSetAtUcode < gRenderTextureInfos[i].updateAtUcodeCount ) { t = i; break; } } } if( t >= 0 ) return -1; } if( r >= 0 && status.gDlistCount - g_uRecentCIInfoPtrs[r]->lastUsedFrame <= 3 && g_uRecentCIInfoPtrs[r]->bCopied == false ) { DEBUGGER_IF_DUMP((logTextureBuffer&&r==1),TRACE2("Hit current front buffer at %08X, size=0x%X", addr, memsize)); DEBUGGER_IF_DUMP((logTextureBuffer&&r==0),TRACE2("Hit current back buffer at %08X, size=0x%X", addr, memsize)); DEBUGGER_IF_DUMP((logTextureBuffer&&r>1),TRACE2("Hit old back buffer at %08X, size=0x%X", addr, memsize)); SaveBackBuffer(r, NULL, true); } return r; } uint8 CIFindIndex(uint16 val) { for( int i=0; i<=0xFF; i++ ) { if( val == g_wRDPTlut[i] ) { return (uint8)i; } } return 0; } void TexRectToFrameBuffer_8b(uint32 dwXL, uint32 dwYL, uint32 dwXH, uint32 dwYH, float t0u0, float t0v0, float t0u1, float t0v1, uint32 dwTile) { // Copy the framebuffer texture into the N64 framebuffer memory // Used in Yoshi /* uint32 maxW = g_pRenderTextureInfo->CI_Info.dwWidth; uint32 maxH = maxW*3/4; if( status.dwTvSystem == TV_SYSTEM_PAL ) { maxH = maxW*9/11; } */ uint32 maxW = g_pRenderTextureInfo->N64Width; uint32 maxH = g_pRenderTextureInfo->N64Height; uint32 maxOff = maxW*maxH; TMEMLoadMapInfo &info = g_tmemLoadAddrMap[gRDP.tiles[dwTile].dwTMem]; uint32 dwWidth = dwXH-dwXL; uint32 dwHeight = dwYH-dwYL; float xScale = (t0u1-t0u0)/dwWidth; float yScale = (t0v1-t0v0)/dwHeight; uint8* dwSrc = g_pRDRAMu8 + info.dwLoadAddress; uint8* dwDst = g_pRDRAMu8 + g_pRenderTextureInfo->CI_Info.dwAddr; uint32 dwSrcPitch = gRDP.tiles[dwTile].dwPitch; uint32 dwDstPitch = g_pRenderTextureInfo->CI_Info.dwWidth; uint32 dwSrcOffX = gRDP.tiles[dwTile].hilite_sl; uint32 dwSrcOffY = gRDP.tiles[dwTile].hilite_tl; uint32 dwLeft = dwXL; uint32 dwTop = dwYL; dwWidth = std::min(dwWidth, maxW-dwLeft); dwHeight = std::min(dwHeight, maxH-dwTop); if( maxH <= dwTop ) return; for (uint32 y = 0; y < dwHeight; y++) { uint32 dwByteOffset = (uint32)(((y*yScale+dwSrcOffY) * dwSrcPitch) + dwSrcOffX); for (uint32 x = 0; x < dwWidth; x++) { if( (((y+dwTop)*dwDstPitch+x+dwLeft)^0x3) > maxOff ) { #ifdef DEBUGGER TRACE0("Warning: Offset exceeds limit"); #endif continue; } dwDst[((y+dwTop)*dwDstPitch+x+dwLeft)^0x3] = dwSrc[(uint32)(dwByteOffset+x*xScale) ^ 0x3]; } } TXTRBUF_DUMP(DebuggerAppendMsg("TexRect To FrameBuffer: X0=%d, Y0=%d, X1=%d, Y1=%d,\n\t\tfS0=%f, fT0=%f, fS1=%f, fT1=%f ", dwXL, dwYL, dwXH, dwYH, t0v0, t0v0, t0u1, t0v1);); } void TexRectToN64FrameBuffer_16b(uint32 x0, uint32 y0, uint32 width, uint32 height, uint32 dwTile) { // Copy the framebuffer texture into the N64 RDRAM framebuffer memory structure DrawInfo srcInfo; if( g_textures[dwTile].m_pCTexture->StartUpdate(&srcInfo) == false ) { DebuggerAppendMsg("Fail to lock texture:TexRectToN64FrameBuffer_16b" ); return; } uint32 n64CIaddr = g_CI.dwAddr; uint32 n64CIwidth = g_CI.dwWidth; for (uint32 y = 0; y < height; y++) { uint32* pSrc = (uint32*)((uint8*)srcInfo.lpSurface + y * srcInfo.lPitch); uint16* pN64Buffer = (uint16*)(g_pRDRAMu8+(n64CIaddr&(g_dwRamSize-1)))+(y+y0)*n64CIwidth; for (uint32 x = 0; x < width; x++) { pN64Buffer[x+x0] = ConvertRGBATo555(pSrc[x]); } } g_textures[dwTile].m_pCTexture->EndUpdate(&srcInfo); } #define FAST_CRC_CHECKING_INC_X 13 #define FAST_CRC_CHECKING_INC_Y 11 #define FAST_CRC_MIN_Y_INC 2u #define FAST_CRC_MIN_X_INC 2u #define FAST_CRC_MAX_X_INC 7 #define FAST_CRC_MAX_Y_INC 3 extern uint32 dwAsmHeight; extern uint32 dwAsmPitch; extern uint32 dwAsmdwBytesPerLine; extern uint32 dwAsmCRC; extern uint8* pAsmStart; uint32 CalculateRDRAMCRC(void *pPhysicalAddress, uint32 left, uint32 top, uint32 width, uint32 height, uint32 size, uint32 pitchInBytes ) { dwAsmCRC = 0; dwAsmdwBytesPerLine = ((width<=32 || (dwAsmdwBytesPerLine>>2)>=16)) { uint32 realWidthInDWORD = dwAsmdwBytesPerLine>>2; uint32 xinc = realWidthInDWORD / FAST_CRC_CHECKING_INC_X; if( xinc < FAST_CRC_MIN_X_INC ) { xinc = std::min(FAST_CRC_MIN_X_INC, width); } if( xinc > FAST_CRC_MAX_X_INC ) { xinc = FAST_CRC_MAX_X_INC; } uint32 yinc = height / FAST_CRC_CHECKING_INC_Y; if( yinc < FAST_CRC_MIN_Y_INC ) { yinc = std::min(FAST_CRC_MIN_Y_INC, height); } if( yinc > FAST_CRC_MAX_Y_INC ) { yinc = FAST_CRC_MAX_Y_INC; } uint32 pitch = pitchInBytes>>2; uint32 *pStart = (uint32*)(pPhysicalAddress); pStart += (top * pitch) + (((left<>3); // The original assembly code had a bug in it (it incremented pStart by 'pitch' in bytes, not in dwords) // This C code implements the same algorithm as the ASM but without the bug uint32 y = 0; while (y < height) { uint32 x = 0; while (x < realWidthInDWORD) { dwAsmCRC = (dwAsmCRC << 4) + ((dwAsmCRC >> 28) & 15); dwAsmCRC += pStart[x]; x += xinc; dwAsmCRC += x; } dwAsmCRC ^= y; y += yinc; pStart += pitch; } } else { try { dwAsmdwBytesPerLine = ((width<>1); dwAsmHeight = height - 1; dwAsmPitch = pitchInBytes; #if defined(NO_ASM) uint32 pitch = pitchInBytes>>2; uint32* pStart = (uint32*)pPhysicalAddress; pStart += (top * pitch) + (((left<>3); int y = dwAsmHeight; while(y >= 0) { uint32 esi = 0; int x = dwAsmdwBytesPerLine - 4; while(x >= 0) { esi = *(uint32*)(pAsmStart + x); esi ^= x; dwAsmCRC = (dwAsmCRC << 4) + ((dwAsmCRC >> 28) & 15); dwAsmCRC += esi; x-=4; } esi ^= y; dwAsmCRC += esi; pAsmStart += dwAsmPitch; y--; } #elif !defined(__GNUC__) // !defined(NO_ASM) __asm { push eax push ebx push ecx push edx push esi mov ecx, pAsmStart; // = pStart mov edx, 0 // The CRC mov eax, dwAsmHeight // = y l2: mov ebx, dwAsmdwBytesPerLine // = x sub ebx, 4 l1: mov esi, [ecx+ebx] xor esi, ebx rol edx, 4 add edx, esi sub ebx, 4 jge l1 xor esi, eax add edx, esi add ecx, dwAsmPitch dec eax jge l2 mov dwAsmCRC, edx pop esi pop edx pop ecx pop ebx pop eax } #elif defined(__x86_64__) // defined(__GNUC__) && !defined(NO_ASM) asm volatile(" xorl %k2, %k2 \n" " movslq %k4, %q4 \n" "0: \n" " movslq %3, %%rbx \n" " sub $4, %%rbx \n" "1: \n" " movl (%0,%%rbx,1), %%eax \n" " xorl %%ebx, %%eax \n" " roll $4, %k2 \n" " addl %%eax, %k2 \n" " sub $4, %%rbx \n" " jge 1b \n" " xorl %k1, %%eax \n" " addl %%eax, %k2 \n" " add %q4, %0 \n" " decl %k1 \n" " jge 0b \n" : "+r"(pAsmStart), "+r"(dwAsmHeight), "=&r"(dwAsmCRC) : "m"(dwAsmdwBytesPerLine), "r"(dwAsmPitch) : "%rbx", "%rax", "memory", "cc" ); #elif !defined(__PIC__) // !defined(__x86_64__) && defined(__GNUC__) && !defined(NO_ASM) asm volatile("pusha \n" "mov %[pAsmStart], %%ecx \n" // = pStart "mov $0, %%edx \n" // The CRC "mov %[dwAsmHeight], %%eax \n" // = y "0: \n" //l2: "mov %[dwAsmdwBytesPerLine], %%ebx \n" // = x "sub $4, %%ebx \n" "1: \n" //l1: "mov (%%ecx,%%ebx), %%esi \n" "xor %%ebx, %%esi \n" "rol $4, %%edx \n" "add %%esi, %%edx \n" "sub $4, %%ebx \n" "jge 1b \n" //jge l1 "xor %%eax, %%esi \n" "add %%esi, %%edx \n" "add %[dwAsmPitch], %%ecx \n" "dec %%eax \n" "jge 0b \n" //jge l2 "mov %%edx, %[dwAsmCRC] \n" "popa \n" : [pAsmStart]"+m"(pAsmStart), [dwAsmHeight]"+m"(dwAsmHeight), [dwAsmCRC]"=m"(dwAsmCRC) : [dwAsmdwBytesPerLine]"m"(dwAsmdwBytesPerLine), [dwAsmPitch]"m"(dwAsmPitch) : "memory", "cc" ); #else // defined(__PIC__) && !defined(__x86_64__) && defined(__GNUC__) && !defined(NO_ASM) unsigned int saveEBX; unsigned int saveEAX; unsigned int saveECX; unsigned int saveEDX; unsigned int saveESI; unsigned int asmdwBytesPerLine = dwAsmdwBytesPerLine; unsigned int asmPitch = dwAsmPitch; unsigned int asmHeight = dwAsmHeight; unsigned int asmCRC; asm volatile("mov %%ebx, %2 \n" "mov %%eax, %5 \n" "mov %%ecx, %7 \n" "mov %%edx, %8 \n" "mov %%esi, %9 \n" "mov %0, %%ecx \n" // = pStart "mov $0, %%edx \n" // The CRC "mov %1, %%eax \n" // = y "0: \n" //l2: "mov %3, %%ebx \n" // = x "sub $4, %%ebx \n" "1: \n" //l1: "mov (%%ecx,%%ebx), %%esi \n" "xor %%ebx, %%esi \n" "rol $4, %%edx \n" "add %%esi, %%edx \n" "sub $4, %%ebx \n" "jge 1b \n" //jge l1 "xor %%eax, %%esi \n" "add %%esi, %%edx \n" "add %4, %%ecx \n" "dec %%eax \n" "jge 0b \n" //jge l2 "mov %2, %%ebx \n" "mov %%edx, %6 \n" "mov %5, %%eax \n" "mov %7, %%ecx \n" "mov %8, %%edx \n" "mov %9, %%esi \n" : : "m"(pAsmStart), "m"(asmHeight), "m"(saveEBX), "m"(asmdwBytesPerLine), "m"(asmPitch), "m"(saveEAX), "m"(asmCRC), "m"(saveECX), "m"(saveEDX), "m"(saveESI) : "memory", "cc" ); dwAsmCRC = asmCRC; #endif } catch(...) { TRACE0("Exception in texture CRC calculation"); } } return dwAsmCRC; } unsigned char CalculateMaxCI(void *pPhysicalAddress, uint32 left, uint32 top, uint32 width, uint32 height, uint32 size, uint32 pitchInBytes ) { uint32 x, y; unsigned char *buf; unsigned char val = 0; if( TXT_SIZE_8b == size ) { for( y = 0; y val ) val = buf[x]; if( val == 0xFF ) return 0xFF; } } } else { unsigned char val1,val2; left >>= 1; width >>= 1; for( y = 0; y>4; val2 = buf[x]&0xF; if( val1 > val ) val = val1; if( val2 > val ) val = val2; if( val == 0xF ) return 0xF; } } } return val; } bool FrameBufferManager::FrameBufferInRDRAMCheckCRC() { RecentCIInfo &p = *(g_uRecentCIInfoPtrs[0]); uint8 *pFrameBufferBase = (uint8*)(g_pRDRAMu8+p.dwAddr); uint32 pitch = (p.dwWidth << p.dwSize ) >> 1; uint32 crc = CalculateRDRAMCRC(pFrameBufferBase, 0, 0, p.dwWidth, p.dwHeight, p.dwSize, pitch); if( crc != p.dwCRC ) { p.dwCRC = crc; TRACE0("Frame Buffer CRC mismitch, it is modified by CPU"); return false; } else { return true; } } extern std::vector frameWriteRecord; void FrameBufferManager::FrameBufferWriteByCPU(uint32 addr, uint32 size) { if( !frameBufferOptions.bProcessCPUWrite ) return; //WARNING(TRACE2("Frame Buffer Write, addr=%08X, CI Addr=%08X", addr, g_CI.dwAddr)); status.frameWriteByCPU = TRUE; frameWriteRecord.push_back(addr&(g_dwRamSize-1)); } extern RECT frameWriteByCPURect; extern std::vector frameWriteByCPURects; extern RECT frameWriteByCPURectArray[20][20]; extern bool frameWriteByCPURectFlag[20][20]; #define FRAMEBUFFER_IN_BLOCK bool FrameBufferManager::ProcessFrameWriteRecord() { int size = frameWriteRecord.size(); if( size == 0 ) return false; int index = FindRecentCIInfoIndex(frameWriteRecord[0]); if( index == -1 ) { LOG_TEXTURE(TRACE1("Frame Buffer Write to non-record addr = %08X", frameWriteRecord[0])); frameWriteRecord.clear(); return false; } else { uint32 base = g_uRecentCIInfoPtrs[index]->dwAddr; uint32 uwidth = g_uRecentCIInfoPtrs[index]->dwWidth; uint32 uheight = g_uRecentCIInfoPtrs[index]->dwHeight; uint32 upitch = uwidth<<1; frameWriteByCPURect.left=uwidth-1; frameWriteByCPURect.top = uheight-1; frameWriteByCPURect.right=0; frameWriteByCPURect.bottom = 0; int x, y, off; for( int i=0; idwMemSize ) { y = off/upitch; x = (off - y*upitch)>>1; #ifdef FRAMEBUFFER_IN_BLOCK int xidx=x/32; int yidx=y/24; RECT &rect = frameWriteByCPURectArray[xidx][yidx]; if( !frameWriteByCPURectFlag[xidx][yidx] ) { rect.left=rect.right=x; rect.top=rect.bottom=y; frameWriteByCPURectFlag[xidx][yidx]=true; } else { if( x < rect.left ) rect.left = x; if( x > rect.right ) rect.right = x; if( y < rect.top ) rect.top = y; if( y > rect.bottom ) rect.bottom = y; } #else if( x < frameWriteByCPURect.left ) frameWriteByCPURect.left = x; if( x > frameWriteByCPURect.right ) frameWriteByCPURect.right = x; if( y < frameWriteByCPURect.top ) frameWriteByCPURect.top = y; if( y > frameWriteByCPURect.bottom ) frameWriteByCPURect.bottom = y; #endif } } frameWriteRecord.clear(); LOG_TEXTURE(TRACE4("Frame Buffer Write: Left=%d, Top=%d, Right=%d, Bottom=%d", frameWriteByCPURect.left, frameWriteByCPURect.top, frameWriteByCPURect.right, frameWriteByCPURect.bottom)); return true; } } void FrameBufferManager::FrameBufferReadByCPU( uint32 addr ) { ///return; // it does not work very well anyway if( !frameBufferOptions.bProcessCPURead ) return; addr &= (g_dwRamSize-1); int index = FindRecentCIInfoIndex(addr); if( index == -1 ) { // Check if this is the depth buffer uint32 size = 2*g_RecentCIInfo[0].dwWidth*g_RecentCIInfo[0].dwHeight; addr &= 0x3FFFFFFF; if( addr >= g_ZI.dwAddr && addr < g_ZI.dwAddr + size ) { TXTRBUF_OR_CI_DUMP(TRACE1("Depth Buffer read, reported by emulator, addr=%08X", addr)); } else { return; } } if( status.gDlistCount - g_uRecentCIInfoPtrs[index]->lastUsedFrame > 3 ) { // Ok, we don't have this frame anymore return; } //TXTRBUF_OR_CI_DUMP(TRACE1("FB Read By CPU at %08X", addr)); if( g_uRecentCIInfoPtrs[index]->bCopied ) return; //if( addr != g_uRecentCIInfoPtrs[index]->dwAddr ) return; TXTRBUF_OR_CI_DUMP(TRACE1("Frame Buffer read, reported by emulator, addr=%08X", addr)); uint32 size = 0x1000 - addr%0x1000; CheckAddrInBackBuffers(addr, size, true); DEBUGGER_IF_DUMP(pauseAtNext,{TRACE0("Frame Buffer read");}); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE, {DebuggerAppendMsg("Paused after setting Frame Buffer read:\n Cur CI Addr: 0x%08x, Fmt: %s Size: %s Width: %d", g_CI.dwAddr, pszImgFormat[g_CI.dwFormat], pszImgSize[g_CI.dwSize], g_CI.dwWidth);}); } extern RECT frameWriteByCPURect; extern std::vector frameWriteByCPURects; extern RECT frameWriteByCPURectArray[20][20]; extern bool frameWriteByCPURectFlag[20][20]; #define FRAMEBUFFER_IN_BLOCK void FrameBufferManager::UpdateFrameBufferBeforeUpdateFrame() { if( (frameBufferOptions.bProcessCPUWrite && status.frameWriteByCPU ) || (frameBufferOptions.bLoadBackBufFromRDRAM && !FrameBufferInRDRAMCheckCRC() ) ) // Checks if frame buffer has been modified by CPU // Only happens to Dr. Mario { if( frameBufferOptions.bProcessCPUWrite ) { if( ProcessFrameWriteRecord() ) { #ifdef FRAMEBUFFER_IN_BLOCK int i,j; for( i=0; i<20; i++) { for( j=0; j<20; j++ ) { if( frameWriteByCPURectFlag[i][j] ) { CRender::GetRender()->DrawFrameBuffer(false, frameWriteByCPURectArray[i][j].left, frameWriteByCPURectArray[i][j].top, frameWriteByCPURectArray[i][j].right-frameWriteByCPURectArray[i][j].left+1, frameWriteByCPURectArray[i][j].bottom-frameWriteByCPURectArray[i][j].top+1); } } } for( i=0; i<20; i++) { for( j=0; j<20; j++ ) { if( frameWriteByCPURectFlag[i][j] ) { ClearN64FrameBufferToBlack(frameWriteByCPURectArray[i][j].left, frameWriteByCPURectArray[i][j].top, frameWriteByCPURectArray[i][j].right-frameWriteByCPURectArray[i][j].left+1, frameWriteByCPURectArray[i][j].bottom-frameWriteByCPURectArray[i][j].top+1); frameWriteByCPURectFlag[i][j] = false; } } } //memset(frameWriteByCPURectArray, 0, sizeof(frameWriteByCPURectArray)); //memset(frameWriteByCPURectFlag, 0, sizeof(frameWriteByCPURectFlag)); #else CRender::GetRender()->DrawFrameBuffer(false, frameWriteByCPURect.left, frameWriteByCPURect.top, frameWriteByCPURect.right-frameWriteByCPURect.left, frameWriteByCPURect.bottom-frameWriteByCPURect.top); ClearN64FrameBufferToBlack(frameWriteByCPURect.left, frameWriteByCPURect.top, frameWriteByCPURect.right-frameWriteByCPURect.left+1, frameWriteByCPURect.bottom-frameWriteByCPURect.top+1); /* int size = frameWriteByCPURects.size(); for( int i=0; iDrawFrameBuffer(false, frameWriteByCPURects[i].left, frameWriteByCPURects[i].top, frameWriteByCPURects[i].right-frameWriteByCPURects[i].left, frameWriteByCPURects[i].bottom-frameWriteByCPURects[i].top); ClearN64FrameBufferToBlack(frameWriteByCPURects[i].left, frameWriteByCPURects[i].top, frameWriteByCPURects[i].right-frameWriteByCPURects[i].left+1, frameWriteByCPURects[i].bottom-frameWriteByCPURects[i].top+1); } frameWriteByCPURects.clear(); */ #endif } status.frameWriteByCPU = FALSE; } else { if (CRender::IsAvailable()) { RecentCIInfo &p = *(g_uRecentCIInfoPtrs[0]); CRender::GetRender()->DrawFrameBuffer(false, 0,0,p.dwWidth,p.dwHeight); ClearN64FrameBufferToBlack(); } } } } uint32 FrameBufferManager::ComputeCImgHeight(SetImgInfo &info, uint32 &height) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction for( int i=0; i<10; i++ ) { uint32 w0 = *(uint32 *)(g_pRDRAMu8 + dwPC + i*8); uint32 w1 = *(uint32 *)(g_pRDRAMu8 + dwPC + 4 + i*8); if( (w0>>24) == RDP_SETSCISSOR ) { height = ((w1>>0 )&0xFFF)/4; TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height)); return RDP_SETSCISSOR; } if( (w0>>24) == RDP_FILLRECT ) { uint32 x0 = ((w1>>12)&0xFFF)/4; uint32 y0 = ((w1>>0 )&0xFFF)/4; uint32 x1 = ((w0>>12)&0xFFF)/4; uint32 y1 = ((w0>>0 )&0xFFF)/4; if( x0 == 0 && y0 == 0 ) { if( x1 == info.dwWidth ) { height = y1; TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height)); return RDP_FILLRECT; } if(x1 == (unsigned int)(info.dwWidth-1)) { height = y1+1; TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height)); return RDP_FILLRECT; } } } if( (w0>>24) == RDP_SETCIMG ) { goto step2; } if( (w0>>24) == RDP_SETCIMG ) { goto step2; } } if( gRDP.scissor.left == 0 && gRDP.scissor.top == 0 && (unsigned int)gRDP.scissor.right == info.dwWidth ) { height = gRDP.scissor.bottom; TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height)); return RDP_SETSCISSOR+1; } step2: TXTRBUF_DETAIL_DUMP(TRACE0("Not sure about buffer height")); height = info.dwWidth*3/4; if( status.dwTvSystem == TV_SYSTEM_PAL ) { height = info.dwWidth*9/11; } if( gRDP.scissor.bottom < (int)height && gRDP.scissor.bottom != 0 ) { height = gRDP.scissor.bottom; } if( info.dwAddr + height*info.dwWidth*info.dwSize >= g_dwRamSize ) { height = info.dwWidth*3/4; if( status.dwTvSystem == TV_SYSTEM_PAL ) { height = info.dwWidth*9/11; } if( gRDP.scissor.bottom < (int)height && gRDP.scissor.bottom != 0 ) { height = gRDP.scissor.bottom; } if( info.dwAddr + height*info.dwWidth*info.dwSize >= g_dwRamSize ) { height = ( g_dwRamSize - info.dwAddr ) / info.dwWidth; } } TXTRBUF_DETAIL_DUMP(TRACE1("render_texture height = %d", height)); return 0; } int FrameBufferManager::CheckRenderTexturesWithNewCI(SetImgInfo &CIinfo, uint32 height, bool byNewTxtrBuf) { int matchidx = -1; uint32 memsize = ((height*CIinfo.dwWidth)>>1)<>1)< CIinfo.dwAddr && info.CI_Info.dwAddr < CIinfo.dwAddr + memsize) covered = true; else if( info.CI_Info.dwAddr+memsize2 > CIinfo.dwAddr && info.CI_Info.dwAddr+memsize2 < CIinfo.dwAddr + memsize) covered = true; else if( CIinfo.dwAddr > info.CI_Info.dwAddr && CIinfo.dwAddr < info.CI_Info.dwAddr + memsize2 ) covered = true; else if( CIinfo.dwAddr+ memsize > info.CI_Info.dwAddr && CIinfo.dwAddr+ memsize < info.CI_Info.dwAddr + memsize2 ) covered = true; } if( covered ) { //SAFE_DELETE(info.psurf); if( info.pRenderTexture->IsBeingRendered() ) { TRACE0("Error, covering a render_texture which is being rendered"); TRACE3("New addrr=%08X, width=%d, height=%d", CIinfo.dwAddr, CIinfo.dwWidth, height ); TRACE3("Old addrr=%08X, width=%d, height=%d", info.CI_Info.dwAddr, info.N64Width, info.N64Height ); } info.isUsed = false; TXTRBUF_DUMP(TRACE5("Delete txtr buf %d at %08X, covered by new CI at %08X, Width=%d, Height=%d", i, info.CI_Info.dwAddr, CIinfo.dwAddr, CIinfo.dwWidth, height )); SAFE_DELETE(info.pRenderTexture); info.txtEntry.pTexture = NULL; continue; } } return matchidx; } extern RecentCIInfo *g_uRecentCIInfoPtrs[5]; RenderTextureInfo newRenderTextureInfo; int FrameBufferManager::FindASlot(void) { int idx; // Find an empty slot bool found = false; for( int i=0; iN64Height);}); } int FrameBufferManager::SetBackBufferAsRenderTexture(SetImgInfo &CIinfo, int ciInfoIdx) { // MUDLORD: // OK, heres the drill! // // We set the graphics card's back buffer's contents as a render_texure // This is done due to how the current framebuffer implementation detects // changes to the backbuffer memory pointer and then we do a texture // copy. This might be slow since it doesnt use hardware auxillary buffers RenderTextureInfo tempRenderTextureInfo; memcpy(&(tempRenderTextureInfo.CI_Info), &CIinfo, sizeof(SetImgInfo)); tempRenderTextureInfo.N64Width = g_uRecentCIInfoPtrs[ciInfoIdx]->dwLastWidth; tempRenderTextureInfo.N64Height = g_uRecentCIInfoPtrs[ciInfoIdx]->dwLastHeight; tempRenderTextureInfo.knownHeight = true; tempRenderTextureInfo.maxUsedHeight = 0; tempRenderTextureInfo.bufferWidth = windowSetting.uDisplayWidth; tempRenderTextureInfo.bufferHeight = windowSetting.uDisplayHeight; tempRenderTextureInfo.scaleX = tempRenderTextureInfo.bufferWidth / float(tempRenderTextureInfo.N64Width); tempRenderTextureInfo.scaleY = tempRenderTextureInfo.bufferHeight / float(tempRenderTextureInfo.N64Height); status.bFrameBufferIsDrawn = false; status.bFrameBufferDrawnByTriangles = false; tempRenderTextureInfo.updateAtFrame = status.gDlistCount; tempRenderTextureInfo.updateAtUcodeCount = status.gUcodeCount; // Checking against previous render_texture infos //uint32 memsize = ((tempRenderTextureInfo.N64Height*tempRenderTextureInfo.N64Width)>>1)<= 0) ? matchidx : FindASlot(); if( gRenderTextureInfos[idxToUse].pRenderTexture == NULL || matchidx < 0 ) { gRenderTextureInfos[idxToUse].pRenderTexture = new COGLRenderTexture(tempRenderTextureInfo.bufferWidth, tempRenderTextureInfo.bufferHeight, &gRenderTextureInfos[idxToUse], AS_BACK_BUFFER_SAVE); } // Need to set all variables for gRenderTextureInfos[idxToUse] CRenderTexture *pRenderTexture = gRenderTextureInfos[idxToUse].pRenderTexture; memcpy(&gRenderTextureInfos[idxToUse], &tempRenderTextureInfo, sizeof(RenderTextureInfo) ); gRenderTextureInfos[idxToUse].pRenderTexture = pRenderTexture; gRenderTextureInfos[idxToUse].isUsed = true; gRenderTextureInfos[idxToUse].txtEntry.pTexture = pRenderTexture->m_pTexture; gRenderTextureInfos[idxToUse].txtEntry.txtrBufIdx = idxToUse+1; TXTRBUF_DUMP(TRACE2("Set back buf as render_texture %d, addr=%08X", idxToUse, CIinfo.dwAddr)); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE, {DebuggerAppendMsg("Paused after setting render_texture:\nAddr: 0x%08x, Fmt: %s Size: %s Width: %d, Height:%d", CIinfo.dwAddr, pszImgFormat[CIinfo.dwFormat], pszImgSize[CIinfo.dwSize], CIinfo.dwWidth, g_pRenderTextureInfo->N64Height);}); return idxToUse; } void FrameBufferManager::CloseRenderTexture(bool toSave) { if( m_curRenderTextureIndex < 0 ) return; status.bHandleN64RenderTexture = false; if( status.bDirectWriteIntoRDRAM ) { // TODO: Implement } else { RestoreNormalBackBuffer(); if( !toSave || !status.bFrameBufferIsDrawn || !status.bFrameBufferDrawnByTriangles ) { TXTRBUF_DUMP(TRACE0("Closing render_texture without save");); SAFE_DELETE(gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture); gRenderTextureInfos[m_curRenderTextureIndex].isUsed = false; TXTRBUF_DUMP(TRACE1("Delete render_texture %d",m_curRenderTextureIndex);); } else { TXTRBUF_DUMP(TRACE1("Closing render_texture %d", m_curRenderTextureIndex);); StoreRenderTextureToRDRAM(); if( frameBufferOptions.bRenderTextureWriteBack ) { SAFE_DELETE(gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture); gRenderTextureInfos[m_curRenderTextureIndex].isUsed = false; TXTRBUF_DUMP(TRACE1("Delete render_texture %d after writing back to RDRAM",m_curRenderTextureIndex);); } else { g_pRenderTextureInfo->crcInRDRAM = ComputeRenderTextureCRCInRDRAM(m_curRenderTextureIndex); g_pRenderTextureInfo->crcCheckedAtFrame = status.gDlistCount; } } } SetScreenMult(windowSetting.uDisplayWidth/windowSetting.fViWidth, windowSetting.uDisplayHeight/windowSetting.fViHeight); CRender::g_pRender->UpdateClipRectangle(); CRender::g_pRender->ApplyScissorWithClipRatio(); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE, { DebuggerAppendMsg("Paused after saving render_texture %d:\nAddr: 0x%08x, Fmt: %s Size: %s Width: %d", m_curRenderTextureIndex, g_pRenderTextureInfo->CI_Info.dwAddr, pszImgFormat[g_pRenderTextureInfo->CI_Info.dwFormat], pszImgSize[g_pRenderTextureInfo->CI_Info.dwSize], g_pRenderTextureInfo->CI_Info.dwWidth); }); } void FrameBufferManager::ClearN64FrameBufferToBlack(uint32 left, uint32 top, uint32 width, uint32 height) { RecentCIInfo &p = *(g_uRecentCIInfoPtrs[0]); uint16 *frameBufferBase = (uint16*)(g_pRDRAMu8+p.dwAddr); uint32 pitch = p.dwWidth; if( width == 0 || height == 0 ) { uint32 len = p.dwHeight*p.dwWidth*p.dwSize; if( p.dwSize == TXT_SIZE_4b ) len = (p.dwHeight*p.dwWidth)>>1; memset(frameBufferBase, 0, len); } else { for( uint32 y=0; yUpdateFrame(); RecentCIInfo *info = g_uRecentCIInfoPtrs[i]; StoreBackBufferToRDRAM( info->dwAddr, info->dwFormat, info->dwSize, info->dwWidth, info->dwHeight, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, addr, 0x1000-addr%0x1000); TRACE1("Copy back for CI Addr=%08X", info->dwAddr); } } // We do these checks to see if a render_texture operation is occurring... void FrameBufferManager::CheckRenderTextureCRCInRDRAM(void) { for( int i=0; iIsBeingRendered() ) continue; if( gRenderTextureInfos[i].crcCheckedAtFrame < status.gDlistCount ) { uint32 crc = ComputeRenderTextureCRCInRDRAM(i); if( gRenderTextureInfos[i].crcInRDRAM != crc ) { // RDRAM has been modified by CPU core TXTRBUF_DUMP(TRACE2("Delete txtr buf %d at %08X, CRC in RDRAM changed", i, gRenderTextureInfos[i].CI_Info.dwAddr )); SAFE_DELETE(gRenderTextureInfos[i].pRenderTexture); gRenderTextureInfos[i].isUsed = false; continue; } else { gRenderTextureInfos[i].crcCheckedAtFrame = status.gDlistCount; } } } } // Check render_texture memory addresses int FrameBufferManager::CheckAddrInRenderTextures(uint32 addr, bool checkcrc) { for( int i=0; iIsBeingRendered() ) continue; uint32 bufHeight = gRenderTextureInfos[i].knownHeight ? gRenderTextureInfos[i].N64Height : gRenderTextureInfos[i].maxUsedHeight; uint32 bufMemSize = gRenderTextureInfos[i].CI_Info.dwSize*gRenderTextureInfos[i].N64Width*bufHeight; if( addr >=gRenderTextureInfos[i].CI_Info.dwAddr && addr < gRenderTextureInfos[i].CI_Info.dwAddr+bufMemSize) { if(checkcrc) { // Check the CRC in RDRAM if( gRenderTextureInfos[i].crcCheckedAtFrame < status.gDlistCount ) { uint32 crc = ComputeRenderTextureCRCInRDRAM(i); if( gRenderTextureInfos[i].crcInRDRAM != crc ) { // RDRAM has been modified by CPU core TRACE3("Buf %d CRC in RDRAM changed from %08X to %08X", i, gRenderTextureInfos[i].crcInRDRAM, crc ); TXTRBUF_DUMP(TRACE2("Delete txtr buf %d at %08X, crcInRDRAM failed.", i, gRenderTextureInfos[i].CI_Info.dwAddr )); SAFE_DELETE(gRenderTextureInfos[i].pRenderTexture); gRenderTextureInfos[i].isUsed = false; continue; } else { gRenderTextureInfos[i].crcCheckedAtFrame = status.gDlistCount; } } } TXTRBUF_DUMP(TRACE2("Loading texture addr = %08X from txtr buf %d", addr, i)); return i; } } return -1; } // Load texture from render_texture buffer void FrameBufferManager::LoadTextureFromRenderTexture(TxtrCacheEntry* pEntry, int infoIdx) { if( infoIdx < 0 || infoIdx >= numOfTxtBufInfos ) { infoIdx = CheckAddrInRenderTextures(pEntry->ti.Address); } if( infoIdx >= 0 && gRenderTextureInfos[infoIdx].isUsed && gRenderTextureInfos[infoIdx].pRenderTexture ) { TXTRBUF_DUMP(TRACE1("Loading from render_texture %d", infoIdx)); gRenderTextureInfos[infoIdx].pRenderTexture->LoadTexture(pEntry); } } void FrameBufferManager::RestoreNormalBackBuffer() { if( m_curRenderTextureIndex >= 0 && m_curRenderTextureIndex < numOfTxtBufInfos ) { if( gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture ) gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture->SetAsRenderTarget(false); m_isRenderingToTexture = false; m_lastTextureBufferIndex = m_curRenderTextureIndex; } if( !status.bFrameBufferIsDrawn || !status.bFrameBufferDrawnByTriangles ) { gRenderTextureInfos[m_curRenderTextureIndex].isUsed = false; TXTRBUF_DUMP(TRACE2("Delete txtr buf %d at %08X, it is never rendered", m_curRenderTextureIndex, gRenderTextureInfos[m_curRenderTextureIndex].CI_Info.dwAddr )); SAFE_DELETE(gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture); } } uint32 FrameBufferManager::ComputeRenderTextureCRCInRDRAM(int infoIdx) { if( infoIdx >= numOfTxtBufInfos || infoIdx < 0 || !gRenderTextureInfos[infoIdx].isUsed ) return 0; RenderTextureInfo &info = gRenderTextureInfos[infoIdx]; uint32 height = info.knownHeight ? info.N64Height : info.maxUsedHeight; uint8 *pAddr = (uint8*)(g_pRDRAMu8+info.CI_Info.dwAddr); uint32 pitch = (info.N64Width << info.CI_Info.dwSize ) >> 1; return CalculateRDRAMCRC(pAddr, 0, 0, info.N64Width, height, info.CI_Info.dwSize, pitch); } // Activates texture buffer for drawing void FrameBufferManager::ActiveTextureBuffer(void) { status.bCIBufferIsRendered = true; if( status.bHandleN64RenderTexture ) { // Checking against previous render_texture infos int matchidx = -1; //uint32 memsize = ((newRenderTextureInfo.N64Height*newRenderTextureInfo.N64Width)>>1)<= 0 ) { // Reuse the matched slot idxToUse = matchidx; } else { idxToUse = FindASlot(); } if( gRenderTextureInfos[idxToUse].pRenderTexture == NULL || matchidx < 0 ) { int w = newRenderTextureInfo.bufferWidth; if( newRenderTextureInfo.knownHeight == RDP_SETSCISSOR && newRenderTextureInfo.CI_Info.dwAddr == g_ZI.dwAddr ) { w = gRDP.scissor.right; } gRenderTextureInfos[idxToUse].pRenderTexture = new COGLRenderTexture(w, newRenderTextureInfo.bufferHeight, &gRenderTextureInfos[idxToUse], AS_RENDER_TARGET); } // Need to set all variables for gRenderTextureInfos[idxToUse] CRenderTexture *pRenderTexture = gRenderTextureInfos[idxToUse].pRenderTexture; memcpy(&gRenderTextureInfos[idxToUse], &newRenderTextureInfo, sizeof(RenderTextureInfo) ); gRenderTextureInfos[idxToUse].pRenderTexture = pRenderTexture; gRenderTextureInfos[idxToUse].isUsed = true; gRenderTextureInfos[idxToUse].txtEntry.pTexture = pRenderTexture->m_pTexture; gRenderTextureInfos[idxToUse].txtEntry.txtrBufIdx = idxToUse+1; g_pRenderTextureInfo = &gRenderTextureInfos[idxToUse]; // Active the render_texture if( m_curRenderTextureIndex >= 0 && gRenderTextureInfos[m_curRenderTextureIndex].isUsed && gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture ) { gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture->SetAsRenderTarget(false); m_isRenderingToTexture = false; } if( gRenderTextureInfos[idxToUse].pRenderTexture->SetAsRenderTarget(true) ) { m_isRenderingToTexture = true; //Clear(CLEAR_COLOR_AND_DEPTH_BUFFER,0x80808080,1.0f); if( frameBufferOptions.bFillRectNextTextureBuffer ) CGraphicsContext::Get()->Clear(CLEAR_COLOR_BUFFER,gRDP.fillColor,1.0f); else if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS && g_pRenderTextureInfo->N64Width > 64 && g_pRenderTextureInfo->N64Width < 300 ) { CGraphicsContext::Get()->Clear(CLEAR_COLOR_BUFFER,0,1.0f); } else if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS && g_pRenderTextureInfo->N64Width < 64 && g_pRenderTextureInfo->N64Width > 32 ) { CGraphicsContext::Get()->Clear(CLEAR_COLOR_BUFFER,0,1.0f); } m_curRenderTextureIndex = idxToUse; status.bDirectWriteIntoRDRAM = false; //SetScreenMult(1, 1); SetScreenMult(gRenderTextureInfos[m_curRenderTextureIndex].scaleX, gRenderTextureInfos[m_curRenderTextureIndex].scaleY); CRender::g_pRender->UpdateClipRectangle(); // If needed, draw RDRAM into the render_texture //if( frameBufferOptions.bLoadRDRAMIntoRenderTexture ) //{ // CRender::GetRender()->LoadTxtrBufFromRDRAM(); //} } TXTRBUF_DUMP(TRACE2("Rendering to render_texture %d, addr=%08X", idxToUse, g_CI.dwAddr)); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE, {DebuggerAppendMsg("Paused after activating render_texture:\nAddr: 0x%08x, Fmt: %s Size: %s Width: %d, Height:%d", g_CI.dwAddr, pszImgFormat[g_CI.dwFormat], pszImgSize[g_CI.dwSize], g_CI.dwWidth, g_pRenderTextureInfo->N64Height);}); } else { UpdateRecentCIAddr(g_CI); CheckRenderTexturesWithNewCI(g_CI,gRDP.scissor.bottom,false); } } #define SAVE_CI {g_CI.dwAddr = newCI.dwAddr;g_CI.dwFormat = newCI.dwFormat;g_CI.dwSize = newCI.dwSize;g_CI.dwWidth = newCI.dwWidth;g_CI.bpl=newCI.bpl;} // Sets CI address for framebuffer copies void FrameBufferManager::Set_CI_addr(SetImgInfo &newCI) { bool wasDrawingTextureBuffer = status.bN64IsDrawingTextureBuffer; status.bN64IsDrawingTextureBuffer = ( newCI.dwSize != TXT_SIZE_16b || newCI.dwFormat != TXT_FMT_RGBA || newCI.dwWidth < 200 || ( newCI.dwAddr != g_ZI.dwAddr && newCI.dwWidth != 512 && !g_pFrameBufferManager->HasAddrBeenDisplayed(newCI.dwAddr, newCI.dwWidth)) ); status.bN64FrameBufferIsUsed = status.bN64IsDrawingTextureBuffer; if( !wasDrawingTextureBuffer && g_CI.dwAddr == g_ZI.dwAddr && status.bCIBufferIsRendered ) { TXTRBUF_DUMP(TRACE0("ZI is rendered")); if( options.enableHackForGames != HACK_FOR_CONKER && g_uRecentCIInfoPtrs[0]->bCopied == false ) { // Conker is not actually using a backbuffer g_pFrameBufferManager->UpdateRecentCIAddr(g_CI); if( status.leftRendered != -1 && status.topRendered != -1 && status.rightRendered != -1 && status.bottomRendered != -1 ) { RECT rect={status.leftRendered,status.topRendered,status.rightRendered,status.bottomRendered}; g_pFrameBufferManager->SaveBackBuffer(0,&rect); } else { g_pFrameBufferManager->SaveBackBuffer(0,NULL); } } } frameBufferOptions.bFillRectNextTextureBuffer = false; if( g_CI.dwAddr == newCI.dwAddr && status.bHandleN64RenderTexture && (g_CI.dwFormat != newCI.dwFormat || g_CI.dwSize != newCI.dwSize || g_CI.dwWidth != newCI.dwWidth ) ) { // Mario Tennis player shadow g_pFrameBufferManager->CloseRenderTexture(true); if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS ) frameBufferOptions.bFillRectNextTextureBuffer = true; // Hack for Mario Tennis } SAVE_CI; if( g_CI.dwAddr == g_ZI.dwAddr && !status.bN64IsDrawingTextureBuffer ) { if( g_pFrameBufferManager->IsDIaRenderTexture() ) { status.bN64IsDrawingTextureBuffer = true; status.bN64FrameBufferIsUsed = status.bN64IsDrawingTextureBuffer; } } status.bCIBufferIsRendered = false; status.leftRendered = status.topRendered = status.rightRendered = status.bottomRendered = -1; if( currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_CI_CHANGE && !status.bN64IsDrawingTextureBuffer ) { if( status.curRenderBuffer == 0 ) { status.curRenderBuffer = g_CI.dwAddr; } else if( status.curRenderBuffer != g_CI.dwAddr ) { status.curDisplayBuffer = status.curRenderBuffer; CGraphicsContext::Get()->UpdateFrame(); status.curRenderBuffer = g_CI.dwAddr; DEBUGGER_IF_DUMP(pauseAtNext,{DebuggerAppendMsg("Screen Update because CI change to %08X, Display Buf=%08X", status.curRenderBuffer, status.curDisplayBuffer);}); } } if( frameBufferOptions.bAtEachFrameUpdate && !status.bHandleN64RenderTexture ) { if( status.curRenderBuffer != g_CI.dwAddr ) { if( status.gDlistCount%(currentRomOptions.N64FrameBufferWriteBackControl+1) == 0 ) { g_pFrameBufferManager->StoreBackBufferToRDRAM(status.curRenderBuffer, newCI.dwFormat, newCI.dwSize, windowSetting.uViWidth, windowSetting.uViHeight, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); } } //status.curDisplayBuffer = status.curRenderBuffer; status.curRenderBuffer = g_CI.dwAddr; } switch( currentRomOptions.N64RenderToTextureEmuType ) { case TXT_BUF_NONE: if( status.bHandleN64RenderTexture ) g_pFrameBufferManager->CloseRenderTexture(false); status.bHandleN64RenderTexture = false; // Don't handle N64 render_texture stuffs if( !status.bN64IsDrawingTextureBuffer ) g_pFrameBufferManager->UpdateRecentCIAddr(g_CI); break; default: if( status.bHandleN64RenderTexture ) { #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_RENDER_TEXTURE ) { pauseAtNext = TRUE; eventToPause = NEXT_RENDER_TEXTURE; } #endif g_pFrameBufferManager->CloseRenderTexture(true); } status.bHandleN64RenderTexture = status.bN64IsDrawingTextureBuffer; if( status.bHandleN64RenderTexture ) { if( options.enableHackForGames != HACK_FOR_BANJO_TOOIE ) { g_pFrameBufferManager->SetRenderTexture(); } } else { #ifdef DEBUGGER if( g_CI.dwWidth == 512 && pauseAtNext && (eventToPause==NEXT_OBJ_BG || eventToPause==NEXT_SET_CIMG) ) { DebuggerAppendMsg("Warning SetCImg: new Addr=0x%08X, fmt:%s size=%sb, Width=%d\n", g_CI.dwAddr, pszImgFormat[newCI.dwFormat], pszImgSize[newCI.dwSize], newCI.dwWidth); } #endif //g_pFrameBufferManager->UpdateRecentCIAddr(g_CI); // Delay this until the CI buffer is actally drawn } break; } TXTRBUF_DUMP(TRACE4("SetCImg : Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_CI.dwAddr, pszImgFormat[newCI.dwFormat], pszImgSize[newCI.dwSize], newCI.dwWidth)); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG, { DebuggerAppendMsg("Pause after SetCImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_CI.dwAddr, pszImgFormat[newCI.dwFormat], pszImgSize[newCI.dwSize], newCI.dwWidth); } ); } void FrameBufferManager::StoreRenderTextureToRDRAM(int infoIdx) { if( !frameBufferOptions.bRenderTextureWriteBack ) return; if( infoIdx < 0 ) infoIdx = m_lastTextureBufferIndex; if( !gRenderTextureInfos[infoIdx].pRenderTexture ) return; if( gRenderTextureInfos[infoIdx].pRenderTexture->IsBeingRendered() ) { TXTRBUF_DUMP(TRACE1("Cannot SaveTextureBuffer %d, it is being rendered", infoIdx)); return; } gRenderTextureInfos[infoIdx].pRenderTexture->StoreToRDRAM(infoIdx); } //does FB copy to N64 RDAM structure void FrameBufferManager::CopyBufferToRDRAM(uint32 addr, uint32 fmt, uint32 siz, uint32 width, uint32 height, uint32 bufWidth, uint32 bufHeight, uint32 startaddr, uint32 memsize, uint32 pitch, TextureFmt bufFmt, void *buffer, uint32 bufPitch) { uint32 startline=0; if( startaddr == 0xFFFFFFFF ) startaddr = addr; startline = (startaddr-addr)/siz/pitch; if( startline >= height ) { //TRACE0("Warning: check me"); startline = height; } uint32 endline = height; if( memsize != 0xFFFFFFFF ) { endline = (startaddr+memsize-addr)/siz; if( endline % pitch == 0 ) endline /= pitch; else endline = endline/pitch+1; } if( endline > height ) { endline = height; } if( memsize != 0xFFFFFFFF ) { TXTRBUF_DUMP(DebuggerAppendMsg("Start at: 0x%X, from line %d to %d", startaddr-addr, startline, endline);); } int indexes[600]; { float sx; int sx0; float ratio = bufWidth/(float)width; for( uint32 j=0; jIsBeingRendered() ) { TRACE1("Render texture %d is being rendered, cannot display", infoIdx); } else { TRACE1("Texture buffer %d:", infoIdx); TRACE1("Addr=%08X", gRenderTextureInfos[infoIdx].CI_Info.dwAddr); TRACE2("Width=%d, Created Height=%d", gRenderTextureInfos[infoIdx].N64Width,gRenderTextureInfos[infoIdx].N64Height); TRACE2("Fmt=%d, Size=%d", gRenderTextureInfos[infoIdx].CI_Info.dwFormat,gRenderTextureInfos[infoIdx].CI_Info.dwSize); } } else { TRACE1("Texture buffer %d is not used", infoIdx); } } #endif // Saves backbuffer // this is the core to the current framebuffer code // We need to save backbuffer when changed by framebuffer // so that we can use it for framebuffer effects void FrameBufferManager::SaveBackBuffer(int ciInfoIdx, RECT* pSrcRect, bool forceToSaveToRDRAM) { RecentCIInfo &ciInfo = *g_uRecentCIInfoPtrs[ciInfoIdx]; if( ciInfoIdx == 1 ) // to save the current front buffer { CGraphicsContext::Get()->UpdateFrame(true); } if( frameBufferOptions.bWriteBackBufToRDRAM || forceToSaveToRDRAM ) { uint32 width = ciInfo.dwWidth; uint32 height = ciInfo.dwHeight; if( ciInfo.dwWidth == *g_GraphicsInfo.VI_WIDTH_REG && ciInfo.dwWidth != windowSetting.uViWidth ) { width = windowSetting.uViWidth; height = windowSetting.uViHeight; } StoreBackBufferToRDRAM( ciInfo.dwAddr, ciInfo.dwFormat, ciInfo.dwSize, width, height, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); g_uRecentCIInfoPtrs[ciInfoIdx]->bCopied = true; if( ciInfoIdx == 1 ) // to save the current front buffer { CGraphicsContext::Get()->UpdateFrame(true); } return; } SetImgInfo tempinfo; tempinfo.dwAddr = ciInfo.dwAddr; tempinfo.dwFormat = ciInfo.dwFormat; tempinfo.dwSize = ciInfo.dwSize; tempinfo.dwWidth = ciInfo.dwWidth; int idx = SetBackBufferAsRenderTexture(tempinfo, ciInfoIdx); CopyBackBufferToRenderTexture(idx, ciInfo, pSrcRect); gRenderTextureInfos[idx].crcCheckedAtFrame = status.gDlistCount; gRenderTextureInfos[idx].crcInRDRAM = ComputeRenderTextureCRCInRDRAM(idx); DEBUGGER_IF_DUMP((logTextureBuffer&&pSrcRect==NULL),TRACE1("SaveBackBuffer at 0x%08X", ciInfo.dwAddr)); DEBUGGER_IF_DUMP((logTextureBuffer&&pSrcRect),TRACE5("SaveBackBuffer at 0x%08X, {%d,%d -%d,%d)", ciInfo.dwAddr, pSrcRect->left,pSrcRect->top,pSrcRect->right,pSrcRect->bottom)); DEBUGGER_IF_DUMP(( pauseAtNext && eventToPause == NEXT_RENDER_TEXTURE),{g_pFrameBufferManager->DisplayRenderTexture(idx);}); g_uRecentCIInfoPtrs[ciInfoIdx]->bCopied = true; } mupen64plus-video-rice-src-2.6.0/src/FrameBuffer.h000066400000000000000000000140111464507324400216640ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _FRAME_BUFFER_H_ #define _FRAME_BUFFER_H_ #include #include "RenderTexture.h" #include "Texture.h" #include "TextureManager.h" #include "osal_preproc.h" #include "typedefs.h" typedef int SURFFORMAT; extern void TexRectToN64FrameBuffer_16b(uint32 x0, uint32 y0, uint32 width, uint32 height, uint32 dwTile); extern void TexRectToFrameBuffer_8b(uint32 dwXL, uint32 dwYL, uint32 dwXH, uint32 dwYH, float t0u0, float t0v0, float t0u1, float t0v1, uint32 dwTile); class FrameBufferManager { friend class CGraphicsContext; friend class CDXGraphicsContext; public: FrameBufferManager(); virtual ~FrameBufferManager(); void Initialize(); void CloseUp(); void Set_CI_addr(SetImgInfo &newCI); void UpdateRecentCIAddr(SetImgInfo &ciinfo); void SetAddrBeDisplayed(uint32 addr); bool HasAddrBeenDisplayed(uint32 addr, uint32 width); int FindRecentCIInfoIndex(uint32 addr); bool IsDIaRenderTexture(); int CheckAddrInRenderTextures(uint32 addr, bool checkcrc = true); uint32 ComputeRenderTextureCRCInRDRAM(int infoIdx); void CheckRenderTextureCRCInRDRAM(void); int CheckRenderTexturesWithNewCI(SetImgInfo &CIinfo, uint32 height, bool byNewTxtrBuf); virtual void ClearN64FrameBufferToBlack(uint32 left=0, uint32 top=0, uint32 width=0, uint32 height=0); virtual int SetBackBufferAsRenderTexture(SetImgInfo &CIinfo, int ciInfoIdx); void LoadTextureFromRenderTexture(TxtrCacheEntry* pEntry, int infoIdx); void UpdateFrameBufferBeforeUpdateFrame(); virtual void RestoreNormalBackBuffer(); // restore the normal back buffer virtual void CopyBackToFrameBufferIfReadByCPU(uint32 addr); virtual void SetRenderTexture(void); virtual void CloseRenderTexture(bool toSave); virtual void ActiveTextureBuffer(void); int IsAddrInRecentFrameBuffers(uint32 addr); int CheckAddrInBackBuffers(uint32 addr, uint32 memsize, bool copyToRDRAM = false); uint8 CIFindIndex(uint16 val); uint32 ComputeCImgHeight(SetImgInfo &info, uint32 &height); int FindASlot(void); bool ProcessFrameWriteRecord(); void FrameBufferWriteByCPU(uint32 addr, uint32 size); void FrameBufferReadByCPU( uint32 addr ); bool FrameBufferInRDRAMCheckCRC(); void StoreRenderTextureToRDRAM(int infoIdx = -1); virtual bool IsRenderingToTexture() {return m_isRenderingToTexture;} // Device dependent functions virtual void SaveBackBuffer(int ciInfoIdx, RECT* pRect=NULL, bool forceToSaveToRDRAM = false); // Copy the current back buffer to temp buffer virtual void CopyBackBufferToRenderTexture(int idx, RecentCIInfo &ciInfo, RECT* pRect=NULL) {} // Copy the current back buffer to temp buffer virtual void CopyBufferToRDRAM(uint32 addr, uint32 fmt, uint32 siz, uint32 width, uint32 height, uint32 bufWidth, uint32 bufHeight, uint32 startaddr, uint32 memsize, uint32 pitch, TextureFmt bufFmt, void *surf, uint32 bufPitch); virtual void StoreBackBufferToRDRAM(uint32 addr, uint32 fmt, uint32 siz, uint32 width, uint32 height, uint32 bufWidth, uint32 bufHeight, uint32 startaddr=0xFFFFFFFF, uint32 memsize=0xFFFFFFFF, uint32 pitch=0, SURFFORMAT surf_fmt=SURFFMT_A8R8G8B8) {} #ifdef DEBUGGER virtual void DisplayRenderTexture(int infoIdx = -1); #endif protected: bool m_isRenderingToTexture; int m_curRenderTextureIndex; int m_lastTextureBufferIndex; }; class DXFrameBufferManager : public FrameBufferManager { virtual ~DXFrameBufferManager() {} public: // Device dependent functions virtual void CopyBackBufferToRenderTexture(int idx, RecentCIInfo &ciInfo, RECT* pRect=NULL); // Copy the current back buffer to temp buffer virtual void StoreBackBufferToRDRAM(uint32 addr, uint32 fmt, uint32 siz, uint32 width, uint32 height, uint32 bufWidth, uint32 bufHeight, uint32 startaddr=0xFFFFFFFF, uint32 memsize=0xFFFFFFFF, uint32 pitch=0, SURFFORMAT surf_fmt=SURFFMT_A8R8G8B8); }; class OGLFrameBufferManager : public FrameBufferManager { virtual ~OGLFrameBufferManager() {} public: // Device dependent functions virtual void CopyBackBufferToRenderTexture(int idx, RecentCIInfo &ciInfo, RECT* pRect=NULL); // Copy the current back buffer to temp buffer virtual void StoreBackBufferToRDRAM(uint32 addr, uint32 fmt, uint32 siz, uint32 width, uint32 height, uint32 bufWidth, uint32 bufHeight, uint32 startaddr=0xFFFFFFFF, uint32 memsize=0xFFFFFFFF, uint32 pitch=0, SURFFORMAT surf_fmt=SURFFMT_A8R8G8B8); }; extern RenderTextureInfo gRenderTextureInfos[]; extern RenderTextureInfo newRenderTextureInfo; #define NEW_TEXTURE_BUFFER extern RenderTextureInfo g_ZI_saves[2]; extern RenderTextureInfo *g_pRenderTextureInfo; extern FrameBufferManager* g_pFrameBufferManager; extern RecentCIInfo g_RecentCIInfo[]; extern RecentViOriginInfo g_RecentVIOriginInfo[]; extern RenderTextureInfo gRenderTextureInfos[]; extern int numOfTxtBufInfos; extern RecentCIInfo *g_uRecentCIInfoPtrs[5]; extern uint8 RevTlutTable[0x10000]; extern uint32 CalculateRDRAMCRC(void *pAddr, uint32 left, uint32 top, uint32 width, uint32 height, uint32 size, uint32 pitchInBytes ); extern uint16 ConvertRGBATo555(uint8 r, uint8 g, uint8 b, uint8 a); extern uint16 ConvertRGBATo555(uint32 color32); extern void InitTlutReverseLookup(void); #endif mupen64plus-video-rice-src-2.6.0/src/GraphicsContext.cpp000066400000000000000000000044511464507324400231470ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define M64P_PLUGIN_PROTOTYPES 1 #include #include "FrameBuffer.h" #include "GraphicsContext.h" #include "OGLGraphicsContext.h" #include "Video.h" #include "m64p_plugin.h" #include "m64p_vidext.h" #include "osal_preproc.h" #include "typedefs.h" CGraphicsContext* CGraphicsContext::m_pGraphicsContext = NULL; bool CGraphicsContext::needCleanScene = false; CGraphicsContext::CGraphicsContext() : m_bReady(false), m_bWindowed(true) { } CGraphicsContext::~CGraphicsContext() { g_pFrameBufferManager->CloseUp(); } bool CGraphicsContext::Initialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed) { m_bWindowed = (bWindowed != 0); g_pFrameBufferManager->Initialize(); return true; } bool CGraphicsContext::ResizeInitialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed ) { return true; } void CGraphicsContext::CleanUp() { m_bReady = false; } int __cdecl SortFrequenciesCallback( const void* arg1, const void* arg2 ) { unsigned int* p1 = (unsigned int*)arg1; unsigned int* p2 = (unsigned int*)arg2; if( *p1 < *p2 ) return -1; else if( *p1 > *p2 ) return 1; else return 0; } int __cdecl SortResolutionsCallback( const void* arg1, const void* arg2 ) { unsigned int* p1 = (unsigned int*)arg1; unsigned int* p2 = (unsigned int*)arg2; if( *p1 < *p2 ) return -1; else if( *p1 > *p2 ) return 1; else { if( p1[1] < p2[1] ) return -1; else if( p1[1] > p2[1] ) return 1; else return 0; } } mupen64plus-video-rice-src-2.6.0/src/GraphicsContext.h000066400000000000000000000043451464507324400226160ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef GFXCONTEXT_H #define GFXCONTEXT_H #include "CritSect.h" #include "osal_preproc.h" #include "typedefs.h" enum ClearFlag { CLEAR_COLOR_BUFFER=0x01, CLEAR_DEPTH_BUFFER=0x02, CLEAR_COLOR_AND_DEPTH_BUFFER=0x03, }; // This class basically provides an extra level of security for our // multithreaded code. Threads can Grab the CGraphicsContext to prevent // other threads from changing/releasing any of the pointers while it is // running. // It is based on CCritSect for Lock() and Unlock() class CGraphicsContext : public CCritSect { friend class CDeviceBuilder; public: static inline bool IsNull() { return m_pGraphicsContext == NULL; }; static inline CGraphicsContext* Get() { return m_pGraphicsContext; }; inline bool IsReady() const { return m_bReady; }; inline bool IsWindowed() const { return m_bWindowed; }; virtual bool Initialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed ); virtual bool ResizeInitialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed ); virtual void CleanUp(); virtual void Clear(ClearFlag flags, uint32 color=0xFF000000, float depth=1.0f) = 0; virtual void UpdateFrame(bool swaponly=false) = 0; virtual int ToggleFullscreen()=0; // return 0 as the result is windowed static bool needCleanScene; static CGraphicsContext* m_pGraphicsContext; // only the DeviceBuilder should modify this protected: bool m_bReady; bool m_bWindowed; virtual ~CGraphicsContext(); CGraphicsContext(); }; #endif mupen64plus-video-rice-src-2.6.0/src/OGLCombiner.cpp000066400000000000000000001667511464507324400221560ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - OGLCombiner.cpp * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2003 Rice1964 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "CombinerDefs.h" #include "GraphicsContext.h" #include "OGLCombiner.h" #include "OGLDebug.h" #include "OGLRender.h" #include "OGLGraphicsContext.h" #include "OGLTexture.h" #include "RenderBase.h" #include "osal_opengl.h" #include "osal_preproc.h" class CRender; //======================================================================== static uint32 DirectX_OGL_BlendFuncMaps [] = { GL_SRC_ALPHA, //Nothing GL_ZERO, //BLEND_ZERO = 1, GL_ONE, //BLEND_ONE = 2, GL_SRC_COLOR, //BLEND_SRCCOLOR = 3, GL_ONE_MINUS_SRC_COLOR, //BLEND_INVSRCCOLOR = 4, GL_SRC_ALPHA, //BLEND_SRCALPHA = 5, GL_ONE_MINUS_SRC_ALPHA, //BLEND_INVSRCALPHA = 6, GL_DST_ALPHA, //BLEND_DESTALPHA = 7, GL_ONE_MINUS_DST_ALPHA, //BLEND_INVDESTALPHA = 8, GL_DST_COLOR, //BLEND_DESTCOLOR = 9, GL_ONE_MINUS_DST_COLOR, //BLEND_INVDESTCOLOR = 10, GL_SRC_ALPHA_SATURATE, //BLEND_SRCALPHASAT = 11, GL_SRC_ALPHA_SATURATE, //BLEND_BOTHSRCALPHA = 12, GL_SRC_ALPHA_SATURATE, //BLEND_BOTHINVSRCALPHA = 13, }; //======================================================================== #include "OGLExtensions.h" #include static char newFrgStr[4092]; // The main buffer for store fragment shader string static const char *vertexShaderStr = "#version " GLSL_VERSION "\n" "uniform vec2 uFogMinMax;\n" "\n" "attribute vec4 inPosition;\n" "attribute vec2 inTexCoord0;\n" "attribute vec2 inTexCoord1;\n" "attribute float inFog;\n" "attribute vec4 inShadeColor;\n" "\n" "varying vec2 vertexTexCoord0;\n" "varying vec2 vertexTexCoord1;\n" "varying float vertexFog;\n" "varying vec4 vertexShadeColor;\n" "\n" "void main()\n" "{\n" "gl_Position = inPosition;\n" "vertexTexCoord0 = inTexCoord0;\n" "vertexTexCoord1 = inTexCoord1;\n" "vertexFog = clamp((uFogMinMax[1] - inFog) / (uFogMinMax[1] - uFogMinMax[0]), 0.0, 1.0);\n" "vertexShadeColor = inShadeColor;\n" "}\n"; static const char *fragmentShaderHeader = "#version " GLSL_VERSION "\n" "#ifdef GL_ES\n" "precision lowp float;\n" "#else\n" "#define lowp\n" "#define mediump\n" "#define highp\n" "#endif\n" "\n" "uniform vec4 uBlendColor;\n" "uniform vec4 uPrimColor;\n" "uniform vec4 uEnvColor;\n" "uniform vec3 uChromaKeyCenter;\n" "uniform vec3 uChromaKeyScale;\n" "uniform vec3 uChromaKeyWidth;\n" "uniform float uLodFrac;\n" "uniform float uPrimLodFrac;\n" "uniform float uK5;\n" "uniform float uK4;\n" "uniform sampler2D uTex0;\n" "uniform sampler2D uTex1;\n" "uniform vec4 uFogColor;\n" "\n" "varying vec2 vertexTexCoord0;\n" "varying vec2 vertexTexCoord1;\n" "varying float vertexFog;\n" "varying vec4 vertexShadeColor;\n" "\n" "void main()\n" "{\n" "vec4 outColor;\n"; //Fragment shader for InitCycleCopy static const char *fragmentCopyHeader = "#version " GLSL_VERSION "\n" "#ifdef GL_ES\n" "precision lowp float;\n" "#else\n" "#define lowp\n" "#define mediump\n" "#define highp\n" "#endif\n" "\n" "uniform vec4 uBlendColor;\n" "uniform sampler2D uTex0;\n" "varying vec2 vertexTexCoord0;\n" "void main()\n" "{\n" "vec4 outColor = texture2D(uTex0,vertexTexCoord0);\n"; //Fragment shader for InitCycleFill (the only self contain fragment shader) static const char *fragmentFill = "#version " GLSL_VERSION "\n" "#ifdef GL_ES\n" "precision lowp float;\n" "#else\n" "#define lowp\n" "#define mediump\n" "#define highp\n" "#endif\n" "\n" "uniform vec4 uFillColor;\n" "void main()\n" "{\n" "gl_FragColor = uFillColor;\n" "}\n"; static const char *fragmentShaderFooter = "gl_FragColor = outColor;\n" "}\n"; static GLuint createShader( GLenum shaderType, const char* shaderSrc ) { assert( shaderSrc != NULL ); GLuint shader = glCreateShader( shaderType ); OPENGL_CHECK_ERRORS // GL_VERTEX_SHADER, GL_FRAGMENT_SHADER glShaderSource(shader, 1, &shaderSrc, NULL); OPENGL_CHECK_ERRORS glCompileShader(shader); OPENGL_CHECK_ERRORS GLint status; glGetShaderiv(shader, GL_COMPILE_STATUS, &status); OPENGL_CHECK_ERRORS if (status == GL_FALSE) { printf("Compile shader failed:\n"); printf("Shader type: "); switch(shaderType) { case GL_VERTEX_SHADER : printf("Vertex\n"); break; case GL_FRAGMENT_SHADER : printf("Fragment\n"); break; default: printf("Unknown?\n"); break; } GLint param = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, ¶m); OPENGL_CHECK_ERRORS GLsizei infoLogLength = (GLsizei) param; assert( infoLogLength >= 0 ); GLchar *pInfoLog = new GLchar[ infoLogLength+1 ]; glGetShaderInfoLog(shader, infoLogLength, NULL, pInfoLog); OPENGL_CHECK_ERRORS printf("Info log:\n%s\n", pInfoLog); printf("GLSL code:\n%s\n", shaderSrc); glDeleteShader(shader); OPENGL_CHECK_ERRORS delete[] pInfoLog; } return shader; }; static GLuint createProgram(const GLuint vShader, GLuint fShader) { assert( vShader > CC_NULL_SHADER ); assert( fShader > CC_NULL_SHADER ); GLuint program = glCreateProgram(); OPENGL_CHECK_ERRORS glAttachShader(program, vShader); OPENGL_CHECK_ERRORS glAttachShader(program, fShader); OPENGL_CHECK_ERRORS glBindAttribLocation(program,VS_POSITION,"inPosition"); OPENGL_CHECK_ERRORS glBindAttribLocation(program,VS_TEXCOORD0,"inTexCoord0"); OPENGL_CHECK_ERRORS glBindAttribLocation(program,VS_TEXCOORD1,"inTexCoord1"); OPENGL_CHECK_ERRORS glBindAttribLocation(program,VS_FOG,"inFog"); OPENGL_CHECK_ERRORS glBindAttribLocation(program,VS_COLOR,"inShadeColor"); OPENGL_CHECK_ERRORS glLinkProgram(program); GLint status; glGetProgramiv(program, GL_LINK_STATUS, &status); OPENGL_CHECK_ERRORS if (status == GL_FALSE) { printf("Program link failed.\n"); GLint param = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, ¶m); OPENGL_CHECK_ERRORS GLsizei infoLogLength = (GLsizei) param; assert( infoLogLength >= 0 ); GLchar *pInfoLog = new GLchar[ infoLogLength+1 ]; glGetProgramInfoLog(program, infoLogLength, NULL, pInfoLog); OPENGL_CHECK_ERRORS printf("Info log:\n%s\n", pInfoLog); glDeleteProgram(program); OPENGL_CHECK_ERRORS delete[] pInfoLog; } glDetachShader(program, vShader); OPENGL_CHECK_ERRORS glDetachShader(program, fShader); OPENGL_CHECK_ERRORS return program; } COGLColorCombiner::COGLColorCombiner(CRender *pRender) : CColorCombiner(pRender), m_pOGLRender((OGLRender*)pRender), m_currentProgram(CC_NULL_PROGRAM) { m_vtxShader = createShader( GL_VERTEX_SHADER, vertexShaderStr ); // Generate Fill program GLuint frgShaderFill = createShader( GL_FRAGMENT_SHADER, fragmentFill ); m_fillProgram = createProgram(m_vtxShader, frgShaderFill); m_fillColorLoc = glGetUniformLocation(m_fillProgram,"uFillColor"); OPENGL_CHECK_ERRORS glDeleteShader( frgShaderFill ); OPENGL_CHECK_ERRORS } COGLColorCombiner::~COGLColorCombiner() { if( glIsShader( m_vtxShader ) == GL_TRUE ) glDeleteShader(m_vtxShader); OPENGL_CHECK_ERRORS if ( glIsProgram( m_fillProgram ) == GL_TRUE ) glDeleteProgram( m_fillProgram ); OPENGL_CHECK_ERRORS // Remove every created OpenGL programs ShaderSaveType* saveType = NULL; for( size_t i=0; iprogram ) == GL_TRUE ) glDeleteProgram( saveType->program ); OPENGL_CHECK_ERRORS } } bool COGLColorCombiner::Initialize(void) { return true; } void COGLColorCombiner::DisableCombiner(void) { useProgram( CC_NULL_PROGRAM ); OPENGL_CHECK_ERRORS } void COGLColorCombiner::InitCombinerCycleCopy(void) { // Look if we already have a compiled program for the current state. int shaderId = FindCompiledShaderId(); if( shaderId == -1 ) { shaderId = GenerateCopyProgram(); } const GLuint &program = m_generatedPrograms[shaderId].program; useProgram( program ); m_pOGLRender->EnableTexUnit(0,TRUE); GenerateCombinerSetting(); GenerateCombinerSettingConstants( shaderId ); glEnableVertexAttribArray(VS_POSITION); OPENGL_CHECK_ERRORS glEnableVertexAttribArray(VS_TEXCOORD0); OPENGL_CHECK_ERRORS glDisableVertexAttribArray(VS_COLOR); OPENGL_CHECK_ERRORS glDisableVertexAttribArray(VS_TEXCOORD1); OPENGL_CHECK_ERRORS glDisableVertexAttribArray(VS_FOG); OPENGL_CHECK_ERRORS COGLTexture* pTexture = g_textures[gRSP.curTile].m_pCOGLTexture; if( pTexture ) { m_pOGLRender->BindTexture(pTexture->m_dwTextureName, 0); m_pOGLRender->SetTexelRepeatFlags(gRSP.curTile); } } void COGLColorCombiner::InitCombinerCycleFill(void) { useProgram( m_fillProgram ); glUniform4f( m_fillColorLoc, ((gRDP.fillColor>>16)&0xFF)/255.0f, ((gRDP.fillColor>>8) &0xFF)/255.0f, ((gRDP.fillColor) &0xFF)/255.0f, ((gRDP.fillColor>>24)&0xFF)/255.0f); OPENGL_CHECK_ERRORS } // Generate the Blender (BL) part of the fragment shader void COGLColorCombiner::genFragmentBlenderStr( char *newFrgStr ) { //////////////////////////////////////////////////////////////////////////// // BL (Blender). Equation: (A*P+B*M)/(A+B) //////////////////////////////////////////////////////////////////////////// /*uint16 tmpblender = gRDP.otherMode.blender; //RDP_BlenderSetting &bl = *(RDP_BlenderSetting*)(&(blender)); RDP_BlenderSetting* blender = (RDP_BlenderSetting*)(&tmpblender); switch( blender->c1_m1a ) // A cycle 1 { case 0 : // CC output alpha strcat(newFrgStr, "float BL_A = outColor.a;\n"); break; case 1 : // fog alpha (register) strcat(newFrgStr, "float BL_A = vertexFog;\n"); break; case 2 : // shade alpha strcat(newFrgStr, "float BL_A = vertexShadeColor.a;\n"); break; case 3 : // 0.0 strcat(newFrgStr, "float BL_A = 0.0;\n"); break; } switch( blender->c1_m1b ) // P cycle 1 (Same as M) { case 0 : // pixel rgb strcat(newFrgStr, "vec3 BL_P = outColor.rgb;\n"); break; case 1 : // TODO: 1 memory RGB (what is that?) //strcat(newFrgStr, "vec3 BL_P = vec3(1.0, 0.0, 1.0);\n"); //purple... strcat(newFrgStr, "vec3 BL_P = uPrimColor.rgb;\n"); break; case 2 : // blend rgb (register) strcat(newFrgStr, "vec3 BL_P = uBlendColor.rgb;\n"); break; case 3 : // fog rgb (register) //strcat(newFrgStr, "vec3 BL_P = uFogColor.rgb;\n"); strcat(newFrgStr, "vec3 BL_P = vec3(1.0, 0.0, 1.0);\n"); //purple... break; } switch( blender->c1_m2a ) // B cycle 1 { case 0 : // 1.0 - ‘a mux’ output strcat(newFrgStr, "float BL_B = 1.0 - BL_A;\n"); break; case 1 : // memory alpha // TODO: memory alpha (what is that?) strcat(newFrgStr, "float BL_B = 1.0;\n"); break; case 2 : // 1.0 strcat(newFrgStr, "float BL_B = 1.0;\n"); break; case 3 : // 0.0 strcat(newFrgStr, "float BL_B = 0.0;\n"); break; } switch( blender->c1_m2b ) // M cycle 1 (Same as P) { case 0 : // pixel rgb strcat(newFrgStr, "vec3 BL_M = outColor.rgb;\n"); break; case 1 : // TODO: 1 memory RGB (what is that?) //strcat(newFrgStr, "vec3 BL_M = vec3(1.0, 0.0, 1.0);\n"); //purple... strcat(newFrgStr, "vec3 BL_M = uPrimColor.rgb;\n"); break; case 2 : // blend rgb (register) strcat(newFrgStr, "vec3 BL_M = uBlendColor.rgb;\n"); break; case 3 : // fog rgb (register) //strcat(newFrgStr, "vec3 BL_M = uFogColor.rgb;\n"); strcat(newFrgStr, "vec3 BL_M = vec3(1.0, 0.0, 1.0);\n"); //purple... break; } strcat(newFrgStr, "outColor = ( vec4(BL_P.rgb, BL_A) + vec4(BL_M.rgb, BL_B) ) / vec4( BL_A + BL_B );\n");*/ // When aa_en and alpha_cvg_sel are enabled, N64 do a nice and smoother clamp (aka coverage is smooth). // This try to simulate the "smooth" clamp increasing the value to avoid pixelized clamp /*if( gRDP.otherMode.aa_en ) { strcat(newFrgStr, "float clamp_value = 0.5;\n"); } else { strcat(newFrgStr, "float clamp_value = 0.004;\n"); // default value 1/255 = 0.004 }*/ /* // As we don't have coverage in GLSL, we consider coverage = alpha if( gRDP.otherMode.alpha_cvg_sel ) // Use coverage bits for alpha calculation { if( gRDP.otherMode.cvg_x_alpha ) { // texture cutout mode (Mario Kart 64 kart sprites/Mario 64 trees/some 1080SB face to cam border trees) strcat(newFrgStr, "if( outColor.a < clamp_value ) discard;\n"); } else { //strcat(newFrgStr, "outColor.a = 1.0;\n"); } } else if( gRDP.otherMode.cvg_x_alpha ) { // strict texture cutout mode (Mario Kart 64 items sprites /1080SB border trees) strcat(newFrgStr, "if( outColor.a < 0.004 ) discard;\n"); }*/ //} strcat(newFrgStr, "float coverage = 1.0;\n"); if( gRDP.otherMode.cvg_x_alpha ) { /*strcat(newFrgStr, "if( outColor.a > 0.004 ) {\n"); strcat(newFrgStr, " coverage = 1.0;\n"); strcat(newFrgStr, "} else {\n"); strcat(newFrgStr, " coverage = 0.0;\n"); strcat(newFrgStr, "}\n");*/ strcat(newFrgStr, "coverage = coverage * outColor.a;\n"); } if( gRDP.otherMode.alpha_cvg_sel ) // Use coverage bits for alpha calculation { // texture cutof (MK64 kart sprites/Mario 64 trees/1080SB "face to cam" border trees) strcat(newFrgStr, "coverage = step( 0.5, coverage );\n"); strcat(newFrgStr, "outColor.a = coverage;\n"); } /*if( gRDP.otherMode.clr_on_cvg ) // SSB64 first ground sprites { strcat(newFrgStr, "if( coverage < 0.004 ) discard;\n"); }*/ /*switch( gRDP.otherMode.cvg_dst ) { case CVG_DST_CLAMP : strcat(newFrgStr, "if( coverage < 0.99 ) coverage = 0.0 ;\n"); break; case CVG_DST_WRAP : strcat(newFrgStr, "if( coverage > 0.004 ) coverage = 1.0 ;\n"); break; case CVG_DST_FULL : strcat(newFrgStr, "coverage = 1.0 ;\n"); break; case CVG_DST_SAVE : strcat(newFrgStr, "coverage = 0.0 ;\n"); break; default : break; }*/ strcat(newFrgStr, "if( coverage < 0.1 ) discard;\n"); switch( gRDP.otherMode.alpha_compare ) { case RDP_ALPHA_COMPARE_THRESHOLD : // keep value if outColor.a >= uBlendColor.a //strcat(newFrgStr, "if( abs( uBlendColor.a - outColor.a ) < 0.00000001 ) discard;\n"); // Top Gear Rally use this mode for opacity strcat(newFrgStr, "if( outColor.a < uBlendColor.a ) discard;\n"); break; case RDP_ALPHA_COMPARE_DITHER : strcat(newFrgStr, "if( outColor.a < fract(sin(dot(gl_FragCoord.xy, vec2(12.9898, 78.233)))* 43758.5453) ) discard;\n"); break; case RDP_ALPHA_COMPARE_NONE : default : break; } if( gRDP.bFogEnableInBlender && gRSP.bFogEnabled ) { strcat(newFrgStr, "outColor.rgb = mix(uFogColor.rgb, outColor.rgb, vertexFog);\n"); //strcat(newFrgStr, "outColor.rgb = vec3(vertexFog,vertexFog,vertexFog);\n"); } } // Generate a program for the current combiner state // The main part of the function add one line for each part of the combiner. // A, B, C, D (colors) and a, b, c, d (alpha). So if you modify the part of one of them // don't forget to modify the part for the other (A and a, B and b, etc...) GLuint COGLColorCombiner::GenerateCycle12Program() { newFrgStr[0] = 0; strcat(newFrgStr, fragmentShaderHeader); //////////////////////////////////////////////////////////////////////////// // Colors (rgb) Cycle 1 //////////////////////////////////////////////////////////////////////////// // A0 (Cycle 1) switch( m_sources[CS_COLOR_A0] ) { case CCMUX_COMBINED : // 0 (this commented numbers are related to the Color Combiner schema) printf("CCMUX_COMBINED for AColor. This should never happen in cycle 1.\n"); //strcat(newFrgStr, "vec3 AColor = vec3(1.0, 1.0, 1.0);\n"); // set "something". break; case CCMUX_TEXEL0 : // 1 strcat(newFrgStr, "vec3 AColor = texture2D(uTex0,vertexTexCoord0).rgb;\n"); break; case CCMUX_TEXEL1 : // 2 strcat(newFrgStr, "vec3 AColor = texture2D(uTex1,vertexTexCoord1).rgb;\n"); break; case CCMUX_PRIMITIVE : // 3 strcat(newFrgStr, "vec3 AColor = uPrimColor.rgb;\n"); break; case CCMUX_SHADE : // 4 strcat(newFrgStr, "vec3 AColor = vertexShadeColor.rgb;\n"); break; case CCMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "vec3 AColor = uEnvColor.rgb;\n"); break; case CCMUX_1 : // 6 strcat(newFrgStr, "vec3 AColor = vec3(1.0);\n"); break; case CCMUX_NOISE : // 7 strcat(newFrgStr, "vec3 AColor = noise3(0.0);\n"); break; case CCMUX_0 : // 8 default: // everything > CCMUX_0 (8) is 0 strcat(newFrgStr, "vec3 AColor = vec3(0.0);\n"); break; } // B0 (Cycle 1) switch( m_sources[CS_COLOR_B0] ) { case CCMUX_COMBINED : // 0 printf("CCMUX_COMBINED for BColor. This should never happen in cycle 1.\n"); //strcat(newFrgStr, "vec3 BColor = vec3(1.0, 1.0, 1.0);\n"); // set "something". break; case CCMUX_TEXEL0 : // 1 strcat(newFrgStr, "vec3 BColor = texture2D(uTex0,vertexTexCoord0).rgb;\n"); break; case CCMUX_TEXEL1 :// 2 strcat(newFrgStr, "vec3 BColor = texture2D(uTex1,vertexTexCoord1).rgb;\n"); break; case CCMUX_PRIMITIVE : // 3 strcat(newFrgStr, "vec3 BColor = uPrimColor.rgb;\n"); break; case CCMUX_SHADE : // 4 strcat(newFrgStr, "vec3 BColor = vertexShadeColor.rgb;\n"); break; case CCMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "vec3 BColor = uEnvColor.rgb;\n"); break; case CCMUX_CENTER : // 6 printf("CCMUX_CENTER for BColor. This should never happen in cycle 1.\n"); //strcat(newFrgStr, "vec3 BColor = uChromaKeyCenter;\n"); break; case CCMUX_K4 : // 7 strcat(newFrgStr, "vec3 BColor = vec3(uK4);\n"); break; case CCMUX_0 : // 8 default: // everything > CCMUX_0 (8) is 0 strcat(newFrgStr, "vec3 BColor = vec3(0.0);\n"); break; } // C0 (Cycle 1) switch( m_sources[CS_COLOR_C0] ) { case CCMUX_COMBINED : // 0 printf("CCMUX_COMBINED for CColor. This should never happen in cycle 1.\n"); //strcat(newFrgStr, "vec3 CColor = vec3(1.0, 1.0, 1.0);\n"); // set "something". break; case CCMUX_TEXEL0 : // 1 strcat(newFrgStr, "vec3 CColor = texture2D(uTex0,vertexTexCoord0).rgb;\n"); break; case CCMUX_TEXEL1 :// 2 strcat(newFrgStr, "vec3 CColor = texture2D(uTex1,vertexTexCoord1).rgb;\n"); break; case CCMUX_PRIMITIVE : // 3 strcat(newFrgStr, "vec3 CColor = uPrimColor.rgb;\n"); break; case CCMUX_SHADE : // 4 strcat(newFrgStr, "vec3 CColor = vertexShadeColor.rgb;\n"); break; case CCMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "vec3 CColor = uEnvColor.rgb;\n"); break; case CCMUX_SCALE : // 6 printf("CCMUX_SCALE for CColor. This should never happen in cycle 1.\n"); //strcat(newFrgStr, "vec3 CColor = uChromaKeyScale;\n"); break; case CCMUX_COMBINED_ALPHA : // 7 printf("CCMUX_COMBINED_ALPHA for CColor. This should never happen in cycle 1.\n"); //strcat(newFrgStr, "vec3 CColor = uEnvColor;\n"); break; case CCMUX_TEXEL0_ALPHA : // 8 strcat(newFrgStr, "vec3 CColor = vec3(texture2D(uTex0,vertexTexCoord0).a);\n"); break; case CCMUX_TEXEL1_ALPHA : // 9 strcat(newFrgStr, "vec3 CColor = vec3(texture2D(uTex1,vertexTexCoord1).a);\n"); break; case CCMUX_PRIMITIVE_ALPHA : // 10 strcat(newFrgStr, "vec3 CColor = vec3(uPrimColor.a);\n"); break; case CCMUX_SHADE_ALPHA : // 11 strcat(newFrgStr, "vec3 CColor = vec3(vertexShadeColor.a);\n"); break; case CCMUX_ENV_ALPHA : // 12 strcat(newFrgStr, "vec3 CColor = vec3(uEnvColor.a);\n"); break; case CCMUX_LOD_FRACTION : // 13 strcat(newFrgStr, "vec3 CColor = vec3(uLodFrac);\n"); // Used by Goldeneye64 break; case CCMUX_PRIM_LOD_FRAC : // 14 strcat(newFrgStr, "vec3 CColor = vec3(uPrimLodFrac);\n"); // Used by Doom64 break; case CCMUX_K5 : // 15 strcat(newFrgStr, "vec3 CColor = vec3(uK5);\n"); break; case CCMUX_0 : // 16 default: // everything > CCMUX_0 (16) is 0 strcat(newFrgStr, "vec3 CColor = vec3(0.0);\n"); break; } // D0 (Cycle 1) switch( m_sources[CS_COLOR_D0] ) { case CCMUX_COMBINED : // 0 printf("CCMUX_COMBINED for DColor. This should never happen in cycle 1.\n"); //strcat(newFrgStr, "vec3 DColor = vec3(1.0, 1.0, 1.0);\n"); // set "something". break; case CCMUX_TEXEL0 : // 1 strcat(newFrgStr, "vec3 DColor = texture2D(uTex0,vertexTexCoord0).rgb;\n"); break; case CCMUX_TEXEL1 :// 2 strcat(newFrgStr, "vec3 DColor = texture2D(uTex1,vertexTexCoord1).rgb;\n"); break; case CCMUX_PRIMITIVE : // 3 strcat(newFrgStr, "vec3 DColor = uPrimColor.rgb;\n"); break; case CCMUX_SHADE : // 4 strcat(newFrgStr, "vec3 DColor = vertexShadeColor.rgb;\n"); break; case CCMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "vec3 DColor = uEnvColor.rgb;\n"); break; case CCMUX_1 : // 6 strcat(newFrgStr, "vec3 DColor = vec3(1.0);\n"); break; case CCMUX_0 : // 7 default: // everything > CCMUX_0 (7) is 0 strcat(newFrgStr, "vec3 DColor = vec3(0.0);\n"); break; } //////////////////////////////////////////////////////////////////////////// // Alphas (float) Cycle 1 //////////////////////////////////////////////////////////////////////////// // a0 (Cycle 1) (same than b0 and c0 actually) switch( m_sources[CS_ALPHA_A0] ) { case ACMUX_COMBINED : // 0 printf("ACMUX_COMBINED for AAlpha. This should never happen in cycle 1.\n"); //strcat(newFrgStr, "float AAlpha = 1.0;\n"); // set "something". break; case ACMUX_TEXEL0 : // 1 strcat(newFrgStr, "float AAlpha = texture2D(uTex0,vertexTexCoord0).a;\n"); break; case ACMUX_TEXEL1 : // 2 strcat(newFrgStr, "float AAlpha = texture2D(uTex1,vertexTexCoord1).a;\n"); break; case ACMUX_PRIMITIVE : // 3 strcat(newFrgStr, "float AAlpha = uPrimColor.a;\n"); break; case ACMUX_SHADE : // 4 strcat(newFrgStr, "float AAlpha = vertexShadeColor.a;\n"); break; case ACMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "float AAlpha = uEnvColor.a;\n"); break; case ACMUX_1 : // 6 strcat(newFrgStr, "float AAlpha = 1.0;\n"); break; case ACMUX_0 : // 7 default: // everything > CCMUX_0 (7) is 0 strcat(newFrgStr, "float AAlpha = 0.0;\n"); break; } // b0 (Cycle 1) (same than a0 and c0 actually) switch( m_sources[CS_ALPHA_B0] ) { case ACMUX_COMBINED : // 0 printf("ACMUX_COMBINED for BAlpha. This should never happen in cycle 1.\n"); //strcat(newFrgStr, "float BAlpha = 1.0;\n"); // set "something". break; case ACMUX_TEXEL0 : // 1 strcat(newFrgStr, "float BAlpha = texture2D(uTex0,vertexTexCoord0).a;\n"); break; case ACMUX_TEXEL1 : // 2 strcat(newFrgStr, "float BAlpha = texture2D(uTex1,vertexTexCoord1).a;\n"); break; case ACMUX_PRIMITIVE : // 3 strcat(newFrgStr, "float BAlpha = uPrimColor.a;\n"); break; case ACMUX_SHADE : // 4 strcat(newFrgStr, "float BAlpha = vertexShadeColor.a;\n"); break; case ACMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "float BAlpha = uEnvColor.a;\n"); break; case ACMUX_1 : // 6 strcat(newFrgStr, "float BAlpha = 1.0;\n"); break; case ACMUX_0 : // 7 default: // everything > CCMUX_0 (7) is 0 strcat(newFrgStr, "float BAlpha = 0.0;\n"); break; } // c0 (Cycle 1) kind of "exotic" switch( m_sources[CS_ALPHA_C0] ) { case ACMUX_LOD_FRACTION : // 0 strcat(newFrgStr, "float CAlpha = uLodFrac;\n"); break; case ACMUX_TEXEL0 : // 1 strcat(newFrgStr, "float CAlpha = texture2D(uTex0,vertexTexCoord0).a;\n"); break; case ACMUX_TEXEL1 : // 2 strcat(newFrgStr, "float CAlpha = texture2D(uTex1,vertexTexCoord1).a;\n"); break; case ACMUX_PRIMITIVE : // 3 strcat(newFrgStr, "float CAlpha = uPrimColor.a;\n"); break; case ACMUX_SHADE : // 4 strcat(newFrgStr, "float CAlpha = vertexShadeColor.a;\n"); break; case ACMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "float CAlpha = uEnvColor.a;\n"); break; case ACMUX_PRIM_LOD_FRAC : // 6 strcat(newFrgStr, "float CAlpha = uPrimLodFrac;\n"); break; case ACMUX_0 : // 7 default: // everything > CCMUX_0 (7) is 0 strcat(newFrgStr, "float CAlpha = 0.0;\n"); break; } // d0 (Cycle 1) (same than a0 and b0 actually) switch( m_sources[CS_ALPHA_D0] ) { case ACMUX_COMBINED : // 0 printf("ACMUX_COMBINED for DAlpha. This should never happen in cycle 1.\n"); //strcat(newFrgStr, "float DAlpha = 1.0;\n"); // set "something". break; case ACMUX_TEXEL0 : // 1 strcat(newFrgStr, "float DAlpha = texture2D(uTex0,vertexTexCoord0).a;\n"); break; case ACMUX_TEXEL1 : // 2 strcat(newFrgStr, "float DAlpha = texture2D(uTex1,vertexTexCoord1).a;\n"); break; case ACMUX_PRIMITIVE : // 3 strcat(newFrgStr, "float DAlpha = uPrimColor.a;\n"); break; case ACMUX_SHADE : // 4 strcat(newFrgStr, "float DAlpha = vertexShadeColor.a;\n"); break; case ACMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "float DAlpha = uEnvColor.a;\n"); break; case ACMUX_1 : // 6 strcat(newFrgStr, "float DAlpha = 1.0;\n"); break; case ACMUX_0 : // 7 default: // everything > CCMUX_0 (7) is 0 strcat(newFrgStr, "float DAlpha = 0.0;\n"); break; } strcat(newFrgStr, "vec3 cycle1Color = (AColor - BColor) * CColor + DColor;\n"); //strcat(newFrgStr, "vec3 cycle1Color = vec3(float(AColor), float(CColor), float(DColor));\n"); strcat(newFrgStr, "float cycle1Alpha = (AAlpha - BAlpha) * CAlpha + DAlpha;\n"); //strcat(newFrgStr, "float cycle1Alpha = AAlpha;\n"); //strcat(newFrgStr, "outColor.rgb = vec3(greaterThan(cycle1Color, vec3(1.0)));\n"); //strcat(newFrgStr, "outColor.rgb = cycle1Color;\n"); //strcat(newFrgStr, "outColor.a = cycle1Alpha;\n"); switch( gRDP.otherMode.cycle_type ) { case CYCLE_TYPE_1 : // 1 cycle mode? compute the fragment color strcat(newFrgStr, "outColor.rgb = cycle1Color;\n"); strcat(newFrgStr, "outColor.a = cycle1Alpha;\n"); break; case CYCLE_TYPE_2 : { // 2 cycle mode? add another color computation // Chroma key if( gRDP.otherMode.key_en ) { strcat(newFrgStr, "float resultChromaKeyR = clamp( 0.0, (-abs( (cycle1Color.r - uChromaKeyCenter.r) * uChromaKeyScale.r) + uChromaKeyWidth.r), 1.0);\n"); strcat(newFrgStr, "float resultChromaKeyG = clamp( 0.0, (-abs( (cycle1Color.g - uChromaKeyCenter.g) * uChromaKeyScale.g) + uChromaKeyWidth.g), 1.0);\n"); strcat(newFrgStr, "float resultChromaKeyB = clamp( 0.0, (-abs( (cycle1Color.b - uChromaKeyCenter.b) * uChromaKeyScale.b) + uChromaKeyWidth.b), 1.0);\n"); strcat(newFrgStr, "float resultChromaKeyA = min( resultChromaKeyR, resultChromaKeyG, resultChromaKeyB );\n"); strcat(newFrgStr, "outColor = vec4( resultChromaKeyR, resultChromaKeyG, resultChromaKeyB, resultChromaKeyA );\n"); } else { // Color combiner //////////////////////////////////////////////////////////////////////////// // Colors (rgb) Cycle 2 //////////////////////////////////////////////////////////////////////////// // A0 (Cycle 2) switch( m_sources[CS_COLOR_A1] ) { case CCMUX_COMBINED : // 0 strcat(newFrgStr, "AColor = cycle1Color;\n"); break; case CCMUX_TEXEL0 : // 1 strcat(newFrgStr, "AColor = texture2D(uTex0,vertexTexCoord0).rgb;\n"); break; case CCMUX_TEXEL1 : // 2 strcat(newFrgStr, "AColor = texture2D(uTex1,vertexTexCoord1).rgb;\n"); break; case CCMUX_PRIMITIVE : // 3 strcat(newFrgStr, "AColor = uPrimColor.rgb;\n"); break; case CCMUX_SHADE : // 4 strcat(newFrgStr, "AColor = vertexShadeColor.rgb;\n"); break; case CCMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "AColor = uEnvColor.rgb;\n"); break; case CCMUX_1 : // 6 strcat(newFrgStr, "AColor = vec3(1.0, 1.0, 1.0);\n"); break; case CCMUX_NOISE : // 7 strcat(newFrgStr, "AColor = noise3(0.0);\n"); break; case CCMUX_0 : // 8 default: // everything > CCMUX_0 (8) is 0 strcat(newFrgStr, "AColor = vec3(0.0, 0.0, 0.0);\n"); break; } // B0 (Cycle 2) switch( m_sources[CS_COLOR_B1] ) { case CCMUX_COMBINED : // 0 strcat(newFrgStr, "BColor = cycle1Color;\n"); break; case CCMUX_TEXEL0 : // 1 strcat(newFrgStr, "BColor = texture2D(uTex0,vertexTexCoord0).rgb;\n"); break; case CCMUX_TEXEL1 :// 2 strcat(newFrgStr, "BColor = texture2D(uTex1,vertexTexCoord1).rgb;\n"); break; case CCMUX_PRIMITIVE : // 3 strcat(newFrgStr, "BColor = uPrimColor.rgb;\n"); break; case CCMUX_SHADE : // 4 strcat(newFrgStr, "BColor = vertexShadeColor.rgb;\n"); break; case CCMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "BColor = uEnvColor.rgb;\n"); break; case CCMUX_CENTER : // 6 strcat(newFrgStr, "BColor = uChromaKeyCenter;\n"); break; case CCMUX_K4 : // 7 strcat(newFrgStr, "BColor = vec3(uK4);\n"); break; case CCMUX_0 : // 8 default: // everything > CCMUX_0 (8) is 0 strcat(newFrgStr, "BColor = vec3(0.0, 0.0, 0.0);\n"); break; } // C0 (Cycle 2) switch( m_sources[CS_COLOR_C1] ) { case CCMUX_COMBINED : // 0 strcat(newFrgStr, "CColor = cycle1Color;\n"); break; case CCMUX_TEXEL0 : // 1 strcat(newFrgStr, "CColor = texture2D(uTex0,vertexTexCoord0).rgb;\n"); break; case CCMUX_TEXEL1 :// 2 strcat(newFrgStr, "CColor = texture2D(uTex1,vertexTexCoord1).rgb;\n"); break; case CCMUX_PRIMITIVE : // 3 strcat(newFrgStr, "CColor = uPrimColor.rgb;\n"); break; case CCMUX_SHADE : // 4 strcat(newFrgStr, "CColor = vertexShadeColor.rgb;\n"); break; case CCMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "CColor = uEnvColor.rgb;\n"); break; case CCMUX_SCALE : // 6 strcat(newFrgStr, "CColor = uChromaKeyScale;\n"); break; case CCMUX_COMBINED_ALPHA : // 7 strcat(newFrgStr, "CColor = vec3(cycle1Alpha);\n"); break; case CCMUX_TEXEL0_ALPHA : // 8 strcat(newFrgStr, "CColor = vec3(texture2D(uTex0,vertexTexCoord0).a);\n"); break; case CCMUX_TEXEL1_ALPHA : // 9 strcat(newFrgStr, "CColor = vec3(texture2D(uTex1,vertexTexCoord1).a);\n"); break; case CCMUX_PRIMITIVE_ALPHA : // 10 strcat(newFrgStr, "CColor = vec3(uPrimColor.a);\n"); break; case CCMUX_SHADE_ALPHA : // 11 strcat(newFrgStr, "CColor = vec3(vertexShadeColor.a);\n"); break; case CCMUX_ENV_ALPHA : // 12 strcat(newFrgStr, "CColor = vec3(uEnvColor.a);\n"); break; case CCMUX_LOD_FRACTION : // 13 strcat(newFrgStr, "CColor = vec3(uLodFrac);\n"); break; case CCMUX_PRIM_LOD_FRAC : // 14 strcat(newFrgStr, "CColor = vec3(uPrimLodFrac);\n"); break; case CCMUX_K5 : // 15 strcat(newFrgStr, "CColor = vec3(uK5);\n"); break; case CCMUX_0 : // 16 default: // everything > CCMUX_0 (16) is 0 strcat(newFrgStr, "CColor = vec3(0.0, 0.0, 0.0);\n"); break; } // D0 (Cycle 2) switch( m_sources[CS_COLOR_D1] ) { case CCMUX_COMBINED : // 0 strcat(newFrgStr, "DColor = cycle1Color;\n"); break; case CCMUX_TEXEL0 : // 1 strcat(newFrgStr, "DColor = texture2D(uTex0,vertexTexCoord0).rgb;\n"); break; case CCMUX_TEXEL1 :// 2 strcat(newFrgStr, "DColor = texture2D(uTex1,vertexTexCoord1).rgb;\n"); break; case CCMUX_PRIMITIVE : // 3 strcat(newFrgStr, "DColor = uPrimColor.rgb;\n"); break; case CCMUX_SHADE : // 4 strcat(newFrgStr, "DColor = vertexShadeColor.rgb;\n"); break; case CCMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "DColor = uEnvColor.rgb;\n"); break; case CCMUX_1 : // 6 strcat(newFrgStr, "DColor = vec3(1.0, 1.0, 1.0);\n"); break; case CCMUX_0 : // 7 default: // everything > CCMUX_0 (7) is 0 strcat(newFrgStr, "DColor = vec3(0.0, 0.0, 0.0);\n"); break; } //////////////////////////////////////////////////////////////////////////// // Alphas (float) Cycle 2 //////////////////////////////////////////////////////////////////////////// // a0 (Cycle 2) (same than b0 and c0 actually) switch( m_sources[CS_ALPHA_A1] ) { case ACMUX_COMBINED : // 0 strcat(newFrgStr, "AAlpha = cycle1Alpha;\n"); break; case ACMUX_TEXEL0 : // 1 strcat(newFrgStr, "AAlpha = texture2D(uTex0,vertexTexCoord0).a;\n"); break; case ACMUX_TEXEL1 : // 2 strcat(newFrgStr, "AAlpha = texture2D(uTex1,vertexTexCoord1).a;\n"); break; case ACMUX_PRIMITIVE : // 3 strcat(newFrgStr, "AAlpha = uPrimColor.a;\n"); break; case ACMUX_SHADE : // 4 strcat(newFrgStr, "AAlpha = vertexShadeColor.a;\n"); break; case ACMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "AAlpha = uEnvColor.a;\n"); break; case ACMUX_1 : // 6 strcat(newFrgStr, "AAlpha = 1.0;\n"); break; case ACMUX_0 : // 7 default: // everything > CCMUX_0 (7) is 0 strcat(newFrgStr, "AAlpha = 0.0;\n"); break; } // b0 (Cycle 2) (same than a0 and c0 actually) switch( m_sources[CS_ALPHA_B1] ) { case ACMUX_COMBINED : // 0 strcat(newFrgStr, "BAlpha = cycle1Alpha;\n"); break; case ACMUX_TEXEL0 : // 1 strcat(newFrgStr, "BAlpha = texture2D(uTex0,vertexTexCoord0).a;\n"); break; case ACMUX_TEXEL1 : // 2 strcat(newFrgStr, "BAlpha = texture2D(uTex1,vertexTexCoord1).a;\n"); break; case ACMUX_PRIMITIVE : // 3 strcat(newFrgStr, "BAlpha = uPrimColor.a;\n"); break; case ACMUX_SHADE : // 4 strcat(newFrgStr, "BAlpha = vertexShadeColor.a;\n"); break; case ACMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "BAlpha = uEnvColor.a;\n"); break; case ACMUX_1 : // 6 strcat(newFrgStr, "BAlpha = 1.0;\n"); break; case ACMUX_0 : // 7 default: // everything > CCMUX_0 (7) is 0 strcat(newFrgStr, "BAlpha = 0.0;\n"); break; } // c0 (Cycle 2) kind of "exotic" switch( m_sources[CS_ALPHA_C1] ) { case ACMUX_LOD_FRACTION : // 0 strcat(newFrgStr, "CAlpha = uLodFrac;\n"); break; case ACMUX_TEXEL0 : // 1 strcat(newFrgStr, "CAlpha = texture2D(uTex0,vertexTexCoord0).a;\n"); break; case ACMUX_TEXEL1 : // 2 strcat(newFrgStr, "CAlpha = texture2D(uTex1,vertexTexCoord1).a;\n"); break; case ACMUX_PRIMITIVE : // 3 strcat(newFrgStr, "CAlpha = uPrimColor.a;\n"); break; case ACMUX_SHADE : // 4 strcat(newFrgStr, "CAlpha = vertexShadeColor.a;\n"); break; case ACMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "CAlpha = uEnvColor.a;\n"); break; case ACMUX_PRIM_LOD_FRAC : // 6 strcat(newFrgStr, "CAlpha = uPrimLodFrac;\n"); break; case ACMUX_0 : // 7 default: // everything > CCMUX_0 (7) is 0 strcat(newFrgStr, "CAlpha = 0.0;\n"); break; } // d0 (Cycle 2) (same than a0 and b0 actually) switch( m_sources[CS_ALPHA_D1] ) { case ACMUX_COMBINED : // 0 strcat(newFrgStr, "DAlpha = cycle1Alpha;\n"); break; case ACMUX_TEXEL0 : // 1 strcat(newFrgStr, "DAlpha = texture2D(uTex0,vertexTexCoord0).a;\n"); break; case ACMUX_TEXEL1 : // 2 strcat(newFrgStr, "DAlpha = texture2D(uTex1,vertexTexCoord1).a;\n"); break; case ACMUX_PRIMITIVE : // 3 strcat(newFrgStr, "DAlpha = uPrimColor.a;\n"); break; case ACMUX_SHADE : // 4 strcat(newFrgStr, "DAlpha = vertexShadeColor.a;\n"); break; case ACMUX_ENVIRONMENT : // 5 strcat(newFrgStr, "DAlpha = uEnvColor.a;\n"); break; case ACMUX_1 : // 6 strcat(newFrgStr, "DAlpha = 1.0;\n"); break; case ACMUX_0 : // 7 default: // everything > CCMUX_0 (7) is 0 strcat(newFrgStr, "DAlpha = 0.0;\n"); break; } strcat(newFrgStr, "outColor.rgb = (AColor - BColor) * CColor + DColor;\n"); strcat(newFrgStr, "outColor.a = (AAlpha - BAlpha) * CAlpha + DAlpha;\n"); //strcat(newFrgStr, "outColor.rgb = cycle1Color;\n"); //strcat(newFrgStr, "outColor.a = cycle1Alpha;\n"); break; } } // end case CYCLE_TYPE_2 case CYCLE_TYPE_COPY : case CYCLE_TYPE_FILL : default : // TODO? break; } // end switch cycle type //strcat(newFrgStr, "outColor.rgb = vec3(greaterThan(outColor.rgb, vec3(1.0)));\n"); genFragmentBlenderStr( newFrgStr ); strcat( newFrgStr, fragmentShaderFooter ); // (always the same) //////////////////////////////////////////////////////////////////////////// // Create the program //////////////////////////////////////////////////////////////////////////// GLuint frgShader = createShader( GL_FRAGMENT_SHADER, newFrgStr ); GLuint program = createProgram( m_vtxShader, frgShader ); glDeleteShader(frgShader); OPENGL_CHECK_ERRORS //////////////////////////////////////////////////////////////////////////// // Generate and store the save ype //////////////////////////////////////////////////////////////////////////// ShaderSaveType saveType; saveType.combineMode1 = m_combineMode1; saveType.combineMode2 = m_combineMode2; saveType.cycle_type = gRDP.otherMode.cycle_type; saveType.key_enabled = gRDP.otherMode.key_en; //saveType.blender = gRDP.otherMode.blender; saveType.alpha_compare = gRDP.otherMode.alpha_compare; saveType.aa_en = gRDP.otherMode.aa_en; //saveType.z_cmp = gRDP.otherMode.z_cmp; //saveType.z_upd = gRDP.otherMode.z_upd; saveType.alpha_cvg_sel = gRDP.otherMode.alpha_cvg_sel; saveType.cvg_x_alpha = gRDP.otherMode.cvg_x_alpha; //saveType.clr_on_cvg = gRDP.otherMode.clr_on_cvg; //saveType.cvg_dst = gRDP.otherMode.cvg_dst; saveType.fog_enabled = gRSP.bFogEnabled; saveType.fog_in_blender = gRDP.bFogEnableInBlender; saveType.program = program; StoreUniformLocations( saveType ); m_generatedPrograms.push_back( saveType ); return m_generatedPrograms.size()-1; // id of the shader save type } GLuint COGLColorCombiner::GenerateCopyProgram() { assert( gRDP.otherMode.cycle_type == CYCLE_TYPE_COPY ); assert( m_vtxShader != CC_NULL_SHADER ); newFrgStr[0] = 0; strcat(newFrgStr, fragmentCopyHeader); // (always the same) genFragmentBlenderStr(newFrgStr); strcat(newFrgStr, fragmentShaderFooter); // (always the same) //////////////////////////////////////////////////////////////////////////// // Create the program //////////////////////////////////////////////////////////////////////////// GLuint frgShader = createShader( GL_FRAGMENT_SHADER, newFrgStr ); GLuint program = createProgram( m_vtxShader, frgShader ); glDeleteShader(frgShader); OPENGL_CHECK_ERRORS //////////////////////////////////////////////////////////////////////////// // Generate and store the save type //////////////////////////////////////////////////////////////////////////// ShaderSaveType saveType; // (as it a copy shader, only blender values are saved) saveType.cycle_type = gRDP.otherMode.cycle_type; saveType.alpha_compare = gRDP.otherMode.alpha_compare; saveType.aa_en = gRDP.otherMode.aa_en; //saveType.z_cmp = gRDP.otherMode.z_cmp; //saveType.z_upd = gRDP.otherMode.z_upd; saveType.alpha_cvg_sel = gRDP.otherMode.alpha_cvg_sel; saveType.cvg_x_alpha = gRDP.otherMode.cvg_x_alpha; saveType.fog_enabled = gRSP.bFogEnabled; saveType.fog_in_blender = gRDP.bFogEnableInBlender; saveType.program = program; StoreUniformLocations( saveType ); m_generatedPrograms.push_back( saveType ); return m_generatedPrograms.size()-1; } // Set vertex attribute pointers. // The program must be bind before use this. void COGLColorCombiner::GenerateCombinerSetting() { glEnableVertexAttribArray(VS_POSITION); OPENGL_CHECK_ERRORS; glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); OPENGL_CHECK_ERRORS; glEnableVertexAttribArray(VS_TEXCOORD0); OPENGL_CHECK_ERRORS; glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u)); OPENGL_CHECK_ERRORS; glEnableVertexAttribArray(VS_TEXCOORD1); OPENGL_CHECK_ERRORS; glVertexAttribPointer(VS_TEXCOORD1,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[1].u)); OPENGL_CHECK_ERRORS; glEnableVertexAttribArray(VS_COLOR); OPENGL_CHECK_ERRORS; glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); OPENGL_CHECK_ERRORS; glEnableVertexAttribArray(VS_FOG); OPENGL_CHECK_ERRORS; glVertexAttribPointer(VS_FOG,1,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][4])); OPENGL_CHECK_ERRORS; } // Bind various uniforms void COGLColorCombiner::GenerateCombinerSettingConstants( int shaderId ) { assert( shaderId >= 0 ); const ShaderSaveType &saveType = m_generatedPrograms[ shaderId ]; // Vertex shader if( saveType.fogMaxMinLoc != CC_INACTIVE_UNIFORM ) { glUniform2f( saveType.fogMaxMinLoc, gRSPfFogMin , gRSPfFogMax ); OPENGL_CHECK_ERRORS; } // Fragment shader if( saveType.blendColorLoc != CC_INACTIVE_UNIFORM ) { glUniform4f( saveType.blendColorLoc, gRDP.fvBlendColor[0], gRDP.fvBlendColor[1], gRDP.fvBlendColor[2], gRDP.fvBlendColor[3]); OPENGL_CHECK_ERRORS } if( saveType.primColorLoc != CC_INACTIVE_UNIFORM ) { glUniform4f( saveType.primColorLoc, gRDP.fvPrimitiveColor[0], gRDP.fvPrimitiveColor[1], gRDP.fvPrimitiveColor[2], gRDP.fvPrimitiveColor[3]); OPENGL_CHECK_ERRORS } if( saveType.envColorLoc != CC_INACTIVE_UNIFORM ) { glUniform4f( saveType.envColorLoc, gRDP.fvEnvColor[0], gRDP.fvEnvColor[1], gRDP.fvEnvColor[2], gRDP.fvEnvColor[3]); OPENGL_CHECK_ERRORS } if( saveType.chromaKeyCenterLoc != CC_INACTIVE_UNIFORM ) { glUniform3f( saveType.chromaKeyCenterLoc, gRDP.keyCenterR/255.0f, gRDP.keyCenterG/255.0f, gRDP.keyCenterB/255.0f); OPENGL_CHECK_ERRORS } if( saveType.chromaKeyScaleLoc != CC_INACTIVE_UNIFORM ) { glUniform3f( saveType.chromaKeyScaleLoc, gRDP.keyScaleR/255.0f, gRDP.keyScaleG/255.0f, gRDP.keyScaleB/255.0f); OPENGL_CHECK_ERRORS } if( saveType.chromaKeyWidthLoc != CC_INACTIVE_UNIFORM ) { glUniform3f( saveType.chromaKeyWidthLoc, gRDP.keyWidthR/255.0f, gRDP.keyWidthG/255.0f, gRDP.keyWidthB/255.0f); OPENGL_CHECK_ERRORS } if( saveType.lodFracLoc != CC_INACTIVE_UNIFORM ) { glUniform1f( saveType.lodFracLoc, gRDP.LODFrac/255.0f ); OPENGL_CHECK_ERRORS } if( saveType.primLodFracLoc != CC_INACTIVE_UNIFORM ) { glUniform1f( saveType.primLodFracLoc, gRDP.primLODFrac/255.0f ); OPENGL_CHECK_ERRORS } if( saveType.k5Loc != CC_INACTIVE_UNIFORM ) { glUniform1f( saveType.k5Loc, gRDP.K5/255.0f ); OPENGL_CHECK_ERRORS } if( saveType.k4Loc != CC_INACTIVE_UNIFORM ) { glUniform1f( saveType.k4Loc, gRDP.K4/255.0f ); OPENGL_CHECK_ERRORS } if( saveType.tex0Loc != CC_INACTIVE_UNIFORM ) { glUniform1i( saveType.tex0Loc,0 ); OPENGL_CHECK_ERRORS } if( saveType.tex1Loc != CC_INACTIVE_UNIFORM ) { glUniform1i( saveType.tex1Loc,1 ); OPENGL_CHECK_ERRORS } if( saveType.fogColorLoc != CC_INACTIVE_UNIFORM ) { glUniform4f( saveType.fogColorLoc, gRDP.fvFogColor[0], gRDP.fvFogColor[1], gRDP.fvFogColor[2], gRDP.fvFogColor[3]); OPENGL_CHECK_ERRORS; } } ////////////////////////////////////////////////////////////////////////// void COGLColorCombiner::InitCombinerCycle12(void) { // Look if we already have a compiled program for the current state. int shaderId = FindCompiledShaderId(); if( shaderId == -1 ) { shaderId = GenerateCycle12Program(); } const GLuint &program = m_generatedPrograms[shaderId].program; useProgram( program ); GenerateCombinerSettingConstants( shaderId ); GenerateCombinerSetting(); m_pOGLRender->SetAllTexelRepeatFlag(); } // Store every uniform locations on the given shader // We don't know if every of them are used in the program so some of them will return -1 but we don't care // Note: glGetUniformLocation doesn't need glUseProgram to work. void COGLColorCombiner::StoreUniformLocations( ShaderSaveType &saveType ) { assert( saveType.program != CC_NULL_PROGRAM ); saveType.fogMaxMinLoc = glGetUniformLocation( saveType.program, "uFogMinMax" ); saveType.blendColorLoc = glGetUniformLocation( saveType.program, "uBlendColor" ); saveType.primColorLoc = glGetUniformLocation( saveType.program, "uPrimColor" ); saveType.envColorLoc = glGetUniformLocation( saveType.program, "uEnvColor" ); saveType.chromaKeyCenterLoc = glGetUniformLocation( saveType.program, "uChromaKeyCenter" ); saveType.chromaKeyScaleLoc = glGetUniformLocation( saveType.program, "uChromaKeyScale" ); saveType.chromaKeyWidthLoc = glGetUniformLocation( saveType.program, "uChromaKeyWidth" ); saveType.lodFracLoc = glGetUniformLocation( saveType.program, "uLodFrac" ); saveType.primLodFracLoc = glGetUniformLocation( saveType.program, "uPrimLodFrac" ); saveType.k5Loc = glGetUniformLocation( saveType.program, "uK5" ); saveType.k4Loc = glGetUniformLocation( saveType.program, "uK4" ); saveType.tex0Loc = glGetUniformLocation( saveType.program, "uTex0" ); saveType.tex1Loc = glGetUniformLocation( saveType.program, "uTex1" ); saveType.fogColorLoc = glGetUniformLocation( saveType.program, "uFogColor" ); } // Return a shader id that match the current state in the current compiled shader "database". // Return -1 if no shader is found int COGLColorCombiner::FindCompiledShaderId() { int shaderId = -1; ShaderSaveType* saveType = NULL; for( size_t i=0; icombineMode1 == m_combineMode1 && saveType->combineMode2 == m_combineMode2 && saveType->cycle_type == gRDP.otherMode.cycle_type // 1 or 2? && saveType->key_enabled == gRDP.otherMode.key_en // Blender && saveType->alpha_compare == gRDP.otherMode.alpha_compare && saveType->aa_en == gRDP.otherMode.aa_en //&& saveType->z_cmp == gRDP.otherMode.z_cmp //&& saveType->z_upd == gRDP.otherMode.z_upd && saveType->alpha_cvg_sel == gRDP.otherMode.alpha_cvg_sel && saveType->cvg_x_alpha == gRDP.otherMode.cvg_x_alpha && saveType->fog_enabled == gRSP.bFogEnabled && saveType->fog_in_blender == gRDP.bFogEnableInBlender ) shaderId = i; break; case CYCLE_TYPE_COPY : // don't care about Color Combiner stuff, just Blender if( saveType->cycle_type == CYCLE_TYPE_COPY && saveType->alpha_compare == gRDP.otherMode.alpha_compare && saveType->aa_en == gRDP.otherMode.aa_en //&& saveType->z_cmp == gRDP.otherMode.z_cmp //&& saveType->z_upd == gRDP.otherMode.z_upd && saveType->alpha_cvg_sel == gRDP.otherMode.alpha_cvg_sel && saveType->cvg_x_alpha == gRDP.otherMode.cvg_x_alpha && saveType->fog_enabled == gRSP.bFogEnabled && saveType->fog_in_blender == gRDP.bFogEnableInBlender ) shaderId = i; break; case CYCLE_TYPE_FILL : DebugMessage(M64MSG_WARNING, "Lookup for a cycle type Fill shader. It should never happend."); break; default : DebugMessage(M64MSG_WARNING, "Lookup for a unknown cycle type. It should never happend."); break; } // end switch cycle type } // end loop return shaderId; } // Can save a useless OpenGL program switch. void COGLColorCombiner::useProgram( const GLuint &program ) { if( program != m_currentProgram ) { glUseProgram( program ); OPENGL_CHECK_ERRORS m_currentProgram = program; } } // COGLBlender void COGLBlender::NormalAlphaBlender(void) { glEnable(GL_BLEND); OPENGL_CHECK_ERRORS; glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); OPENGL_CHECK_ERRORS; } void COGLBlender::DisableAlphaBlender(void) { glEnable(GL_BLEND); OPENGL_CHECK_ERRORS; glBlendFunc(GL_ONE, GL_ZERO); OPENGL_CHECK_ERRORS; } void COGLBlender::BlendFunc(uint32 srcFunc, uint32 desFunc) { glBlendFunc(DirectX_OGL_BlendFuncMaps[srcFunc], DirectX_OGL_BlendFuncMaps[desFunc]); OPENGL_CHECK_ERRORS; } void COGLBlender::Enable() { glEnable(GL_BLEND); OPENGL_CHECK_ERRORS; } void COGLBlender::Disable() { glDisable(GL_BLEND); OPENGL_CHECK_ERRORS; } void COGLColorCombiner::InitCombinerBlenderForSimpleTextureDraw(uint32 tile) { if( g_textures[tile].m_pCTexture ) { m_pOGLRender->EnableTexUnit(0,TRUE); glBindTexture(GL_TEXTURE_2D, ((COGLTexture*)(g_textures[tile].m_pCTexture))->m_dwTextureName); OPENGL_CHECK_ERRORS; } m_pOGLRender->SetAllTexelRepeatFlag(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); OPENGL_CHECK_ERRORS; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); OPENGL_CHECK_ERRORS; glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering OPENGL_CHECK_ERRORS; glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering OPENGL_CHECK_ERRORS; glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); OPENGL_CHECK_ERRORS; m_pOGLRender->SetAlphaTestEnable(FALSE); } mupen64plus-video-rice-src-2.6.0/src/OGLCombiner.h000066400000000000000000000107201464507324400216030ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - OGLCombiner.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Rice1964 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef _OGL_COMBINER_H_ #define _OGL_COMBINER_H_ #include #include "osal_opengl.h" #include "Blender.h" #include "Combiner.h" #include "typedefs.h" class CRender; class OGLRender; class COGLColorCombiner : public CColorCombiner { public: bool Initialize(void); void InitCombinerBlenderForSimpleTextureDraw(uint32 tile=0); protected: friend class OGLDeviceBuilder; void DisableCombiner(void); void InitCombinerCycleCopy(void); void InitCombinerCycleFill(void); void InitCombinerCycle12(void); COGLColorCombiner(CRender *pRender); ~COGLColorCombiner(); OGLRender *m_pOGLRender; private: #define CC_NULL_PROGRAM 0 // Invalid OpenGL program #define CC_NULL_SHADER 0 // Invalid OpenGL shader #define CC_INACTIVE_UNIFORM -1 // Invalid program uniform typedef struct { uint32 combineMode1; uint32 combineMode2; unsigned int cycle_type; // 1/2/fill/copy unsigned int key_enabled:1; // Chroma key //uint16 blender; unsigned int alpha_compare; // None/Threshold/Dither unsigned int aa_en:1; //unsigned int z_cmp:1; //unsigned int z_upd:1; unsigned int alpha_cvg_sel:1; unsigned int cvg_x_alpha:1; unsigned int fog_enabled:1; unsigned int fog_in_blender:1; //unsigned int clr_on_cvg; //unsigned int cvg_dst; GLuint program; // Progam uniform locations GLint fogMaxMinLoc; GLint blendColorLoc; GLint primColorLoc; GLint envColorLoc; GLint chromaKeyCenterLoc; GLint chromaKeyScaleLoc; GLint chromaKeyWidthLoc; GLint lodFracLoc; GLint primLodFracLoc; GLint k5Loc; GLint k4Loc; GLint tex0Loc; GLint tex1Loc; GLint fogColorLoc; } ShaderSaveType; void genFragmentBlenderStr( char *newFrgStr ); GLuint GenerateCycle12Program(); GLuint GenerateCopyProgram(); void GenerateCombinerSetting(); void GenerateCombinerSettingConstants( int shaderId ); void StoreUniformLocations( ShaderSaveType &saveType ); int FindCompiledShaderId(); void useProgram( const GLuint &program ); GLuint m_vtxShader; // Generate vertex shader once as it never change GLuint m_fillProgram; // Generate fill program once as it never change GLint m_fillColorLoc; // fill color uniform's program location std::vector m_generatedPrograms; GLuint m_currentProgram; // Used to avoid multiple glUseProgram calls }; class COGLBlender : public CBlender { public: void NormalAlphaBlender(void); void DisableAlphaBlender(void); void BlendFunc(uint32 srcFunc, uint32 desFunc); void Enable(); void Disable(); protected: friend class OGLDeviceBuilder; COGLBlender(CRender *pRender) : CBlender(pRender), m_pOGLRender((OGLRender*)pRender) {}; ~COGLBlender() {}; OGLRender *m_pOGLRender; }; #endif mupen64plus-video-rice-src-2.6.0/src/OGLDebug.h000066400000000000000000000045141464507324400210770ustar00rootroot00000000000000/* OGLDebug.h Copyright (C) 2009 Richard Goedeken This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if !defined(OPENGL_DEBUG_H) #define OPENGL_DEBUG_H #if defined(OPENGL_DEBUG) #define OPENGL_CHECK_ERRORS { const GLenum errcode = glGetError(); if (errcode != GL_NO_ERROR) fprintf(stderr, "OpenGL Error code %i in '%s' line %i\n", errcode, __FILE__, __LINE__-1); } #else #define OPENGL_CHECK_ERRORS #endif /* Dump client state (for informational purposes) int rval = 0; void *ptr; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &rval); printf("GL_ARRAY_BUFFER_BINDING: %i\n", rval); glGetPointerv(GL_COLOR_ARRAY_POINTER, &ptr); printf("GL_COLOR_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_COLOR_ARRAY), (int) ptr); glGetPointerv(GL_FOG_COORD_ARRAY_POINTER, &ptr); printf("GL_FOG_COORDINATE_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_FOG_COORDINATE_ARRAY), (int) ptr); glGetPointerv(GL_INDEX_ARRAY_POINTER, &ptr); printf("GL_INDEX_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_INDEX_ARRAY), (int) ptr); glGetPointerv(GL_NORMAL_ARRAY_POINTER, &ptr); printf("GL_NORMAL_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_NORMAL_ARRAY), (int) ptr); glGetPointerv(GL_SECONDARY_COLOR_ARRAY_POINTER, &ptr); printf("GL_SECONDARY_COLOR_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_SECONDARY_COLOR_ARRAY), (int) ptr); glGetPointerv(GL_TEXTURE_COORD_ARRAY_POINTER, &ptr); printf("GL_TEXTURE_COORD_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_TEXTURE_COORD_ARRAY), (int) ptr); glGetPointerv(GL_VERTEX_ARRAY_POINTER, &ptr); printf("GL_VERTEX_ARRAY: %i (%lx)\n", (int) glIsEnabled(GL_VERTEX_ARRAY), (int) ptr); */ #endif /* OPENGL_DEBUG_H */ mupen64plus-video-rice-src-2.6.0/src/OGLExtensions.cpp000066400000000000000000000223541464507324400225450ustar00rootroot00000000000000/* OGLExtensions.cpp Copyright (C) 2009 Richard Goedeken This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This source file contains code for assigning function pointers to some OpenGL functions. */ #include "osal_opengl.h" #include "OGLExtensions.h" #include "Video.h" #include "m64p_types.h" #if !defined(__APPLE__) static void APIENTRY EmptyFunc(void) { return; } #define INIT_EMPTY_FUNC(type, funcname) type funcname = (type) EmptyFunc; #define INIT_GL_FUNC(type, funcname) \ funcname = (type) CoreVideo_GL_GetProcAddress(#funcname); \ if (funcname == NULL) { DebugMessage(M64MSG_WARNING, \ "Couldn't get address of OpenGL function: '%s'", #funcname); funcname = (type) EmptyFunc; } #endif #ifdef USE_GLES // OpenGL ES headers already load every functions so this place is reserved // for maybe future ES extensions. #else // Desktop OpenGL #if defined(WIN32) // Windows is OpenGL 1.1 INIT_EMPTY_FUNC(PFNGLACTIVETEXTUREPROC, glActiveTexture) // Added in OpenGL 1.3 INIT_EMPTY_FUNC(PFNGLCREATESHADERPROC, glCreateShader) INIT_EMPTY_FUNC(PFNGLSHADERSOURCEPROC, glShaderSource) INIT_EMPTY_FUNC(PFNGLCOMPILESHADERPROC, glCompileShader) INIT_EMPTY_FUNC(PFNGLGETSHADERIVPROC, glGetShaderiv) INIT_EMPTY_FUNC(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog) INIT_EMPTY_FUNC(PFNGLCREATEPROGRAMPROC, glCreateProgram) INIT_EMPTY_FUNC(PFNGLATTACHSHADERPROC, glAttachShader) INIT_EMPTY_FUNC(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation) INIT_EMPTY_FUNC(PFNGLLINKPROGRAMPROC, glLinkProgram) INIT_EMPTY_FUNC(PFNGLGETPROGRAMIVPROC, glGetProgramiv) INIT_EMPTY_FUNC(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog) INIT_EMPTY_FUNC(PFNGLDETACHSHADERPROC, glDetachShader) INIT_EMPTY_FUNC(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation) INIT_EMPTY_FUNC(PFNGLDELETESHADERPROC, glDeleteShader) INIT_EMPTY_FUNC(PFNGLDELETEPROGRAMPROC, glDeleteProgram) INIT_EMPTY_FUNC(PFNGLISSHADERPROC, glIsShader) INIT_EMPTY_FUNC(PFNGLISPROGRAMPROC, glIsProgram) INIT_EMPTY_FUNC(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray) INIT_EMPTY_FUNC(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray) INIT_EMPTY_FUNC(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) INIT_EMPTY_FUNC(PFNGLUNIFORM4FPROC, glUniform4f) INIT_EMPTY_FUNC(PFNGLUNIFORM3FPROC, glUniform3f) INIT_EMPTY_FUNC(PFNGLUNIFORM2FPROC, glUniform2f) INIT_EMPTY_FUNC(PFNGLUNIFORM1FPROC, glUniform1f) INIT_EMPTY_FUNC(PFNGLUNIFORM1IPROC, glUniform1i) INIT_EMPTY_FUNC(PFNGLUSEPROGRAMPROC, glUseProgram) #elif defined(__APPLE__) // OSX already support OpenGL 2.1 functions. #else // Linux (OpenGL 1.3) and others INIT_EMPTY_FUNC(PFNGLCREATESHADERPROC, glCreateShader) INIT_EMPTY_FUNC(PFNGLSHADERSOURCEPROC, glShaderSource) INIT_EMPTY_FUNC(PFNGLCOMPILESHADERPROC, glCompileShader) INIT_EMPTY_FUNC(PFNGLGETSHADERIVPROC, glGetShaderiv) INIT_EMPTY_FUNC(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog) INIT_EMPTY_FUNC(PFNGLCREATEPROGRAMPROC, glCreateProgram) INIT_EMPTY_FUNC(PFNGLATTACHSHADERPROC, glAttachShader) INIT_EMPTY_FUNC(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation) INIT_EMPTY_FUNC(PFNGLLINKPROGRAMPROC, glLinkProgram) INIT_EMPTY_FUNC(PFNGLGETPROGRAMIVPROC, glGetProgramiv) INIT_EMPTY_FUNC(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog) INIT_EMPTY_FUNC(PFNGLDETACHSHADERPROC, glDetachShader) INIT_EMPTY_FUNC(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation) INIT_EMPTY_FUNC(PFNGLDELETESHADERPROC, glDeleteShader) INIT_EMPTY_FUNC(PFNGLDELETEPROGRAMPROC, glDeleteProgram) INIT_EMPTY_FUNC(PFNGLISSHADERPROC, glIsShader) INIT_EMPTY_FUNC(PFNGLISPROGRAMPROC, glIsProgram) INIT_EMPTY_FUNC(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray) INIT_EMPTY_FUNC(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray) INIT_EMPTY_FUNC(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) INIT_EMPTY_FUNC(PFNGLUNIFORM4FPROC, glUniform4f) INIT_EMPTY_FUNC(PFNGLUNIFORM3FPROC, glUniform3f) INIT_EMPTY_FUNC(PFNGLUNIFORM2FPROC, glUniform2f) INIT_EMPTY_FUNC(PFNGLUNIFORM1FPROC, glUniform1f) INIT_EMPTY_FUNC(PFNGLUNIFORM1IPROC, glUniform1i) INIT_EMPTY_FUNC(PFNGLUSEPROGRAMPROC, glUseProgram) #endif // OS specific #endif // USE_GLES void OGLExtensions_Init(void) { // See above for #ifdef #else documentation #ifdef USE_GLES // empty #else #if defined(WIN32) INIT_GL_FUNC(PFNGLACTIVETEXTUREPROC, glActiveTexture) INIT_GL_FUNC(PFNGLCREATESHADERPROC, glCreateShader) INIT_GL_FUNC(PFNGLSHADERSOURCEPROC, glShaderSource) INIT_GL_FUNC(PFNGLCOMPILESHADERPROC, glCompileShader) INIT_GL_FUNC(PFNGLGETSHADERIVPROC, glGetShaderiv) INIT_GL_FUNC(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog) INIT_GL_FUNC(PFNGLCREATEPROGRAMPROC, glCreateProgram) INIT_GL_FUNC(PFNGLATTACHSHADERPROC, glAttachShader) INIT_GL_FUNC(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation) INIT_GL_FUNC(PFNGLLINKPROGRAMPROC, glLinkProgram) INIT_GL_FUNC(PFNGLGETPROGRAMIVPROC, glGetProgramiv) INIT_GL_FUNC(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog) INIT_GL_FUNC(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation) INIT_GL_FUNC(PFNGLDETACHSHADERPROC, glDetachShader) INIT_GL_FUNC(PFNGLDELETESHADERPROC, glDeleteShader) INIT_GL_FUNC(PFNGLDELETEPROGRAMPROC, glDeleteProgram) INIT_GL_FUNC(PFNGLISSHADERPROC, glIsShader) INIT_GL_FUNC(PFNGLISPROGRAMPROC, glIsProgram) INIT_GL_FUNC(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray) INIT_GL_FUNC(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray) INIT_GL_FUNC(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) INIT_GL_FUNC(PFNGLUNIFORM4FPROC, glUniform4f) INIT_GL_FUNC(PFNGLUNIFORM3FPROC, glUniform3f) INIT_GL_FUNC(PFNGLUNIFORM2FPROC, glUniform2f) INIT_GL_FUNC(PFNGLUNIFORM1FPROC, glUniform1f) INIT_GL_FUNC(PFNGLUNIFORM1IPROC, glUniform1i) INIT_GL_FUNC(PFNGLUSEPROGRAMPROC, glUseProgram) #elif defined(__APPLE__) // empty #else INIT_GL_FUNC(PFNGLCREATESHADERPROC, glCreateShader) INIT_GL_FUNC(PFNGLSHADERSOURCEPROC, glShaderSource) INIT_GL_FUNC(PFNGLCOMPILESHADERPROC, glCompileShader) INIT_GL_FUNC(PFNGLGETSHADERIVPROC, glGetShaderiv) INIT_GL_FUNC(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog) INIT_GL_FUNC(PFNGLCREATEPROGRAMPROC, glCreateProgram) INIT_GL_FUNC(PFNGLATTACHSHADERPROC, glAttachShader) INIT_GL_FUNC(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation) INIT_GL_FUNC(PFNGLLINKPROGRAMPROC, glLinkProgram) INIT_GL_FUNC(PFNGLGETPROGRAMIVPROC, glGetProgramiv) INIT_GL_FUNC(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog) INIT_GL_FUNC(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation) INIT_GL_FUNC(PFNGLDETACHSHADERPROC, glDetachShader) INIT_GL_FUNC(PFNGLDELETESHADERPROC, glDeleteShader) INIT_GL_FUNC(PFNGLDELETEPROGRAMPROC, glDeleteProgram) INIT_GL_FUNC(PFNGLISSHADERPROC, glIsShader) INIT_GL_FUNC(PFNGLISPROGRAMPROC, glIsProgram) INIT_GL_FUNC(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray) INIT_GL_FUNC(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray) INIT_GL_FUNC(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) INIT_GL_FUNC(PFNGLUNIFORM4FPROC, glUniform4f) INIT_GL_FUNC(PFNGLUNIFORM3FPROC, glUniform3f) INIT_GL_FUNC(PFNGLUNIFORM2FPROC, glUniform2f) INIT_GL_FUNC(PFNGLUNIFORM1FPROC, glUniform1f) INIT_GL_FUNC(PFNGLUNIFORM1IPROC, glUniform1i) INIT_GL_FUNC(PFNGLUSEPROGRAMPROC, glUseProgram) #endif // OS specific #endif // USE_GLES } mupen64plus-video-rice-src-2.6.0/src/OGLExtensions.h000066400000000000000000000111041464507324400222010ustar00rootroot00000000000000/* OGLExtensions.h Copyright (C) 2009 Richard Goedeken This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This header file contains function pointers to some OpenGL functions */ /* This is only necessary because Windows does not contain development support for OpenGL versions beyond 1.1 */ #ifndef OGL_EXTENSIONS_H #define OGL_EXTENSIONS_H #include "osal_opengl.h" /* Just call this one function to load up the function pointers. */ void OGLExtensions_Init(void); // See OGLExtensions.cpp for #ifdef #else documentation #ifdef USE_GLES // nothing #else #if defined(WIN32) extern PFNGLACTIVETEXTUREPROC glActiveTexture; extern PFNGLCREATESHADERPROC glCreateShader; extern PFNGLSHADERSOURCEPROC glShaderSource; extern PFNGLCOMPILESHADERPROC glCompileShader; extern PFNGLGETSHADERIVPROC glGetShaderiv; extern PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; extern PFNGLCREATEPROGRAMPROC glCreateProgram; extern PFNGLATTACHSHADERPROC glAttachShader; extern PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation; extern PFNGLLINKPROGRAMPROC glLinkProgram; extern PFNGLGETPROGRAMIVPROC glGetProgramiv; extern PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; extern PFNGLDETACHSHADERPROC glDetachShader; extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; extern PFNGLDELETESHADERPROC glDeleteShader; extern PFNGLDELETEPROGRAMPROC glDeleteProgram; extern PFNGLISSHADERPROC glIsShader; extern PFNGLISPROGRAMPROC glIsProgram; extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; extern PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; extern PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; extern PFNGLUNIFORM4FPROC glUniform4f; extern PFNGLUNIFORM3FPROC glUniform3f; extern PFNGLUNIFORM2FPROC glUniform2f; extern PFNGLUNIFORM1FPROC glUniform1f; extern PFNGLUNIFORM1IPROC glUniform1i; extern PFNGLUSEPROGRAMPROC glUseProgram; #elif defined(__APPLE__) // nothing #else extern PFNGLCREATESHADERPROC glCreateShader; extern PFNGLSHADERSOURCEPROC glShaderSource; extern PFNGLCOMPILESHADERPROC glCompileShader; extern PFNGLGETSHADERIVPROC glGetShaderiv; extern PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; extern PFNGLCREATEPROGRAMPROC glCreateProgram; extern PFNGLATTACHSHADERPROC glAttachShader; extern PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation; extern PFNGLLINKPROGRAMPROC glLinkProgram; extern PFNGLGETPROGRAMIVPROC glGetProgramiv; extern PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; extern PFNGLDETACHSHADERPROC glDetachShader; extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; extern PFNGLDELETESHADERPROC glDeleteShader; extern PFNGLDELETEPROGRAMPROC glDeleteProgram; extern PFNGLISSHADERPROC glIsShader; extern PFNGLISPROGRAMPROC glIsProgram; extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; extern PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; extern PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; extern PFNGLUNIFORM4FPROC glUniform4f; extern PFNGLUNIFORM3FPROC glUniform3f; extern PFNGLUNIFORM2FPROC glUniform2f; extern PFNGLUNIFORM1FPROC glUniform1f; extern PFNGLUNIFORM1IPROC glUniform1i; extern PFNGLUSEPROGRAMPROC glUseProgram; #endif // OS specific #endif // USE_GLES #endif // OGL_EXTENSIONS_H mupen64plus-video-rice-src-2.6.0/src/OGLGraphicsContext.cpp000066400000000000000000000355041464507324400235140ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "Texture.h" #include "m64p_types.h" #include "osal_opengl.h" #define M64P_PLUGIN_PROTOTYPES 1 #include "Config.h" #include "Debugger.h" #include "m64p_plugin.h" #ifndef USE_GLES #include "OGLExtensions.h" #endif #include "OGLDebug.h" #include "OGLGraphicsContext.h" #include "TextureManager.h" #include "Video.h" #include "version.h" COGLGraphicsContext::COGLGraphicsContext() : m_pExtensionStr(NULL) { } COGLGraphicsContext::~COGLGraphicsContext() { } bool COGLGraphicsContext::Initialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed ) { DebugMessage(M64MSG_INFO, "Initializing OpenGL Device Context."); Lock(); CGraphicsContext::Initialize(dwWidth, dwHeight, bWindowed ); if( bWindowed ) { windowSetting.statusBarHeightToUse = windowSetting.statusBarHeight; windowSetting.toolbarHeightToUse = windowSetting.toolbarHeight; } else { windowSetting.statusBarHeightToUse = 0; windowSetting.toolbarHeightToUse = 0; } int depthBufferDepth = options.OpenglDepthBufferSetting; int colorBufferDepth = 32; int bVerticalSync = windowSetting.bVerticalSync; if( options.colorQuality == TEXTURE_FMT_A4R4G4B4 ) colorBufferDepth = 16; // init sdl & gl DebugMessage(M64MSG_VERBOSE, "Initializing video subsystem..."); if (CoreVideo_Init() != M64ERR_SUCCESS) return false; /* hard-coded attribute values */ const int iDOUBLEBUFFER = 1; /* set opengl attributes */ CoreVideo_GL_SetAttribute(M64P_GL_DOUBLEBUFFER, iDOUBLEBUFFER); CoreVideo_GL_SetAttribute(M64P_GL_SWAP_CONTROL, bVerticalSync); CoreVideo_GL_SetAttribute(M64P_GL_BUFFER_SIZE, colorBufferDepth); CoreVideo_GL_SetAttribute(M64P_GL_DEPTH_SIZE, depthBufferDepth); /* set multisampling */ if (options.multiSampling > 0) { CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLEBUFFERS, 1); if (options.multiSampling <= 2) CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 2); else if (options.multiSampling <= 4) CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 4); else if (options.multiSampling <= 8) CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 8); else CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 16); } /* Set the video mode */ m64p_video_mode ScreenMode = bWindowed ? M64VIDEO_WINDOWED : M64VIDEO_FULLSCREEN; m64p_video_flags flags = M64VIDEOFLAG_SUPPORT_RESIZING; if (CoreVideo_SetVideoMode(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, colorBufferDepth, ScreenMode, flags) != M64ERR_SUCCESS) { DebugMessage(M64MSG_ERROR, "Failed to set %i-bit video mode: %ix%i", colorBufferDepth, (int)windowSetting.uDisplayWidth, (int)windowSetting.uDisplayHeight); CoreVideo_Quit(); return false; } /* check that our opengl attributes were properly set */ int iActual; if (CoreVideo_GL_GetAttribute(M64P_GL_DOUBLEBUFFER, &iActual) == M64ERR_SUCCESS) if (iActual != iDOUBLEBUFFER) DebugMessage(M64MSG_WARNING, "Failed to set GL_DOUBLEBUFFER to %i. (it's %i)", iDOUBLEBUFFER, iActual); if (CoreVideo_GL_GetAttribute(M64P_GL_SWAP_CONTROL, &iActual) == M64ERR_SUCCESS) if (iActual != bVerticalSync) DebugMessage(M64MSG_WARNING, "Failed to set GL_SWAP_CONTROL to %i. (it's %i)", bVerticalSync, iActual); if (CoreVideo_GL_GetAttribute(M64P_GL_BUFFER_SIZE, &iActual) == M64ERR_SUCCESS) if (iActual != colorBufferDepth) DebugMessage(M64MSG_WARNING, "Failed to set GL_BUFFER_SIZE to %i. (it's %i)", colorBufferDepth, iActual); if (CoreVideo_GL_GetAttribute(M64P_GL_DEPTH_SIZE, &iActual) == M64ERR_SUCCESS) if (iActual != depthBufferDepth) DebugMessage(M64MSG_WARNING, "Failed to set GL_DEPTH_SIZE to %i. (it's %i)", depthBufferDepth, iActual); #ifndef USE_GLES /* Get function pointers to OpenGL extensions (blame Microsoft Windows for this) */ OGLExtensions_Init(); #endif char caption[500]; sprintf(caption, "%s v%i.%i.%i", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION)); CoreVideo_SetCaption(caption); SetWindowMode(); m_pExtensionStr = glGetString(GL_EXTENSIONS); OPENGL_CHECK_ERRORS const unsigned char* renderStr = glGetString(GL_RENDERER); const unsigned char* versionStr = glGetString(GL_VERSION); const unsigned char* vendorStr = glGetString(GL_VENDOR); if (renderStr == NULL || versionStr == NULL || vendorStr == NULL) { DebugMessage(M64MSG_ERROR, "Can't get OpenGL informations. It's maybe a problem with your driver."); CoreVideo_Quit(); return false; } DebugMessage(M64MSG_INFO, "Using OpenGL: %.60s - %.128s : %.60s", renderStr, versionStr, vendorStr); InitLimits(); InitState(); InitOGLExtension(); Unlock(); Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); // Clear buffers UpdateFrame(); Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); UpdateFrame(); m_bReady = true; return true; } bool COGLGraphicsContext::ResizeInitialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed ) { Lock(); CGraphicsContext::Initialize(dwWidth, dwHeight, bWindowed ); int depthBufferDepth = options.OpenglDepthBufferSetting; int colorBufferDepth = 32; int bVerticalSync = windowSetting.bVerticalSync; if( options.colorQuality == TEXTURE_FMT_A4R4G4B4 ) colorBufferDepth = 16; /* hard-coded attribute values */ const int iDOUBLEBUFFER = 1; /* set opengl attributes */ CoreVideo_GL_SetAttribute(M64P_GL_DOUBLEBUFFER, iDOUBLEBUFFER); CoreVideo_GL_SetAttribute(M64P_GL_SWAP_CONTROL, bVerticalSync); CoreVideo_GL_SetAttribute(M64P_GL_BUFFER_SIZE, colorBufferDepth); CoreVideo_GL_SetAttribute(M64P_GL_DEPTH_SIZE, depthBufferDepth); /* set multisampling */ if (options.multiSampling > 0) { CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLEBUFFERS, 1); if (options.multiSampling <= 2) CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 2); else if (options.multiSampling <= 4) CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 4); else if (options.multiSampling <= 8) CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 8); else CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 16); } /* Call Mupen64plus core Video Extension to resize the window, which will create a new OpenGL Context under SDL */ if (CoreVideo_ResizeWindow(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight) != M64ERR_SUCCESS) { DebugMessage(M64MSG_ERROR, "Failed to set %i-bit video mode: %ix%i", colorBufferDepth, (int)windowSetting.uDisplayWidth, (int)windowSetting.uDisplayHeight); CoreVideo_Quit(); return false; } InitState(); Unlock(); Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); // Clear buffers UpdateFrame(); Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); UpdateFrame(); return true; } // Init limiting OpenGL values void COGLGraphicsContext::InitLimits(void) { glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS,&m_maxTextureImageUnits); OPENGL_CHECK_ERRORS; } void COGLGraphicsContext::InitState(void) { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); OPENGL_CHECK_ERRORS; glClearDepth(1.0f); OPENGL_CHECK_ERRORS; #ifndef USE_GLES glShadeModel(GL_SMOOTH); OPENGL_CHECK_ERRORS; glDisable(GL_ALPHA_TEST); OPENGL_CHECK_ERRORS; #endif glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); OPENGL_CHECK_ERRORS; glDisable(GL_BLEND); OPENGL_CHECK_ERRORS; glFrontFace(GL_CCW); OPENGL_CHECK_ERRORS; glDisable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; #ifndef USE_GLES glDisable(GL_NORMALIZE); OPENGL_CHECK_ERRORS; #endif glDepthFunc(GL_LEQUAL); OPENGL_CHECK_ERRORS; glEnable(GL_DEPTH_TEST); OPENGL_CHECK_ERRORS; #ifndef USE_GLES glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); OPENGL_CHECK_ERRORS; #endif glEnable(GL_BLEND); OPENGL_CHECK_ERRORS; #ifndef USE_GLES glEnable(GL_ALPHA_TEST); OPENGL_CHECK_ERRORS; #endif glDepthRange(0.0f, 1.0f); OPENGL_CHECK_ERRORS; } void COGLGraphicsContext::InitOGLExtension(void) { // Optional extension features m_bSupportAnisotropicFiltering = IsExtensionSupported("GL_EXT_texture_filter_anisotropic"); // Compute maxAnisotropicFiltering m_maxAnisotropicFiltering = 0; if( m_bSupportAnisotropicFiltering && (options.anisotropicFiltering == 2 || options.anisotropicFiltering == 4 || options.anisotropicFiltering == 8 || options.anisotropicFiltering == 16)) { //Get the max value of aniso that the graphic card support glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &m_maxAnisotropicFiltering); OPENGL_CHECK_ERRORS; // If user want more aniso than hardware can do if(options.anisotropicFiltering > (uint32) m_maxAnisotropicFiltering) { DebugMessage(M64MSG_INFO, "A value of '%i' is set for AnisotropicFiltering option but the hardware has a maximum value of '%i' so this will be used", options.anisotropicFiltering, m_maxAnisotropicFiltering); } //check if user want less anisotropy than hardware can do if((uint32) m_maxAnisotropicFiltering > options.anisotropicFiltering) m_maxAnisotropicFiltering = options.anisotropicFiltering; } m_bSupportTextureFormatBGRA = IsExtensionSupported("GL_EXT_texture_format_BGRA8888"); m_bSupportDepthClampNV = IsExtensionSupported("GL_NV_depth_clamp"); } bool COGLGraphicsContext::IsExtensionSupported(const char* pExtName) { if (strstr((const char*)m_pExtensionStr, pExtName) != NULL) { DebugMessage(M64MSG_VERBOSE, "OpenGL Extension '%s' is supported.", pExtName); return true; } else { DebugMessage(M64MSG_VERBOSE, "OpenGL Extension '%s' is NOT supported.", pExtName); return false; } } void COGLGraphicsContext::CleanUp() { CoreVideo_Quit(); m_bReady = false; } void COGLGraphicsContext::Clear(ClearFlag dwFlags, uint32 color, float depth) { uint32 flag=0; if( dwFlags&CLEAR_COLOR_BUFFER ) flag |= GL_COLOR_BUFFER_BIT; if( dwFlags&CLEAR_DEPTH_BUFFER ) flag |= GL_DEPTH_BUFFER_BIT; float r = ((color>>16)&0xFF)/255.0f; float g = ((color>> 8)&0xFF)/255.0f; float b = ((color )&0xFF)/255.0f; float a = ((color>>24)&0xFF)/255.0f; glClearColor(r, g, b, a); OPENGL_CHECK_ERRORS; glClearDepth(depth); OPENGL_CHECK_ERRORS; glClear(flag); //Clear color buffer and depth buffer OPENGL_CHECK_ERRORS; } void COGLGraphicsContext::UpdateFrame(bool swaponly) { status.gFrameCount++; glFlush(); OPENGL_CHECK_ERRORS; //glFinish(); //wglSwapIntervalEXT(0); /* if (debuggerPauseCount == countToPause) { static int iShotNum = 0; // get width, height, allocate buffer to store image int width = windowSetting.uDisplayWidth; int height = windowSetting.uDisplayHeight; printf("Saving debug images: width=%i height=%i\n", width, height); short *buffer = (short *) malloc(((width+3)&~3)*(height+1)*4); glReadBuffer( GL_FRONT ); // set up a BMGImage struct struct BMGImageStruct img; memset(&img, 0, sizeof(BMGImageStruct)); InitBMGImage(&img); img.bits = (unsigned char *) buffer; img.bits_per_pixel = 32; img.height = height; img.width = width; img.scan_width = width * 4; // store the RGB color image char chFilename[64]; sprintf(chFilename, "dbg_rgb_%03i.png", iShotNum); glReadPixels(0,0,width,height, GL_BGRA, GL_UNSIGNED_BYTE, buffer); WritePNG(chFilename, img); // store the Z buffer sprintf(chFilename, "dbg_Z_%03i.png", iShotNum); glReadPixels(0,0,width,height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buffer); //img.bits_per_pixel = 16; //img.scan_width = width * 2; WritePNG(chFilename, img); // dump a subset of the Z data for (int y = 0; y < 480; y += 16) { for (int x = 0; x < 640; x+= 16) printf("%4hx ", buffer[y*640 + x]); printf("\n"); } printf("\n"); // free memory and get out of here free(buffer); iShotNum++; } */ // if emulator defined a render callback function, call it before buffer swap if(renderCallback) { // For OGLFT (used by OSD) to work, we need to disable shaders // (which implicitly passe OpenGL in fixed pipeline mode) GLint program; glGetIntegerv(GL_CURRENT_PROGRAM ,&program); glUseProgram(0); (*renderCallback)(status.bScreenIsDrawn); glUseProgram(program); } CoreVideo_GL_SwapBuffers(); /*if(options.bShowFPS) { static unsigned int lastTick=0; static int frames=0; unsigned int nowTick = SDL_GetTicks(); frames++; if(lastTick + 5000 <= nowTick) { char caption[200]; sprintf(caption, "%s v%i.%i.%i - %.3f VI/S", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION), frames/5.0); CoreVideo_SetCaption(caption); frames = 0; lastTick = nowTick; } }*/ glDepthMask(GL_TRUE); OPENGL_CHECK_ERRORS; glClearDepth(1.0f); OPENGL_CHECK_ERRORS; if( !g_curRomInfo.bForceScreenClear ) { glClear(GL_DEPTH_BUFFER_BIT); OPENGL_CHECK_ERRORS; } else needCleanScene = true; status.bScreenIsDrawn = false; } bool COGLGraphicsContext::SetFullscreenMode() { windowSetting.statusBarHeightToUse = 0; windowSetting.toolbarHeightToUse = 0; return true; } bool COGLGraphicsContext::SetWindowMode() { windowSetting.statusBarHeightToUse = windowSetting.statusBarHeight; windowSetting.toolbarHeightToUse = windowSetting.toolbarHeight; return true; } int COGLGraphicsContext::ToggleFullscreen() { if (CoreVideo_ToggleFullScreen() == M64ERR_SUCCESS) { m_bWindowed = !m_bWindowed; if(m_bWindowed) SetWindowMode(); else SetFullscreenMode(); } return m_bWindowed?0:1; } mupen64plus-video-rice-src-2.6.0/src/OGLGraphicsContext.h000066400000000000000000000046761464507324400231670ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _OGL_CONTEXT_H_ #define _OGL_CONTEXT_H_ #include "GraphicsContext.h" #include "osal_preproc.h" #include "typedefs.h" class COGLGraphicsContext : public CGraphicsContext { public: virtual ~COGLGraphicsContext(); static inline COGLGraphicsContext* Get(void) { return (COGLGraphicsContext*)CGraphicsContext::m_pGraphicsContext; }; bool Initialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed ); bool ResizeInitialize(uint32 dwWidth, uint32 dwHeight, BOOL bWindowed ); void CleanUp(); void Clear(ClearFlag dwFlags, uint32 color=0xFF000000, float depth=1.0f); void UpdateFrame(bool swaponly=false); int ToggleFullscreen(); // return 0 as the result is windowed //Get methods (TODO, remove all friend class and use get methods instead) inline bool IsSupportAnisotropicFiltering() { return m_bSupportAnisotropicFiltering; }; inline int getMaxAnisotropicFiltering() { return m_maxAnisotropicFiltering; }; inline int getMaxTextureImageUnits() { return m_maxTextureImageUnits; }; inline bool IsSupportTextureFormatBGRA() { return m_bSupportTextureFormatBGRA; }; inline bool IsSupportDepthClampNV() { return m_bSupportDepthClampNV; }; protected: friend class OGLDeviceBuilder; COGLGraphicsContext(); void InitLimits(void); void InitState(void); void InitOGLExtension(void); bool SetFullscreenMode(); bool SetWindowMode(); private: const unsigned char* m_pExtensionStr; // OpenGL limits int m_maxTextureImageUnits; // Optional OGL extension features bool IsExtensionSupported(const char* pExtName); bool m_bSupportAnisotropicFiltering; int m_maxAnisotropicFiltering; bool m_bSupportTextureFormatBGRA; bool m_bSupportDepthClampNV; }; #endif mupen64plus-video-rice-src-2.6.0/src/OGLRender.cpp000066400000000000000000001001331464507324400216150ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "Combiner.h" #include "CombinerDefs.h" #include "Config.h" #include "Debugger.h" #include "GraphicsContext.h" #include "RSP_Parser.h" #include "Texture.h" #include "Video.h" #include "m64p_plugin.h" #include "osal_opengl.h" #include "OGLExtensions.h" #include "OGLDebug.h" #include "OGLGraphicsContext.h" #include "OGLRender.h" #include "OGLTexture.h" #include "TextureManager.h" // FIXME: Use OGL internal L/T and matrix stack // FIXME: Use OGL lookupAt function // FIXME: Use OGL DisplayList UVFlagMap OGLXUVFlagMaps[] = { {TEXTURE_UV_FLAG_WRAP, GL_REPEAT}, {TEXTURE_UV_FLAG_MIRROR, GL_MIRRORED_REPEAT_ARB}, {TEXTURE_UV_FLAG_CLAMP, GL_CLAMP}, }; //=================================================================== OGLRender::OGLRender() { } OGLRender::~OGLRender() { } bool OGLRender::InitDeviceObjects() { // enable Z-buffer by default ZBufferEnable(true); return true; } bool OGLRender::ClearDeviceObjects() { return true; } void OGLRender::Initialize(void) { glViewportWrapper(0, windowSetting.statusBarHeightToUse, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); OPENGL_CHECK_ERRORS; OGLXUVFlagMaps[TEXTURE_UV_FLAG_MIRROR].realFlag = GL_MIRRORED_REPEAT; OGLXUVFlagMaps[TEXTURE_UV_FLAG_CLAMP].realFlag = GL_CLAMP_TO_EDGE; glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); OPENGL_CHECK_ERRORS; glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u)); OPENGL_CHECK_ERRORS; glVertexAttribPointer(VS_TEXCOORD1,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[1].u)); OPENGL_CHECK_ERRORS; glVertexAttribPointer(VS_FOG,1,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][4])); OPENGL_CHECK_ERRORS; glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); OPENGL_CHECK_ERRORS; // Initialize multitexture m_maxTexUnits = COGLGraphicsContext::Get()->getMaxTextureImageUnits(); /* limited by size 8 arrays like m_maxTexUnits, mtex... */ if (m_maxTexUnits > 8) m_maxTexUnits = 8; for( int i=0; i<8; i++ ) { m_textureUnitMap[i] = -1; m_curBoundTex[i] = -1; } m_textureUnitMap[0] = 0; // T0 is usually using texture unit 0 m_textureUnitMap[1] = 1; // T1 is usually using texture unit 1 #ifndef USE_GLES if( COGLGraphicsContext::Get()->IsSupportDepthClampNV() ) { glEnable(GL_DEPTH_CLAMP_NV); OPENGL_CHECK_ERRORS; } #endif } //=================================================================== TextureFilterMap OglTexFilterMap[2]= { {FILTER_POINT, GL_NEAREST}, {FILTER_LINEAR, GL_LINEAR}, }; void OGLRender::ApplyTextureFilter() { static uint32 minflag[8], magflag[8]; static uint32 mtex[8]; int iMinFilter, iMagFilter; //Compute iMinFilter and iMagFilter if(m_dwMinFilter == FILTER_LINEAR) //Texture will use filtering { iMagFilter = GL_LINEAR; //Texture filtering method user want switch(options.mipmapping) { case TEXTURE_BILINEAR_FILTER: iMinFilter = GL_LINEAR_MIPMAP_NEAREST; break; case TEXTURE_TRILINEAR_FILTER: iMinFilter = GL_LINEAR_MIPMAP_LINEAR; break; case TEXTURE_NO_FILTER: iMinFilter = GL_NEAREST_MIPMAP_NEAREST; break; case TEXTURE_NO_MIPMAP: default: //Bilinear without mipmap iMinFilter = GL_LINEAR; } } else //dont use filtering, all is nearest { iMagFilter = GL_NEAREST; if(options.mipmapping) iMinFilter = GL_NEAREST_MIPMAP_NEAREST; else iMinFilter = GL_NEAREST; } for( int i=0; i>2)/(float)0x3FFF; glClearDepth(depth); OPENGL_CHECK_ERRORS; glClear(flag); OPENGL_CHECK_ERRORS; } void OGLRender::ClearZBuffer(float depth) { uint32 flag=GL_DEPTH_BUFFER_BIT; glClearDepth(depth); OPENGL_CHECK_ERRORS; glClear(flag); OPENGL_CHECK_ERRORS; } void OGLRender::SetZCompare(BOOL bZCompare) { if( g_curRomInfo.bForceDepthBuffer ) bZCompare = TRUE; gRSP.bZBufferEnabled = bZCompare; if( bZCompare == TRUE ) { //glEnable(GL_DEPTH_TEST); glDepthFunc( GL_LEQUAL ); OPENGL_CHECK_ERRORS; } else { //glDisable(GL_DEPTH_TEST); glDepthFunc( GL_ALWAYS ); OPENGL_CHECK_ERRORS; } } void OGLRender::SetZUpdate(BOOL bZUpdate) { if( g_curRomInfo.bForceDepthBuffer ) bZUpdate = TRUE; if( bZUpdate ) { //glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); OPENGL_CHECK_ERRORS; } else { glDepthMask(GL_FALSE); OPENGL_CHECK_ERRORS; } } void OGLRender::ApplyZBias(int bias) { float f1; // polygon offset factor float f2; // polygon offset units if (bias > 0) { if (options.bForcePolygonOffset) { f1 = options.polygonOffsetFactor; f2 = options.polygonOffsetUnits; } else { f1 = -3.0f; // z offset = -3.0 * std::max(abs(dz/dx),abs(dz/dy)) per pixel delta z slope f2 = -3.0f; // z offset += -3.0 * 1 bit } glEnable(GL_POLYGON_OFFSET_FILL); // enable z offsets OPENGL_CHECK_ERRORS; } else { f1 = 0.0f; f2 = 0.0f; glDisable(GL_POLYGON_OFFSET_FILL); // disable z offsets OPENGL_CHECK_ERRORS; } glPolygonOffset(f1, f2); // set bias functions OPENGL_CHECK_ERRORS; } void OGLRender::SetZBias(int bias) { #if defined(DEBUGGER) if( pauseAtNext == true ) DebuggerAppendMsg("Set zbias = %d", bias); #endif // set member variable and apply the setting in opengl m_dwZBias = bias; ApplyZBias(bias); } // TODO: Remove this functions as alpha clip is done in Color Combiner void OGLRender::SetAlphaRef(uint32 dwAlpha) { if (m_dwAlpha != dwAlpha) { m_dwAlpha = dwAlpha; #ifndef USE_GLES //glAlphaFunc(GL_GEQUAL, (float)dwAlpha); OPENGL_CHECK_ERRORS; #endif } } // TODO: Remove this functions as alpha clip is done in Color Combiner void OGLRender::ForceAlphaRef(uint32 dwAlpha) { #ifndef USE_GLES //float ref = dwAlpha/255.0f; //glAlphaFunc(GL_GEQUAL, ref); OPENGL_CHECK_ERRORS; #else m_dwAlpha = dwAlpha; #endif } void OGLRender::SetFillMode(FillMode mode) { #ifndef USE_GLES if( mode == RICE_FILLMODE_WINFRAME ) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); OPENGL_CHECK_ERRORS; } else { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); OPENGL_CHECK_ERRORS; } #endif } void OGLRender::SetCullMode(bool bCullFront, bool bCullBack) { CRender::SetCullMode(bCullFront, bCullBack); if( bCullFront && bCullBack ) { glCullFace(GL_FRONT_AND_BACK); OPENGL_CHECK_ERRORS; glEnable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; } else if( bCullFront ) { glCullFace(GL_FRONT); OPENGL_CHECK_ERRORS; glEnable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; } else if( bCullBack ) { glCullFace(GL_BACK); OPENGL_CHECK_ERRORS; glEnable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; } else { glDisable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; } } bool OGLRender::SetCurrentTexture(int tile, CTexture *handler,uint32 dwTileWidth, uint32 dwTileHeight, TxtrCacheEntry *pTextureEntry) { RenderTexture &texture = g_textures[tile]; texture.pTextureEntry = pTextureEntry; if( handler!= NULL && texture.m_lpsTexturePtr != handler->GetTexture() ) { texture.m_pCTexture = handler; texture.m_lpsTexturePtr = handler->GetTexture(); texture.m_dwTileWidth = dwTileWidth; texture.m_dwTileHeight = dwTileHeight; if( handler->m_bIsEnhancedTexture ) { texture.m_fTexWidth = (float)pTextureEntry->pTexture->m_dwCreatedTextureWidth; texture.m_fTexHeight = (float)pTextureEntry->pTexture->m_dwCreatedTextureHeight; } else { texture.m_fTexWidth = (float)handler->m_dwCreatedTextureWidth; texture.m_fTexHeight = (float)handler->m_dwCreatedTextureHeight; } } return true; } bool OGLRender::SetCurrentTexture(int tile, TxtrCacheEntry *pEntry) { if (pEntry != NULL && pEntry->pTexture != NULL) { SetCurrentTexture( tile, pEntry->pTexture, pEntry->ti.WidthToCreate, pEntry->ti.HeightToCreate, pEntry); return true; } else { SetCurrentTexture( tile, NULL, 64, 64, NULL ); return false; } return true; } void OGLRender::SetAddressUAllStages(uint32 dwTile, TextureUVFlag dwFlag) { SetTextureUFlag(dwFlag, dwTile); } void OGLRender::SetAddressVAllStages(uint32 dwTile, TextureUVFlag dwFlag) { SetTextureVFlag(dwFlag, dwTile); } void OGLRender::SetTexWrapS(int unitno,GLuint flag) { static GLuint mflag[8]; static GLuint mtex[8]; if( m_curBoundTex[unitno] != mtex[unitno] || mflag[unitno] != flag ) { mtex[unitno] = m_curBoundTex[0]; mflag[unitno] = flag; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, flag); OPENGL_CHECK_ERRORS; } } void OGLRender::SetTexWrapT(int unitno,GLuint flag) { static GLuint mflag[8]; static GLuint mtex[8]; if( m_curBoundTex[unitno] != mtex[unitno] || mflag[unitno] != flag ) { mtex[unitno] = m_curBoundTex[0]; mflag[unitno] = flag; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, flag); OPENGL_CHECK_ERRORS; } } void OGLRender::SetTextureUFlag(TextureUVFlag dwFlag, uint32 dwTile) { TileUFlags[dwTile] = dwFlag; int tex; if( dwTile == gRSP.curTile ) tex=0; else if( dwTile == ((gRSP.curTile+1)&7) ) tex=1; else { if( dwTile == ((gRSP.curTile+2)&7) ) tex=2; else if( dwTile == ((gRSP.curTile+3)&7) ) tex=3; else { TRACE2("Incorrect tile number for OGL SetTextureUFlag: cur=%d, tile=%d", gRSP.curTile, dwTile); return; } } for( int textureNo=0; textureNo<8; textureNo++) { if( m_textureUnitMap[textureNo] == tex ) { glActiveTexture(GL_TEXTURE0+textureNo); OPENGL_CHECK_ERRORS; COGLTexture* pTexture = g_textures[(gRSP.curTile+tex)&7].m_pCOGLTexture; if( pTexture ) { EnableTexUnit(textureNo,TRUE); BindTexture(pTexture->m_dwTextureName, textureNo); } SetTexWrapS(textureNo, OGLXUVFlagMaps[dwFlag].realFlag); } } } void OGLRender::SetTextureVFlag(TextureUVFlag dwFlag, uint32 dwTile) { TileVFlags[dwTile] = dwFlag; int tex; if( dwTile == gRSP.curTile ) tex=0; else if( dwTile == ((gRSP.curTile+1)&7) ) tex=1; else { if( dwTile == ((gRSP.curTile+2)&7) ) tex=2; else if( dwTile == ((gRSP.curTile+3)&7) ) tex=3; else { TRACE2("Incorrect tile number for OGL SetTextureVFlag: cur=%d, tile=%d", gRSP.curTile, dwTile); return; } } for( int textureNo=0; textureNo<8; textureNo++) { if( m_textureUnitMap[textureNo] == tex ) { COGLTexture* pTexture = g_textures[(gRSP.curTile+tex)&7].m_pCOGLTexture; if( pTexture ) { EnableTexUnit(textureNo,TRUE); BindTexture(pTexture->m_dwTextureName, textureNo); } SetTexWrapT(textureNo, OGLXUVFlagMaps[dwFlag].realFlag); } } } // Basic render drawing functions bool OGLRender::RenderTexRect() { glViewportWrapper(0, windowSetting.statusBarHeightToUse, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); OPENGL_CHECK_ERRORS; GLboolean cullface = glIsEnabled(GL_CULL_FACE); glDisable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; GLubyte colour[] = { g_texRectTVtx[3].r, g_texRectTVtx[3].g, g_texRectTVtx[3].b, g_texRectTVtx[3].a, g_texRectTVtx[2].r, g_texRectTVtx[2].g, g_texRectTVtx[2].b, g_texRectTVtx[2].a, g_texRectTVtx[1].r, g_texRectTVtx[1].g, g_texRectTVtx[1].b, g_texRectTVtx[1].a, g_texRectTVtx[0].r, g_texRectTVtx[0].g, g_texRectTVtx[0].b, g_texRectTVtx[0].a }; GLfloat tex[] = { g_texRectTVtx[3].tcord[0].u,g_texRectTVtx[3].tcord[0].v, g_texRectTVtx[2].tcord[0].u,g_texRectTVtx[2].tcord[0].v, g_texRectTVtx[1].tcord[0].u,g_texRectTVtx[1].tcord[0].v, g_texRectTVtx[0].tcord[0].u,g_texRectTVtx[0].tcord[0].v }; GLfloat tex2[] = { g_texRectTVtx[3].tcord[1].u,g_texRectTVtx[3].tcord[1].v, g_texRectTVtx[2].tcord[1].u,g_texRectTVtx[2].tcord[1].v, g_texRectTVtx[1].tcord[1].u,g_texRectTVtx[1].tcord[1].v, g_texRectTVtx[0].tcord[1].u,g_texRectTVtx[0].tcord[1].v }; float w = windowSetting.uDisplayWidth / 2.0f, h = windowSetting.uDisplayHeight / 2.0f, inv = 1.0f; GLfloat vertices[] = { -inv + g_texRectTVtx[3].x / w, inv - g_texRectTVtx[3].y / h, g_texRectTVtx[3].z, 1, -inv + g_texRectTVtx[2].x / w, inv - g_texRectTVtx[2].y / h, g_texRectTVtx[3].z, 1, -inv + g_texRectTVtx[1].x / w, inv - g_texRectTVtx[1].y / h, g_texRectTVtx[3].z, 1, -inv + g_texRectTVtx[0].x / w, inv - g_texRectTVtx[0].y / h, g_texRectTVtx[3].z, 1 }; glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, &colour ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,0,&vertices); glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, 0, &tex); glVertexAttribPointer(VS_TEXCOORD1,2,GL_FLOAT,GL_FALSE, 0, &tex2); OPENGL_CHECK_ERRORS; glDrawArrays(GL_TRIANGLE_FAN,0,4); OPENGL_CHECK_ERRORS; //Restore old pointers glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u)); glVertexAttribPointer(VS_TEXCOORD1,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[1].u)); if( cullface ) glEnable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; return true; } bool OGLRender::RenderFillRect(uint32 dwColor, float depth) { uint8 a = (dwColor>>24); uint8 r = ((dwColor>>16)&0xFF); uint8 g = ((dwColor>>8)&0xFF); uint8 b = (dwColor&0xFF); glViewportWrapper(0, windowSetting.statusBarHeightToUse, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); OPENGL_CHECK_ERRORS; GLboolean cullface = glIsEnabled(GL_CULL_FACE); glDisable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; GLubyte colour[] = { r,g,b,a, r,g,b,a, r,g,b,a, r,g,b,a}; float w = windowSetting.uDisplayWidth / 2.0f, h = windowSetting.uDisplayHeight / 2.0f, inv = 1.0f; GLfloat vertices[] = { -inv + m_fillRectVtx[0].x / w, inv - m_fillRectVtx[1].y / h, depth, 1, -inv + m_fillRectVtx[1].x / w, inv - m_fillRectVtx[1].y / h, depth, 1, -inv + m_fillRectVtx[1].x / w, inv - m_fillRectVtx[0].y / h, depth, 1, -inv + m_fillRectVtx[0].x / w, inv - m_fillRectVtx[0].y / h, depth, 1 }; glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_FALSE, 0, &colour ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,0,&vertices); glDisableVertexAttribArray(VS_TEXCOORD0); glDisableVertexAttribArray(VS_TEXCOORD1); OPENGL_CHECK_ERRORS; glDrawArrays(GL_TRIANGLE_FAN,0,4); OPENGL_CHECK_ERRORS; //Restore old pointers glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); glEnableVertexAttribArray(VS_TEXCOORD0); glEnableVertexAttribArray(VS_TEXCOORD1); if( cullface ) glEnable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; return true; } bool OGLRender::RenderLine3D() { #ifndef USE_GLES ApplyZBias(0); // disable z offsets glBegin(GL_TRIANGLE_FAN); glColor4f(m_line3DVtx[1].r, m_line3DVtx[1].g, m_line3DVtx[1].b, m_line3DVtx[1].a); glVertex3f(m_line3DVector[3].x, m_line3DVector[3].y, -m_line3DVtx[1].z); glVertex3f(m_line3DVector[2].x, m_line3DVector[2].y, -m_line3DVtx[0].z); glColor4ub(m_line3DVtx[0].r, m_line3DVtx[0].g, m_line3DVtx[0].b, m_line3DVtx[0].a); glVertex3f(m_line3DVector[1].x, m_line3DVector[1].y, -m_line3DVtx[1].z); glVertex3f(m_line3DVector[0].x, m_line3DVector[0].y, -m_line3DVtx[0].z); glEnd(); OPENGL_CHECK_ERRORS; ApplyZBias(m_dwZBias); // set Z offset back to previous value #endif return true; } extern FiddledVtx * g_pVtxBase; // This is so weired that I can not do vertex transform by myself. I have to use // OpenGL internal transform bool OGLRender::RenderFlushTris() { ApplyZBias(m_dwZBias); // set the bias factors glViewportWrapper(windowSetting.vpLeftW, windowSetting.uDisplayHeight-windowSetting.vpTopW-windowSetting.vpHeightW+windowSetting.statusBarHeightToUse, windowSetting.vpWidthW, windowSetting.vpHeightW, false); OPENGL_CHECK_ERRORS; //if options.bOGLVertexClipper == FALSE ) { glDrawElements( GL_TRIANGLES, gRSP.numVertices, GL_UNSIGNED_SHORT, g_vtxIndex ); OPENGL_CHECK_ERRORS; } /* else { //ClipVertexesOpenGL(); // Redo the index // Set the array glVertexPointer( 4, GL_FLOAT, sizeof(float)*5, &(g_vtxProjected5Clipped[0][0]) ); glEnableClientState( GL_VERTEX_ARRAY ); glActiveTexture( GL_TEXTURE0 ); glTexCoordPointer( 2, GL_FLOAT, sizeof( TLITVERTEX ), &(g_clippedVtxBuffer[0].tcord[0].u) ); glEnableClientState( GL_TEXTURE_COORD_ARRAY ); glActiveTexture( GL_TEXTURE1 ); glTexCoordPointer( 2, GL_FLOAT, sizeof( TLITVERTEX ), &(g_clippedVtxBuffer[0].tcord[1].u) ); glEnableClientState( GL_TEXTURE_COORD_ARRAY ); glDrawElements( GL_TRIANGLES, gRSP.numVertices, GL_UNSIGNED_INT, g_vtxIndex ); // Reset the array glActiveTexture( GL_TEXTURE0 ); glTexCoordPointer( 2, GL_FLOAT, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u) ); glEnableClientState( GL_TEXTURE_COORD_ARRAY ); glActiveTexture( GL_TEXTURE1 ); glTexCoordPointer( 2, GL_FLOAT, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[1].u) ); glEnableClientState( GL_TEXTURE_COORD_ARRAY ); glVertexPointer( 4, GL_FLOAT, sizeof(float)*5, &(g_vtxProjected5[0][0]) ); glEnableClientState( GL_VERTEX_ARRAY ); } */ return true; } void OGLRender::DrawSimple2DTexture(float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, COLOR dif, float z, float rhw) { if( status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_1ST_PRIMITIVE ) { status.bVIOriginIsUpdated=false; CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG,{DebuggerAppendMsg("Screen Update at 1st Simple2DTexture");}); } StartDrawSimple2DTexture(x0, y0, x1, y1, u0, v0, u1, v1, dif, z, rhw); GLboolean cullface = glIsEnabled(GL_CULL_FACE); glDisable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; glViewportWrapper(0, windowSetting.statusBarHeightToUse, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); OPENGL_CHECK_ERRORS; GLubyte colour[] = { g_texRectTVtx[0].r, g_texRectTVtx[0].g, g_texRectTVtx[0].b, g_texRectTVtx[0].a, g_texRectTVtx[1].r, g_texRectTVtx[1].g, g_texRectTVtx[1].b, g_texRectTVtx[1].a, g_texRectTVtx[2].r, g_texRectTVtx[2].g, g_texRectTVtx[2].b, g_texRectTVtx[2].a, g_texRectTVtx[0].r, g_texRectTVtx[0].g, g_texRectTVtx[0].b, g_texRectTVtx[0].a, g_texRectTVtx[2].r, g_texRectTVtx[2].g, g_texRectTVtx[2].b, g_texRectTVtx[2].a, g_texRectTVtx[3].r, g_texRectTVtx[3].g, g_texRectTVtx[3].b, g_texRectTVtx[3].a, }; GLfloat tex[] = { g_texRectTVtx[0].tcord[0].u,g_texRectTVtx[0].tcord[0].v, g_texRectTVtx[1].tcord[0].u,g_texRectTVtx[1].tcord[0].v, g_texRectTVtx[2].tcord[0].u,g_texRectTVtx[2].tcord[0].v, g_texRectTVtx[0].tcord[0].u,g_texRectTVtx[0].tcord[0].v, g_texRectTVtx[2].tcord[0].u,g_texRectTVtx[2].tcord[0].v, g_texRectTVtx[3].tcord[0].u,g_texRectTVtx[3].tcord[0].v, }; GLfloat tex2[] = { g_texRectTVtx[0].tcord[1].u,g_texRectTVtx[0].tcord[1].v, g_texRectTVtx[1].tcord[1].u,g_texRectTVtx[1].tcord[1].v, g_texRectTVtx[2].tcord[1].u,g_texRectTVtx[2].tcord[1].v, g_texRectTVtx[0].tcord[1].u,g_texRectTVtx[0].tcord[1].v, g_texRectTVtx[2].tcord[1].u,g_texRectTVtx[2].tcord[1].v, g_texRectTVtx[3].tcord[1].u,g_texRectTVtx[3].tcord[1].v, }; float w = windowSetting.uDisplayWidth / 2.0f, h = windowSetting.uDisplayHeight / 2.0f, inv = 1.0f; GLfloat vertices[] = { -inv + g_texRectTVtx[0].x/ w, inv - g_texRectTVtx[0].y/ h, -g_texRectTVtx[0].z,1, -inv + g_texRectTVtx[1].x/ w, inv - g_texRectTVtx[1].y/ h, -g_texRectTVtx[1].z,1, -inv + g_texRectTVtx[2].x/ w, inv - g_texRectTVtx[2].y/ h, -g_texRectTVtx[2].z,1, -inv + g_texRectTVtx[0].x/ w, inv - g_texRectTVtx[0].y/ h, -g_texRectTVtx[0].z,1, -inv + g_texRectTVtx[2].x/ w, inv - g_texRectTVtx[2].y/ h, -g_texRectTVtx[2].z,1, -inv + g_texRectTVtx[3].x/ w, inv - g_texRectTVtx[3].y/ h, -g_texRectTVtx[3].z,1 }; glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_FALSE, 0, &colour ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,0,&vertices); glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, 0, &tex); glVertexAttribPointer(VS_TEXCOORD1,2,GL_FLOAT,GL_FALSE, 0, &tex2); OPENGL_CHECK_ERRORS; glDrawArrays(GL_TRIANGLES,0,6); OPENGL_CHECK_ERRORS; //Restore old pointers glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u)); glVertexAttribPointer(VS_TEXCOORD1,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[1].u)); if( cullface ) glEnable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; } void OGLRender::DrawSimpleRect(int nX0, int nY0, int nX1, int nY1, uint32 dwColor, float depth, float rhw) { StartDrawSimpleRect(nX0, nY0, nX1, nY1, dwColor, depth, rhw); GLboolean cullface = glIsEnabled(GL_CULL_FACE); glDisable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; uint8 a = (dwColor>>24); uint8 r = ((dwColor>>16)&0xFF); uint8 g = ((dwColor>>8)&0xFF); uint8 b = (dwColor&0xFF); GLubyte colour[] = { r,g,b,a, r,g,b,a, r,g,b,a, r,g,b,a}; float w = windowSetting.uDisplayWidth / 2.0f, h = windowSetting.uDisplayHeight / 2.0f, inv = 1.0f; GLfloat vertices[] = { -inv + m_simpleRectVtx[1].x / w, inv - m_simpleRectVtx[0].y / h, -depth, 1, -inv + m_simpleRectVtx[1].x / w, inv - m_simpleRectVtx[1].y / h, -depth, 1, -inv + m_simpleRectVtx[0].x / w, inv - m_simpleRectVtx[1].y / h, -depth, 1, -inv + m_simpleRectVtx[0].x / w, inv - m_simpleRectVtx[0].y / h, -depth, 1 }; glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_FALSE, 0, &colour ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,0,&vertices); glDisableVertexAttribArray(VS_TEXCOORD0); glDisableVertexAttribArray(VS_TEXCOORD1); OPENGL_CHECK_ERRORS; glDrawArrays(GL_TRIANGLE_FAN,0,4); OPENGL_CHECK_ERRORS; //Restore old pointers glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); glEnableVertexAttribArray(VS_TEXCOORD0); glEnableVertexAttribArray(VS_TEXCOORD1); if( cullface ) glEnable(GL_CULL_FACE); OPENGL_CHECK_ERRORS; } void OGLRender::SetViewportRender() { glViewportWrapper(windowSetting.vpLeftW, windowSetting.uDisplayHeight-windowSetting.vpTopW-windowSetting.vpHeightW+windowSetting.statusBarHeightToUse, windowSetting.vpWidthW, windowSetting.vpHeightW); OPENGL_CHECK_ERRORS; } void OGLRender::RenderReset() { CRender::RenderReset(); } // TODO: Remove this functions as it's now handled by the Color Combiner void OGLRender::SetAlphaTestEnable(BOOL bAlphaTestEnable) { /*#ifdef DEBUGGER if( bAlphaTestEnable && debuggerEnableAlphaTest ) #else if( bAlphaTestEnable ) #endif glEnable(GL_ALPHA_TEST); else glDisable(GL_ALPHA_TEST); OPENGL_CHECK_ERRORS;*/ } void OGLRender::BindTexture(GLuint texture, int unitno) { if( unitno < m_maxTexUnits ) { if( m_curBoundTex[unitno] != texture ) { glActiveTexture(GL_TEXTURE0+unitno); OPENGL_CHECK_ERRORS; glBindTexture(GL_TEXTURE_2D,texture); OPENGL_CHECK_ERRORS; m_curBoundTex[unitno] = texture; } } } void OGLRender::DisBindTexture(GLuint texture, int unitno) { glActiveTexture(GL_TEXTURE0+unitno); OPENGL_CHECK_ERRORS; glBindTexture(GL_TEXTURE_2D, 0); //Not to bind any texture OPENGL_CHECK_ERRORS; m_curBoundTex[unitno] = 0; } // This function was intent to activate of disable texture of given OpenGL // texture unit. This has no sense anymore as the combiner use GLSL to use a // texture or not. // Technically, we don't need this function anymore but a side effect of it was // it activate a given texture unit and this side effect as some important // scope at some places (in SetTextureUFlag for example) so we let it for now. void OGLRender::EnableTexUnit(int unitno, BOOL flag) { glActiveTexture(GL_TEXTURE0+unitno); OPENGL_CHECK_ERRORS; } void OGLRender::UpdateScissor() { if( options.bEnableHacks && g_CI.dwWidth == 0x200 && gRDP.scissor.right == 0x200 && g_CI.dwWidth>(*g_GraphicsInfo.VI_WIDTH_REG & 0xFFF) ) { // Hack for RE2 uint32 width = *g_GraphicsInfo.VI_WIDTH_REG & 0xFFF; uint32 height = (gRDP.scissor.right*gRDP.scissor.bottom)/width; glEnable(GL_SCISSOR_TEST); OPENGL_CHECK_ERRORS; glScissor(0, int(height*windowSetting.fMultY+windowSetting.statusBarHeightToUse), int(width*windowSetting.fMultX), int(height*windowSetting.fMultY) ); OPENGL_CHECK_ERRORS; } else { UpdateScissorWithClipRatio(); } } void OGLRender::ApplyRDPScissor(bool force) { if( !force && status.curScissor == RDP_SCISSOR ) return; if( options.bEnableHacks && g_CI.dwWidth == 0x200 && gRDP.scissor.right == 0x200 && g_CI.dwWidth>(*g_GraphicsInfo.VI_WIDTH_REG & 0xFFF) ) { // Hack for RE2 uint32 width = *g_GraphicsInfo.VI_WIDTH_REG & 0xFFF; uint32 height = (gRDP.scissor.right*gRDP.scissor.bottom)/width; glEnable(GL_SCISSOR_TEST); OPENGL_CHECK_ERRORS; glScissor(0, int(height*windowSetting.fMultY+windowSetting.statusBarHeightToUse), int(width*windowSetting.fMultX), int(height*windowSetting.fMultY) ); OPENGL_CHECK_ERRORS; } else { glScissor(int(gRDP.scissor.left*windowSetting.fMultX), int((windowSetting.uViHeight-gRDP.scissor.bottom)*windowSetting.fMultY+windowSetting.statusBarHeightToUse), int((gRDP.scissor.right-gRDP.scissor.left)*windowSetting.fMultX), int((gRDP.scissor.bottom-gRDP.scissor.top)*windowSetting.fMultY )); OPENGL_CHECK_ERRORS; } status.curScissor = RDP_SCISSOR; } void OGLRender::ApplyScissorWithClipRatio(bool force) { if( !force && status.curScissor == RSP_SCISSOR ) return; glEnable(GL_SCISSOR_TEST); OPENGL_CHECK_ERRORS; glScissor(windowSetting.clipping.left, int((windowSetting.uViHeight-gRSP.real_clip_scissor_bottom)*windowSetting.fMultY)+windowSetting.statusBarHeightToUse, windowSetting.clipping.width, windowSetting.clipping.height); OPENGL_CHECK_ERRORS; status.curScissor = RSP_SCISSOR; } void OGLRender::SetFogColor(uint32 r, uint32 g, uint32 b, uint32 a) { gRDP.fogColor = COLOR_RGBA(r, g, b, a); gRDP.fvFogColor[0] = r/255.0f; //r gRDP.fvFogColor[1] = g/255.0f; //g gRDP.fvFogColor[2] = b/255.0f; //b gRDP.fvFogColor[3] = a/255.0f; //a } void OGLRender::EndRendering(void) { #ifndef USE_GLES glFlush(); OPENGL_CHECK_ERRORS; #endif if( CRender::gRenderReferenceCount > 0 ) CRender::gRenderReferenceCount--; } // TODO: Seems to be useless now. void OGLRender::glViewportWrapper(GLint x, GLint y, GLsizei width, GLsizei height, bool flag) { static GLint mx=0,my=0; static GLsizei m_width=0, m_height=0; static bool mflag=true; if( x!=mx || y!=my || width!=m_width || height!=m_height || mflag!=flag) { mx=x; my=y; m_width=width; m_height=height; mflag=flag; glLoadIdentity(); OPENGL_CHECK_ERRORS; glViewport(x,y,width,height); OPENGL_CHECK_ERRORS; } } mupen64plus-video-rice-src-2.6.0/src/OGLRender.h000066400000000000000000000067421464507324400212750ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _OGL_RENDER_H_ #define _OGL_RENDER_H_ #include "Combiner.h" #include "RSP_S2DEX.h" #include "Render.h" #include "RenderBase.h" #include "osal_opengl.h" #include "osal_preproc.h" #include "typedefs.h" class CTexture; struct TxtrCacheEntry; class OGLRender : public CRender { friend class COGLColorCombiner; friend class COGLBlender; friend class OGLDeviceBuilder; protected: OGLRender(); public: ~OGLRender(); void Initialize(void); bool InitDeviceObjects(); bool ClearDeviceObjects(); void ApplyTextureFilter(); void SetShadeMode(RenderShadeMode mode); void ZBufferEnable(BOOL bZBuffer); void ClearBuffer(bool cbuffer, bool zbuffer); void ClearZBuffer(float depth); void SetZCompare(BOOL bZCompare); void SetZUpdate(BOOL bZUpdate); void SetZBias(int bias); void ApplyZBias(int bias); void SetAlphaRef(uint32 dwAlpha); void ForceAlphaRef(uint32 dwAlpha); void SetFillMode(FillMode mode); void SetViewportRender(); void RenderReset(); void SetCullMode(bool bCullFront, bool bCullBack); void SetAlphaTestEnable(BOOL bAlphaTestEnable); void UpdateScissor(); void ApplyRDPScissor(bool force=false); void ApplyScissorWithClipRatio(bool force=false); bool SetCurrentTexture(int tile, CTexture *handler,uint32 dwTileWidth, uint32 dwTileHeight, TxtrCacheEntry *pTextureEntry); bool SetCurrentTexture(int tile, TxtrCacheEntry *pTextureEntry); void SetAddressUAllStages(uint32 dwTile, TextureUVFlag dwFlag); void SetAddressVAllStages(uint32 dwTile, TextureUVFlag dwFlag); void SetTextureUFlag(TextureUVFlag dwFlag, uint32 tile); void SetTextureVFlag(TextureUVFlag dwFlag, uint32 tile); virtual void BindTexture(GLuint texture, int unitno); virtual void DisBindTexture(GLuint texture, int unitno); void DrawSimple2DTexture(float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, COLOR dif, float z, float rhw); void DrawSimpleRect(int nX0, int nY0, int nX1, int nY1, uint32 dwColor, float depth, float rhw); void DrawSpriteR_Render(); void DrawObjBGCopy(uObjBg &info); void DrawText(const char* str, RECT *rect); void SetFogColor(uint32 r, uint32 g, uint32 b, uint32 a); void EndRendering(void); void glViewportWrapper(GLint x, GLint y, GLsizei width, GLsizei height, bool flag=true); virtual void EnableTexUnit(int unitno, BOOL flag); virtual void SetTexWrapS(int unitno,GLuint flag); virtual void SetTexWrapT(int unitno,GLuint flag); protected: // Basic render drawing functions bool RenderFlushTris(); bool RenderTexRect(); bool RenderFillRect(uint32 dwColor, float depth); bool RenderLine3D(); GLuint m_curBoundTex[8]; GLint m_maxTexUnits; int m_textureUnitMap[8]; }; #endif mupen64plus-video-rice-src-2.6.0/src/OGLRenderExt.cpp000066400000000000000000000115721464507324400223060ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "osal_opengl.h" #include "OGLExtensions.h" #include "OGLRender.h" #include "RSP_Parser.h" #include "RSP_S2DEX.h" #include "Render.h" #include "RenderBase.h" #include "Video.h" #include "m64p_types.h" #include "osal_preproc.h" #include "typedefs.h" extern Matrix g_MtxReal; extern uObjMtxReal gObjMtxReal; //======================================================================== void OGLRender::DrawText(const char* str, RECT *rect) { return; } void OGLRender::DrawSpriteR_Render() // With Rotation { glViewportWrapper(0, windowSetting.statusBarHeightToUse, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); GLboolean cullface = glIsEnabled(GL_CULL_FACE); glDisable(GL_CULL_FACE); GLfloat colour[] = { gRDP.fvPrimitiveColor[0], gRDP.fvPrimitiveColor[1], gRDP.fvPrimitiveColor[2], gRDP.fvPrimitiveColor[3], gRDP.fvPrimitiveColor[0], gRDP.fvPrimitiveColor[1], gRDP.fvPrimitiveColor[2], gRDP.fvPrimitiveColor[3], gRDP.fvPrimitiveColor[0], gRDP.fvPrimitiveColor[1], gRDP.fvPrimitiveColor[2], gRDP.fvPrimitiveColor[3], gRDP.fvPrimitiveColor[0], gRDP.fvPrimitiveColor[1], gRDP.fvPrimitiveColor[2], gRDP.fvPrimitiveColor[3], gRDP.fvPrimitiveColor[0], gRDP.fvPrimitiveColor[1], gRDP.fvPrimitiveColor[2], gRDP.fvPrimitiveColor[3], gRDP.fvPrimitiveColor[0], gRDP.fvPrimitiveColor[1], gRDP.fvPrimitiveColor[2], gRDP.fvPrimitiveColor[3], }; GLfloat tex[] = { g_texRectTVtx[0].tcord[0].u,g_texRectTVtx[0].tcord[0].v, g_texRectTVtx[1].tcord[0].u,g_texRectTVtx[1].tcord[0].v, g_texRectTVtx[2].tcord[0].u,g_texRectTVtx[2].tcord[0].v, g_texRectTVtx[0].tcord[0].u,g_texRectTVtx[0].tcord[0].v, g_texRectTVtx[2].tcord[0].u,g_texRectTVtx[2].tcord[0].v, g_texRectTVtx[3].tcord[0].u,g_texRectTVtx[3].tcord[0].v, }; GLfloat tex2[] = { g_texRectTVtx[0].tcord[1].u,g_texRectTVtx[0].tcord[1].v, g_texRectTVtx[1].tcord[1].u,g_texRectTVtx[1].tcord[1].v, g_texRectTVtx[2].tcord[1].u,g_texRectTVtx[2].tcord[1].v, g_texRectTVtx[0].tcord[1].u,g_texRectTVtx[0].tcord[1].v, g_texRectTVtx[2].tcord[1].u,g_texRectTVtx[2].tcord[1].v, g_texRectTVtx[3].tcord[1].u,g_texRectTVtx[3].tcord[1].v, }; float w = windowSetting.uDisplayWidth / 2.0f, h = windowSetting.uDisplayHeight / 2.0f, inv = 1.0f; GLfloat vertices[] = { -inv + g_texRectTVtx[0].x/ w, inv - g_texRectTVtx[0].y/ h, -g_texRectTVtx[0].z,1, -inv + g_texRectTVtx[1].x/ w, inv - g_texRectTVtx[1].y/ h, -g_texRectTVtx[1].z,1, -inv + g_texRectTVtx[2].x/ w, inv - g_texRectTVtx[2].y/ h, -g_texRectTVtx[2].z,1, -inv + g_texRectTVtx[0].x/ w, inv - g_texRectTVtx[0].y/ h, -g_texRectTVtx[0].z,1, -inv + g_texRectTVtx[2].x/ w, inv - g_texRectTVtx[2].y/ h, -g_texRectTVtx[2].z,1, -inv + g_texRectTVtx[3].x/ w, inv - g_texRectTVtx[3].y/ h, -g_texRectTVtx[3].z,1 }; glVertexAttribPointer(VS_COLOR, 4, GL_FLOAT,GL_FALSE, 0, &colour ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,0,&vertices); glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, 0, &tex); glVertexAttribPointer(VS_TEXCOORD1,2,GL_FLOAT,GL_FALSE, 0, &tex2); //OPENGL_CHECK_ERRORS; glDrawArrays(GL_TRIANGLES,0,6); //OPENGL_CHECK_ERRORS; //Restore old pointers glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u)); glVertexAttribPointer(VS_TEXCOORD1,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[1].u)); if( cullface ) glEnable(GL_CULL_FACE); } void OGLRender::DrawObjBGCopy(uObjBg &info) { if( IsUsedAsDI(g_CI.dwAddr) ) { DebugMessage(M64MSG_WARNING, "Unimplemented: write into Z buffer. Was mostly commented out in Rice Video 6.1.0"); return; } else { CRender::LoadObjBGCopy(info); CRender::DrawObjBGCopy(info); } } mupen64plus-video-rice-src-2.6.0/src/OGLTexture.cpp000066400000000000000000000115571464507324400220510ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "Config.h" #include "Debugger.h" #include "GraphicsContext.h" #include "OGLDebug.h" #include "OGLGraphicsContext.h" #include "OGLTexture.h" #include "TextureManager.h" #include "osal_opengl.h" COGLTexture::COGLTexture(uint32 dwWidth, uint32 dwHeight, TextureUsage usage) : CTexture(dwWidth,dwHeight,usage), m_glInternalFmt(GL_RGBA) { // FIXME: If usage is AS_RENDER_TARGET, we need to create pbuffer instead of regular texture m_dwTextureFmt = TEXTURE_FMT_A8R8G8B8; // Always use 32bit to load texture glGenTextures( 1, &m_dwTextureName ); OPENGL_CHECK_ERRORS; // Make the width and height be the power of 2 uint32 w; for (w = 1; w < dwWidth; w <<= 1); m_dwCreatedTextureWidth = w; for (w = 1; w < dwHeight; w <<= 1); m_dwCreatedTextureHeight = w; if (dwWidth*dwHeight > 256*256) TRACE4("Large texture: (%d x %d), created as (%d x %d)", dwWidth, dwHeight,m_dwCreatedTextureWidth,m_dwCreatedTextureHeight); m_fYScale = (float)m_dwCreatedTextureHeight/(float)m_dwHeight; m_fXScale = (float)m_dwCreatedTextureWidth/(float)m_dwWidth; m_pTexture = malloc(m_dwCreatedTextureWidth * m_dwCreatedTextureHeight * GetPixelSize()); switch( options.textureQuality ) { case TXT_QUALITY_DEFAULT: if( options.colorQuality == TEXTURE_FMT_A4R4G4B4 ) m_glInternalFmt = GL_RGBA4; break; case TXT_QUALITY_32BIT: break; case TXT_QUALITY_16BIT: m_glInternalFmt = GL_RGBA4; break; }; #ifndef USE_GLES m_glFmt = GL_BGRA; m_glType = GL_UNSIGNED_INT_8_8_8_8_REV; #else m_glInternalFmt = m_glFmt = COGLGraphicsContext::Get()->IsSupportTextureFormatBGRA() ? GL_BGRA_EXT : GL_RGBA; m_glType = GL_UNSIGNED_BYTE; #endif LOG_TEXTURE(TRACE2("New texture: (%d, %d)", dwWidth, dwHeight)); // We create the OGL texture here and will use glTexSubImage2D to increase performance. glBindTexture(GL_TEXTURE_2D, m_dwTextureName); OPENGL_CHECK_ERRORS; glTexImage2D(GL_TEXTURE_2D, 0, m_glInternalFmt, m_dwCreatedTextureWidth, m_dwCreatedTextureHeight, 0, m_glFmt, m_glType, NULL); OPENGL_CHECK_ERRORS; } COGLTexture::~COGLTexture() { // FIXME: If usage is AS_RENDER_TARGET, we need to destroy the pbuffer glDeleteTextures(1, &m_dwTextureName); OPENGL_CHECK_ERRORS; free(m_pTexture); m_pTexture = NULL; m_dwWidth = 0; m_dwHeight = 0; } bool COGLTexture::StartUpdate(DrawInfo *di) { if (m_pTexture == NULL) return false; di->dwHeight = (uint16)m_dwHeight; di->dwWidth = (uint16)m_dwWidth; di->dwCreatedHeight = m_dwCreatedTextureHeight; di->dwCreatedWidth = m_dwCreatedTextureWidth; di->lpSurface = m_pTexture; di->lPitch = GetPixelSize()*m_dwCreatedTextureWidth; return true; } void COGLTexture::EndUpdate(DrawInfo *di) { glBindTexture(GL_TEXTURE_2D, m_dwTextureName); OPENGL_CHECK_ERRORS; // mipmap support if(options.mipmapping) { int maximumAnistropy = COGLGraphicsContext::Get()->getMaxAnisotropicFiltering(); //if getMaxAnisotropicFiltering() return more than 0, so aniso is supported and maxAnisotropicFiltering is set // Set Anisotropic filtering (mipmapping have to be activated, aniso filtering is not effective without) if( maximumAnistropy ) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maximumAnistropy); OPENGL_CHECK_ERRORS; } #ifndef USE_GLES // Tell to hardware to generate mipmap (himself) when glTexImage2D is called glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); OPENGL_CHECK_ERRORS; #endif } // Copy the image data from main memory to video card texture memory // On little-endian systems (x86 and many others), ARGB datas send in BGRA order // and RGBA datas are send as ABGR (something we try to avoid). glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_dwCreatedTextureWidth, m_dwCreatedTextureHeight, m_glFmt, m_glType, m_pTexture); OPENGL_CHECK_ERRORS; #ifdef USE_GLES if(options.mipmapping) glGenerateMipmap(GL_TEXTURE_2D); OPENGL_CHECK_ERRORS; #endif } mupen64plus-video-rice-src-2.6.0/src/OGLTexture.h000066400000000000000000000031101464507324400215000ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _OGL_TEXTURE_H_ #define _OGL_TEXTURE_H_ #include "Texture.h" #include "TextureManager.h" #include "osal_opengl.h" #include "typedefs.h" class COGLTexture : public CTexture { friend class COGLRenderTexture; public: ~COGLTexture(); bool StartUpdate(DrawInfo *di); void EndUpdate(DrawInfo *di); GLuint m_dwTextureName; protected: friend class OGLDeviceBuilder; COGLTexture(uint32 dwWidth, uint32 dwHeight, TextureUsage usage = AS_NORMAL); private: /* Note for the futur, the implmentation dependant values can be * retrieved using (OGL 4.3 et OGLES 3): * GLenum format, type; * glGetInternalformativ(GL_TEXTURE_2D, GL_RGBA, GL_TEXTURE_IMAGE_FORMAT, 1, &format); * glGetInternalformativ(GL_TEXTURE_2D, GL_RGBA, GL_TEXTURE_IMAGE_TYPE, 1, &type); */ GLuint m_glInternalFmt; GLuint m_glFmt; GLuint m_glType; }; #endif mupen64plus-video-rice-src-2.6.0/src/RDP_Texture.h000066400000000000000000002140411464507324400216520ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // Texture related ucode #include #include #include "Render.h" #undef min #undef max uint32 g_TmemFlag[16]; void SetTmemFlag(uint32 tmemAddr, uint32 size); bool IsTmemFlagValid(uint32 tmemAddr); uint32 GetValidTmemInfoIndex(uint32 tmemAddr); void EnhanceTexture(TxtrCacheEntry *pEntry); void LoadHiresTexture( TxtrCacheEntry &entry ); extern TMEMLoadMapInfo g_tmemInfo0; // Info for Tmem=0 extern TMEMLoadMapInfo g_tmemInfo1; // Info for Tmem=0x100 TmemType g_Tmem; /************************************************************************/ /* */ /************************************************************************/ uint32 sizeShift[4] = {2,1,0,0}; uint32 sizeIncr[4] = {3,1,0,0}; uint32 sizeBytes[4] = {0,1,2,4}; inline uint32 Txl2Words(uint32 width, uint32 size) { if( size == TXT_SIZE_4b ) return std::max(1u, width/16); else return std::max(1u, width*sizeBytes[size]/8); } inline uint32 CalculateImgSize(uint32 width, uint32 height, uint32 size) { //(((width)*(height) + siz##_INCR) >> siz##_SHIFT) -1 return (((width)*(height) + sizeIncr[size]) >> sizeShift[size]) -1; } inline uint32 CalculateDXT(uint32 txl2words) { //#define CALC_DXT(width, b_txl) ((2048 + TXL2WORDS(width, b_txl) - 1) / TXL2WORDS(width, b_txl)) if( txl2words == 0 ) return 1; else return (2048+txl2words-1)/txl2words; } inline uint32 ReverseDXT(uint32 val, uint32 lrs, uint32 width, uint32 size) { //#define TXL2WORDS(txls, b_txl) MAX(1, ((txls)*(b_txl)/8)) if( val == 0x800 ) return 1; unsigned int low = 2047/val; if( CalculateDXT(low) > val ) low++; unsigned int high = 2047/(val-1); if( low == high ) return low; for( unsigned int i=low; i<=high; i++ ) { if( Txl2Words(width, size) == i ) return i; } return (low+high)/2; //dxt = 2047 / (dxt-1); } // The following inline assemble routines are borrowed from glN64, I am too tired to // rewrite these routine by myself. // Rice, 02/24/2004 inline void UnswapCopy( void *src, void *dest, uint32 numBytes ) { #if !defined(__GNUC__) && !defined(NO_ASM) __asm { mov ecx, 0 mov esi, dword ptr [src] mov edi, dword ptr [dest] mov ebx, esi and ebx, 3 // ebx = number of leading bytes cmp ebx, 0 jz StartDWordLoop neg ebx add ebx, 4 cmp ebx, [numBytes] jle NotGreater mov ebx, [numBytes] NotGreater: mov ecx, ebx xor esi, 3 LeadingLoop: // Copies leading bytes, in reverse order (un-swaps) mov al, byte ptr [esi] mov byte ptr [edi], al sub esi, 1 add edi, 1 loop LeadingLoop add esi, 5 StartDWordLoop: mov ecx, dword ptr [numBytes] sub ecx, ebx // Don't copy what's already been copied mov ebx, ecx and ebx, 3 // add ecx, 3 // Round up to nearest dword shr ecx, 2 cmp ecx, 0 // If there's nothing to do, don't do it jle StartTrailingLoop // Copies from source to destination, bswap-ing first DWordLoop: mov eax, dword ptr [esi] bswap eax mov dword ptr [edi], eax add esi, 4 add edi, 4 loop DWordLoop StartTrailingLoop: cmp ebx, 0 jz Done mov ecx, ebx xor esi, 3 TrailingLoop: mov al, byte ptr [esi] mov byte ptr [edi], al sub esi, 1 add edi, 1 loop TrailingLoop Done: } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) asm volatile(" movl %k1, %%ebx \n" " andl $3, %%ebx \n" " cmpl $0, %%ebx \n" " jz 2f \n" " negl %%ebx \n" " addl $4, %%ebx \n" " cmpl %k2, %%ebx \n" " jle 0f \n" " movl %k2, %%ebx \n" "0: \n" " movl %%ebx, %%ecx \n" " xor $3, %1 \n" "1: \n" " movb (%1), %%al \n" " movb %%al, (%0) \n" " sub $1, %1 \n" " add $1, %0 \n" " decl %%ecx \n" " jne 1b \n" " add $5, %1 \n" "2: \n" " movl %k2, %%ecx \n" " subl %%ebx, %%ecx \n" " movl %%ecx, %%ebx \n" " andl $3, %%ebx \n" " shrl $2, %%ecx \n" " cmpl $0, %%ecx \n" " jle 4f \n" "3: \n" " movl (%1), %%eax \n" " bswapl %%eax \n" " movl %%eax, (%0) \n" " add $4, %1 \n" " add $4, %0 \n" " decl %%ecx \n" " jne 3b \n" "4: \n" " cmpl $0, %%ebx \n" " jz 6f \n" " xor $3, %1 \n" "5: \n" " movb (%1), %%al \n" " movb %%al, (%0) \n" " sub $1, %1 \n" " add $1, %0 \n" " decl %%ebx \n" " jne 5b \n" "6: \n" :"+r"(dest), "+r"(src) :"r"(numBytes) : "memory", "cc", "%rax", "%rbx", "%rcx" ); #elif !defined(NO_ASM) unsigned int saveEBX; asm volatile ("mov %%ebx, %2 \n" "mov $0, %%ecx \n" "mov %0, %%esi \n" "mov %1, %%edi \n" "mov %%esi, %%ebx \n" "and $3, %%ebx \n" // ebx = number of leading bytes "cmp $0, %%ebx \n" "jz 2f \n" //jz StartDWordLoop "neg %%ebx \n" "add $4, %%ebx \n" "cmp %3, %%ebx \n" "jle 0f \n" //jle NotGreater "mov %3, %%ebx \n" "0: \n" //NotGreater: "mov %%ebx, %%ecx \n" "xor $3, %%esi \n" "1: \n" //LeadingLoop: // Copies leading bytes, in reverse order (un-swaps) "mov (%%esi), %%al \n" "mov %%al, (%%edi) \n" "sub $1, %%esi \n" "add $1, %%edi \n" "loop 1b \n" //loop LeadingLoop "add $5, %%esi \n" "2: \n" //StartDWordLoop: "mov %3, %%ecx \n" "sub %%ebx, %%ecx \n" // Don't copy what's already been copied "mov %%ecx, %%ebx \n" "and $3, %%ebx \n" // add ecx, 3 // Round up to nearest dword "shr $2, %%ecx \n" "cmp $0, %%ecx \n" // If there's nothing to do, don't do it "jle 4f \n" //jle StartTrailingLoop // Copies from source to destination, bswap-ing first "3: \n" //DWordLoop: "mov (%%esi), %%eax \n" "bswap %%eax \n" "mov %%eax, (%%edi) \n" "add $4, %%esi \n" "add $4, %%edi \n" "loop 3b \n" //loop DWordLoop "4: \n" //StartTrailingLoop: "cmp $0, %%ebx \n" "jz 6f \n" //jz Done "mov %%ebx, %%ecx \n" "xor $3, %%esi \n" "5: \n" //TrailingLoop: "mov (%%esi), %%al \n" "mov %%al, (%%edi) \n" "sub $1, %%esi \n" "add $1, %%edi \n" "loop 5b \n" //loop TrailingLoop "6: \n" //Done: "mov %2, %%ebx \n" : : "m"(src), "m"(dest), "m"(saveEBX), "m"(numBytes) : "memory", "cc", "%ecx", "%esi", "%edi", "%eax" ); #endif } inline void DWordInterleave( void *mem, uint32 numDWords ) { #if !defined(__GNUC__) && !defined(NO_ASM) __asm { mov esi, dword ptr [mem] mov edi, dword ptr [mem] add edi, 4 mov ecx, dword ptr [numDWords] DWordInterleaveLoop: mov eax, dword ptr [esi] mov ebx, dword ptr [edi] mov dword ptr [esi], ebx mov dword ptr [edi], eax add esi, 8 add edi, 8 loop DWordInterleaveLoop } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) asm volatile("0: \n" " movl (%0), %%eax \n" " movl 8(%0), %%ebx \n" " movl %%eax, 8(%0) \n" " movl %%ebx, (%0) \n" " add $8, %0 \n" " decl %k1 \n" " jne 0b \n" : "+r"(mem), "+r"(numDWords) : : "memory", "cc", "%rax", "%rbx" ); #elif !defined(NO_ASM) unsigned int saveEBX; asm volatile ("mov %%ebx, %2 \n" "mov %0, %%esi \n" "mov %0, %%edi \n" "add $4, %%edi \n" "mov %1, %%ecx \n" "0: \n" //DWordInterleaveLoop: "mov (%%esi), %%eax \n" "mov (%%edi), %%ebx \n" "mov %%ebx, (%%esi) \n" "mov %%eax, (%%edi) \n" "add $8, %%esi \n" "add $8, %%edi \n" "loop 0b \n" //loop DWordInterleaveLoop "mov %2, %%ebx \n" : : "m"(mem), "m"(numDWords), "m"(saveEBX) : "memory", "cc", "%esi", "%edi", "%ecx", "%eax" ); #endif } inline void QWordInterleave( void *mem, uint32 numDWords ) { #if !defined(__GNUC__) && !defined(NO_ASM) __asm { // Interleave the line on the qword mov esi, dword ptr [mem] mov edi, dword ptr [mem] add edi, 8 mov ecx, dword ptr [numDWords] shr ecx, 1 QWordInterleaveLoop: mov eax, dword ptr [esi] mov ebx, dword ptr [edi] mov dword ptr [esi], ebx mov dword ptr [edi], eax add esi, 4 add edi, 4 mov eax, dword ptr [esi] mov ebx, dword ptr [edi] mov dword ptr [esi], ebx mov dword ptr [edi], eax add esi, 12 add edi, 12 loop QWordInterleaveLoop } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) asm volatile(" shr $1, %k1 \n" "0: \n" " mov (%0), %%rax \n" " mov 8(%0), %%rbx \n" " mov %%rax, 8(%0) \n" " mov %%rbx, (%0) \n" " add $16, %0 \n" " decl %k1 \n" " jne 0b \n" : "+r"(mem), "+r"(numDWords) : : "memory", "cc", "%rax", "%rbx" ); #elif !defined(NO_ASM) // GCC assumed unsigned int saveEBX; asm volatile("mov %%ebx, %2 \n" // Interleave the line on the qword "mov %0, %%esi \n" "mov %0, %%edi \n" "add $8, %%edi \n" "mov %1, %%ecx \n" "shr $1, %%ecx \n" "0: \n" //QWordInterleaveLoop: "mov (%%esi), %%eax \n" "mov (%%edi), %%ebx \n" "mov %%ebx, (%%esi) \n" "mov %%eax, (%%edi) \n" "add $4, %%esi \n" "add $4, %%edi \n" "mov (%%esi), %%eax \n" "mov (%%edi), %%ebx \n" "mov %%ebx, (%%esi) \n" "mov %%eax, (%%edi) \n" "add $12, %%esi \n" "add $12, %%edi \n" "loop 0b \n" //loop QWordInterleaveLoop "mov %2, %%ebx \n" : : "m"(mem), "m"(numDWords), "m"(saveEBX) : "memory", "cc", "%esi", "%edi", "%ecx", "%eax" ); #endif } inline uint32 swapdword( uint32 value ) { #if defined(__INTEL_COMPILER) && !defined(NO_ASM) __asm { mov eax, dword ptr [value] bswap eax } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) asm volatile(" bswapl %k0 \n" : "+r"(value) : : ); return value; #elif defined(__GNUC__) && defined(__i386__) && !defined(NO_ASM) asm volatile("bswapl %0 \n" : "+r"(value) : : ); return value; #else return ((value & 0xff000000) >> 24) | ((value & 0x00ff0000) >> 8) | ((value & 0x0000ff00) << 8) | ((value & 0x000000ff) << 24); #endif } inline uint16 swapword( uint16 value ) { #if defined(__INTEL_COMPILER) && !defined(NO_ASM) __asm { mov ax, word ptr [value] xchg ah, al } #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) && !defined(NO_ASM) asm volatile("xchg %%al, %%ah \n" : "+a"(value) : : ); return value; #else return ((value & 0xff00) >> 8) | ((value & 0x00ff) << 8); #endif } void ComputeTileDimension(int mask, int clamp, int mirror, int width, uint32 &widthToCreate, uint32 &widthToLoad) { int maskwidth = mask > 0 ? (1< 0 ) { if( width > maskwidth ) { if( clamp == 0 ) { // clamp is not used, so just use the dwTileMaskWidth as the real width widthToCreate = widthToLoad = maskwidth; } else { widthToLoad = maskwidth; //gti.WidthToCreate = dwTileWidth; // keep the current WidthToCreate, we will do mirror/wrap // during texture loading, not during rendering } } else if( width < maskwidth ) { // dwTileWidth < dwTileMaskWidth if( clamp == 0 ) { if( maskwidth%width == 0 ) { if( (maskwidth/width)%2 == 0 || mirror == 0 ) { // Do nothing // gti.WidthToLoad = gti.WidthToCreate = gRDP.tiles[tileno].dwWidth = dwTileWidth } else { widthToCreate = maskwidth; } } else { widthToCreate = maskwidth; //widthToLoad = maskwidth; } } else { widthToCreate = maskwidth; //widthToLoad = maskwidth; } } else // dwTileWidth == dwTileMaskWidth { } // Some hacks, to limit the image size if( mask >= 8 ) { if( maskwidth / width >= 2 ) { widthToCreate = width; } } } } bool conkerSwapHack=false; bool CalculateTileSizes_method_2(int tileno, TMEMLoadMapInfo *info, TxtrInfo >i) { Tile &tile = gRDP.tiles[tileno]; Tile &loadtile = gRDP.tiles[RDP_TXT_LOADTILE]; uint32 dwPitch; // Now Initialize the texture dimension int dwTileWidth; int dwTileHeight; if( info->bSetBy == CMD_LOADTILE ) { if( tile.sl >= tile.sh ) { dwTileWidth = info->dwWidth; // From SetTImage dwTileWidth = dwTileWidth << info->dwSize >> tile.dwSize; } else { dwTileWidth= tile.sh - tile.sl + 1; } if( tile.tl >= tile.th ) { dwTileHeight= info->th - info->tl + 1; } else { dwTileHeight= tile.th - tile.tl + 1; } } else { if( tile.dwMaskS == 0 || tile.bClampS ) { dwTileWidth = tile.hilite_sh - tile.hilite_sl +1; if( dwTileWidth < tile.sh - tile.sl +1 ) dwTileWidth = tile.sh - tile.sl +1; if( dwTileWidth <= 0 ) { DebuggerAppendMsg("Error"); } } else { if( tile.dwMaskS < 8 ) dwTileWidth = (1 << tile.dwMaskS ); else if( tile.dwLine ) { dwTileWidth = (tile.dwLine<<5)>>tile.dwSize; } else { if( tile.sl <= tile.sh ) { dwTileWidth = tile.sh - tile.sl +1; } else if( loadtile.sl <= loadtile.sh ) { dwTileWidth = loadtile.sh - loadtile.sl +1; } else { dwTileWidth = tile.sh - tile.sl +1; } } } if( tile.dwMaskT == 0 || tile.bClampT ) { dwTileHeight= tile.hilite_th - tile.hilite_tl +1; if( dwTileHeight < tile.th - tile.tl +1 ) dwTileHeight = tile.th - tile.tl +1; if( dwTileHeight <= 0 ) { DebuggerAppendMsg("Error"); } } else { if( tile.dwMaskT < 8 ) dwTileHeight = (1 << tile.dwMaskT ); else if( tile.tl <= tile.th ) { dwTileHeight = tile.th - tile.tl +1; } else if( loadtile.tl <= loadtile.th ) { dwTileHeight = loadtile.th - loadtile.tl +1; } else { dwTileHeight = tile.th - tile.tl +1; } } } int dwTileMaskWidth = tile.dwMaskS > 0 ? (1 << tile.dwMaskS ) : 0; int dwTileMaskHeight = tile.dwMaskT > 0 ? (1 << tile.dwMaskT ) : 0; if( dwTileWidth < 0 || dwTileHeight < 0) { if( dwTileMaskWidth > 0 ) dwTileWidth = dwTileMaskWidth; else if( dwTileWidth < 0 ) dwTileWidth = -dwTileWidth; if( dwTileMaskHeight > 0 ) dwTileHeight = dwTileMaskHeight; else if( dwTileHeight < 0 ) dwTileHeight = -dwTileHeight; } if( dwTileWidth-dwTileMaskWidth == 1 && dwTileMaskWidth && dwTileHeight-dwTileMaskHeight == 1 && dwTileMaskHeight ) { // Hack for Mario Kart dwTileWidth--; dwTileHeight--; } ComputeTileDimension(tile.dwMaskS, tile.bClampS, tile.bMirrorS, dwTileWidth, gti.WidthToCreate, gti.WidthToLoad); tile.dwWidth = gti.WidthToCreate; ComputeTileDimension(tile.dwMaskT, tile.bClampT, tile.bMirrorT, dwTileHeight, gti.HeightToCreate, gti.HeightToLoad); tile.dwHeight = gti.HeightToCreate; #ifdef DEBUGGER if( gti.WidthToCreate < gti.WidthToLoad ) TRACE2("Check me, width to create = %d, width to load = %d", gti.WidthToCreate, gti.WidthToLoad); if( gti.HeightToCreate < gti.HeightToLoad ) TRACE2("Check me, height to create = %d, height to load = %d", gti.HeightToCreate, gti.HeightToLoad); #endif gti.bSwapped = info->bSwapped; if( info->bSetBy == CMD_LOADTILE ) { // It was a tile - the pitch is set by LoadTile dwPitch = info->dwWidth<<(info->dwSize-1); if( dwPitch == 0 ) { dwPitch = 1024; // Hack for Bust-A-Move } } else //Set by LoadBlock { // It was a block load - the pitch is determined by the tile size if (info->dxt == 0 || info->dwTmem != tile.dwTMem ) { dwPitch = tile.dwLine << 3; gti.bSwapped = TRUE; if( info->dwTmem != tile.dwTMem && info->dxt != 0 && info->dwSize == TXT_SIZE_16b && tile.dwSize == TXT_SIZE_4b ) conkerSwapHack = true; } else { uint32 DXT = info->dxt; if( info->dxt > 1 ) { DXT = ReverseDXT(info->dxt, info->sh, dwTileWidth, tile.dwSize); } dwPitch = DXT << 3; } if (tile.dwSize == TXT_SIZE_32b) dwPitch = tile.dwLine << 4; } gti.Pitch = tile.dwPitch = dwPitch; if( (gti.WidthToLoad < gti.WidthToCreate || tile.bSizeIsValid == false) && tile.dwMaskS > 0 && gti.WidthToLoad != (unsigned int)dwTileMaskWidth && info->bSetBy == CMD_LOADBLOCK ) //if( (gti.WidthToLoad < gti.WidthToCreate ) && tile.dwMaskS > 0 && gti.WidthToLoad != dwTileMaskWidth && // info->bSetBy == CMD_LOADBLOCK ) { // We have got the pitch now, recheck the width_to_load uint32 pitchwidth = dwPitch<<1>>tile.dwSize; if( pitchwidth == (unsigned int)dwTileMaskWidth ) { gti.WidthToLoad = pitchwidth; } } if( (gti.HeightToLoad < gti.HeightToCreate || tile.bSizeIsValid == false) && tile.dwMaskT > 0 && gti.HeightToLoad != (unsigned int)dwTileMaskHeight && info->bSetBy == CMD_LOADBLOCK ) //if( (gti.HeightToLoad < gti.HeightToCreate ) && tile.dwMaskT > 0 && gti.HeightToLoad != dwTileMaskHeight && // info->bSetBy == CMD_LOADBLOCK ) { //uint32 pitchwidth = dwPitch<<1>>tile.dwSize; uint32 pitchHeight = (info->dwTotalWords<<1)/dwPitch; if( pitchHeight == (unsigned int)dwTileMaskHeight || gti.HeightToLoad == 1 ) { gti.HeightToLoad = pitchHeight; } } if( gti.WidthToCreate < gti.WidthToLoad ) gti.WidthToCreate = gti.WidthToLoad; if( gti.HeightToCreate < gti.HeightToLoad ) gti.HeightToCreate = gti.HeightToLoad; if( info->bSetBy == CMD_LOADTILE ) { gti.LeftToLoad = (info->sl<dwSize)>>tile.dwSize; gti.TopToLoad = info->tl; } else { gti.LeftToLoad = (info->sl<dwSize)>>tile.dwSize; gti.TopToLoad = (info->tl<dwSize)>>tile.dwSize; } uint32 total64BitWordsToLoad = (gti.HeightToLoad*gti.WidthToLoad)>>(4-tile.dwSize); if( total64BitWordsToLoad + tile.dwTMem > 0x200 ) { //TRACE0("Warning: texture loading tmem is over range"); if( gti.WidthToLoad > gti.HeightToLoad ) { uint32 newheight = (dwPitch << 1 )>> tile.dwSize; tile.dwWidth = gti.WidthToLoad = gti.WidthToCreate = std::min(newheight, (gti.WidthToLoad&0xFFFFFFFE)); tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = ((0x200 - tile.dwTMem) << (4-tile.dwSize)) / gti.WidthToLoad; } else { tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = info->dwTotalWords / ((gti.WidthToLoad << tile.dwSize) >> 1); } } // Check the info if( (info->dwTotalWords>>2) < total64BitWordsToLoad+tile.dwTMem-info->dwTmem - 4 ) { // Hack here if( (options.enableHackForGames == HACK_FOR_ZELDA||options.enableHackForGames == HACK_FOR_ZELDA_MM) && (unsigned int)tileno != gRSP.curTile ) { return false; } if( total64BitWordsToLoad+tile.dwTMem-info->dwTmem <= 0x200 ) { LOG_TEXTURE(TRACE4("Fix me, info is not covering this Tmem address,Info start: 0x%x, total=0x%x, Tmem start: 0x%x, total=0x%x", info->dwTmem,info->dwTotalWords>>2, tile.dwTMem, total64BitWordsToLoad)); } } //Check memory boundary if( gti.Address + gti.HeightToLoad*gti.Pitch >= g_dwRamSize ) { WARNING(TRACE0("Warning: texture loading tmem is over range 3")); gti.HeightToCreate = gti.HeightToLoad = tile.dwHeight = (g_dwRamSize-gti.Address)/gti.Pitch; } return true; } bool CalculateTileSizes_method_1(int tileno, TMEMLoadMapInfo *info, TxtrInfo >i) { Tile &tile = gRDP.tiles[tileno]; //Tile &loadtile = gRDP.tiles[RDP_TXT_LOADTILE]; // Now Initialize the texture dimension int loadwidth, loadheight; int maskwidth = tile.dwMaskS ? (1 << tile.dwMaskS ) : 0; int maskheight = tile.dwMaskT ? (1 << tile.dwMaskT ) : 0; int clampwidth = abs(tile.hilite_sh - tile.hilite_sl) +1; int clampheight = abs(tile.hilite_th - tile.hilite_tl) +1; int linewidth = tile.dwLine << (5 - tile.dwSize); gti.bSwapped = info->bSwapped; if( info->bSetBy == CMD_LOADTILE ) { loadwidth = (abs(info->sh - info->sl) + 1) << info->dwSize >> tile.dwSize; loadheight = (abs(info->th - info->tl) + 1) << info->dwSize >> tile.dwSize; tile.dwPitch = info->dwWidth << info->dwSize >> 1; if( tile.dwPitch == 0 ) tile.dwPitch = 1024; // Hack for Bust-A-Move gti.LeftToLoad = (info->sl<dwSize)>>tile.dwSize; gti.TopToLoad = info->tl; } else { loadwidth = abs(tile.sh - tile.sl) +1; if( tile.dwMaskS ) { loadwidth = maskwidth; } loadheight = abs(tile.th - tile.tl) +1; if( tile.dwMaskT ) { loadheight = maskheight; } // It was a block load - the pitch is determined by the tile size if (tile.dwSize == TXT_SIZE_32b) tile.dwPitch = tile.dwLine << 4; else if (info->dxt == 0 ) { tile.dwPitch = tile.dwLine << 3; gti.bSwapped = TRUE; if( info->dwTmem != tile.dwTMem && info->dxt != 0 && info->dwSize == TXT_SIZE_16b && tile.dwSize == TXT_SIZE_4b ) conkerSwapHack = true; } else { uint32 DXT = info->dxt; if( info->dxt > 1 ) { DXT = ReverseDXT(info->dxt, info->sh, loadwidth, tile.dwSize); } tile.dwPitch = DXT << 3; } gti.LeftToLoad = (info->sl<dwSize)>>tile.dwSize; gti.TopToLoad = (info->tl<dwSize)>>tile.dwSize; } if( options.enableHackForGames == HACK_FOR_MARIO_KART ) { if( loadwidth-maskwidth == 1 && tile.dwMaskS ) { loadwidth--; if( loadheight%2 ) loadheight--; } if( loadheight-maskheight == 1 && tile.dwMaskT ) { loadheight--; if(loadwidth%2) loadwidth--; } if( loadwidth - ((g_TI.dwWidth<>tile.dwSize) == 1 ) { loadwidth--; if( loadheight%2 ) loadheight--; } } // Limit the texture size if( g_curRomInfo.bUseSmallerTexture ) { if( tile.dwMaskS && tile.bClampS ) { if( !tile.bMirrorS ) { if( clampwidth/maskwidth >= 2 ) { clampwidth = maskwidth; tile.bForceWrapS = true; } else if( clampwidth && maskwidth/clampwidth >= 2 ) { maskwidth = clampwidth; tile.bForceClampS = true; } } else { if( clampwidth/maskwidth == 2 ) { clampwidth = maskwidth*2; tile.bForceWrapS = false; } else if( clampwidth/maskwidth > 2 ) { clampwidth = maskwidth*2; tile.bForceWrapS = true; } } } if( tile.dwMaskT && tile.bClampT ) { if( !tile.bMirrorT ) { if( clampheight/maskheight >= 2 ) { clampheight = maskheight; tile.bForceWrapT = true; } else if( clampheight && maskheight/clampheight >= 2 ) { maskwidth = clampwidth; tile.bForceClampT = true; } } else { if( clampheight/maskheight == 2 ) { clampheight = maskheight*2; tile.bForceWrapT = false; } else if( clampheight/maskheight >= 2 ) { clampheight = maskheight*2; tile.bForceWrapT = true; } } } } else { //if( clampwidth > linewidth ) clampwidth = linewidth; if( clampwidth > 512 && clampheight > 512 ) { if( clampwidth > maskwidth && maskwidth && clampheight > 256 ) clampwidth = maskwidth; if( clampheight > maskheight && maskheight && clampheight > 256 ) clampheight = maskheight; } if( tile.dwMaskS > 8 && tile.dwMaskT > 8 ) { maskwidth = loadwidth; maskheight = loadheight; } else { if( tile.dwMaskS > 10 ) maskwidth = loadwidth; if( tile.dwMaskT > 10 ) maskheight = loadheight; } } gti.Pitch = tile.dwPitch; if( tile.dwMaskS == 0 || tile.bClampS ) { gti.WidthToLoad = linewidth ? std::min( linewidth, maskwidth ? std::min(clampwidth,maskwidth) : clampwidth ) : clampwidth; if( tile.dwMaskS && clampwidth < maskwidth ) tile.dwWidth = gti.WidthToCreate = clampwidth; else tile.dwWidth = gti.WidthToCreate = std::max(clampwidth,maskwidth); } else { gti.WidthToLoad = loadwidth > 2 ? std::min(loadwidth,maskwidth) : maskwidth; if( linewidth ) gti.WidthToLoad = std::min( linewidth, (int)gti.WidthToLoad ); tile.dwWidth = gti.WidthToCreate = maskwidth; } if( tile.dwMaskT == 0 || tile.bClampT ) { gti.HeightToLoad = maskheight ? std::min(clampheight,maskheight) : clampheight; if( tile.dwMaskT && clampheight < maskheight ) tile.dwHeight = gti.HeightToCreate = clampheight; else tile.dwHeight = gti.HeightToCreate = std::max(clampheight,maskheight); } else { gti.HeightToLoad = loadheight > 2 ? std::min(loadheight,maskheight) : maskheight; tile.dwHeight = gti.HeightToCreate = maskheight; } if( options.enableHackForGames == HACK_FOR_MARIO_KART ) { if( gti.WidthToLoad - ((g_TI.dwWidth<>tile.dwSize) == 1 ) { gti.WidthToLoad--; if( gti.HeightToLoad%2 ) gti.HeightToLoad--; } } // Double check uint32 total64BitWordsToLoad = (gti.HeightToLoad*gti.WidthToLoad)>>(4-tile.dwSize); if( total64BitWordsToLoad + tile.dwTMem > 0x200 ) { //TRACE0("Warning: texture loading tmem is over range"); if( gti.WidthToLoad > gti.HeightToLoad ) { uint32 newheight = (tile.dwPitch << 1 )>> tile.dwSize; tile.dwWidth = gti.WidthToLoad = gti.WidthToCreate = std::min(newheight, (gti.WidthToLoad&0xFFFFFFFE)); tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = ((0x200 - tile.dwTMem) << (4-tile.dwSize)) / gti.WidthToLoad; } else { tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = info->dwTotalWords / ((gti.WidthToLoad << tile.dwSize) >> 1); } } // Check the info if( (info->dwTotalWords>>2) < total64BitWordsToLoad+tile.dwTMem-info->dwTmem - 4 ) { // Hack here if( (options.enableHackForGames == HACK_FOR_ZELDA||options.enableHackForGames == HACK_FOR_ZELDA_MM) && (unsigned int)tileno != gRSP.curTile ) { return false; } if( total64BitWordsToLoad+tile.dwTMem-info->dwTmem <= 0x200 ) { LOG_TEXTURE(TRACE4("Fix me, info is not covering this Tmem address,Info start: 0x%x, total=0x%x, Tmem start: 0x%x, total=0x%x", info->dwTmem,info->dwTotalWords>>2, tile.dwTMem, total64BitWordsToLoad)); } } //Check memory boundary if( gti.Address + gti.HeightToLoad*gti.Pitch >= g_dwRamSize ) { WARNING(TRACE0("Warning: texture loading tmem is over range 3")); gti.HeightToCreate = gti.HeightToLoad = tile.dwHeight = (g_dwRamSize-gti.Address)/gti.Pitch; } return true; } TxtrCacheEntry* LoadTexture(uint32 tileno) { //TxtrCacheEntry *pEntry = NULL; TxtrInfo gti; Tile &tile = gRDP.tiles[tileno]; // Retrieve the tile loading info uint32 infoTmemAddr = tile.dwTMem; TMEMLoadMapInfo *info = &g_tmemLoadAddrMap[infoTmemAddr]; if( !IsTmemFlagValid(infoTmemAddr) ) { infoTmemAddr = GetValidTmemInfoIndex(infoTmemAddr); info = &g_tmemLoadAddrMap[infoTmemAddr]; } if( info->dwFormat != tile.dwFormat ) { // Check the tile format, hack for Zelda's road if( tileno != gRSP.curTile && tile.dwTMem == gRDP.tiles[gRSP.curTile].dwTMem && tile.dwFormat != gRDP.tiles[gRSP.curTile].dwFormat ) { //TRACE1("Tile %d format is not matching the loaded texture format", tileno); return NULL; } } gti = tile; // Copy tile info to textureInfo entry gti.TLutFmt = gRDP.otherMode.text_tlut <dwLoadAddress+(tile.dwTMem-infoTmemAddr)*8) & (g_dwRamSize-1) ; gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address; gti.tileNo = tileno; if( g_curRomInfo.bTxtSizeMethod2 ) { if( !CalculateTileSizes_method_2(tileno, info, gti) ) return NULL; } else { if( !CalculateTileSizes_method_1(tileno, info, gti) ) return NULL; } LOG_TEXTURE( { TRACE0("Loading texture:\n"); DebuggerAppendMsg("Left: %d, Top: %d, Width: %d, Height: %d, Size to Load (%d, %d)", gti.LeftToLoad, gti.TopToLoad, gti.WidthToCreate, gti.HeightToCreate, gti.WidthToLoad, gti.HeightToLoad); DebuggerAppendMsg("Pitch: %d, Addr: 0x%08x", gti.Pitch, gti.Address); }); // Option for faster loading tiles if( g_curRomInfo.bFastLoadTile && info->bSetBy == CMD_LOADTILE && ((gti.Pitch<<1)>>gti.Size) <= 0x400 //&& ((gti.Pitch<<1)>>gti.Size) > 128 && status.primitiveType == PRIM_TEXTRECT ) { uint32 idx = tileno-gRSP.curTile; status.LargerTileRealLeft[idx] = gti.LeftToLoad; gti.LeftToLoad=0; gti.WidthToLoad = gti.WidthToCreate = ((gti.Pitch<<1)>>gti.Size); status.UseLargerTile[idx]=true; } // Loading the textures by using texture cache manager return gTextureManager.GetTexture(>i, true, true, true); // Load the texture by using texture cache } void PrepareTextures() { if( gRDP.textureIsChanged || !currentRomOptions.bFastTexCRC ) { status.UseLargerTile[0]=false; status.UseLargerTile[1]=false; int tilenos[2]; if( CRender::g_pRender->IsTexel0Enable() || gRDP.otherMode.cycle_type == CYCLE_TYPE_COPY ) tilenos[0] = gRSP.curTile; else tilenos[0] = -1; if( gRSP.curTile<7 && CRender::g_pRender->IsTexel1Enable() ) tilenos[1] = gRSP.curTile+1; else tilenos[1] = -1; for( int i=0; i<2; i++ ) { if( tilenos[i] < 0 ) continue; TxtrCacheEntry *pEntry = LoadTexture(tilenos[i]); if (pEntry && pEntry->pTexture ) { if( pEntry->txtrBufIdx <= 0 ) { if( pEntry->pEnhancedTexture && pEntry->dwEnhancementFlag == TEXTURE_EXTERNAL && !options.bLoadHiResTextures ) { SAFE_DELETE(pEntry->pEnhancedTexture); } if( options.bLoadHiResTextures && (pEntry->pEnhancedTexture == NULL || pEntry->dwEnhancementFlag < TEXTURE_EXTERNAL ) ) { LoadHiresTexture(*pEntry); } if( pEntry->pEnhancedTexture == NULL || (pEntry->dwEnhancementFlag != options.textureEnhancement && pEntry->dwEnhancementFlag < TEXTURE_EXTERNAL ) ) { EnhanceTexture(pEntry); } } CRender::g_pRender->SetCurrentTexture( tilenos[i], (pEntry->pEnhancedTexture)?pEntry->pEnhancedTexture:pEntry->pTexture, pEntry->ti.WidthToLoad, pEntry->ti.HeightToLoad, pEntry); } else { pEntry = gTextureManager.GetBlackTexture(); CRender::g_pRender->SetCurrentTexture( tilenos[i], pEntry->pTexture, 4, 4, pEntry); _VIDEO_DisplayTemporaryMessage("Fail to load texture, use black to replace"); } } gRDP.textureIsChanged = false; } } extern uint32 g_TxtLoadBy;; void DLParser_LoadTLut(Gfx *gfx) { gRDP.textureIsChanged = true; uint32 tileno = gfx->loadtile.tile; uint32 uls = gfx->loadtile.sl/4; uint32 ult = gfx->loadtile.tl/4; uint32 lrs = gfx->loadtile.sh/4; uint32 lrt = gfx->loadtile.th/4; #ifdef DEBUGGER uint32 dwTLutFmt = (gRDP.otherModeH >> RSP_SETOTHERMODE_SHIFT_TEXTLUT)&0x3; #endif uint32 dwCount; // starting location in the palettes uint32 dwTMEMOffset = gRDP.tiles[tileno].dwTMem - 256; // number to copy dwCount = ((uint16)((gfx->words.w1) >> 14) & 0x03FF) + 1; uint32 dwRDRAMOffset = 0; Tile &tile = gRDP.tiles[tileno]; tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false; tile.hilite_sl = tile.sl = uls; tile.hilite_tl = tile.tl = ult; tile.sh = lrs; tile.th = lrt; tile.bSizeIsValid = true; tile.lastTileCmd = CMD_LOADTLUT; #ifdef DEBUGGER /* if((((gfx->words.w0)>>12)&0x3) != 0 || (((gfx->words.w0))&0x3) != 0 || (((gfx->words.w1)>>12)&0x3) != 0 || (((gfx->words.w1))&0x3) != 0) TRACE0("Load tlut, sl,tl,sh,th are not integers"); */ #endif dwCount = (lrs - uls)+1; dwRDRAMOffset = (uls + ult*g_TI.dwWidth )*2; uint32 dwPalAddress = g_TI.dwAddr + dwRDRAMOffset; //Copy PAL to the PAL memory uint16 *srcPal = (uint16*)(g_pRDRAMu8 + (dwPalAddress& (g_dwRamSize-1)) ); for (uint32 i=0; iloadtile.tile; uint32 uls = gfx->loadtile.sl; uint32 ult = gfx->loadtile.tl; uint32 lrs = gfx->loadtile.sh; uint32 dxt = gfx->loadtile.th; // 1.11 fixed point Tile &tile = gRDP.tiles[tileno]; tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false; uint32 size = lrs+1; if( tile.dwSize == TXT_SIZE_32b ) size<<=1; SetTmemFlag(tile.dwTMem, size>>2); TMEMLoadMapInfo &info = g_tmemLoadAddrMap[tile.dwTMem]; info.bSwapped = (dxt == 0? TRUE : FALSE); info.sl = tile.hilite_sl = tile.sl = uls; info.sh = tile.hilite_sh = tile.sh = lrs; info.tl = tile.tl = ult; info.th = tile.th = dxt; tile.bSizeIsValid = false; tile.lastTileCmd = CMD_LOADBLOCK; info.dwLoadAddress = g_TI.dwAddr; info.bSetBy = CMD_LOADBLOCK; info.dxt = dxt; info.dwLine = tile.dwLine; info.dwFormat = g_TI.dwFormat; info.dwSize = g_TI.dwSize; info.dwWidth = g_TI.dwWidth; info.dwTotalWords = size; info.dwTmem = tile.dwTMem; if( gRDP.tiles[tileno].dwTMem == 0 ) { if( size >= 1024 ) { memcpy(&g_tmemInfo0, &info, sizeof(TMEMLoadMapInfo) ); g_tmemInfo0.dwTotalWords = size>>2; } if( size == 2048 ) { memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) ); g_tmemInfo1.dwTotalWords = size>>2; } } else if( tile.dwTMem == 0x100 ) { if( size == 1024 ) { memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) ); g_tmemInfo1.dwTotalWords = size>>2; } } g_TxtLoadBy = CMD_LOADBLOCK; if( options.bUseFullTMEM ) { uint32 bytes = (lrs + 1) << tile.dwSize >> 1; uint32 address = g_TI.dwAddr + ult * g_TI.bpl + (uls << g_TI.dwSize >> 1); if ((bytes == 0) || ((address + bytes) > g_dwRamSize) || (((tile.dwTMem << 3) + bytes) > 4096)) { return; } uint64* src = (uint64*)(g_pRDRAMu8+address); uint64* dest = &g_Tmem.g_Tmem64bit[tile.dwTMem]; if( dxt > 0) { void (*Interleave)( void *mem, uint32 numDWords ); uint32 line = (2047 + dxt) / dxt; uint32 bpl = line << 3; uint32 height = bytes / bpl; if (tile.dwSize == TXT_SIZE_32b) Interleave = QWordInterleave; else Interleave = DWordInterleave; for (uint32 y = 0; y < height; y++) { UnswapCopy( src, dest, bpl ); if (y & 1) Interleave( dest, line ); src += line; dest += line; } } else UnswapCopy( src, dest, bytes ); } LOG_UCODE(" Tile:%d (%d,%d - %d) DXT:0x%04x\n", tileno, uls, ult, lrs, dxt); LOG_TEXTURE( { DebuggerAppendMsg("LoadBlock:%d (%d,%d,%d) DXT:0x%04x(%X)\n", tileno, uls, ult, (((gfx->words.w1)>>12)&0x0FFF), dxt, ((gfx->words.w1)&0x0FFF)); }); DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD); } void swap(uint32 &a, uint32 &b) { uint32 temp = a; a = b; b = temp; } void DLParser_LoadTile(Gfx *gfx) { gRDP.textureIsChanged = true; uint32 tileno = gfx->loadtile.tile; uint32 uls = gfx->loadtile.sl/4; uint32 ult = gfx->loadtile.tl/4; uint32 lrs = gfx->loadtile.sh/4; uint32 lrt = gfx->loadtile.th/4; Tile &tile = gRDP.tiles[tileno]; tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false; if (lrt < ult) swap(lrt, ult); if (lrs < uls) swap(lrs, uls); tile.hilite_sl = tile.sl = uls; tile.hilite_tl = tile.tl = ult; tile.hilite_sh = tile.sh = lrs; tile.hilite_th = tile.th = lrt; tile.bSizeIsValid = true; // compute block height, and bpl of source and destination uint32 bpl = (lrs - uls + 1) << tile.dwSize >> 1; uint32 height = lrt - ult + 1; uint32 line = tile.dwLine; if (tile.dwSize == TXT_SIZE_32b) line <<= 1; if (((tile.dwTMem << 3) + line * height) > 4096) // check destination ending point (TMEM is 4k bytes) return; if( options.bUseFullTMEM ) { void (*Interleave)( void *mem, uint32 numDWords ); uint32 address, y; uint64 *dest; uint8 *src; if( g_TI.bpl == 0 ) { if( options.enableHackForGames == HACK_FOR_BUST_A_MOVE ) { g_TI.bpl = 1024; // Hack for Bust-A-Move } else { TRACE0("Warning: g_TI.bpl = 0" ); } } address = g_TI.dwAddr + tile.tl * g_TI.bpl + (tile.sl << g_TI.dwSize >> 1); src = &g_pRDRAMu8[address]; dest = &g_Tmem.g_Tmem64bit[tile.dwTMem]; if ((address + height * bpl) > g_dwRamSize) // check source ending point { return; } // Line given for 32-bit is half what it seems it should since they split the // high and low words. I'm cheating by putting them together. if (tile.dwSize == TXT_SIZE_32b) { Interleave = QWordInterleave; } else { Interleave = DWordInterleave; } if( tile.dwLine == 0 ) { //tile.dwLine = 1; return; } for (y = 0; y < height; y++) { UnswapCopy( src, dest, bpl ); if (y & 1) Interleave( dest, line ); src += g_TI.bpl; dest += line; } } for( int i=0; i<8; i++ ) { if( gRDP.tiles[i].dwTMem == tile.dwTMem ) gRDP.tiles[i].lastTileCmd = CMD_LOADTILE; } uint32 size = line * height; SetTmemFlag(tile.dwTMem,size ); LOG_TEXTURE( { DebuggerAppendMsg("LoadTile:%d (%d,%d) -> (%d,%d) [%d x %d]\n", tileno, uls, ult, lrs, lrt, (lrs - uls)+1, (lrt - ult)+1); }); DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD); LOG_UCODE(" Tile:%d (%d,%d) -> (%d,%d) [%d x %d]", tileno, uls, ult, lrs, lrt, (lrs - uls)+1, (lrt - ult)+1); TMEMLoadMapInfo &info = g_tmemLoadAddrMap[tile.dwTMem]; info.dwLoadAddress = g_TI.dwAddr; info.dwFormat = g_TI.dwFormat; info.dwSize = g_TI.dwSize; info.dwWidth = g_TI.dwWidth; info.sl = uls; info.sh = lrs; info.tl = ult; info.th = lrt; info.dxt = 0; info.dwLine = tile.dwLine; info.dwTmem = tile.dwTMem; info.dwTotalWords = size<<2; info.bSetBy = CMD_LOADTILE; info.bSwapped =FALSE; g_TxtLoadBy = CMD_LOADTILE; if( tile.dwTMem == 0 ) { if( size >= 256 ) { memcpy(&g_tmemInfo0, &info, sizeof(TMEMLoadMapInfo) ); g_tmemInfo0.dwTotalWords = size; } if( size == 512 ) { memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) ); g_tmemInfo1.dwTotalWords = size; } } else if( tile.dwTMem == 0x100 ) { if( size == 256 ) { memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) ); g_tmemInfo1.dwTotalWords = size; } } } const char *pszOnOff[2] = {"Off", "On"}; uint32 lastSetTile; void DLParser_SetTile(Gfx *gfx) { gRDP.textureIsChanged = true; uint32 tileno = gfx->settile.tile; Tile &tile = gRDP.tiles[tileno]; tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false; lastSetTile = tileno; tile.dwFormat = gfx->settile.fmt; tile.dwSize = gfx->settile.siz; tile.dwLine = gfx->settile.line; tile.dwTMem = gfx->settile.tmem; tile.dwPalette = gfx->settile.palette; tile.bClampT = gfx->settile.ct; tile.bMirrorT = gfx->settile.mt; tile.dwMaskT = gfx->settile.maskt; tile.dwShiftT = gfx->settile.shiftt; tile.bClampS = gfx->settile.cs; tile.bMirrorS = gfx->settile.ms; tile.dwMaskS = gfx->settile.masks; tile.dwShiftS = gfx->settile.shifts; tile.fShiftScaleS = 1.0f; if( tile.dwShiftS ) { if( tile.dwShiftS > 10 ) { tile.fShiftScaleS = (float)(1 << (16 - tile.dwShiftS)); } else { tile.fShiftScaleS = (float)1.0f/(1 << tile.dwShiftS); } } tile.fShiftScaleT = 1.0f; if( tile.dwShiftT ) { if( tile.dwShiftT > 10 ) { tile.fShiftScaleT = (float)(1 << (16 - tile.dwShiftT)); } else { tile.fShiftScaleT = (float)1.0f/(1 << tile.dwShiftT); } } // Hack for DK64 /* if( tile.dwMaskS > 0 && tile.dwMaskT > 0 && tile.dwMaskS < 8 && tile.dwMaskT < 8 ) { tile.sh = tile.sl + (1<loadtile.tile; int sl = gfx->loadtile.sl; int tl = gfx->loadtile.tl; int sh = gfx->loadtile.sh; int th = gfx->loadtile.th; Tile &tile = gRDP.tiles[tileno]; tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false; if( options.bUseFullTMEM ) { tile.bSizeIsValid = true; tile.hilite_sl = tile.sl = sl / 4; tile.hilite_tl = tile.tl = tl / 4; tile.hilite_sh = tile.sh = sh / 4; tile.hilite_th = tile.th = th / 4; tile.fhilite_sl = tile.fsl = sl / 4.0f; tile.fhilite_tl = tile.ftl = tl / 4.0f; tile.fhilite_sh = tile.fsh = sh / 4.0f; tile.fhilite_th = tile.fth = th / 4.0f; tile.lastTileCmd = CMD_SETTILE_SIZE; } else { if( tile.lastTileCmd != CMD_SETTILE_SIZE ) { tile.bSizeIsValid = true; if( sl/4 > sh/4 || tl/4 > th/4 || (sh == 0 && tile.dwShiftS==0 && th == 0 && tile.dwShiftT ==0 ) ) { #ifdef DEBUGGER if( sl != 0 || tl != 0 || sh != 0 || th != 0 ) { if( tile.dwMaskS==0 || tile.dwMaskT==0 ) TRACE0("Check me, setTileSize is not correct"); } #endif tile.bSizeIsValid = false; } tile.hilite_sl = tile.sl = sl / 4; tile.hilite_tl = tile.tl = tl / 4; tile.hilite_sh = tile.sh = sh / 4; tile.hilite_th = tile.th = th / 4; tile.fhilite_sl = tile.fsl = sl / 4.0f; tile.fhilite_tl = tile.ftl = tl / 4.0f; tile.fhilite_sh = tile.fsh = sh / 4.0f; tile.fhilite_th = tile.fth = th / 4.0f; tile.lastTileCmd = CMD_SETTILE_SIZE; } else { tile.fhilite_sh = tile.fsh; tile.fhilite_th = tile.fth; tile.fhilite_sl = tile.fsl = (sl>0x7ff ? (sl-0xfff) : sl)/4.0f; tile.fhilite_tl = tile.ftl = (tl>0x7ff ? (tl-0xfff) : tl)/4.0f; tile.hilite_sl = sl>0x7ff ? (sl-0xfff) : sl; tile.hilite_tl = tl>0x7ff ? (tl-0xfff) : tl; tile.hilite_sl /= 4; tile.hilite_tl /= 4; tile.hilite_sh = sh/4; tile.hilite_th = th/4; tile.lastTileCmd = CMD_SETTILE_SIZE; } } LOG_TEXTURE( { DebuggerAppendMsg("SetTileSize:%d (%d/4,%d/4) -> (%d/4,%d/4) [%d x %d]\n", tileno, sl, tl, sh, th, ((sh/4) - (sl/4)) + 1, ((th/4) - (tl/4)) + 1); }); DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD); LOG_UCODE(" Tile:%d (%d,%d) -> (%d,%d) [%d x %d]", tileno, sl/4, tl/4, sh/4, th/4, ((sh/4) - (sl/4)) + 1, ((th/4) - (tl/4)) + 1); } extern const char *pszImgFormat[8];// = {"RGBA", "YUV", "CI", "IA", "I", "?1", "?2", "?3"}; extern const char *pszImgSize[4];// = {"4", "8", "16", "32"}; void DLParser_SetTImg(Gfx *gfx) { gRDP.textureIsChanged = true; g_TI.dwFormat = gfx->setimg.fmt; g_TI.dwSize = gfx->setimg.siz; g_TI.dwWidth = gfx->setimg.width + 1; g_TI.dwAddr = RSPSegmentAddr((gfx->setimg.addr)); g_TI.bpl = g_TI.dwWidth << g_TI.dwSize >> 1; #ifdef DEBUGGER if( g_TI.dwAddr == 0x00ffffff) { TRACE0("Check me here in setTimg"); } LOG_TEXTURE(TRACE4("SetTImage: 0x%08x Fmt: %s/%s Width in Pixel: %d\n", g_TI.dwAddr, pszImgFormat[g_TI.dwFormat], pszImgSize[g_TI.dwSize], g_TI.dwWidth)); DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD); LOG_UCODE("Image: 0x%08x Fmt: %s/%s Width in Pixel: %d", g_TI.dwAddr, pszImgFormat[g_TI.dwFormat], pszImgSize[g_TI.dwSize], g_TI.dwWidth); #endif } void DLParser_TexRect(Gfx *gfx) { //Gtexrect *gtextrect = (Gtexrect *)gfx; if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); status.primitiveType = PRIM_TEXTRECT; // This command used 128bits, and not 64 bits. This means that we have to look one // Command ahead in the buffer, and update the PC. uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4+8); uint32 dwHalf1 = *(uint32 *)(g_pRDRAMu8 + dwPC); uint32 dwHalf2 = *(uint32 *)(g_pRDRAMu8 + dwPC+8); if( options.enableHackForGames == HACK_FOR_ALL_STAR_BASEBALL || options.enableHackForGames == HACK_FOR_MLB ) { if( ((dwHalf1>>24) == 0xb4 || (dwHalf1>>24) == 0xb3 || (dwHalf1>>24) == 0xb2 || (dwHalf1>>24) == 0xe1) && ((dwHalf2>>24) == 0xb4 || (dwHalf2>>24) == 0xb3 || (dwHalf2>>24) == 0xb2 || (dwHalf2>>24) == 0xf1) ) { // Increment PC so that it points to the right place gDlistStack[gDlistStackPointer].pc += 16; } else { // Hack for some games, All_Star_Baseball_2000 gDlistStack[gDlistStackPointer].pc += 8; dwCmd3 = dwCmd2; //dwCmd2 = dwHalf1; //dwCmd2 = 0; // fix me here dwCmd2 = (((dwHalf1>>12)&0x03FF)<<17) | (((dwHalf1)&0x03FF)<<1); } } else { gDlistStack[gDlistStackPointer].pc += 16; } // Hack for Mario Tennis if( !status.bHandleN64RenderTexture && g_CI.dwAddr == g_ZI.dwAddr ) { return; } LOG_UCODE("0x%08x: %08x %08x", dwPC, *(uint32 *)(g_pRDRAMu8 + dwPC+0), *(uint32 *)(g_pRDRAMu8 + dwPC+4)); LOG_UCODE("0x%08x: %08x %08x", dwPC+8, *(uint32 *)(g_pRDRAMu8 + dwPC+8), *(uint32 *)(g_pRDRAMu8 + dwPC+8+4)); uint32 dwXH = (((gfx->words.w0)>>12)&0x0FFF)/4; uint32 dwYH = (((gfx->words.w0) )&0x0FFF)/4; uint32 tileno = ((gfx->words.w1)>>24)&0x07; uint32 dwXL = (((gfx->words.w1)>>12)&0x0FFF)/4; uint32 dwYL = (((gfx->words.w1) )&0x0FFF)/4; uint16 uS = (uint16)( dwCmd2>>16)&0xFFFF; uint16 uT = (uint16)( dwCmd2 )&0xFFFF; uint16 uDSDX = (uint16)(( dwCmd3>>16)&0xFFFF); uint16 uDTDY = (uint16)(( dwCmd3 )&0xFFFF); if( (int)dwXL >= gRDP.scissor.right || (int)dwYL >= gRDP.scissor.bottom || (int)dwXH < gRDP.scissor.left || (int)dwYH < gRDP.scissor.top ) { // Clipping return; } short s16S = *(short*)(&uS); short s16T = *(short*)(&uT); short s16DSDX = *(short*)(&uDSDX); short s16DTDY = *(short*)(&uDTDY); uint32 curTile = gRSP.curTile; ForceMainTextureIndex(tileno); float fS0 = s16S / 32.0f; float fT0 = s16T / 32.0f; float fDSDX = s16DSDX / 1024.0f; float fDTDY = s16DTDY / 1024.0f; uint32 cycletype = gRDP.otherMode.cycle_type; if (cycletype == CYCLE_TYPE_COPY) { fDSDX /= 4.0f; // In copy mode 4 pixels are copied at once. dwXH++; dwYH++; } else if (cycletype == CYCLE_TYPE_FILL) { dwXH++; dwYH++; } if( fDSDX == 0 ) fDSDX = 1; if( fDTDY == 0 ) fDTDY = 1; float fS1 = fS0 + (fDSDX * (dwXH - dwXL)); float fT1 = fT0 + (fDTDY * (dwYH - dwYL)); LOG_UCODE(" Tile:%d Screen(%d,%d) -> (%d,%d)", tileno, dwXL, dwYL, dwXH, dwYH); LOG_UCODE(" Tex:(%#5f,%#5f) -> (%#5f,%#5f) (DSDX:%#5f DTDY:%#5f)", fS0, fT0, fS1, fT1, fDSDX, fDTDY); LOG_UCODE(""); float t0u0 = (fS0-gRDP.tiles[tileno].hilite_sl) * gRDP.tiles[tileno].fShiftScaleS; float t0v0 = (fT0-gRDP.tiles[tileno].hilite_tl) * gRDP.tiles[tileno].fShiftScaleT; float t0u1 = t0u0 + (fDSDX * (dwXH - dwXL))*gRDP.tiles[tileno].fShiftScaleS; float t0v1 = t0v0 + (fDTDY * (dwYH - dwYL))*gRDP.tiles[tileno].fShiftScaleT; if( dwXL==0 && dwYL==0 && dwXH==windowSetting.fViWidth-1 && dwYH==windowSetting.fViHeight-1 && t0u0 == 0 && t0v0==0 && t0u1==0 && t0v1==0 ) { //Using TextRect to clear the screen } else { if( status.bHandleN64RenderTexture && //status.bDirectWriteIntoRDRAM && g_pRenderTextureInfo->CI_Info.dwFormat == gRDP.tiles[tileno].dwFormat && g_pRenderTextureInfo->CI_Info.dwSize == gRDP.tiles[tileno].dwSize && gRDP.tiles[tileno].dwFormat == TXT_FMT_CI && gRDP.tiles[tileno].dwSize == TXT_SIZE_8b ) { if( options.enableHackForGames == HACK_FOR_YOSHI ) { // Hack for Yoshi background image PrepareTextures(); TexRectToFrameBuffer_8b(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_FLUSH_TRI || eventToPause == NEXT_TEXTRECT), { DebuggerAppendMsg("TexRect: tile=%d, X0=%d, Y0=%d, X1=%d, Y1=%d,\nfS0=%f, fT0=%f, ScaleS=%f, ScaleT=%f\n", gRSP.curTile, dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY); DebuggerAppendMsg("Pause after TexRect for Yoshi\n"); }); } else { if( frameBufferOptions.bUpdateCIInfo ) { PrepareTextures(); TexRectToFrameBuffer_8b(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno); } if( !status.bDirectWriteIntoRDRAM ) { CRender::g_pRender->TexRect(dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY); status.dwNumTrisRendered += 2; } } } else { CRender::g_pRender->TexRect(dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY); status.bFrameBufferDrawnByTriangles = true; status.dwNumTrisRendered += 2; } } if( status.bHandleN64RenderTexture ) g_pRenderTextureInfo->maxUsedHeight = std::max(g_pRenderTextureInfo->maxUsedHeight,(int)dwYH); ForceMainTextureIndex(curTile); } void DLParser_TexRectFlip(Gfx *gfx) { status.bCIBufferIsRendered = true; status.primitiveType = PRIM_TEXTRECTFLIP; // This command used 128bits, and not 64 bits. This means that we have to look one // Command ahead in the buffer, and update the PC. uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4+8); // Increment PC so that it points to the right place gDlistStack[gDlistStackPointer].pc += 16; uint32 dwXH = (((gfx->words.w0)>>12)&0x0FFF)/4; uint32 dwYH = (((gfx->words.w0) )&0x0FFF)/4; uint32 tileno = ((gfx->words.w1)>>24)&0x07; uint32 dwXL = (((gfx->words.w1)>>12)&0x0FFF)/4; uint32 dwYL = (((gfx->words.w1) )&0x0FFF)/4; uint32 dwS = ( dwCmd2>>16)&0xFFFF; uint32 dwT = ( dwCmd2 )&0xFFFF; int nDSDX = (int)(short)(( dwCmd3>>16)&0xFFFF); int nDTDY = (int)(short)(( dwCmd3 )&0xFFFF); uint32 curTile = gRSP.curTile; ForceMainTextureIndex(tileno); float fS0 = (float)dwS / 32.0f; float fT0 = (float)dwT / 32.0f; float fDSDX = (float)nDSDX / 1024.0f; float fDTDY = (float)nDTDY / 1024.0f; uint32 cycletype = gRDP.otherMode.cycle_type; if (cycletype == CYCLE_TYPE_COPY) { fDSDX /= 4.0f; // In copy mode 4 pixels are copied at once. dwXH++; dwYH++; } else if (cycletype == CYCLE_TYPE_FILL) { dwXH++; dwYH++; } float fS1 = fS0 + (fDSDX * (dwYH - dwYL)); float fT1 = fT0 + (fDTDY * (dwXH - dwXL)); LOG_UCODE(" Tile:%d (%d,%d) -> (%d,%d)", tileno, dwXL, dwYL, dwXH, dwYH); LOG_UCODE(" Tex:(%#5f,%#5f) -> (%#5f,%#5f) (DSDX:%#5f DTDY:%#5f)", fS0, fT0, fS1, fT1, fDSDX, fDTDY); LOG_UCODE(""); float t0u0 = (fS0) * gRDP.tiles[tileno].fShiftScaleS-gRDP.tiles[tileno].sl; float t0v0 = (fT0) * gRDP.tiles[tileno].fShiftScaleT-gRDP.tiles[tileno].tl; float t0u1 = t0u0 + (fDSDX * (dwYH - dwYL))*gRDP.tiles[tileno].fShiftScaleS; float t0v1 = t0v0 + (fDTDY * (dwXH - dwXL))*gRDP.tiles[tileno].fShiftScaleT; CRender::g_pRender->TexRectFlip(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1); status.dwNumTrisRendered += 2; if( status.bHandleN64RenderTexture ) g_pRenderTextureInfo->maxUsedHeight = std::max(g_pRenderTextureInfo->maxUsedHeight,int(dwYL+(dwXH-dwXL))); ForceMainTextureIndex(curTile); } /************************************************************************/ /* */ /************************************************************************/ /* * TMEM emulation * There are 0x200's 64bits entry in TMEM * Usually, textures are loaded into TMEM at 0x0, and TLUT is loaded at 0x100 * of course, the whole TMEM can be used by textures if TLUT is not used, and TLUT * can be at other address of TMEM. * * We don't want to emulate TMEM by creating a block of memory for TMEM and load * everything into the block of memory, this will be slow. */ typedef struct TmemInfoEntry{ uint32 start; uint32 length; uint32 rdramAddr; TmemInfoEntry* next; } TmemInfoEntry; const int tmenMaxEntry=20; TmemInfoEntry tmenEntryBuffer[20]={{0}}; TmemInfoEntry *g_pTMEMInfo=NULL; TmemInfoEntry *g_pTMEMFreeList=tmenEntryBuffer; void TMEM_Init() { g_pTMEMInfo=NULL; g_pTMEMFreeList=tmenEntryBuffer; int i; for( i=0; inext; p->start = tmemstart; p->length = length; p->rdramAddr = rdramaddr; p->next = NULL; } else { while ( tmemstart > (p->start+p->length) ) { if( p->next != NULL ) { p = p->next; continue; } else { break; } } if ( p->start == tmemstart ) { // need to replace the block of 'p' // or append a new block depend the block lengths if( length == p->length ) { p->rdramAddr = rdramaddr; return; } else if( length < p->length ) { TmemInfoEntry *newentry = g_pTMEMFreeList; g_pTMEMFreeList = g_pTMEMFreeList->next; newentry->length = p->length - length; newentry->next = p->next; newentry->rdramAddr = p->rdramAddr + p->length; newentry->start = p->start + p->length; p->length = length; p->next = newentry; p->rdramAddr = rdramaddr; } } else if( p->start > tmemstart ) { // p->start > tmemstart, need to insert the new block before 'p' TmemInfoEntry *newentry = g_pTMEMFreeList; g_pTMEMFreeList = g_pTMEMFreeList->next; if( length+tmemstart < p->start+p->length ) { newentry->length = p->length - length; newentry->next = p->next; newentry->rdramAddr = p->rdramAddr + p->length; newentry->start = p->start + p->length; p->length = length; p->next = newentry; p->rdramAddr = rdramaddr; p->start = tmemstart; } else if( length+tmemstart == p->start+p->length ) { } } else { } } } uint32 TMEM_GetRdramAddr(uint32 tmemstart, uint32 length) { return 0; } /* * New implementation of texture loading */ bool IsTmemFlagValid(uint32 tmemAddr) { uint32 index = tmemAddr>>5; uint32 bitIndex = (tmemAddr&0x1F); return ((g_TmemFlag[index] & (1<>5; uint32 bitIndex = (tmemAddr&0x1F); if ((g_TmemFlag[index] & (1<>5; uint32 bitIndex = (tmemAddr&0x1F); #ifdef DEBUGGER if( size > 0x200 ) { DebuggerAppendMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size); size = 0x200-tmemAddr; } #endif if( bitIndex == 0 ) { uint32 i; for( i=0; i< (size>>5); i++ ) { g_TmemFlag[index+i] = 0; } if( (size&0x1F) != 0 ) { //ErrorMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size); g_TmemFlag[index+i] &= ~((1<<(size&0x1F))-1); } g_TmemFlag[index] |= 1; } else { if( bitIndex + size <= 0x1F ) { uint32 val = g_TmemFlag[index]; uint32 mask = (1<<(bitIndex))-1; mask |= ~((1<<(bitIndex + size))-1); val &= mask; val |= (1<>5); i++ ) { g_TmemFlag[index+i] = 0; } if( (size&0x1F) != 0 ) { //ErrorMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size); g_TmemFlag[index+i] &= ~((1<<(size&0x1F))-1); } } } } mupen64plus-video-rice-src-2.6.0/src/RSP_GBI0.h000066400000000000000000000626531464507324400207240ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "Render.h" #include "Timing.h" void RSP_GBI1_SpNoop(Gfx *gfx) { SP_Timing(RSP_GBI1_SpNoop); if( (gfx+1)->words.cmd == 0x00 && gRSP.ucode >= 17 ) { RSP_RDP_NOIMPL("Double SPNOOP, Skip remain ucodes, PC=%08X, Cmd1=%08X", gDlistStack[gDlistStackPointer].pc, gfx->words.w1); RDP_GFX_PopDL(); //if( gRSP.ucode < 17 ) TriggerDPInterrupt(); } } void RSP_GBI0_Mtx(Gfx *gfx) { SP_Timing(RSP_GBI0_Mtx); uint32 addr = RSPSegmentAddr((gfx->gbi0matrix.addr)); LOG_UCODE(" Command: %s %s %s Length %d Address 0x%08x", gfx->gbi0matrix.projection == 1 ? "Projection" : "ModelView", gfx->gbi0matrix.load == 1 ? "Load" : "Mul", gfx->gbi0matrix.push == 1 ? "Push" : "NoPush", gfx->gbi0matrix.len, addr); if (addr + 64 > g_dwRamSize) { TRACE1("Mtx: Address invalid (0x%08x)", addr); return; } LoadMatrix(addr); if (gfx->gbi0matrix.projection) { CRender::g_pRender->SetProjection(matToLoad, gfx->gbi0matrix.push, gfx->gbi0matrix.load); } else { CRender::g_pRender->SetWorldView(matToLoad, gfx->gbi0matrix.push, gfx->gbi0matrix.load); } #ifdef DEBUGGER const char *loadstr = gfx->gbi0matrix.load == 1 ? "Load" : "Mul"; const char *pushstr = gfx->gbi0matrix.push == 1 ? "Push" : "Nopush"; int projlevel = CRender::g_pRender->GetProjectMatrixLevel(); int worldlevel = CRender::g_pRender->GetWorldViewMatrixLevel(); if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) { pauseAtNext = false; debuggerPause = true; if (gfx->gbi0matrix.projection) { TRACE3("Pause after %s and %s Matrix: Projection, level=%d\n", loadstr, pushstr, projlevel ); } else { TRACE3("Pause after %s and %s Matrix: WorldView level=%d\n", loadstr, pushstr, worldlevel); } } else { if( pauseAtNext && logMatrix ) { if (gfx->gbi0matrix.projection) { TRACE3("Matrix: %s and %s Projection level=%d\n", loadstr, pushstr, projlevel); } else { TRACE3("Matrix: %s and %s WorldView\n level=%d", loadstr, pushstr, worldlevel); } } } #endif } void RSP_GBI1_Reserved(Gfx *gfx) { SP_Timing(RSP_GBI1_Reserved); RSP_RDP_NOIMPL("RDP: Reserved (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); } void RSP_GBI1_MoveMem(Gfx *gfx) { SP_Timing(RSP_GBI1_MoveMem); uint32 type = ((gfx->words.w0)>>16)&0xFF; uint32 dwLength = ((gfx->words.w0))&0xFFFF; uint32 addr = RSPSegmentAddr((gfx->words.w1)); switch (type) { case RSP_GBI1_MV_MEM_VIEWPORT: { LOG_UCODE(" RSP_GBI1_MV_MEM_VIEWPORT. Address: 0x%08x, Length: 0x%04x", addr, dwLength); RSP_MoveMemViewport(addr); } break; case RSP_GBI1_MV_MEM_LOOKATY: LOG_UCODE(" RSP_GBI1_MV_MEM_LOOKATY"); break; case RSP_GBI1_MV_MEM_LOOKATX: LOG_UCODE(" RSP_GBI1_MV_MEM_LOOKATX"); break; case RSP_GBI1_MV_MEM_L0: case RSP_GBI1_MV_MEM_L1: case RSP_GBI1_MV_MEM_L2: case RSP_GBI1_MV_MEM_L3: case RSP_GBI1_MV_MEM_L4: case RSP_GBI1_MV_MEM_L5: case RSP_GBI1_MV_MEM_L6: case RSP_GBI1_MV_MEM_L7: { uint32 dwLight = (type-RSP_GBI1_MV_MEM_L0)/2; LOG_UCODE(" RSP_GBI1_MV_MEM_L%d", dwLight); LOG_UCODE(" Light%d: Length:0x%04x, Address: 0x%08x", dwLight, dwLength, addr); RSP_MoveMemLight(dwLight, addr); } break; case RSP_GBI1_MV_MEM_TXTATT: LOG_UCODE(" RSP_GBI1_MV_MEM_TXTATT"); break; case RSP_GBI1_MV_MEM_MATRIX_1: RSP_GFX_Force_Matrix(addr); break; case RSP_GBI1_MV_MEM_MATRIX_2: break; case RSP_GBI1_MV_MEM_MATRIX_3: break; case RSP_GBI1_MV_MEM_MATRIX_4: break; default: RSP_RDP_NOIMPL("MoveMem: Unknown Move Type, cmd=%08X, %08X", gfx->words.w0, gfx->words.w1); break; } } void RSP_GBI0_Vtx(Gfx *gfx) { SP_Timing(RSP_GBI0_Vtx); int n = gfx->gbi0vtx.n + 1; int v0 = gfx->gbi0vtx.v0; uint32 addr = RSPSegmentAddr((gfx->gbi0vtx.addr)); LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d, Length: 0x%04x", addr, v0, n, gfx->gbi0vtx.len); if ((v0 + n) > 80) { TRACE3("Warning, invalid vertex positions, N=%d, v0=%d, Addr=0x%08X", n, v0, addr); n = 32 - v0; } // Check that address is valid... if ((addr + n*16) > g_dwRamSize) { TRACE1("Vertex Data: Address out of range (0x%08x)", addr); } else { ProcessVertexData(addr, v0, n); status.dwNumVertices += n; DisplayVertexInfo(addr, v0, n); } } void RSP_GBI0_DL(Gfx *gfx) { SP_Timing(RSP_GBI0_DL); uint32 addr = RSPSegmentAddr((gfx->gbi0dlist.addr)) & (g_dwRamSize-1); LOG_UCODE(" Address=0x%08x Push: 0x%02x", addr, gfx->gbi0dlist.param); if( addr > g_dwRamSize ) { RSP_RDP_NOIMPL("Error: DL addr = %08X out of range, PC=%08X", addr, gDlistStack[gDlistStackPointer].pc ); addr &= (g_dwRamSize-1); DebuggerPauseCountN( NEXT_DLIST ); } if( gfx->gbi0dlist.param == RSP_DLIST_PUSH ) gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = addr; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; LOG_UCODE("Level=%d", gDlistStackPointer+1); LOG_UCODE("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); } void RSP_GBI1_RDPHalf_Cont(Gfx *gfx) { SP_Timing(RSP_GBI1_RDPHalf_Cont); LOG_UCODE("RDPHalf_Cont: (Ignored)"); } void RSP_GBI1_RDPHalf_2(Gfx *gfx) { SP_Timing(RSP_GBI1_RDPHalf_2); LOG_UCODE("RDPHalf_2: (Ignored)"); } void RSP_GBI1_RDPHalf_1(Gfx *gfx) { SP_Timing(RSP_GBI1_RDPHalf_1); LOG_UCODE("RDPHalf_1: (Ignored)"); } void RSP_GBI1_Line3D(Gfx *gfx) { status.primitiveType = PRIM_LINE3D; uint32 dwPC = gDlistStack[gDlistStackPointer].pc; BOOL bTrisAdded = FALSE; if( gfx->ln3dtri2.v3 == 0 ) { // Flying Dragon uint32 dwV0 = gfx->ln3dtri2.v0/gRSP.vertexMult; uint32 dwV1 = gfx->ln3dtri2.v1/gRSP.vertexMult; uint32 dwWidth = gfx->ln3dtri2.v2; //uint32 dwFlag = gfx->ln3dtri2.v3/gRSP.vertexMult; CRender::g_pRender->SetCombinerAndBlender(); status.dwNumTrisRendered++; CRender::g_pRender->Line3D(dwV0, dwV1, dwWidth); SP_Timing(RSP_GBI1_Line3D); DP_Timing(RSP_GBI1_Line3D); } else { do { uint32 dwV3 = gfx->ln3dtri2.v3/gRSP.vertexMult; uint32 dwV0 = gfx->ln3dtri2.v0/gRSP.vertexMult; uint32 dwV1 = gfx->ln3dtri2.v1/gRSP.vertexMult; uint32 dwV2 = gfx->ln3dtri2.v2/gRSP.vertexMult; LOG_UCODE(" Line3D: V0: %d, V1: %d, V2: %d, V3: %d", dwV0, dwV1, dwV2, dwV3); // Do first tri if (IsTriangleVisible(dwV0, dwV1, dwV2)) { DEBUG_DUMP_VERTEXES("Line3D 1/2", dwV0, dwV1, dwV2); if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } bTrisAdded = true; PrepareTriangle(dwV0, dwV1, dwV2); } // Do second tri if (IsTriangleVisible(dwV2, dwV3, dwV0)) { DEBUG_DUMP_VERTEXES("Line3D 2/2", dwV0, dwV1, dwV2); if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } bTrisAdded = true; PrepareTriangle(dwV2, dwV3, dwV0); } gfx++; dwPC += 8; #ifdef DEBUGGER } while (gfx->words.cmd == (uint8)RSP_LINE3D && !(pauseAtNext && eventToPause==NEXT_FLUSH_TRI)); #else } while (gfx->words.cmd == (uint8)RSP_LINE3D); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->SetCombinerAndBlender(); CRender::g_pRender->DrawTriangles(); } } } void RSP_GBI1_ClearGeometryMode(Gfx *gfx) { SP_Timing(RSP_GBI1_ClearGeometryMode); uint32 dwMask = ((gfx->words.w1)); #ifdef DEBUGGER LOG_UCODE(" Mask=0x%08x", dwMask); if (dwMask & G_ZBUFFER) LOG_UCODE(" Disabling ZBuffer"); if (dwMask & G_TEXTURE_ENABLE) LOG_UCODE(" Disabling Texture"); if (dwMask & G_SHADE) LOG_UCODE(" Disabling Shade"); if (dwMask & G_SHADING_SMOOTH) LOG_UCODE(" Disabling Smooth Shading"); if (dwMask & G_CULL_FRONT) LOG_UCODE(" Disabling Front Culling"); if (dwMask & G_CULL_BACK) LOG_UCODE(" Disabling Back Culling"); if (dwMask & G_FOG) LOG_UCODE(" Disabling Fog"); if (dwMask & G_LIGHTING) LOG_UCODE(" Disabling Lighting"); if (dwMask & G_TEXTURE_GEN) LOG_UCODE(" Disabling Texture Gen"); if (dwMask & G_TEXTURE_GEN_LINEAR) LOG_UCODE(" Disabling Texture Gen Linear"); if (dwMask & G_LOD) LOG_UCODE(" Disabling LOD (no impl)"); #endif gRDP.geometryMode &= ~dwMask; RSP_GFX_InitGeometryMode(); } void RSP_GBI1_SetGeometryMode(Gfx *gfx) { SP_Timing(RSP_GBI1_SetGeometryMode); uint32 dwMask = ((gfx->words.w1)); #ifdef DEBUGGER LOG_UCODE(" Mask=0x%08x", dwMask); if (dwMask & G_ZBUFFER) LOG_UCODE(" Enabling ZBuffer"); if (dwMask & G_TEXTURE_ENABLE) LOG_UCODE(" Enabling Texture"); if (dwMask & G_SHADE) LOG_UCODE(" Enabling Shade"); if (dwMask & G_SHADING_SMOOTH) LOG_UCODE(" Enabling Smooth Shading"); if (dwMask & G_CULL_FRONT) LOG_UCODE(" Enabling Front Culling"); if (dwMask & G_CULL_BACK) LOG_UCODE(" Enabling Back Culling"); if (dwMask & G_FOG) LOG_UCODE(" Enabling Fog"); if (dwMask & G_LIGHTING) LOG_UCODE(" Enabling Lighting"); if (dwMask & G_TEXTURE_GEN) LOG_UCODE(" Enabling Texture Gen"); if (dwMask & G_TEXTURE_GEN_LINEAR) LOG_UCODE(" Enabling Texture Gen Linear"); if (dwMask & G_LOD) LOG_UCODE(" Enabling LOD (no impl)"); #endif // DEBUGGER gRDP.geometryMode |= dwMask; RSP_GFX_InitGeometryMode(); } void RSP_GBI1_EndDL(Gfx *gfx) { SP_Timing(RSP_GBI1_EndDL); RDP_GFX_PopDL(); } //static const char * sc_szBlClr[4] = { "In", "Mem", "Bl", "Fog" }; //static const char * sc_szBlA1[4] = { "AIn", "AFog", "AShade", "0" }; //static const char * sc_szBlA2[4] = { "1-A", "AMem", "1", "?" }; void RSP_GBI1_SetOtherModeL(Gfx *gfx) { SP_Timing(RSP_GBI1_SetOtherModeL); uint32 dwShift = ((gfx->words.w0)>>8)&0xFF; uint32 dwLength= ((gfx->words.w0) )&0xFF; uint32 dwData = (gfx->words.w1); uint32 dwMask = ((1<words.w0)>>8)&0xFF; uint32 dwLength= ((gfx->words.w0) )&0xFF; uint32 dwData = (gfx->words.w1); uint32 dwMask = ((1<texture.scaleS) / (65536.0f * 32.0f); float fTextureScaleT = (float)(gfx->texture.scaleT) / (65536.0f * 32.0f); if( (((gfx->words.w1)>>16)&0xFFFF) == 0xFFFF ) { fTextureScaleS = 1/32.0f; } else if( (((gfx->words.w1)>>16)&0xFFFF) == 0x8000 ) { fTextureScaleS = 1/64.0f; } #ifdef DEBUGGER else if( ((gfx->words.w1>>16)&0xFFFF) != 0 ) { //DebuggerAppendMsg("Warning, texture scale = %08X is not integer", (word1>>16)&0xFFFF); } #endif if( (((gfx->words.w1) )&0xFFFF) == 0xFFFF ) { fTextureScaleT = 1/32.0f; } else if( (((gfx->words.w1) )&0xFFFF) == 0x8000 ) { fTextureScaleT = 1/64.0f; } #ifdef DEBUGGER else if( (gfx->words.w1&0xFFFF) != 0 ) { //DebuggerAppendMsg("Warning, texture scale = %08X is not integer", (word1)&0xFFFF); } #endif if( gRSP.ucode == 6 ) { if( fTextureScaleS == 0 ) fTextureScaleS = 1.0f/32.0f; if( fTextureScaleT == 0 ) fTextureScaleT = 1.0f/32.0f; } CRender::g_pRender->SetTextureEnableAndScale(gfx->texture.tile, gfx->texture.enable_gbi0, fTextureScaleS, fTextureScaleT); // What happens if these are 0? Interpret as 1.0f? LOG_TEXTURE( { DebuggerAppendMsg("SetTexture: Level: %d Tile: %d %s\n", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi0 ? "enabled":"disabled"); DebuggerAppendMsg(" ScaleS: %f, ScaleT: %f\n", fTextureScaleS*32.0f, fTextureScaleT*32.0f); }); DEBUGGER_PAUSE_COUNT_N(NEXT_SET_TEXTURE); LOG_UCODE(" Level: %d Tile: %d %s", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi0 ? "enabled":"disabled"); LOG_UCODE(" ScaleS: %f, ScaleT: %f", fTextureScaleS*32.0f, fTextureScaleT*32.0f); } extern void RSP_RDP_InsertMatrix(Gfx *gfx); void RSP_GBI1_MoveWord(Gfx *gfx) { SP_Timing(RSP_GBI1_MoveWord); switch (gfx->gbi0moveword.type) { case RSP_MOVE_WORD_MATRIX: RSP_RDP_InsertMatrix(gfx); break; case RSP_MOVE_WORD_NUMLIGHT: { uint32 dwNumLights = (((gfx->gbi0moveword.value)-0x80000000)/32)-1; LOG_UCODE(" RSP_MOVE_WORD_NUMLIGHT: Val:%d", dwNumLights); gRSP.ambientLightIndex = dwNumLights; SetNumLights(dwNumLights); } break; case RSP_MOVE_WORD_CLIP: { switch (gfx->gbi0moveword.offset) { case RSP_MV_WORD_OFFSET_CLIP_RNX: case RSP_MV_WORD_OFFSET_CLIP_RNY: case RSP_MV_WORD_OFFSET_CLIP_RPX: case RSP_MV_WORD_OFFSET_CLIP_RPY: CRender::g_pRender->SetClipRatio(gfx->gbi0moveword.offset, gfx->gbi0moveword.value); break; default: LOG_UCODE(" RSP_MOVE_WORD_CLIP ? : 0x%08x", gfx->words.w1); break; } } break; case RSP_MOVE_WORD_SEGMENT: { uint32 dwSegment = (gfx->gbi0moveword.offset >> 2) & 0xF; uint32 dwBase = (gfx->gbi0moveword.value)&0x00FFFFFF; LOG_UCODE(" RSP_MOVE_WORD_SEGMENT Seg[%d] = 0x%08x", dwSegment, dwBase); if( dwBase > g_dwRamSize ) { gRSP.segments[dwSegment] = dwBase; #ifdef DEBUGGER if( pauseAtNext ) DebuggerAppendMsg("warning: Segment %d addr is %8X", dwSegment, dwBase); #endif } else { gRSP.segments[dwSegment] = dwBase; } } break; case RSP_MOVE_WORD_FOG: { uint16 wMult = (uint16)(((gfx->gbi0moveword.value) >> 16) & 0xFFFF); uint16 wOff = (uint16)(((gfx->gbi0moveword.value) ) & 0xFFFF); float fMult = (float)(short)wMult; float fOff = (float)(short)wOff; float rng = 128000.0f / fMult; float fMin = 500.0f - (fOff*rng/256.0f); float fMax = rng + fMin; FOG_DUMP(TRACE4("Set Fog: Min=%f, Max=%f, Mul=%f, Off=%f", fMin, fMax, fMult, fOff)); //if( fMult <= 0 || fMin > fMax || fMax < 0 || fMin > 1000 ) if( fMult <= 0 || fMax < 0 ) { // Hack fMin = 996; fMax = 1000; fMult = 0; fOff = 1; } LOG_UCODE(" RSP_MOVE_WORD_FOG/Mul=%d: Off=%d", wMult, wOff); FOG_DUMP(TRACE3("Set Fog: Min=%f, Max=%f, Data=%08X", fMin, fMax, gfx->gbi0moveword.value)); SetFogMinMax(fMin, fMax, fMult, fOff); } break; case RSP_MOVE_WORD_LIGHTCOL: { uint32 dwLight = gfx->gbi0moveword.offset / 0x20; uint32 dwField = (gfx->gbi0moveword.offset & 0x7); LOG_UCODE(" RSP_MOVE_WORD_LIGHTCOL/0x%08x: 0x%08x", gfx->gbi0moveword.offset, gfx->words.w1); switch (dwField) { case 0: if (dwLight == gRSP.ambientLightIndex) { SetAmbientLight( ((gfx->gbi0moveword.value)>>8) ); } else { SetLightCol(dwLight, gfx->gbi0moveword.value); } break; case 4: break; default: TRACE1("RSP_MOVE_WORD_LIGHTCOL with unknown offset 0x%08x", dwField); break; } } break; case RSP_MOVE_WORD_POINTS: { uint32 vtx = gfx->gbi0moveword.offset/40; uint32 where = gfx->gbi0moveword.offset - vtx*40; ModifyVertexInfo(where, vtx, gfx->gbi0moveword.value); } break; case RSP_MOVE_WORD_PERSPNORM: LOG_UCODE(" RSP_MOVE_WORD_PERSPNORM"); //if( word1 != 0x1A ) DebuggerAppendMsg("PerspNorm: 0x%04x", (short)word1); break; default: RSP_RDP_NOIMPL("Unknown MoveWord, %08X, %08X", gfx->words.w0, gfx->words.w1); break; } } void RSP_GBI1_PopMtx(Gfx *gfx) { SP_Timing(RSP_GBI1_PopMtx); LOG_UCODE(" Command: (%s)", gfx->gbi0popmatrix.projection ? "Projection" : "ModelView"); // Do any of the other bits do anything? // So far only Extreme-G seems to Push/Pop projection matrices if (gfx->gbi0popmatrix.projection) { CRender::g_pRender->PopProjection(); } else { CRender::g_pRender->PopWorldView(); } #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) { pauseAtNext = false; debuggerPause = true; DebuggerAppendMsg("Pause after Pop Matrix: %s\n", gfx->gbi0popmatrix.projection ? "Proj":"World"); } else { if( pauseAtNext && logMatrix ) { DebuggerAppendMsg("Pause after Pop Matrix: %s\n", gfx->gbi0popmatrix.projection ? "Proj":"World"); } } #endif } void RSP_GBI1_CullDL(Gfx *gfx) { SP_Timing(RSP_GBI1_CullDL); #ifdef DEBUGGER if( !debuggerEnableCullFace ) { return; //Disable Culling } #endif if( g_curRomInfo.bDisableCulling ) { return; //Disable Culling } uint32 dwVFirst = ((gfx->words.w0) & 0xFFF) / gRSP.vertexMult; uint32 dwVLast = (((gfx->words.w1)) & 0xFFF) / gRSP.vertexMult; LOG_UCODE(" Culling using verts %d to %d", dwVFirst, dwVLast); // Mask into range dwVFirst &= 0x1f; dwVLast &= 0x1f; if( dwVLast < dwVFirst ) return; if( !gRSP.bRejectVtx ) return; for (uint32 i = dwVFirst; i <= dwVLast; i++) { if (g_clipFlag[i] == 0) { LOG_UCODE(" Vertex %d is visible, continuing with display list processing", i); return; } } status.dwNumDListsCulled++; LOG_UCODE(" No vertices were visible, culling rest of display list"); RDP_GFX_PopDL(); } void RSP_GBI1_Tri1(Gfx *gfx) { status.primitiveType = PRIM_TRI1; bool bTrisAdded = false; bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled(); // While the next command pair is Tri1, add vertices uint32 dwPC = gDlistStack[gDlistStackPointer].pc; //uint32 * pCmdBase = (uint32 *)(g_pRDRAMu8 + dwPC); do { uint32 dwV0 = gfx->tri1.v0/gRSP.vertexMult; uint32 dwV1 = gfx->tri1.v1/gRSP.vertexMult; uint32 dwV2 = gfx->tri1.v2/gRSP.vertexMult; if (IsTriangleVisible(dwV0, dwV1, dwV2)) { DEBUG_DUMP_VERTEXES("Tri1", dwV0, dwV1, dwV2); LOG_UCODE(" Tri1: 0x%08x 0x%08x %d,%d,%d", gfx->words.w0, gfx->words.w1, dwV0, dwV1, dwV2); if (!bTrisAdded) { if( bTexturesAreEnabled ) { PrepareTextures(); InitVertexTextureConstants(); } bTrisAdded = true; } PrepareTriangle(dwV0, dwV1, dwV2); } gfx++; dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_TRI1); #else } while (gfx->words.cmd == (uint8)RSP_TRI1); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->SetCombinerAndBlender(); CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at GBI0 TRI1")); } void RSP_GBI0_Tri4(Gfx *gfx) { uint32 w0 = gfx->words.w0; uint32 w1 = gfx->words.w1; status.primitiveType = PRIM_TRI2; // While the next command pair is Tri2, add vertices uint32 dwPC = gDlistStack[gDlistStackPointer].pc; BOOL bTrisAdded = FALSE; do { uint32 dwFlag = (w0>>16)&0xFF; LOG_UCODE(" PD Tri4: 0x%08x 0x%08x Flag: 0x%02x", gfx->words.w0, gfx->words.w1, dwFlag); BOOL bVisible; for( int i=0; i<4; i++) { uint32 v0 = (w1>>(4+(i<<3))) & 0xF; uint32 v1 = (w1>>( (i<<3))) & 0xF; uint32 v2 = (w0>>( (i<<2))) & 0xF; bVisible = IsTriangleVisible(v0, v2, v1); LOG_UCODE(" (%d, %d, %d) %s", v0, v1, v2, bVisible ? "": "(clipped)"); if (bVisible) { DEBUG_DUMP_VERTEXES("Tri4_PerfectDark 1/2", v0, v1, v2); if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } bTrisAdded = true; PrepareTriangle(v0, v2, v1); } } w0 = *(uint32 *)(g_pRDRAMu8 + dwPC+0); w1 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && (w0>>24) == (uint8)RSP_TRI2); #else } while (((w0)>>24) == (uint8)RSP_TRI2); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->SetCombinerAndBlender(); CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at GBI0 TRI4")); gRSP.DKRVtxCount=0; } //Nintro64 uses Sprite2d void RSP_RDP_Nothing(Gfx *gfx) { SP_Timing(RSP_RDP_Nothing); #ifdef DEBUGGER if( logWarning ) { TRACE0("Stack Trace"); for( int i=0; iwords.w0, gfx->words.w1); } DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_UNKNOWN_OP, {TRACE0("Paused at unknown ucode\n");}) if( debuggerContinueWithUnknown ) { return; } #endif if( options.bEnableHacks ) return; gDlistStackPointer=-1; } void RSP_RDP_InsertMatrix(Gfx *gfx) { UpdateCombinedMatrix(); int x = ((gfx->words.w0) & 0x1F) >> 1; int y = x >> 2; x &= 3; if ((gfx->words.w0) & 0x20) { gRSPworldProject.m[y][x] = (float)(int)gRSPworldProject.m[y][x] + ((float)(gfx->words.w1 >> 16) / 65536.0f); gRSPworldProject.m[y][x+1] = (float)(int)gRSPworldProject.m[y][x+1] + ((float)(gfx->words.w1 & 0xFFFF) / 65536.0f); } else { gRSPworldProject.m[y][x] = (float)(short)(gfx->words.w1 >> 16); gRSPworldProject.m[y][x+1] = (float)(short)(gfx->words.w1 & 0xFFFF); } gRSP.bMatrixIsUpdated = false; gRSP.bCombinedMatrixIsUpdated = true; #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) { pauseAtNext = false; debuggerPause = true; DebuggerAppendMsg("Pause after insert matrix: %08X, %08X", gfx->words.w0, gfx->words.w1); } else { if( pauseAtNext && logMatrix ) { DebuggerAppendMsg("insert matrix: %08X, %08X", gfx->words.w0, gfx->words.w1); } } #endif } mupen64plus-video-rice-src-2.6.0/src/RSP_GBI1.h000066400000000000000000000277001464507324400207170ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Render.h" #include "Timing.h" void RSP_GBI1_Vtx(Gfx *gfx) { uint32 addr = RSPSegmentAddr((gfx->gbi1vtx.addr)); uint32 v0 = gfx->gbi1vtx.v0; uint32 n = gfx->gbi1vtx.n; LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d, Length: 0x%04x", addr, v0, n, gfx->gbi1vtx.len); if (addr > g_dwRamSize) { TRACE0(" Address out of range - ignoring load"); return; } if ((v0 + n) > 80) { TRACE5("Warning, invalid vertex positions, N=%d, v0=%d, Addr=0x%08X, Cmd=%08X-%08X", n, v0, addr, gfx->words.w0, gfx->words.w1); return; } ProcessVertexData(addr, v0, n); status.dwNumVertices += n; DisplayVertexInfo(addr, v0, n); } void RSP_GBI1_ModifyVtx(Gfx *gfx) { SP_Timing(RSP_GBI1_ModifyVtx); if( gRSP.ucode == 5 && ((gfx->words.w0)&0x00FFFFFF) == 0 && ((gfx->words.w1)&0xFF000000) == 0x80000000 ) { DLParser_Bomberman2TextRect(gfx); } else { uint32 dwWhere = ((gfx->words.w0) >> 16) & 0xFF; uint32 dwVert = (((gfx->words.w0) ) & 0xFFFF) / 2; uint32 dwValue = (gfx->words.w1); if( dwVert > 80 ) { RSP_RDP_NOIMPL("RSP_GBI1_ModifyVtx: Invalid vertex number: %d", dwVert, 0); return; } // Data for other commands? switch (dwWhere) { case RSP_MV_WORD_OFFSET_POINT_RGBA: // Modify RGBA case RSP_MV_WORD_OFFSET_POINT_XYSCREEN: // Modify X,Y case RSP_MV_WORD_OFFSET_POINT_ZSCREEN: // Modify C case RSP_MV_WORD_OFFSET_POINT_ST: // Texture ModifyVertexInfo(dwWhere, dwVert, dwValue); break; default: RSP_RDP_NOIMPL("RSP_GBI1_ModifyVtx: Setting unk value: 0x%02x, 0x%08x", dwWhere, dwValue); break; } } } void RSP_GBI1_Tri2(Gfx *gfx) { status.primitiveType = PRIM_TRI2; bool bTrisAdded = false; bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled(); // While the next command pair is Tri2, add vertices uint32 dwPC = gDlistStack[gDlistStackPointer].pc; do { // Vertex indices are multiplied by 10 for Mario64, by 2 for MarioKart uint32 dwV0 = gfx->gbi1tri2.v0/gRSP.vertexMult; uint32 dwV1 = gfx->gbi1tri2.v1/gRSP.vertexMult; uint32 dwV2 = gfx->gbi1tri2.v2/gRSP.vertexMult; uint32 dwV3 = gfx->gbi1tri2.v3/gRSP.vertexMult; uint32 dwV4 = gfx->gbi1tri2.v4/gRSP.vertexMult; uint32 dwV5 = gfx->gbi1tri2.v5/gRSP.vertexMult; // Do first tri if (IsTriangleVisible(dwV0, dwV1, dwV2)) { DEBUG_DUMP_VERTEXES("Tri2 1/2", dwV0, dwV1, dwV2); if (!bTrisAdded) { if( bTexturesAreEnabled ) { PrepareTextures(); InitVertexTextureConstants(); } bTrisAdded = true; } PrepareTriangle(dwV0, dwV1, dwV2); } // Do second tri if (IsTriangleVisible(dwV3, dwV4, dwV5)) { DEBUG_DUMP_VERTEXES("Tri2 2/2", dwV3, dwV4, dwV5); if (!bTrisAdded) { if( bTexturesAreEnabled ) { PrepareTextures(); InitVertexTextureConstants(); } bTrisAdded = true; } PrepareTriangle(dwV3, dwV4, dwV5); } gfx++; dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_TRI2); #else } while( gfx->words.cmd == (uint8)RSP_TRI2); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->SetCombinerAndBlender(); CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at GBI1 TRI1")); } extern XVECTOR4 g_vtxNonTransformed[MAX_VERTS]; void RSP_GBI1_BranchZ(Gfx *gfx) { SP_Timing(RSP_GBI1_BranchZ); uint32 vtx = ((gfx->words.w0)&0xFFF)>>1; float vtxdepth = g_vecProjected[vtx].z/g_vecProjected[vtx].w; #ifdef DEBUGGER if( debuggerEnableZBuffer==FALSE || vtxdepth <= (s32)gfx->words.w1 || g_curRomInfo.bForceDepthBuffer ) #else if( vtxdepth <= (s32)(gfx->words.w1) || g_curRomInfo.bForceDepthBuffer ) #endif { uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction uint32 dwDL = *(uint32 *)(g_pRDRAMu8 + dwPC-12); uint32 dwAddr = RSPSegmentAddr(dwDL); LOG_UCODE("BranchZ to DisplayList 0x%08x", dwAddr); gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; } } #ifdef DEBUGGER void DumpUcodeInfo(UcodeInfo &info) { DebuggerAppendMsg("Loading Unknown Ucode:\n%08X-%08X-%08X-%08X, Size=0x%X, CRC=0x%08X\nCode:\n", info.ucDWORD1, info.ucDWORD2, info.ucDWORD3, info.ucDWORD4, info.ucSize, info.ucCRC); DumpHex(info.ucStart,20); TRACE0("Data:\n"); DumpHex(info.ucDStart,20); } #endif void RSP_GBI1_LoadUCode(Gfx *gfx) { SP_Timing(RSP_GBI1_LoadUCode); //TRACE0("Load ucode"); uint32 dwPC = gDlistStack[gDlistStackPointer].pc; uint32 dwUcStart = RSPSegmentAddr((gfx->words.w1)); uint32 dwSize = ((gfx->words.w0)&0xFFFF)+1; uint32 dwUcDStart = RSPSegmentAddr(*(uint32 *)(g_pRDRAMu8 + dwPC-12)); uint32 ucode = DLParser_CheckUcode(dwUcStart, dwUcDStart, dwSize, 8); RSP_SetUcode(ucode, dwUcStart, dwUcDStart, dwSize); DEBUGGER_PAUSE_AND_DUMP(NEXT_SWITCH_UCODE,{DebuggerAppendMsg("Pause at loading ucode");}); } void RSP_GFX_Force_Matrix(uint32 dwAddr) { if (dwAddr + 64 > g_dwRamSize) { DebuggerAppendMsg("ForceMtx: Address invalid (0x%08x)", dwAddr); return; } // Load matrix from dwAddr LoadMatrix(dwAddr); CRender::g_pRender->SetWorldProjectMatrix(matToLoad); DEBUGGER_PAUSE_AND_DUMP(NEXT_MATRIX_CMD,{TRACE0("Paused at ModMatrix Cmd");}); } void DisplayVertexInfo(uint32 dwAddr, uint32 dwV0, uint32 dwN) { #ifdef DEBUGGER s8 *pcSrc = (s8 *)(g_pRDRAMu8 + dwAddr); short *psSrc = (short *)(g_pRDRAMu8 + dwAddr); for (uint32 dwV = dwV0; dwV < dwV0 + dwN; dwV++) { float x = (float)psSrc[0^0x1]; float y = (float)psSrc[1^0x1]; float z = (float)psSrc[2^0x1]; //uint32 wFlags = g_dwVtxFlags[dwV]; //(uint16)psSrc[3^0x1]; uint32 wFlags = 0; uint8 a = pcSrc[12^0x3]; uint8 b = pcSrc[13^0x3]; uint8 c = pcSrc[14^0x3]; uint8 d = pcSrc[15^0x3]; //int nTU = (int)(short)(psSrc[4^0x1]<<4); //int nTV = (int)(short)(psSrc[5^0x1]<<4); //float tu = (float)(nTU>>4); //float tv = (float)(nTV>>4); float tu = (float)(short)(psSrc[4^0x1]); float tv = (float)(short)(psSrc[5^0x1]); XVECTOR4 & t = g_vecProjected[dwV]; psSrc += 8; // Increase by 16 bytes pcSrc += 16; LOG_UCODE(" #%02d Flags: 0x%04x Pos: {% 6f,% 6f,% 6f} Tex: {%+7.2f,%+7.2f}, Extra: %02x %02x %02x %02x (transf: {% 6f,% 6f,% 6f})", dwV, wFlags, x, y, z, tu, tv, a, b, c, d, t.x, t.y, t.z ); } #endif } void RSP_MoveMemLight(uint32 dwLight, uint32 dwAddr) { if( dwLight >= 16 ) { DebuggerAppendMsg("Warning: invalid light # = %d", dwLight); return; } s8 * pcBase = g_pRDRAMs8 + dwAddr; uint32 * pdwBase = (uint32 *)pcBase; float range = 0, x, y, z; if( options.enableHackForGames == HACK_FOR_ZELDA_MM && (pdwBase[0]&0xFF) == 0x08 && (pdwBase[1]&0xFF) == 0xFF ) { gRSPn64lights[dwLight].dwRGBA = pdwBase[0]; gRSPn64lights[dwLight].dwRGBACopy = pdwBase[1]; short* pdwBase16 = (short*)pcBase; x = pdwBase16[5]; y = pdwBase16[4]; z = pdwBase16[7]; range = pdwBase16[6]; } else { gRSPn64lights[dwLight].dwRGBA = pdwBase[0]; gRSPn64lights[dwLight].dwRGBACopy = pdwBase[1]; x = pcBase[8 ^ 0x3]; y = pcBase[9 ^ 0x3]; z = pcBase[10 ^ 0x3]; } LOG_UCODE(" RGBA: 0x%08x, RGBACopy: 0x%08x, x: %d, y: %d, z: %d", gRSPn64lights[dwLight].dwRGBA, gRSPn64lights[dwLight].dwRGBACopy, x, y, z); LIGHT_DUMP(TRACE3("Move Light: %08X, %08X, %08X", pdwBase[0], pdwBase[1], pdwBase[2])); if (dwLight == gRSP.ambientLightIndex) { LOG_UCODE(" (Ambient Light)"); uint32 dwCol = COLOR_RGBA( (gRSPn64lights[dwLight].dwRGBA >> 24)&0xFF, (gRSPn64lights[dwLight].dwRGBA >> 16)&0xFF, (gRSPn64lights[dwLight].dwRGBA >> 8)&0xFF, 0xff); SetAmbientLight( dwCol ); } else { LOG_UCODE(" (Normal Light)"); SetLightCol(dwLight, gRSPn64lights[dwLight].dwRGBA); if (pdwBase[2] == 0) // Direction is 0! { LOG_UCODE(" Light is invalid"); } SetLightDirection(dwLight, x, y, z, range); } } void RSP_MoveMemViewport(uint32 dwAddr) { if( dwAddr+16 >= g_dwRamSize ) { TRACE0("MoveMem Viewport, invalid memory"); return; } short scale[4]; short trans[4]; // dwAddr is offset into RD_RAM of 8 x 16bits of data... scale[0] = *(short *)(g_pRDRAMu8 + ((dwAddr+(0*2))^0x2)); scale[1] = *(short *)(g_pRDRAMu8 + ((dwAddr+(1*2))^0x2)); scale[2] = *(short *)(g_pRDRAMu8 + ((dwAddr+(2*2))^0x2)); scale[3] = *(short *)(g_pRDRAMu8 + ((dwAddr+(3*2))^0x2)); trans[0] = *(short *)(g_pRDRAMu8 + ((dwAddr+(4*2))^0x2)); trans[1] = *(short *)(g_pRDRAMu8 + ((dwAddr+(5*2))^0x2)); trans[2] = *(short *)(g_pRDRAMu8 + ((dwAddr+(6*2))^0x2)); trans[3] = *(short *)(g_pRDRAMu8 + ((dwAddr+(7*2))^0x2)); int nCenterX = trans[0]/4; int nCenterY = trans[1]/4; int nWidth = scale[0]/4; int nHeight = scale[1]/4; // Check for some strange games if( nWidth < 0 ) nWidth = -nWidth; if( nHeight < 0 ) nHeight = -nHeight; int nLeft = nCenterX - nWidth; int nTop = nCenterY - nHeight; int nRight= nCenterX + nWidth; int nBottom= nCenterY + nHeight; //int maxZ = scale[2]; int maxZ = 0x3FF; CRender::g_pRender->SetViewport(nLeft, nTop, nRight, nBottom, maxZ); LOG_UCODE(" Scale: %d %d %d %d = %d,%d", scale[0], scale[1], scale[2], scale[3], nWidth, nHeight); LOG_UCODE(" Trans: %d %d %d %d = %d,%d", trans[0], trans[1], trans[2], trans[3], nCenterX, nCenterY); } // S2DEX uses this - 0xc1 void RSP_S2DEX_SPObjLoadTxtr_Ucode1(Gfx *gfx) { SP_Timing(RSP_S2DEX_SPObjLoadTxtr_Ucode1); // Add S2DEX ucode supporting to F3DEX, see game DT and others status.bUseModifiedUcodeMap = true; RSP_SetUcode(1); memcpy( &LoadedUcodeMap, &ucodeMap1, sizeof(UcodeMap)); LoadedUcodeMap[S2DEX_OBJ_MOVEMEM] = &RSP_S2DEX_OBJ_MOVEMEM; LoadedUcodeMap[S2DEX_OBJ_LOADTXTR] = &RSP_S2DEX_SPObjLoadTxtr; LoadedUcodeMap[S2DEX_OBJ_LDTX_SPRITE] = &RSP_S2DEX_SPObjLoadTxSprite; LoadedUcodeMap[S2DEX_OBJ_LDTX_RECT] = &RSP_S2DEX_SPObjLoadTxRect; LoadedUcodeMap[S2DEX_OBJ_LDTX_RECT_R] = &RSP_S2DEX_SPObjLoadTxRectR; RSP_S2DEX_SPObjLoadTxtr(gfx); } mupen64plus-video-rice-src-2.6.0/src/RSP_GBI2.h000066400000000000000000000673621464507324400207300ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Render.h" #include "Timing.h" void RSP_GBI2_Vtx(Gfx *gfx) { uint32 addr = RSPSegmentAddr((gfx->gbi2vtx.addr)); int vend = gfx->gbi2vtx.vend; int n = gfx->gbi2vtx.n; int v0 = vend - n; LOG_UCODE(" Vtx: Address 0x%08x, vEnd: %d, v0: %d, Num: %d", addr, vend, v0, n); if( vend > 64 ) { DebuggerAppendMsg("Warning, attempting to load into invalid vertex positions, v0=%d, n=%d", v0, n); return; } if ((addr + (n*16)) > g_dwRamSize) { DebuggerAppendMsg("ProcessVertexData: Address out of range (0x%08x)", addr); } else { ProcessVertexData(addr, v0, n); status.dwNumVertices += n; DisplayVertexInfo(addr, v0, n); } } void RSP_GBI2_EndDL(Gfx *gfx) { SP_Timing(RSP_GBI1_EndDL); RDP_GFX_PopDL(); } void RSP_GBI2_CullDL(Gfx *gfx) { SP_Timing(RSP_GBI1_CullDL); #ifdef DEBUGGER if( !debuggerEnableCullFace ) { return; //Disable Culling } #endif if( g_curRomInfo.bDisableCulling ) { return; //Disable Culling } uint32 dwVFirst = (((gfx->words.w0)) & 0xfff) / gRSP.vertexMult; uint32 dwVLast = (((gfx->words.w1)) & 0xfff) / gRSP.vertexMult; LOG_UCODE(" Culling using verts %d to %d", dwVFirst, dwVLast); // Mask into range dwVFirst &= 0x1f; dwVLast &= 0x1f; if( dwVLast < dwVFirst ) return; if( !gRSP.bRejectVtx ) return; for (uint32 i = dwVFirst; i <= dwVLast; i++) { //if (g_dwVtxFlags[i] == 0) if (g_clipFlag[i] == 0) { LOG_UCODE(" Vertex %d is visible, returning", i); return; } } status.dwNumDListsCulled++; LOG_UCODE(" No vertices were visible, culling"); RDP_GFX_PopDL(); } void RSP_GBI2_MoveWord(Gfx *gfx) { SP_Timing(RSP_GBI1_MoveWord); switch (gfx->gbi2moveword.type) { case RSP_MOVE_WORD_MATRIX: RSP_RDP_InsertMatrix(gfx); break; case RSP_MOVE_WORD_NUMLIGHT: { uint32 dwNumLights = gfx->gbi2moveword.value/24; gRSP.ambientLightIndex = dwNumLights; SetNumLights(dwNumLights); } break; case RSP_MOVE_WORD_CLIP: { switch (gfx->gbi2moveword.offset) { case RSP_MV_WORD_OFFSET_CLIP_RNX: case RSP_MV_WORD_OFFSET_CLIP_RNY: case RSP_MV_WORD_OFFSET_CLIP_RPX: case RSP_MV_WORD_OFFSET_CLIP_RPY: CRender::g_pRender->SetClipRatio(gfx->gbi2moveword.offset, gfx->gbi2moveword.value); default: LOG_UCODE(" RSP_MOVE_WORD_CLIP ? : 0x%08x", gfx->words.w1); break; } } break; case RSP_MOVE_WORD_SEGMENT: { uint32 dwSeg = gfx->gbi2moveword.offset / 4; uint32 dwAddr = gfx->gbi2moveword.value & 0x00FFFFFF; // Hack - convert to physical LOG_UCODE(" RSP_MOVE_WORD_SEGMENT Segment[%d] = 0x%08x", dwSeg, dwAddr); if( dwAddr > g_dwRamSize ) { gRSP.segments[dwSeg] = dwAddr; #ifdef DEBUGGER if( pauseAtNext ) DebuggerAppendMsg("warning: Segment %d addr is %8X", dwSeg, dwAddr); #endif } else { gRSP.segments[dwSeg] = dwAddr; } } break; case RSP_MOVE_WORD_FOG: { uint16 wMult = (uint16)((gfx->gbi2moveword.value >> 16) & 0xFFFF); uint16 wOff = (uint16)((gfx->gbi2moveword.value ) & 0xFFFF); float fMult = (float)(short)wMult; float fOff = (float)(short)wOff; float rng = 128000.0f / fMult; float fMin = 500.0f - (fOff*rng/256.0f); float fMax = rng + fMin; FOG_DUMP(TRACE4("Set Fog: Min=%f, Max=%f, Mul=%f, Off=%f", fMin, fMax, fMult, fOff)); //if( fMult <= 0 || fMin > fMax || fMax < 0 || fMin > 1000 ) if( fMult <= 0 || fMax < 0 ) { // Hack fMin = 996; fMax = 1000; fMult = 0; fOff = 1; } SetFogMinMax(fMin, fMax, fMult, fOff); FOG_DUMP(TRACE3("Set Fog: Min=%f, Max=%f, Data=0x%08X", fMin, fMax, gfx->gbi2moveword.value)); } break; case RSP_MOVE_WORD_LIGHTCOL: { uint32 dwLight = gfx->gbi2moveword.offset / 0x18; uint32 dwField = (gfx->gbi2moveword.offset & 0x7); switch (dwField) { case 0: if (dwLight == gRSP.ambientLightIndex) { SetAmbientLight( (gfx->gbi2moveword.value>>8) ); } else { SetLightCol(dwLight, gfx->gbi2moveword.value); } break; case 4: break; default: DebuggerAppendMsg("RSP_MOVE_WORD_LIGHTCOL with unknown offset 0x%08x", dwField); break; } } break; case RSP_MOVE_WORD_PERSPNORM: LOG_UCODE(" RSP_MOVE_WORD_PERSPNORM 0x%04x", (short)gfx->words.w1); break; case RSP_MOVE_WORD_POINTS: LOG_UCODE(" 2nd cmd of Force Matrix"); break; default: { LOG_UCODE(" Ignored!!"); } break; } } void RSP_GBI2_Tri1(Gfx *gfx) { if( gfx->words.w0 == 0x05000017 && gfx->gbi2tri1.flag == 0x80 ) { // The ObjLoadTxtr / Tlut cmd for Evangelion.v64 RSP_S2DEX_SPObjLoadTxtr(gfx); DebuggerAppendMsg("Fix me, SPObjLoadTxtr as RSP_GBI2_Tri2"); } else { status.primitiveType = PRIM_TRI1; bool bTrisAdded = false; bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled(); // While the next command pair is Tri1, add vertices uint32 dwPC = gDlistStack[gDlistStackPointer].pc; //uint32 * pCmdBase = (uint32 *)(g_pRDRAMu8 + dwPC); do { uint32 dwV2 = gfx->gbi2tri1.v2/gRSP.vertexMult; uint32 dwV1 = gfx->gbi2tri1.v1/gRSP.vertexMult; uint32 dwV0 = gfx->gbi2tri1.v0/gRSP.vertexMult; if (IsTriangleVisible(dwV0, dwV1, dwV2)) { DEBUG_DUMP_VERTEXES("ZeldaTri1", dwV0, dwV1, dwV2); LOG_UCODE(" ZeldaTri1: 0x%08x 0x%08x %d,%d,%d", gfx->words.w0, gfx->words.w1, dwV0, dwV1, dwV2); if (!bTrisAdded) { if( bTexturesAreEnabled ) { PrepareTextures(); InitVertexTextureConstants(); } bTrisAdded = true; } PrepareTriangle(dwV0, dwV1, dwV2); } gfx++; dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_ZELDATRI1); #else } while( gfx->words.cmd == (uint8)RSP_ZELDATRI1); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->SetCombinerAndBlender(); CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at GBI2 TRI1")); } } void RSP_GBI2_Tri2(Gfx *gfx) { if( gfx->words.w0 == 0x0600002f && gfx->gbi2tri2.flag == 0x80 ) { // The ObjTxSprite cmd for Evangelion.v64 RSP_S2DEX_SPObjLoadTxSprite(gfx); DebuggerAppendMsg("Fix me, SPObjLoadTxSprite as RSP_GBI2_Tri2"); } else { status.primitiveType = PRIM_TRI2; BOOL bTrisAdded = FALSE; // While the next command pair is Tri2, add vertices uint32 dwPC = gDlistStack[gDlistStackPointer].pc; bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled(); do { uint32 dwV2 = gfx->gbi2tri2.v2; uint32 dwV1 = gfx->gbi2tri2.v1; uint32 dwV0 = gfx->gbi2tri2.v0; uint32 dwV5 = gfx->gbi2tri2.v5; uint32 dwV4 = gfx->gbi2tri2.v4; uint32 dwV3 = gfx->gbi2tri2.v3; LOG_UCODE(" ZeldaTri2: 0x%08x 0x%08x", gfx->words.w0, gfx->words.w1); LOG_UCODE(" V0: %d, V1: %d, V2: %d", dwV0, dwV1, dwV2); LOG_UCODE(" V3: %d, V4: %d, V5: %d", dwV3, dwV4, dwV5); // Do first tri if (IsTriangleVisible(dwV0, dwV1, dwV2)) { DEBUG_DUMP_VERTEXES("ZeldaTri2 1/2", dwV0, dwV1, dwV2); if (!bTrisAdded) { if( bTexturesAreEnabled ) { PrepareTextures(); InitVertexTextureConstants(); } bTrisAdded = true; } PrepareTriangle(dwV0, dwV1, dwV2); } // Do second tri if (IsTriangleVisible(dwV3, dwV4, dwV5)) { DEBUG_DUMP_VERTEXES("ZeldaTri2 2/2", dwV3, dwV4, dwV5); if (!bTrisAdded) { if( bTexturesAreEnabled ) { PrepareTextures(); InitVertexTextureConstants(); } bTrisAdded = true; } PrepareTriangle(dwV3, dwV4, dwV5); } gfx++; dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_ZELDATRI2); #else } while ( gfx->words.cmd == (uint8)RSP_ZELDATRI2 );//&& status.dwNumTrisRendered < 50); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->SetCombinerAndBlender(); CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at GBI2 TRI2")); } } void RSP_GBI2_Line3D(Gfx *gfx) { if( gfx->words.w0 == 0x0700002f && (gfx->words.w1>>24) == 0x80 ) { // The ObjTxSprite cmd for Evangelion.v64 RSP_S2DEX_SPObjLoadTxRect(gfx); } else { status.primitiveType = PRIM_TRI3; uint32 dwPC = gDlistStack[gDlistStackPointer].pc; BOOL bTrisAdded = FALSE; do { uint32 dwV0 = gfx->gbi2line3d.v0/gRSP.vertexMult; uint32 dwV1 = gfx->gbi2line3d.v1/gRSP.vertexMult; uint32 dwV2 = gfx->gbi2line3d.v2/gRSP.vertexMult; uint32 dwV3 = gfx->gbi2line3d.v3/gRSP.vertexMult; uint32 dwV4 = gfx->gbi2line3d.v4/gRSP.vertexMult; uint32 dwV5 = gfx->gbi2line3d.v5/gRSP.vertexMult; LOG_UCODE(" ZeldaTri3: 0x%08x 0x%08x", gfx->words.w0, gfx->words.w1); LOG_UCODE(" V0: %d, V1: %d, V2: %d", dwV0, dwV1, dwV2); LOG_UCODE(" V3: %d, V4: %d, V5: %d", dwV3, dwV4, dwV5); // Do first tri if (IsTriangleVisible(dwV0, dwV1, dwV2)) { DEBUG_DUMP_VERTEXES("ZeldaTri3 1/2", dwV0, dwV1, dwV2); if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } bTrisAdded = true; PrepareTriangle(dwV0, dwV1, dwV2); } // Do second tri if (IsTriangleVisible(dwV3, dwV4, dwV5)) { DEBUG_DUMP_VERTEXES("ZeldaTri3 2/2", dwV3, dwV4, dwV5); if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } bTrisAdded = true; PrepareTriangle(dwV3, dwV4, dwV5); } gfx++; dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_LINE3D); #else } while ( gfx->words.cmd == (uint8)RSP_LINE3D); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->SetCombinerAndBlender(); CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at GBI2 Line3D")); } } void RSP_GBI2_Texture(Gfx *gfx) { SP_Timing(RSP_GBI1_Texture); float fTextureScaleS = (float)(gfx->texture.scaleS) / (65536.0f * 32.0f); float fTextureScaleT = (float)(gfx->texture.scaleT) / (65536.0f * 32.0f); if( (((gfx->words.w1)>>16)&0xFFFF) == 0xFFFF ) { fTextureScaleS = 1/32.0f; } else if( (((gfx->words.w1)>>16)&0xFFFF) == 0x8000 ) { fTextureScaleS = 1/64.0f; } if( (((gfx->words.w1) )&0xFFFF) == 0xFFFF ) { fTextureScaleT = 1/32.0f; } else if( (((gfx->words.w1) )&0xFFFF) == 0x8000 ) { fTextureScaleT = 1/64.0f; } CRender::g_pRender->SetTextureEnableAndScale(gfx->texture.tile, gfx->texture.enable_gbi2, fTextureScaleS, fTextureScaleT); /* if( g_curRomInfo.bTextureScaleHack ) { // Hack, need to verify, refer to N64 programming manual // that if scale = 0.5 (1/64), vtx s,t are also doubled if( ((word1>>16)&0xFFFF) == 0x8000 ) { fTextureScaleS = 1/128.0f; if( ((word1)&0xFFFF) == 0xFFFF ) { fTextureScaleT = 1/64.0f; } } if( ((word1 )&0xFFFF) == 0x8000 ) { fTextureScaleT = 1/128.0f; if( ((word1>>16)&0xFFFF) == 0xFFFF ) { fTextureScaleS = 1/64.0f; } } } */ CRender::g_pRender->SetTextureEnableAndScale(gfx->texture.tile, gfx->texture.enable_gbi2, fTextureScaleS, fTextureScaleT); LOG_TEXTURE( { DebuggerAppendMsg("SetTexture: Level: %d Tile: %d %s\n", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi2 ? "enabled":"disabled"); DebuggerAppendMsg(" ScaleS: %f, ScaleT: %f\n", fTextureScaleS*32.0f, fTextureScaleT*32.0f); }); DEBUGGER_PAUSE_COUNT_N(NEXT_SET_TEXTURE); LOG_UCODE(" Level: %d Tile: %d %s", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi2 ? "enabled":"disabled"); LOG_UCODE(" ScaleS: %f, ScaleT: %f", fTextureScaleS*32.0f, fTextureScaleT*32.0f); } void RSP_GBI2_PopMtx(Gfx *gfx) { SP_Timing(RSP_GBI1_PopMtx); uint8 nCommand = (uint8)(gfx->words.w0 & 0xFF); LOG_UCODE(" PopMtx: 0x%02x (%s)", nCommand, (nCommand & RSP_ZELDA_MTX_PROJECTION) ? "Projection" : "ModelView"); /* if (nCommand & RSP_ZELDA_MTX_PROJECTION) { CRender::g_pRender->PopProjection(); } else*/ { CRender::g_pRender->PopWorldView(); } #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) { pauseAtNext = false; debuggerPause = true; TRACE0("Pause after Pop GBI2_PopMtx:"); } else { if( pauseAtNext && logMatrix ) { TRACE0("Pause after Pop GBI2_PopMtx:"); } } #endif } #define RSP_ZELDA_ZBUFFER 0x00000001 // Guess #define RSP_ZELDA_CULL_BACK 0x00000200 #define RSP_ZELDA_CULL_FRONT 0x00000400 #define RSP_ZELDA_FOG 0x00010000 #define RSP_ZELDA_LIGHTING 0x00020000 #define RSP_ZELDA_TEXTURE_GEN 0x00040000 #define RSP_ZELDA_TEXTURE_GEN_LINEAR 0x00080000 #define RSP_ZELDA_SHADING_SMOOTH 0x00200000 void RSP_GBI2_GeometryMode(Gfx *gfx) { SP_Timing(RSP_GBI2_GeometryMode); uint32 dwAnd = ((gfx->words.w0)) & 0x00FFFFFF; uint32 dwOr = ((gfx->words.w1)) & 0x00FFFFFF; #ifdef DEBUGGER LOG_UCODE(" 0x%08x 0x%08x =(x & 0x%08x) | 0x%08x", gfx->words.w0, gfx->words.w1, dwAnd, dwOr); if ((~dwAnd) & RSP_ZELDA_ZBUFFER) LOG_UCODE(" Disabling ZBuffer"); //if ((~dwAnd) & RSP_ZELDA_TEXTURE_ENABLE) LOG_UCODE(" Disabling Texture"); //if ((~dwAnd) & RSP_ZELDA_SHADE) LOG_UCODE(" Disabling Shade"); if ((~dwAnd) & RSP_ZELDA_SHADING_SMOOTH) LOG_UCODE(" Disabling Flat Shading"); if ((~dwAnd) & RSP_ZELDA_CULL_FRONT) LOG_UCODE(" Disabling Front Culling"); if ((~dwAnd) & RSP_ZELDA_CULL_BACK) LOG_UCODE(" Disabling Back Culling"); if ((~dwAnd) & RSP_ZELDA_FOG) LOG_UCODE(" Disabling Fog"); if ((~dwAnd) & RSP_ZELDA_LIGHTING) LOG_UCODE(" Disabling Lighting"); if ((~dwAnd) & RSP_ZELDA_TEXTURE_GEN) LOG_UCODE(" Disabling Texture Gen"); if ((~dwAnd) & RSP_ZELDA_TEXTURE_GEN_LINEAR) LOG_UCODE(" Disabling Texture Gen Linear"); // if ((~dwAnd) & RSP_ZELDA_LOD) LOG_UCODE(" Disabling LOD (no impl)"); if (dwOr & RSP_ZELDA_ZBUFFER) LOG_UCODE(" Enabling ZBuffer"); //if (dwOr & RSP_ZELDA_TEXTURE_ENABLE) LOG_UCODE(" Enabling Texture"); //if (dwOr & RSP_ZELDA_SHADE) LOG_UCODE(" Enabling Shade"); if (dwOr & RSP_ZELDA_SHADING_SMOOTH) LOG_UCODE(" Enabling Flat Shading"); if (dwOr & RSP_ZELDA_CULL_FRONT) LOG_UCODE(" Enabling Front Culling"); if (dwOr & RSP_ZELDA_CULL_BACK) LOG_UCODE(" Enabling Back Culling"); if (dwOr & RSP_ZELDA_FOG) LOG_UCODE(" Enabling Fog"); if (dwOr & RSP_ZELDA_LIGHTING) LOG_UCODE(" Enabling Lighting"); if (dwOr & RSP_ZELDA_TEXTURE_GEN) LOG_UCODE(" Enabling Texture Gen"); if (dwOr & RSP_ZELDA_TEXTURE_GEN_LINEAR) LOG_UCODE(" Enabling Texture Gen Linear"); ///if (dwOr & RSP_ZELDA_LOD) LOG_UCODE(" Enabling LOD (no impl)"); #endif // DEBUGGER gRDP.geometryMode &= dwAnd; gRDP.geometryMode |= dwOr; bool bCullFront = (gRDP.geometryMode & RSP_ZELDA_CULL_FRONT) ? true : false; bool bCullBack = (gRDP.geometryMode & RSP_ZELDA_CULL_BACK) ? true : false; //BOOL bShade = (gRDP.geometryMode & G_SHADE) ? TRUE : FALSE; //BOOL bFlatShade = (gRDP.geometryMode & RSP_ZELDA_SHADING_SMOOTH) ? TRUE : FALSE; BOOL bFlatShade = (gRDP.geometryMode & RSP_ZELDA_TEXTURE_GEN_LINEAR) ? TRUE : FALSE; if( options.enableHackForGames == HACK_FOR_TIGER_HONEY_HUNT ) bFlatShade = FALSE; bool bFog = (gRDP.geometryMode & RSP_ZELDA_FOG) ? true : false; bool bTextureGen = (gRDP.geometryMode & RSP_ZELDA_TEXTURE_GEN) ? true : false; bool bLighting = (gRDP.geometryMode & RSP_ZELDA_LIGHTING) ? true : false; BOOL bZBuffer = (gRDP.geometryMode & RSP_ZELDA_ZBUFFER) ? TRUE : FALSE; CRender::g_pRender->SetCullMode(bCullFront, bCullBack); //if (bFlatShade||!bShade) CRender::g_pRender->SetShadeMode( SHADE_FLAT ); if (bFlatShade) CRender::g_pRender->SetShadeMode( SHADE_FLAT ); else CRender::g_pRender->SetShadeMode( SHADE_SMOOTH ); SetTextureGen(bTextureGen); SetLighting( bLighting ); CRender::g_pRender->ZBufferEnable( bZBuffer ); CRender::g_pRender->SetFogEnable( bFog ); } int dlistMtxCount=0; extern uint32 dwConkerVtxZAddr; void RSP_GBI2_Mtx(Gfx *gfx) { SP_Timing(RSP_GBI0_Mtx); dwConkerVtxZAddr = 0; // For Conker BFD uint32 addr = RSPSegmentAddr((gfx->gbi2matrix.addr)); if( gfx->gbi2matrix.param == 0 && gfx->gbi2matrix.len == 0 ) { DLParser_Bomberman2TextRect(gfx); return; } LOG_UCODE(" Mtx: %s %s %s Length %d Address 0x%08x", gfx->gbi2matrix.projection ? "Projection" : "ModelView", gfx->gbi2matrix.load ? "Load" : "Mul", gfx->gbi2matrix.nopush==0 ? "Push" : "No Push", gfx->gbi2matrix.len, addr); if (addr + 64 > g_dwRamSize) { DebuggerAppendMsg("ZeldaMtx: Address invalid (0x%08x)", addr); return; } LoadMatrix(addr); if (gfx->gbi2matrix.projection) { // So far only Extreme-G seems to Push/Pop projection matrices CRender::g_pRender->SetProjection(matToLoad, gfx->gbi2matrix.nopush==0, gfx->gbi2matrix.load); } else { CRender::g_pRender->SetWorldView(matToLoad, gfx->gbi2matrix.nopush==0, gfx->gbi2matrix.load); if( options.enableHackForGames == HACK_FOR_SOUTH_PARK_RALLY ) { dlistMtxCount++; if( dlistMtxCount == 2 ) { CRender::g_pRender->ClearZBuffer(1.0f); } } } #ifdef DEBUGGER const char *loadstr = gfx->gbi2matrix.load?"Load":"Mul"; const char *pushstr = gfx->gbi2matrix.nopush==0?"Push":"Nopush"; int projlevel = CRender::g_pRender->GetProjectMatrixLevel(); int worldlevel = CRender::g_pRender->GetWorldViewMatrixLevel(); if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD ) { pauseAtNext = false; debuggerPause = true; if (gfx->gbi2matrix.projection) { DebuggerAppendMsg("Pause after %s and %s Matrix: Projection, level=%d\n", loadstr, pushstr, projlevel ); } else { DebuggerAppendMsg("Pause after %s and %s Matrix: WorldView level=%d\n", loadstr, pushstr, worldlevel); } } else { if( pauseAtNext && logMatrix ) { if (gfx->gbi2matrix.projection) { DebuggerAppendMsg("Matrix: %s and %s Projection level=%d\n", loadstr, pushstr, projlevel); } else { DebuggerAppendMsg("Matrix: %s and %s WorldView\n level=%d", loadstr, pushstr, worldlevel); } } } #endif } void RSP_GBI2_MoveMem(Gfx *gfx) { SP_Timing(RSP_GBI1_MoveMem); uint32 addr = RSPSegmentAddr((gfx->words.w1)); uint32 type = ((gfx->words.w0) ) & 0xFE; //uint32 dwLen = ((gfx->words.w0) >> 16) & 0xFF; //uint32 dwOffset = ((gfx->words.w0) >> 8) & 0xFFFF; switch (type) { case RSP_GBI2_MV_MEM__VIEWPORT: { RSP_MoveMemViewport(addr); } break; case RSP_GBI2_MV_MEM__LIGHT: { uint32 dwOffset2 = ((gfx->words.w0) >> 5) & 0x3FFF; switch (dwOffset2) { case 0x00: { s8 * pcBase = g_pRDRAMs8 + addr; LOG_UCODE(" RSP_GBI1_MV_MEM_LOOKATX %f %f %f", (float)pcBase[8 ^ 0x3], (float)pcBase[9 ^ 0x3], (float)pcBase[10 ^ 0x3]); } break; case 0x18: { s8 * pcBase = g_pRDRAMs8 + addr; LOG_UCODE(" RSP_GBI1_MV_MEM_LOOKATY %f %f %f", (float)pcBase[8 ^ 0x3], (float)pcBase[9 ^ 0x3], (float)pcBase[10 ^ 0x3]); } break; default: //0x30/48/60 { uint32 dwLight = (dwOffset2 - 0x30)/0x18; LOG_UCODE(" Light %d:", dwLight); RSP_MoveMemLight(dwLight, addr); } break; } break; } case RSP_GBI2_MV_MEM__MATRIX: LOG_UCODE("Force Matrix: addr=%08X", addr); RSP_GFX_Force_Matrix(addr); break; case RSP_GBI2_MV_MEM_O_L0: case RSP_GBI2_MV_MEM_O_L1: case RSP_GBI2_MV_MEM_O_L2: case RSP_GBI2_MV_MEM_O_L3: case RSP_GBI2_MV_MEM_O_L4: case RSP_GBI2_MV_MEM_O_L5: case RSP_GBI2_MV_MEM_O_L6: case RSP_GBI2_MV_MEM_O_L7: LOG_UCODE("Zelda Move Light"); RDP_NOIMPL_WARN("Zelda Move Light"); break; case RSP_GBI2_MV_MEM__POINT: LOG_UCODE("Zelda Move Point"); void RDP_NOIMPL_WARN(const char* op); RDP_NOIMPL_WARN("Zelda Move Point"); break; case RSP_GBI2_MV_MEM_O_LOOKATX: if( (gfx->words.w0) == 0xDC170000 && ((gfx->words.w1)&0xFF000000) == 0x80000000 ) { // Ucode for Evangelion.v64, the ObjMatrix cmd RSP_S2DEX_OBJ_MOVEMEM(gfx); } break; case RSP_GBI2_MV_MEM_O_LOOKATY: RSP_RDP_NOIMPL("Not implemented ZeldaMoveMem LOOKATY, Cmd0=0x%08X, Cmd1=0x%08X", gfx->words.w0, gfx->words.w1); break; case 0x02: if( (gfx->words.w0) == 0xDC070002 && ((gfx->words.w1)&0xFF000000) == 0x80000000 ) { RSP_S2DEX_OBJ_MOVEMEM(gfx); break; } default: LOG_UCODE("ZeldaMoveMem Type: Unknown"); RSP_RDP_NOIMPL("Unknown ZeldaMoveMem Type, type=0x%X, Addr=%08X", type, addr); break; } } void RSP_GBI2_DL(Gfx *gfx) { SP_Timing(RSP_GBI0_DL); uint32 dwPush = ((gfx->words.w0) >> 16) & 0xFF; uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); if( dwAddr > g_dwRamSize ) { RSP_RDP_NOIMPL("Error: DL addr = %08X out of range, PC=%08X", dwAddr, gDlistStack[gDlistStackPointer].pc ); dwAddr &= (g_dwRamSize-1); DebuggerPauseCountN( NEXT_DLIST ); } LOG_UCODE(" DL: Push:0x%02x Addr: 0x%08x", dwPush, dwAddr); switch (dwPush) { case RSP_DLIST_PUSH: LOG_UCODE(" Pushing ZeldaDisplayList 0x%08x", dwAddr); gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; break; case RSP_DLIST_NOPUSH: LOG_UCODE(" Jumping to ZeldaDisplayList 0x%08x", dwAddr); if( gDlistStack[gDlistStackPointer].pc == dwAddr+8 ) //Is this a loop { //Hack for Gauntlet Legends gDlistStack[gDlistStackPointer].pc = dwAddr+8; } else gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; break; } LOG_UCODE(""); LOG_UCODE("\\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/"); LOG_UCODE("#############################################"); } void RSP_GBI2_SetOtherModeL(Gfx *gfx) { SP_Timing(RSP_GBI1_SetOtherModeL); uint32 dwShift = ((gfx->words.w0)>>8)&0xFF; uint32 dwLength= ((gfx->words.w0) )&0xFF; uint32 dwData = (gfx->words.w1); // Mask is constructed slightly differently uint32 dwMask = (uint32)((s32)(0x80000000)>>dwLength)>>dwShift; dwData &= dwMask; uint32 modeL = gRDP.otherModeL; modeL = (modeL&(~dwMask)) | dwData; Gfx tempgfx; tempgfx.words.w0 = gRDP.otherModeH; tempgfx.words.w1 = modeL; DLParser_RDPSetOtherMode(&tempgfx ); } void RSP_GBI2_SetOtherModeH(Gfx *gfx) { SP_Timing(RSP_GBI1_SetOtherModeH); uint32 dwLength= (((gfx->words.w0))&0xFF)+1; uint32 dwShift = 32 - (((gfx->words.w0)>>8)&0xFF) - dwLength; uint32 dwData = (gfx->words.w1); uint32 dwMask2 = ((1<words.w0), (gfx->words.w1)); } mupen64plus-video-rice-src-2.6.0/src/RSP_GBI2_ext.h000066400000000000000000000025641464507324400216010ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // Some new GBI2 extension ucodes void RSP_GBI2_DL_Count(Gfx *gfx) { SP_Timing(DP_Minimal); DP_Timing(DP_Minimal); // This cmd is likely to execute number of ucode at the given address uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); { gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = ((gfx->words.w0)&0xFFFF); } } void RSP_GBI2_0x8(Gfx *gfx) { if( ((gfx->words.w0)&0x00FFFFFF) == 0x2F && ((gfx->words.w1)&0xFF000000) == 0x80000000 ) { // V-Rally 64 RSP_S2DEX_SPObjLoadTxRectR(gfx); } else { RSP_RDP_Nothing(gfx); } } mupen64plus-video-rice-src-2.6.0/src/RSP_GBI_Others.h000066400000000000000000001504231464507324400221610ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // A few ucode used in DKR and Others Special games #include #include "Render.h" #include "Timing.h" #include "osal_preproc.h" #undef min #undef max uint32 dwConkerVtxZAddr=0; static void RDP_GFX_DumpVtxInfoDKR(uint32 dwAddr, uint32 dwV0, uint32 dwN); void RDP_GFX_DLInMem(Gfx *gfx) { uint32 dwLimit = ((gfx->words.w0) >> 16) & 0xFF; uint32 dwPush = RSP_DLIST_PUSH; //((gfx->words.w0) >> 16) & 0xFF; uint32 dwAddr = 0x00000000 | (gfx->words.w1); //RSPSegmentAddr((gfx->words.w1)); LOG_UCODE(" Address=0x%08x Push: 0x%02x", dwAddr, dwPush); switch (dwPush) { case RSP_DLIST_PUSH: LOG_UCODE(" Pushing DisplayList 0x%08x", dwAddr); gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = dwLimit; break; case RSP_DLIST_NOPUSH: LOG_UCODE(" Jumping to DisplayList 0x%08x", dwAddr); gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = dwLimit; break; } LOG_UCODE(""); LOG_UCODE("\\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/"); LOG_UCODE("#############################################"); } extern Matrix ALIGN(16, dkrMatrixTransposed) void RSP_Mtx_DKR(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwCommand = ((gfx->words.w0)>>16)&0xFF; //uint32 dwLength = ((gfx->words.w0)) &0xFFFF; dwAddr = (gfx->words.w1)+RSPSegmentAddr(gRSP.dwDKRMatrixAddr); //gRSP.DKRCMatrixIndex = ((gfx->words.w0)>>22)&3; bool mul=false; int index = 0; switch( dwCommand ) { case 0xC0: // DKR gRSP.DKRCMatrixIndex = index = 3; break; case 0x80: // DKR gRSP.DKRCMatrixIndex = index = 2; break; case 0x40: // DKR gRSP.DKRCMatrixIndex = index = 1; break; case 0x20: // DKR gRSP.DKRCMatrixIndex = index = 0; break; case 0x00: gRSP.DKRCMatrixIndex = index = 0; break; case 0x01: //mul = true; gRSP.DKRCMatrixIndex = index = 1; break; case 0x02: //mul = true; gRSP.DKRCMatrixIndex = index = 2; break; case 0x03: //mul = true; gRSP.DKRCMatrixIndex = index = 3; break; case 0x81: index = 1; mul = true; break; case 0x82: index = 2; mul = true; break; case 0x83: index = 3; mul = true; break; default: DebuggerAppendMsg("Fix me, mtx DKR, cmd=%08X", dwCommand); break; } // Load matrix from dwAddr Matrix &mat = gRSP.DKRMatrixes[index]; LoadMatrix(dwAddr); if( mul ) { mat = matToLoad*gRSP.DKRMatrixes[0]; } else { mat = matToLoad; } if( status.isSSEEnabled ) MatrixTranspose(&dkrMatrixTransposed, &mat); DEBUGGER_IF_DUMP(logMatrix,TRACE3("DKR Matrix: cmd=0x%X, idx = %d, mul=%d", dwCommand, index, mul)); LOG_UCODE(" DKR Loading Mtx: %d, command=%d", index, dwCommand); DEBUGGER_PAUSE_AND_DUMP(NEXT_MATRIX_CMD,{TRACE0("Paused at DKR Matrix Cmd");}); } void RSP_Vtx_DKR(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwV0 = (((gfx->words.w0) >> 9 )&0x1F); uint32 dwN = (((gfx->words.w0) >>19 )&0x1F)+1; if( gfx->words.w0 & 0x00010000 ) { if( gRSP.DKRBillBoard ) gRSP.DKRVtxCount = 1; } else { gRSP.DKRVtxCount = 0; } dwV0 += gRSP.DKRVtxCount; LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d", dwAddr, dwV0, dwN); DEBUGGER_ONLY_IF( (pauseAtNext && (eventToPause==NEXT_VERTEX_CMD||eventToPause==NEXT_MATRIX_CMD)), {DebuggerAppendMsg("DKR Vtx: Cmd0=%08X, Cmd1=%08X", (gfx->words.w0), (gfx->words.w1));}); VTX_DUMP(TRACE2("Vtx_DKR, cmd0=%08X cmd1=%08X", (gfx->words.w0), (gfx->words.w1))); VTX_DUMP(TRACE2("Vtx_DKR, v0=%d n=%d", dwV0, dwN)); if (dwV0 >= 32) dwV0 = 31; if ((dwV0 + dwN) > 32) { WARNING(TRACE0("Warning, attempting to load into invalid vertex positions")); dwN = 32 - dwV0; } //if( dwAddr == 0 || dwAddr < 0x2000) { dwAddr = (gfx->words.w1)+RSPSegmentAddr(gRSP.dwDKRVtxAddr); } // Check that address is valid... if ((dwAddr + (dwN*16)) > g_dwRamSize) { WARNING(TRACE1("ProcessVertexData: Address out of range (0x%08x)", dwAddr)); } else { ProcessVertexDataDKR(dwAddr, dwV0, dwN); status.dwNumVertices += dwN; RDP_GFX_DumpVtxInfoDKR(dwAddr, dwV0, dwN); } } void RSP_Vtx_Gemini(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwV0 = (((gfx->words.w0)>>9)&0x1F); uint32 dwN = (((gfx->words.w0) >>19 )&0x1F); LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d", dwAddr, dwV0, dwN); DEBUGGER_ONLY_IF( (pauseAtNext && (eventToPause==NEXT_VERTEX_CMD||eventToPause==NEXT_MATRIX_CMD)), {DebuggerAppendMsg("DKR Vtx: Cmd0=%08X, Cmd1=%08X", (gfx->words.w0), (gfx->words.w1));}); VTX_DUMP(TRACE2("Vtx_DKR, cmd0=%08X cmd1=%08X", (gfx->words.w0), (gfx->words.w1))); if (dwV0 >= 32) dwV0 = 31; if ((dwV0 + dwN) > 32) { TRACE0("Warning, attempting to load into invalid vertex positions"); dwN = 32 - dwV0; } //if( dwAddr == 0 || dwAddr < 0x2000) { dwAddr = (gfx->words.w1)+RSPSegmentAddr(gRSP.dwDKRVtxAddr); } // Check that address is valid... if ((dwAddr + (dwN*16)) > g_dwRamSize) { TRACE1("ProcessVertexData: Address out of range (0x%08x)", dwAddr); } else { ProcessVertexDataDKR(dwAddr, dwV0, dwN); status.dwNumVertices += dwN; RDP_GFX_DumpVtxInfoDKR(dwAddr, dwV0, dwN); } } // DKR verts are extra 4 bytes void RDP_GFX_DumpVtxInfoDKR(uint32 dwAddr, uint32 dwV0, uint32 dwN) { #ifdef DEBUGGER uint32 dwV; int i; short * psSrc = (short *)(g_pRDRAMu8 + dwAddr); i = 0; for (dwV = dwV0; dwV < dwV0 + dwN; dwV++) { float x = (float)psSrc[(i + 0) ^ 1]; float y = (float)psSrc[(i + 1) ^ 1]; float z = (float)psSrc[(i + 2) ^ 1]; //uint16 wFlags = CRender::g_pRender->m_dwVecFlags[dwV]; //(uint16)psSrc[3^0x1]; uint16 wA = psSrc[(i + 3) ^ 1]; uint16 wB = psSrc[(i + 4) ^ 1]; uint8 a = wA>>8; uint8 b = (uint8)wA; uint8 c = wB>>8; uint8 d = (uint8)wB; XVECTOR4 & t = g_vecProjected[dwV]; LOG_UCODE(" #%02d Pos: {% 6f,% 6f,% 6f} Extra: %02x %02x %02x %02x (transf: {% 6f,% 6f,% 6f})", dwV, x, y, z, a, b, c, d, t.x, t.y, t.z ); i+=5; } uint16 * pwSrc = (uint16 *)(g_pRDRAMu8 + dwAddr); i = 0; for (dwV = dwV0; dwV < dwV0 + dwN; dwV++) { LOG_UCODE(" #%02d %04x %04x %04x %04x %04x", dwV, pwSrc[(i + 0) ^ 1], pwSrc[(i + 1) ^ 1], pwSrc[(i + 2) ^ 1], pwSrc[(i + 3) ^ 1], pwSrc[(i + 4) ^ 1]); i += 5; } #endif // DEBUGGER } void DLParser_Set_Addr_Ucode6(Gfx *gfx) { gRSP.dwDKRMatrixAddr = (gfx->words.w0)&0x00FFFFFF; gRSP.dwDKRVtxAddr = (gfx->words.w1)&0x00FFFFFF; gRSP.DKRVtxCount=0; } void RSP_Vtx_WRUS(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwLength = ((gfx->words.w0))&0xFFFF; uint32 dwN= (dwLength + 1) / 0x210; //uint32 dwN= (dwLength >> 9); //uint32 dwV0 = (((gfx->words.w0)>>16)&0x3f)/5; uint32 dwV0 = (((gfx->words.w0)>>16)&0xFF)/5; LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d, Length: 0x%04x", dwAddr, dwV0, dwN, dwLength); if (dwV0 >= 32) dwV0 = 31; if ((dwV0 + dwN) > 32) { TRACE0("Warning, attempting to load into invalid vertex positions"); dwN = 32 - dwV0; } ProcessVertexData(dwAddr, dwV0, dwN); status.dwNumVertices += dwN; DisplayVertexInfo(dwAddr, dwV0, dwN); } void RSP_Vtx_ShadowOfEmpire(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwLength = ((gfx->words.w0))&0xFFFF; uint32 dwN= (((gfx->words.w0) >> 4) & 0xFFF) / 33 + 1; uint32 dwV0 = 0; LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d, Length: 0x%04x", dwAddr, dwV0, dwN, dwLength); if (dwV0 >= 32) dwV0 = 31; if ((dwV0 + dwN) > 32) { TRACE0("Warning, attempting to load into invalid vertex positions"); dwN = 32 - dwV0; } ProcessVertexData(dwAddr, dwV0, dwN); status.dwNumVertices += dwN; DisplayVertexInfo(dwAddr, dwV0, dwN); } void RSP_DL_In_MEM_DKR(Gfx *gfx) { // This cmd is likely to execute number of ucode at the given address uint32 dwAddr = (gfx->words.w1);//RSPSegmentAddr((gfx->words.w1)); { gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = (((gfx->words.w0)>>16)&0xFF); } } uint16 ConvertYUVtoR5G5B5X1(int y, int u, int v) { float r = y + (1.370705f * (v-128)); float g = y - (0.698001f * (v-128)) - (0.337633f * (u-128)); float b = y + (1.732446f * (u-128)); r *= 0.125f; g *= 0.125f; b *= 0.125f; //clipping the result if (r > 32) r = 32; if (g > 32) g = 32; if (b > 32) b = 32; if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0; uint16 c = (uint16)(((uint16)(r) << 11) | ((uint16)(g) << 6) | ((uint16)(b) << 1) | 1); return c; } void TexRectToN64FrameBuffer_YUV_16b(uint32 x0, uint32 y0, uint32 width, uint32 height) { // Convert YUV image at TImg and Copy the texture into the N64 RDRAM framebuffer memory uint32 n64CIaddr = g_CI.dwAddr; uint32 n64CIwidth = g_CI.dwWidth; for (uint32 y = 0; y < height; y++) { uint32* pN64Src = (uint32*)(g_pRDRAMu8+(g_TI.dwAddr&(g_dwRamSize-1)))+y*(g_TI.dwWidth>>1); uint16* pN64Dst = (uint16*)(g_pRDRAMu8+(n64CIaddr&(g_dwRamSize-1)))+(y+y0)*n64CIwidth; for (uint32 x = 0; x < width; x+=2) { uint32 val = *pN64Src++; int y0 = (uint8)val&0xFF; int v = (uint8)(val>>8)&0xFF; int y1 = (uint8)(val>>16)&0xFF; int u = (uint8)(val>>24)&0xFF; pN64Dst[x+x0] = ConvertYUVtoR5G5B5X1(y0,u,v); pN64Dst[x+x0+1] = ConvertYUVtoR5G5B5X1(y1,u,v); } } } extern uObjMtxReal gObjMtxReal; void DLParser_OgreBatter64BG(Gfx *gfx) { #ifdef DEBUGGER uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjTxSprite *ptr = (uObjTxSprite*)(g_pRDRAMu8+dwAddr); #endif PrepareTextures(); CTexture *ptexture = g_textures[0].m_pCTexture; TexRectToN64FrameBuffer_16b( (uint32)gObjMtxReal.X, (uint32)gObjMtxReal.Y, ptexture->m_dwWidth, ptexture->m_dwHeight, gRSP.curTile); #ifdef DEBUGGER CRender::g_pRender->DrawSpriteR(*ptr, false); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((pauseAtNext && (eventToPause==NEXT_OBJ_TXT_CMD|| eventToPause==NEXT_FLUSH_TRI)), {DebuggerAppendMsg("OgreBatter 64 BG: Addr=%08X\n", dwAddr);}); #endif } void DLParser_Bomberman2TextRect(Gfx *gfx) { // Bomberman 64 - The Second Attack! (U) [!] // The 0x02 cmd, list a TexRect cmd if( options.enableHackForGames == HACK_FOR_OGRE_BATTLE && gRDP.tiles[7].dwFormat == TXT_FMT_YUV ) { TexRectToN64FrameBuffer_YUV_16b( (uint32)gObjMtxReal.X, (uint32)gObjMtxReal.Y, 16, 16); //DLParser_OgreBatter64BG((gfx->words.w0), (gfx->words.w1)); return; } uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjSprite *info = (uObjSprite*)(g_pRDRAMu8+dwAddr); uint32 dwTile = gRSP.curTile; PrepareTextures(); uObjTxSprite drawinfo; memcpy( &(drawinfo.sprite), info, sizeof(uObjSprite)); CRender::g_pRender->DrawSpriteR(drawinfo, false, dwTile, 0, 0, drawinfo.sprite.imageW/32, drawinfo.sprite.imageH/32); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((pauseAtNext && (eventToPause==NEXT_TRIANGLE|| eventToPause==NEXT_FLUSH_TRI)), { DebuggerAppendMsg("Bomberman 64 - TextRect: Addr=%08X\n", dwAddr); dwAddr &= (g_dwRamSize-1); DebuggerAppendMsg("%08X-%08X-%08X-%08X-%08X-%08X\n", RDRAM_UWORD(dwAddr), RDRAM_UWORD(dwAddr+4), RDRAM_UWORD(dwAddr+8), RDRAM_UWORD(dwAddr+12), RDRAM_UWORD(dwAddr+16), RDRAM_UWORD(dwAddr+20) ); } ); } void RSP_MoveWord_DKR(Gfx *gfx) { SP_Timing(RSP_GBI1_MoveWord); uint32 dwNumLights; switch ((gfx->words.w0) & 0xFF) { case RSP_MOVE_WORD_NUMLIGHT: dwNumLights = (gfx->words.w1)&0x7; LOG_UCODE(" RSP_MOVE_WORD_NUMLIGHT: Val:%d", dwNumLights); gRSP.ambientLightIndex = dwNumLights; SetNumLights(dwNumLights); //gRSP.DKRBillBoard = (gfx->words.w1)&0x1 ? true : false; gRSP.DKRBillBoard = (gfx->words.w1)&0x7 ? true : false; LOG_UCODE(" gRSP.DKRBillBoard = %d", gRSP.DKRBillBoard); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_MATRIX_CMD, {DebuggerAppendMsg("DKR Moveword, select gRSP.DKRBillBoard %s, cmd0=%08X, cmd1=%08X", gRSP.DKRBillBoard?"true":"false", (gfx->words.w0), (gfx->words.w1));}); break; case RSP_MOVE_WORD_LIGHTCOL: gRSP.DKRCMatrixIndex = ((gfx->words.w1)>>6)&7; //gRSP.DKRCMatrixIndex = ((gfx->words.w1)>>6)&3; LOG_UCODE(" gRSP.DKRCMatrixIndex = %d", gRSP.DKRCMatrixIndex); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_MATRIX_CMD, {DebuggerAppendMsg("DKR Moveword, select matrix %d, cmd0=%08X, cmd1=%08X", gRSP.DKRCMatrixIndex, (gfx->words.w0), (gfx->words.w1));}); break; default: RSP_GBI1_MoveWord(gfx); break; } } void RSP_DMA_Tri_DKR(Gfx *gfx) { BOOL bTrisAdded = FALSE; uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 flag = ((gfx->words.w0) & 0xFF0000) >> 16; if (flag&1) CRender::g_pRender->SetCullMode(false,true); else CRender::g_pRender->SetCullMode(false,false); uint32 dwNum = (((gfx->words.w0) & 0xFFF0) >>4 ); uint32 * pData = (uint32*)&g_pRDRAMu32[dwAddr/4]; if( dwAddr+16*dwNum >= g_dwRamSize ) { TRACE0("DMATRI invalid memory pointer"); return; } TRI_DUMP(TRACE2("DMATRI, addr=%08X, Cmd0=%08X\n", dwAddr, (gfx->words.w0))); status.primitiveType = PRIM_DMA_TRI; for (uint32 i = 0; i < dwNum; i++) { LOG_UCODE(" 0x%08x: %08x %08x %08x %08x", dwAddr + i*16, pData[0], pData[1], pData[2], pData[3]); uint32 dwInfo = pData[0]; uint32 dwV0 = (dwInfo >> 16) & 0x1F; uint32 dwV1 = (dwInfo >> 8) & 0x1F; uint32 dwV2 = (dwInfo ) & 0x1F; TRI_DUMP(TRACE5("DMATRI: %d, %d, %d (%08X-%08X)", dwV0,dwV1,dwV2,(gfx->words.w0),(gfx->words.w1))); //if (IsTriangleVisible(dwV0, dwV1, dwV2)) { DEBUG_DUMP_VERTEXES("DmaTri", dwV0, dwV1, dwV2); LOG_UCODE(" Tri: %d,%d,%d", dwV0, dwV1, dwV2); if (!bTrisAdded )//&& CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } // Generate texture coordinates short s0 = ((short)(pData[1]>>16)); short t0 = ((short)(pData[1]&0xFFFF)); short s1 = ((short)(pData[2]>>16)); short t1 = ((short)(pData[2]&0xFFFF)); short s2 = ((short)(pData[3]>>16)); short t2 = ((short)(pData[3]&0xFFFF)); TRI_DUMP( { DebuggerAppendMsg(" (%d,%d), (%d,%d), (%d,%d)",s0,t0,s1,t1,s2,t2); DebuggerAppendMsg(" (%08X), (%08X), (%08X), (%08X)",pData[0],pData[1],pData[2],pData[3]); }); CRender::g_pRender->SetVtxTextureCoord(dwV0, s0, t0); CRender::g_pRender->SetVtxTextureCoord(dwV1, s1, t1); CRender::g_pRender->SetVtxTextureCoord(dwV2, s2, t2); bTrisAdded = true; PrepareTriangle(dwV0, dwV1, dwV2); } pData += 4; } if (bTrisAdded) { CRender::g_pRender->SetCombinerAndBlender(); CRender::g_pRender->DrawTriangles(); } gRSP.DKRVtxCount=0; } uint32 dwPDCIAddr = 0; void ProcessVertexDataPD(uint32 dwAddr, uint32 dwV0, uint32 dwNum); void RSP_Vtx_PD(Gfx *gfx) { SP_Timing(RSP_GBI0_Vtx); uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwV0 = ((gfx->words.w0)>>16)&0x0F; uint32 dwN = (((gfx->words.w0)>>20)&0x0F)+1; //uint32 dwLength = ((gfx->words.w0))&0xFFFF; LOG_UCODE(" Address 0x%08x, v0: %d, Num: %d", dwAddr, dwV0, dwN); ProcessVertexDataPD(dwAddr, dwV0, dwN); status.dwNumVertices += dwN; } void RSP_Set_Vtx_CI_PD(Gfx *gfx) { // Color index buf address dwPDCIAddr = RSPSegmentAddr((gfx->words.w1)); } void RSP_Tri4_PD(Gfx *gfx) { uint32 w0 = gfx->words.w0; uint32 w1 = gfx->words.w1; status.primitiveType = PRIM_TRI2; // While the next command pair is Tri2, add vertices uint32 dwPC = gDlistStack[gDlistStackPointer].pc; BOOL bTrisAdded = FALSE; do { uint32 dwFlag = (w0>>16)&0xFF; LOG_UCODE(" PD Tri4: 0x%08x 0x%08x Flag: 0x%02x", w0, w1, dwFlag); BOOL bVisible; for( uint32 i=0; i<4; i++) { uint32 v0 = (w1>>(4+(i<<3))) & 0xF; uint32 v1 = (w1>>( (i<<3))) & 0xF; uint32 v2 = (w0>>( (i<<2))) & 0xF; bVisible = IsTriangleVisible(v0, v2, v1); LOG_UCODE(" (%d, %d, %d) %s", v0, v1, v2, bVisible ? "": "(clipped)"); if (bVisible) { DEBUG_DUMP_VERTEXES("Tri4_PerfectDark 1/2", v0, v1, v2); if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } bTrisAdded = true; PrepareTriangle(v0, v2, v1); } } w0 = *(uint32 *)(g_pRDRAMu8 + dwPC+0); w1 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && (w0>>24) == (uint8)RSP_TRI2); #else } while ((w0>>24) == (uint8)RSP_TRI2); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->SetCombinerAndBlender(); CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at PD Tri4")); } void DLParser_Tri4_Conker(Gfx *gfx) { uint32 w0 = gfx->words.w0; uint32 w1 = gfx->words.w1; status.primitiveType = PRIM_TRI2; // While the next command pair is Tri2, add vertices uint32 dwPC = gDlistStack[gDlistStackPointer].pc; BOOL bTrisAdded = FALSE; do { LOG_UCODE(" Conker Tri4: 0x%08x 0x%08x", w0, w1); uint32 idx[12]; idx[0] = (w1 )&0x1F; idx[1] = (w1>> 5)&0x1F; idx[2] = (w1>>10)&0x1F; idx[3] = (w1>>15)&0x1F; idx[4] = (w1>>20)&0x1F; idx[5] = (w1>>25)&0x1F; idx[6] = (w0 )&0x1F; idx[7] = (w0>> 5)&0x1F; idx[8] = (w0>>10)&0x1F; idx[ 9] = (((w0>>15)&0x7)<<2)|(w1>>30); idx[10] = (w0>>18)&0x1F; idx[11] = (w0>>23)&0x1F; BOOL bVisible; for( uint32 i=0; i<4; i++) { uint32 v0=idx[i*3 ]; uint32 v1=idx[i*3+1]; uint32 v2=idx[i*3+2]; bVisible = IsTriangleVisible(v0, v1, v2); LOG_UCODE(" (%d, %d, %d) %s", v0, v1, v2, bVisible ? "": "(clipped)"); if (bVisible) { DEBUG_DUMP_VERTEXES("Tri4 Conker:", v0, v1, v2); if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled()) { PrepareTextures(); InitVertexTextureConstants(); } bTrisAdded = true; PrepareTriangle(v0, v1, v2); } } w0 = *(uint32 *)(g_pRDRAMu8 + dwPC+0); w1 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); dwPC += 8; #ifdef DEBUGGER } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && (w0>>28) == 1 ); #else } while ((w0>>28) == 1); #endif gDlistStack[gDlistStackPointer].pc = dwPC-8; if (bTrisAdded) { CRender::g_pRender->SetCombinerAndBlender(); CRender::g_pRender->DrawTriangles(); } DEBUG_TRIANGLE(TRACE0("Pause at Conker Tri4")); } void RDP_GFX_Force_Vertex_Z_Conker(uint32 dwAddr) { VTX_DUMP( { s8 * pcBase = g_pRDRAMs8 + (dwAddr&(g_dwRamSize-1)); uint32 * pdwBase = (uint32 *)pcBase; for (int i = 0; i < 4; i++) { DebuggerAppendMsg(" %08x %08x %08x %08x", pdwBase[0], pdwBase[1], pdwBase[2], pdwBase[3]); pdwBase+=4; } }); dwConkerVtxZAddr = dwAddr; DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{TRACE0("Paused at RDP_GFX_Force_Matrix_Conker Cmd");}); } void DLParser_MoveMem_Conker(Gfx *gfx) { uint32 dwType = ((gfx->words.w0) ) & 0xFE; uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); if( dwType == RSP_GBI2_MV_MEM__MATRIX ) { LOG_UCODE(" DLParser_MoveMem_Conker"); RDP_GFX_Force_Vertex_Z_Conker(dwAddr); } else if( dwType == RSP_GBI2_MV_MEM__LIGHT ) { LOG_UCODE(" MoveMem Light Conker"); uint32 dwOffset2 = ((gfx->words.w0) >> 5) & 0x3FFF; uint32 dwLight=0xFF; if( dwOffset2 >= 0x30 ) { dwLight = (dwOffset2 - 0x30)/0x30; LOG_UCODE(" Light %d:", dwLight); RSP_MoveMemLight(dwLight, dwAddr); } else { // fix me //TRACE0("Check me in DLParser_MoveMem_Conker - MoveMem Light"); } DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_SET_LIGHT, { DebuggerAppendMsg("RSP_MoveMemLight: %d, Addr=%08X, cmd0=%08X", dwLight, dwAddr, (gfx->words.w0)); TRACE0("Pause after MoveMemLight"); }); } else { RSP_GBI2_MoveMem(gfx); } } extern void ProcessVertexDataConker(uint32 dwAddr, uint32 dwV0, uint32 dwNum); void RSP_Vtx_Conker(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwVEnd = (((gfx->words.w0) )&0xFFF)/2; uint32 dwN = (((gfx->words.w0)>>12)&0xFFF); uint32 dwV0 = dwVEnd - dwN; LOG_UCODE(" Vtx: Address 0x%08x, vEnd: %d, v0: %d, Num: %d", dwAddr, dwVEnd, dwV0, dwN); ProcessVertexDataConker(dwAddr, dwV0, dwN); status.dwNumVertices += dwN; DisplayVertexInfo(dwAddr, dwV0, dwN); } void DLParser_MoveWord_Conker(Gfx *gfx) { uint32 dwType = ((gfx->words.w0) >> 16) & 0xFF; if( dwType != RSP_MOVE_WORD_NUMLIGHT ) { RSP_GBI2_MoveWord(gfx); } else { uint32 dwNumLights = ((gfx->words.w1)/48); LOG_UCODE("Conker RSP_MOVE_WORD_NUMLIGHT: %d", dwNumLights); gRSP.ambientLightIndex = dwNumLights+1; SetNumLights(dwNumLights); DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_SET_LIGHT, { DebuggerAppendMsg("SetNumLights: %d", dwNumLights); TRACE0("Pause after SetNumLights"); }); } } void DLParser_Ucode8_0x0(Gfx *gfx) { LOG_UCODE("DLParser_Ucode8_0x0"); if( (gfx->words.w0) == 0 && (gfx->words.w1) ) { uint32 newaddr = RSPSegmentAddr((gfx->words.w1)); if( newaddr && newaddr < g_dwRamSize) { if( gDlistStackPointer < MAX_DL_STACK_SIZE-1 ) { gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = newaddr+8; // Always skip the first 2 entries gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; } else { DebuggerAppendMsg("Error, gDlistStackPointer overflow"); } } } else { LOG_UCODE("DLParser_Ucode8_0x0, skip 0x%08X, 0x%08x", (gfx->words.w0), (gfx->words.w1)); gDlistStack[gDlistStackPointer].pc += 8; } } uint32 Rogue_Squadron_Vtx_XYZ_Cmd; uint32 Rogue_Squadron_Vtx_XYZ_Addr; uint32 Rogue_Squadron_Vtx_Color_Cmd; uint32 Rogue_Squadron_Vtx_Color_Addr; uint32 GSBlkAddrSaves[100][2]; void ProcessVertexData_Rogue_Squadron(uint32 dwXYZAddr, uint32 dwColorAddr, uint32 dwXYZCmd, uint32 dwColorCmd); void DLParser_RS_Color_Buffer(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); if( dwAddr > g_dwRamSize ) { TRACE0("DL, addr is wrong"); dwAddr = (gfx->words.w1)&(g_dwRamSize-1); } Rogue_Squadron_Vtx_Color_Cmd = (gfx->words.w0); Rogue_Squadron_Vtx_Color_Addr = dwAddr; LOG_UCODE("Vtx_Color at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1)); #ifdef DEBUGGER if( pauseAtNext && (eventToPause == NEXT_VERTEX_CMD ) ) { DebuggerAppendMsg("Vtx_Color at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1)); if( dwAddr < g_dwRamSize ) { DumpHex(dwAddr, std::min(64, g_dwRamSize-dwAddr)); } } #endif ProcessVertexData_Rogue_Squadron(Rogue_Squadron_Vtx_XYZ_Addr, Rogue_Squadron_Vtx_Color_Addr, Rogue_Squadron_Vtx_XYZ_Cmd, Rogue_Squadron_Vtx_Color_Cmd); } void DLParser_RS_Vtx_Buffer(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); if( dwAddr > g_dwRamSize ) { TRACE0("DL, addr is wrong"); dwAddr = (gfx->words.w1)&(g_dwRamSize-1); } LOG_UCODE("Vtx_XYZ at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1)); Rogue_Squadron_Vtx_XYZ_Cmd = (gfx->words.w0); Rogue_Squadron_Vtx_XYZ_Addr = dwAddr; #ifdef DEBUGGER if( pauseAtNext && (eventToPause == NEXT_VERTEX_CMD ) ) { DebuggerAppendMsg("Vtx_XYZ at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1)); if( dwAddr < g_dwRamSize ) { DumpHex(dwAddr, std::min(64, g_dwRamSize-dwAddr)); } } #endif } void DLParser_RS_Block(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode 0x80 at PC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1)); } void DLParser_RS_MoveMem(Gfx *gfx) { //uint32 dwPC = gDlistStack[gDlistStackPointer].pc; //uint32 cmd1 = ((dwPC)&0x00FFFFFF)|0x80000000; RSP_GBI1_MoveMem(gfx); /* LOG_UCODE("RS_MoveMem", ((gfx->words.w0)>>24)); LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, dwCmd2, dwCmd3); dwPC+=8; uint32 dwCmd4 = *(uint32 *)(g_pRDRAMu8 + dwPC); uint32 dwCmd5 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, dwCmd4, dwCmd5); */ gDlistStack[gDlistStackPointer].pc += 16; //DEBUGGER_PAUSE_AND_DUMP(NEXT_SET_MODE_CMD, { // DebuggerAppendMsg("Pause after RS_MoveMem at: %08X\n", dwPC-8); //}); } void DLParser_RS_0xbe(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode %02X, skip 1", ((gfx->words.w0)>>24)); LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, dwCmd2, dwCmd3); gDlistStack[gDlistStackPointer].pc += 8; DEBUGGER_PAUSE_AND_DUMP(NEXT_SET_MODE_CMD, { DebuggerAppendMsg("Pause after RS_0xbe at: %08X\n", dwPC-8); DebuggerAppendMsg("\t0x%08x 0x%08x", (gfx->words.w0), (gfx->words.w1)); DebuggerAppendMsg("\t0x%08x 0x%08x", dwCmd2, dwCmd3); }); } void DLParser_Ucode8_EndDL(Gfx *gfx) { #ifdef DEBUGGER uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; #endif RDP_GFX_PopDL(); DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, DebuggerAppendMsg("PC=%08X: EndDL, return to %08X\n\n", dwPC, gDlistStack[gDlistStackPointer].pc)); } void DLParser_Ucode8_DL(Gfx *gfx) // DL Function Call { #ifdef DEBUGGER uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; #endif uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwAddr); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwAddr+4); if( dwAddr > g_dwRamSize ) { TRACE0("DL, addr is wrong"); dwAddr = (gfx->words.w1)&(g_dwRamSize-1); } // Detect looping /*if(gDlistStackPointer>0 ) { for( int i=0; i>24) == 0x80 ) { GSBlkAddrSaves[gDlistStackPointer][0] = dwCmd2; GSBlkAddrSaves[gDlistStackPointer][1] = dwCmd3; } DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, DebuggerAppendMsg("\nPC=%08X: Call DL at Address %08X - %08X, %08X\n\n", dwPC, dwAddr, dwCmd2, dwCmd3)); } void DLParser_Ucode8_JUMP(Gfx *gfx) // DL Function Call { if( ((gfx->words.w0)&0x00FFFFFF) == 0 ) { #ifdef DEBUGGER uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; #endif uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); if( dwAddr > g_dwRamSize ) { TRACE0("DL, addr is wrong"); dwAddr = (gfx->words.w1)&(g_dwRamSize-1); } #ifdef DEBUGGER uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwAddr); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwAddr+4); #endif gDlistStack[gDlistStackPointer].pc = dwAddr+8; // Jump to new address DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, DebuggerAppendMsg("\nPC=%08X: Jump to Address %08X - %08X, %08X\n\n", dwPC, dwAddr, dwCmd2, dwCmd3)); } else { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode 0x07 at PC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1)); } } void DLParser_Ucode8_Unknown(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode %02X at PC=%08X: 0x%08x 0x%08x\n", ((gfx->words.w0)>>24), dwPC, (gfx->words.w0), (gfx->words.w1)); } void DLParser_Unknown_Skip1(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode %02X, skip 1", ((gfx->words.w0)>>24)); gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1)); gDlistStack[gDlistStackPointer].pc += 8; } void DLParser_Unknown_Skip2(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode %02X, skip 2", ((gfx->words.w0)>>24)); gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1)); gDlistStack[gDlistStackPointer].pc += 16; } void DLParser_Unknown_Skip3(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode %02X, skip 3", ((gfx->words.w0)>>24)); gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1)); gDlistStack[gDlistStackPointer].pc += 24; } void DLParser_Unknown_Skip4(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode %02X, skip 4", ((gfx->words.w0)>>24)); gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); dwPC+=8; gfx++; LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1)); gDlistStack[gDlistStackPointer].pc += 32; } void DLParser_Ucode8_0x05(Gfx *gfx) { // Be careful, 0x05 is variable length ucode /* 0028E4E0: 05020088, 04D0000F - Reserved1 0028E4E8: 6BDC0306, 00000000 - G_NOTHING 0028E4F0: 05010130, 01B0000F - Reserved1 0028E4F8: 918A01CA, 1EC5FF3B - G_NOTHING 0028E500: 05088C68, F5021809 - Reserved1 0028E508: 04000405, 00000000 - RSP_VTX 0028E510: 102ECE60, 202F2AA0 - G_NOTHING 0028E518: 05088C90, F5021609 - Reserved1 0028E520: 04050405, F0F0F0F0 - RSP_VTX 0028E528: 102ED0C0, 202F2D00 - G_NOTHING 0028E530: B5000000, 00000000 - RSP_LINE3D 0028E538: 8028E640, 8028E430 - G_NOTHING 0028E540: 00000000, 00000000 - RSP_SPNOOP */ if((gfx->words.w1) == 0) return; else DLParser_Unknown_Skip4(gfx); } void DLParser_Ucode8_0xb4(Gfx *gfx) { #ifdef DEBUGGER uint32 dwPC = gDlistStack[gDlistStackPointer].pc; #endif if(((gfx->words.w0)&0xFF) == 0x06) DLParser_Unknown_Skip3(gfx); else if(((gfx->words.w0)&0xFF) == 0x04) DLParser_Unknown_Skip1(gfx); else if(((gfx->words.w0)&0xFFF) == 0x600) DLParser_Unknown_Skip3(gfx); else { #ifdef DEBUGGER if(pauseAtNext) { DebuggerAppendMsg("ucode 0xb4 at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1)); } #endif DLParser_Unknown_Skip3(gfx); } } void DLParser_Ucode8_0xb5(Gfx *gfx) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode 0xB5 at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1)); uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC+8); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+12); LOG_UCODE(" : 0x%08x 0x%08x\n", dwCmd2, dwCmd3); //if( dwCmd2 == 0 && dwCmd3 == 0 ) { DLParser_Ucode8_EndDL(gfx); // Check me return; } gDlistStack[gDlistStackPointer].pc += 8; return; if( GSBlkAddrSaves[gDlistStackPointer][0] == 0 || GSBlkAddrSaves[gDlistStackPointer][1] == 0 ) { #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_DLIST) { DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, no next blk\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); } #endif DLParser_Ucode8_EndDL(gfx); // Check me return; } if( ((dwCmd2>>24)!=0x80 && (dwCmd2>>24)!=0x00 ) || ((dwCmd3>>24)!=0x80 && (dwCmd3>>24)!=0x00 ) ) { #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_DLIST) { DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, Unknown\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); } #endif DLParser_Ucode8_EndDL(gfx); // Check me return; } if( (dwCmd2>>24)!= (dwCmd3>>24) ) { #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_DLIST) { DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, Unknown\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); } #endif DLParser_Ucode8_EndDL(gfx); // Check me return; } if( (dwCmd2>>24)==0x80 && (dwCmd3>>24)==0x80 ) { if( dwCmd2 < dwCmd3 ) { // All right, the next block is not ucode, but data #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_DLIST) { DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, next blk is data\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); } #endif DLParser_Ucode8_EndDL(gfx); // Check me return; } uint32 dwCmd4 = *(uint32 *)(g_pRDRAMu8 + (dwCmd2&0x00FFFFFF)); uint32 dwCmd5 = *(uint32 *)(g_pRDRAMu8 + (dwCmd2&0x00FFFFFF)+4); uint32 dwCmd6 = *(uint32 *)(g_pRDRAMu8 + (dwCmd3&0x00FFFFFF)); uint32 dwCmd7 = *(uint32 *)(g_pRDRAMu8 + (dwCmd3&0x00FFFFFF)+4); if( (dwCmd4>>24) != 0x80 || (dwCmd5>>24) != 0x80 || (dwCmd6>>24) != 0x80 || (dwCmd7>>24) != 0x80 || dwCmd4 < dwCmd5 || dwCmd6 < dwCmd7 ) { // All right, the next block is not ucode, but data #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_DLIST) { DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, next blk is data\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); DebuggerAppendMsg("%08X, %08X %08X,%08X\n", dwCmd4, dwCmd5, dwCmd6, dwCmd7); } #endif DLParser_Ucode8_EndDL(gfx); // Check me return; } gDlistStack[gDlistStackPointer].pc += 8; DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, continue\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); ); return; } else if( (dwCmd2>>24)==0x00 && (dwCmd3>>24)==0x00 ) { #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_DLIST) { DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, next blk is data\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); } #endif DLParser_Ucode8_EndDL(gfx); // Check me return; } else if( (dwCmd2>>24)==0x00 && (dwCmd3>>24)==0x00 ) { dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC+16); dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+20); if( (dwCmd2>>24)==0x80 && (dwCmd3>>24)==0x80 && dwCmd2 < dwCmd3 ) { // All right, the next block is not ucode, but data #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_DLIST) { DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, next blk is data\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); } #endif DLParser_Ucode8_EndDL(gfx); // Check me return; } else { gDlistStack[gDlistStackPointer].pc += 8; DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, continue\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3) ); return; } } #ifdef DEBUGGER uint32 dwAddr1 = RSPSegmentAddr(dwCmd2); uint32 dwAddr2 = RSPSegmentAddr(dwCmd3); if( (gfx->words.w1) != 0 ) { DebuggerAppendMsg("!!!! PC=%08X: 0xB5 - %08X : %08X, %08X\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3); } #endif DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, continue\n", dwPC, (gfx->words.w1), dwAddr1, dwAddr2) ); return; } void DLParser_Ucode8_0xbc(Gfx *gfx) { if( ((gfx->words.w0)&0xFFF) == 0x58C ) { DLParser_Ucode8_DL(gfx); } else { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; LOG_UCODE("ucode 0xBC at PC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1)); } } void DLParser_Ucode8_0xbd(Gfx *gfx) { /* 00359A68: BD000000, DB5B0077 - RSP_POPMTX 00359A70: C8C0A000, 00240024 - RDP_TriFill 00359A78: 01000100, 00000000 - RSP_MTX 00359A80: BD000501, DB5B0077 - RSP_POPMTX 00359A88: C8C0A000, 00240024 - RDP_TriFill 00359A90: 01000100, 00000000 - RSP_MTX 00359A98: BD000A02, DB5B0077 - RSP_POPMTX 00359AA0: C8C0A000, 00240024 - RDP_TriFill 00359AA8: 01000100, 00000000 - RSP_MTX 00359AB0: BD000F04, EB6F0087 - RSP_POPMTX 00359AB8: C8C0A000, 00280028 - RDP_TriFill 00359AC0: 01000100, 00000000 - RSP_MTX 00359AC8: BD001403, DB5B0077 - RSP_POPMTX 00359AD0: C8C0A000, 00240024 - RDP_TriFill 00359AD8: 01000100, 00000000 - RSP_MTX 00359AE0: B5000000, 00000000 - RSP_LINE3D 00359AE8: 1A000000, 16000200 - G_NOTHING */ if( (gfx->words.w1) != 0 ) { DLParser_Unknown_Skip2(gfx); return; } uint32 dwPC = gDlistStack[gDlistStackPointer].pc; LOG_UCODE("ucode 0xbd at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1)); } void DLParser_Ucode8_0xbf(Gfx *gfx) { if( ((gfx->words.w0)&0xFF) == 0x02 ) DLParser_Unknown_Skip3(gfx); else DLParser_Unknown_Skip1(gfx); } void PD_LoadMatrix_0xb4(uint32 addr) { const float fRecip = 1.0f / 65536.0f; uint32 data[16]; data[0] = *(uint32*)(g_pRDRAMu8+addr+4+ 0); data[1] = *(uint32*)(g_pRDRAMu8+addr+4+ 8); data[2] = *(uint32*)(g_pRDRAMu8+addr+4+16); data[3] = *(uint32*)(g_pRDRAMu8+addr+4+24); data[8] = *(uint32*)(g_pRDRAMu8+addr+4+32); data[9] = *(uint32*)(g_pRDRAMu8+addr+4+40); data[10] = *(uint32*)(g_pRDRAMu8+addr+4+48); data[11] = *(uint32*)(g_pRDRAMu8+addr+4+56); data[4] = *(uint32*)(g_pRDRAMu8+addr+4+ 0+64); data[5] = *(uint32*)(g_pRDRAMu8+addr+4+ 8+64); data[6] = *(uint32*)(g_pRDRAMu8+addr+4+16+64); data[7] = *(uint32*)(g_pRDRAMu8+addr+4+24+64); data[12] = *(uint32*)(g_pRDRAMu8+addr+4+32+64); data[13] = *(uint32*)(g_pRDRAMu8+addr+4+40+64); data[14] = *(uint32*)(g_pRDRAMu8+addr+4+48+64); data[15] = *(uint32*)(g_pRDRAMu8+addr+4+56+64); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { int hi = *(short *)((unsigned char*)data + (((i<<3)+(j<<1) )^0x2)); int lo = *(uint16*)((unsigned char*)data + (((i<<3)+(j<<1) + 32)^0x2)); matToLoad.m[i][j] = (float)((hi<<16) | lo) * fRecip; } } #ifdef DEBUGGER LOG_UCODE( " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n", matToLoad.m[0][0], matToLoad.m[0][1], matToLoad.m[0][2], matToLoad.m[0][3], matToLoad.m[1][0], matToLoad.m[1][1], matToLoad.m[1][2], matToLoad.m[1][3], matToLoad.m[2][0], matToLoad.m[2][1], matToLoad.m[2][2], matToLoad.m[2][3], matToLoad.m[3][0], matToLoad.m[3][1], matToLoad.m[3][2], matToLoad.m[3][3]); #endif // DEBUGGER } void DLParser_RDPHalf_1_0xb4_GoldenEye(Gfx *gfx) { SP_Timing(RSP_GBI1_RDPHalf_1); if( ((gfx->words.w1)>>24) == 0xce ) { PrepareTextures(); CRender::g_pRender->SetCombinerAndBlender(); uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction //PD_LoadMatrix_0xb4(dwPC + 8*16 - 8); uint32 dw1 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*0+4); //uint32 dw2 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*1+4); //uint32 dw3 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*2+4); //uint32 dw4 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*3+4); //uint32 dw5 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*4+4); //uint32 dw6 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*5+4); //uint32 dw7 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*6+4); uint32 dw8 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*7+4); uint32 dw9 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*8+4); uint32 r = (dw8>>16)&0xFF; uint32 g = (dw8 )&0xFF; uint32 b = (dw9>>16)&0xFF; uint32 a = (dw9 )&0xFF; uint32 color = COLOR_RGBA(r, g, b, a); //int x0 = 0; //int x1 = gRDP.scissor.right; int x0 = gRSP.nVPLeftN; int x1 = gRSP.nVPRightN; int y0 = int(dw1&0xFFFF)/4; int y1 = int(dw1>>16)/4; float xscale = g_textures[0].m_pCTexture->m_dwWidth / (float)(x1-x0); float yscale = g_textures[0].m_pCTexture->m_dwHeight / (float)(y1-y0); //float fs0 = (short)(dw3&0xFFFF)/32768.0f*g_textures[0].m_pCTexture->m_dwWidth; //float ft0 = (short)(dw3>>16)/32768.0f*256; CRender::g_pRender->TexRect(x0,y0,x1,y1,0,0,xscale,yscale,true,color); gDlistStack[gDlistStackPointer].pc += 312; #ifdef DEBUGGER if( logUcodes) { dwPC -= 8; LOG_UCODE("GoldenEye Sky at PC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1)); uint32 *ptr = (uint32 *)(g_pRDRAMu8 + dwPC); for( int i=0; i<21; i++, dwPC+=16,ptr+=4 ) { LOG_UCODE("%08X: %08X %08X %08X %08X", dwPC, ptr[0], ptr[1], ptr[2], ptr[3]); } } #endif DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_FLUSH_TRI, { TRACE0("Pause after Golden Sky Drawing\n"); }); } } void DLParser_RSP_DL_WorldDriver(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); if( dwAddr > g_dwRamSize ) { RSP_RDP_NOIMPL("Error: DL addr = %08X out of range, PC=%08X", dwAddr, gDlistStack[gDlistStackPointer].pc ); dwAddr &= (g_dwRamSize-1); DebuggerPauseCountN( NEXT_DLIST ); } LOG_UCODE(" WorldDriver DisplayList 0x%08x", dwAddr); gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = dwAddr; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; LOG_UCODE("Level=%d", gDlistStackPointer+1); LOG_UCODE("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); } void DLParser_RSP_Pop_DL_WorldDriver(Gfx *gfx) { RDP_GFX_PopDL(); } void DLParser_RSP_Last_Legion_0x80(Gfx *gfx) { gDlistStack[gDlistStackPointer].pc += 16; LOG_UCODE("DLParser_RSP_Last_Legion_0x80"); } void DLParser_RSP_Last_Legion_0x00(Gfx *gfx) { LOG_UCODE("DLParser_RSP_Last_Legion_0x00"); gDlistStack[gDlistStackPointer].pc += 16; if( (gfx->words.w0) == 0 && (gfx->words.w1) ) { uint32 newaddr = RSPSegmentAddr((gfx->words.w1)); if( newaddr >= g_dwRamSize ) { RDP_GFX_PopDL(); return; } //uint32 dw1 = *(uint32 *)(g_pRDRAMu8 + newaddr+8*0+4); uint32 pc1 = *(uint32 *)(g_pRDRAMu8 + newaddr+8*1+4); uint32 pc2 = *(uint32 *)(g_pRDRAMu8 + newaddr+8*4+4); pc1 = RSPSegmentAddr(pc1); pc2 = RSPSegmentAddr(pc2); if( pc1 && pc1 != 0xffffff && pc1 < g_dwRamSize) { // Need to call both DL gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = pc1; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; } if( pc2 && pc2 != 0xffffff && pc2 < g_dwRamSize ) { gDlistStackPointer++; gDlistStack[gDlistStackPointer].pc = pc2; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; } } else if( (gfx->words.w1) == 0 ) { RDP_GFX_PopDL(); } else { // (gfx->words.w0) != 0 RSP_RDP_Nothing(gfx); RDP_GFX_PopDL(); } } void DLParser_TexRect_Last_Legion(Gfx *gfx) { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); status.primitiveType = PRIM_TEXTRECT; // This command used 128bits, and not 64 bits. This means that we have to look one // Command ahead in the buffer, and update the PC. uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC); uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4); gDlistStack[gDlistStackPointer].pc += 8; LOG_UCODE("0x%08x: %08x %08x", dwPC, *(uint32 *)(g_pRDRAMu8 + dwPC+0), *(uint32 *)(g_pRDRAMu8 + dwPC+4)); uint32 dwXH = (((gfx->words.w0)>>12)&0x0FFF)/4; uint32 dwYH = (((gfx->words.w0) )&0x0FFF)/4; uint32 tileno = ((gfx->words.w1)>>24)&0x07; uint32 dwXL = (((gfx->words.w1)>>12)&0x0FFF)/4; uint32 dwYL = (((gfx->words.w1) )&0x0FFF)/4; if( (int)dwXL >= gRDP.scissor.right || (int)dwYL >= gRDP.scissor.bottom || (int)dwXH < gRDP.scissor.left || (int)dwYH < gRDP.scissor.top ) { // Clipping return; } uint16 uS = (uint16)( dwCmd2>>16)&0xFFFF; uint16 uT = (uint16)( dwCmd2 )&0xFFFF; short s16S = *(short*)(&uS); short s16T = *(short*)(&uT); uint16 uDSDX = (uint16)(( dwCmd3>>16)&0xFFFF); uint16 uDTDY = (uint16)(( dwCmd3 )&0xFFFF); short s16DSDX = *(short*)(&uDSDX); short s16DTDY = *(short*)(&uDTDY); uint32 curTile = gRSP.curTile; ForceMainTextureIndex(tileno); float fS0 = s16S / 32.0f; float fT0 = s16T / 32.0f; float fDSDX = s16DSDX / 1024.0f; float fDTDY = s16DTDY / 1024.0f; uint32 cycletype = gRDP.otherMode.cycle_type; if (cycletype == CYCLE_TYPE_COPY) { fDSDX /= 4.0f; // In copy mode 4 pixels are copied at once. dwXH++; dwYH++; } else if (cycletype == CYCLE_TYPE_FILL) { dwXH++; dwYH++; } if( fDSDX == 0 ) fDSDX = 1; if( fDTDY == 0 ) fDTDY = 1; float fS1 = fS0 + (fDSDX * (dwXH - dwXL)); float fT1 = fT0 + (fDTDY * (dwYH - dwYL)); LOG_UCODE(" Tile:%d Screen(%d,%d) -> (%d,%d)", tileno, dwXL, dwYL, dwXH, dwYH); LOG_UCODE(" Tex:(%#5f,%#5f) -> (%#5f,%#5f) (DSDX:%#5f DTDY:%#5f)", fS0, fT0, fS1, fT1, fDSDX, fDTDY); LOG_UCODE(""); float t0u0 = (fS0-gRDP.tiles[tileno].hilite_sl) * gRDP.tiles[tileno].fShiftScaleS; float t0v0 = (fT0-gRDP.tiles[tileno].hilite_tl) * gRDP.tiles[tileno].fShiftScaleT; float t0u1 = t0u0 + (fDSDX * (dwXH - dwXL))*gRDP.tiles[tileno].fShiftScaleS; float t0v1 = t0v0 + (fDTDY * (dwYH - dwYL))*gRDP.tiles[tileno].fShiftScaleT; if( dwXL==0 && dwYL==0 && dwXH==windowSetting.fViWidth-1 && dwYH==windowSetting.fViHeight-1 && t0u0 == 0 && t0v0==0 && t0u1==0 && t0v1==0 ) { //Using TextRect to clear the screen } else { if( status.bHandleN64RenderTexture && //status.bDirectWriteIntoRDRAM && g_pRenderTextureInfo->CI_Info.dwFormat == gRDP.tiles[tileno].dwFormat && g_pRenderTextureInfo->CI_Info.dwSize == gRDP.tiles[tileno].dwSize && gRDP.tiles[tileno].dwFormat == TXT_FMT_CI && gRDP.tiles[tileno].dwSize == TXT_SIZE_8b ) { if( options.enableHackForGames == HACK_FOR_YOSHI ) { // Hack for Yoshi background image PrepareTextures(); TexRectToFrameBuffer_8b(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_FLUSH_TRI || eventToPause == NEXT_TEXTRECT), { DebuggerAppendMsg("TexRect: tile=%d, X0=%d, Y0=%d, X1=%d, Y1=%d,\nfS0=%f, fT0=%f, ScaleS=%f, ScaleT=%f\n", gRSP.curTile, dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY); DebuggerAppendMsg("Pause after TexRect for Yoshi\n"); }); } else { if( frameBufferOptions.bUpdateCIInfo ) { PrepareTextures(); TexRectToFrameBuffer_8b(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno); } if( !status.bDirectWriteIntoRDRAM ) { CRender::g_pRender->TexRect(dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY); status.dwNumTrisRendered += 2; } } } else { CRender::g_pRender->TexRect(dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY); status.bFrameBufferDrawnByTriangles = true; status.dwNumTrisRendered += 2; } } if( status.bHandleN64RenderTexture ) g_pRenderTextureInfo->maxUsedHeight = std::max(g_pRenderTextureInfo->maxUsedHeight,(int)dwYH); ForceMainTextureIndex(curTile); } mupen64plus-video-rice-src-2.6.0/src/RSP_GBI_Sprite2D.h000066400000000000000000000124321464507324400223460ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // Sprite2D Ucodes #include "Render.h" Sprite2DInfo g_Sprite2DInfo; uint32 g_SavedUcode=1; void RSP_GBI_Sprite2DBase(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); dwAddr &= (g_dwRamSize-1); //RSP_RDP_NOIMPL("RDP: Sprite2D (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); g_Sprite2DInfo.spritePtr = (SpriteStruct *)(g_pRDRAMs8+dwAddr); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_SPRITE_2D, {DebuggerAppendMsg("Pause after Sprite2DBase: Addr=%08X\n", dwAddr);}); } typedef struct{ uint32 SourceImagePointer; uint32 TlutPointer; short SubImageWidth; short Stride; char SourceImageBitSize; char SourceImageType; short SubImageHeight; short scaleY; short scaleX; short SourceImageOffsetS; char dummy1[2]; short px; short SourceImageOffsetT; char dummy2[2]; short py; } PuzzleMasterSprite; void RSP_GBI_Sprite2D_PuzzleMaster64(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); dwAddr &= (g_dwRamSize-1); g_Sprite2DInfo.spritePtr = (SpriteStruct *)(g_pRDRAMs8+dwAddr); g_Sprite2DInfo.flipX = 0; g_Sprite2DInfo.flipY = 0; g_Sprite2DInfo.px = 0; g_Sprite2DInfo.py = 0; SpriteStruct tempInfo; memcpy(&tempInfo, g_Sprite2DInfo.spritePtr, sizeof(SpriteStruct)); PuzzleMasterSprite info; memcpy(&info, g_Sprite2DInfo.spritePtr, sizeof(PuzzleMasterSprite)); g_Sprite2DInfo.px = info.px>>2; g_Sprite2DInfo.py = info.py>>2; g_Sprite2DInfo.scaleX = info.scaleX / 1024.0f; g_Sprite2DInfo.scaleY = info.scaleY / 1024.0f; tempInfo.SourceImageOffsetS = info.SourceImageOffsetS; tempInfo.SourceImageOffsetT = info.SourceImageOffsetT; g_Sprite2DInfo.spritePtr = &tempInfo; CRender::g_pRender->DrawSprite2D(g_Sprite2DInfo, 1); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_SPRITE_2D, {DebuggerAppendMsg("Pause after Sprite2DBase: Addr=%08X\n", dwAddr);}); } void RSP_GBI1_Sprite2DDraw(Gfx *gfx) { // This ucode is shared by PopMtx and gSPSprite2DDraw g_Sprite2DInfo.px = (short)(((gfx->words.w1)>>16)&0xFFFF)/4; g_Sprite2DInfo.py = (short)((gfx->words.w1)&0xFFFF)/4; //RSP_RDP_NOIMPL("gSPSprite2DDraw is not implemented", (gfx->words.w0), (gfx->words.w1)); CRender::g_pRender->DrawSprite2D(g_Sprite2DInfo, 1); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_SPRITE_2D, {DebuggerAppendMsg("Pause after Sprite2DDraw at (%d, %d)\n", g_Sprite2DInfo.px, g_Sprite2DInfo.py);}); LoadedUcodeMap[RSP_SPRITE2D_SCALEFLIP] = &RSP_GBI1_CullDL; LoadedUcodeMap[RSP_SPRITE2D_DRAW] = &RSP_GBI1_PopMtx; LoadedUcodeMap[RSP_SPRITE2D_BASE] = &RSP_GBI1_Sprite2DBase; } void RSP_GBI0_Sprite2DDraw(Gfx *gfx) { // This ucode is shared by PopMtx and gSPSprite2DDraw g_Sprite2DInfo.px = (short)(((gfx->words.w1)>>16)&0xFFFF)/4; g_Sprite2DInfo.py = (short)((gfx->words.w1)&0xFFFF)/4; //RSP_RDP_NOIMPL("gSPSprite2DDraw is not implemented", (gfx->words.w0), (gfx->words.w1)); CRender::g_pRender->DrawSprite2D(g_Sprite2DInfo, 0); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_SPRITE_2D, {TRACE0("Pause after Sprite2DDraw\n");}); } void RSP_GBI1_Sprite2DScaleFlip(Gfx *gfx) { g_Sprite2DInfo.scaleX = (((gfx->words.w1)>>16)&0xFFFF)/1024.0f; g_Sprite2DInfo.scaleY = ((gfx->words.w1)&0xFFFF)/1024.0f; if( ((gfx->words.w1)&0xFFFF) < 0x100 ) { g_Sprite2DInfo.scaleY = g_Sprite2DInfo.scaleX; } g_Sprite2DInfo.flipX = (uint8)(((gfx->words.w0)>>8)&0xFF); g_Sprite2DInfo.flipY = (uint8)((gfx->words.w0)&0xFF); //RSP_RDP_NOIMPL("RSP_SPRITE2D_SCALEFLIP is not implemented", (gfx->words.w0), (gfx->words.w1)); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_SPRITE_2D, {DebuggerAppendMsg("Pause after Sprite2DScaleFlip, Flip (%d,%d), Scale (%f, %f)\n", g_Sprite2DInfo.flipX, g_Sprite2DInfo.flipY, g_Sprite2DInfo.scaleX, g_Sprite2DInfo.scaleY);}); } void RSP_GBI1_Sprite2DBase(Gfx *gfx) { if( !status.bUseModifiedUcodeMap ) { memcpy( &LoadedUcodeMap, &ucodeMap1, sizeof(UcodeMap)); status.bUseModifiedUcodeMap = true; } LoadedUcodeMap[RSP_SPRITE2D_BASE] = &RSP_GBI_Sprite2DBase; LoadedUcodeMap[RSP_SPRITE2D_SCALEFLIP] = &RSP_GBI1_Sprite2DScaleFlip; LoadedUcodeMap[RSP_SPRITE2D_DRAW] = &RSP_GBI1_Sprite2DDraw; TRACE0("Adding Sprite2D ucodes to ucode 1"); RSP_GBI_Sprite2DBase(gfx); } void RSP_GBI0_Sprite2DBase(Gfx *gfx) { //Weired, this ucode 0 game is using ucode 1, but sprite2D cmd is working differently from //normal ucode1 sprite2D game TRACE0("Ucode 0 game is using Sprite2D, and using ucode 1 codes, create a new ucode for me"); RSP_GBI_Sprite2DBase(gfx); } mupen64plus-video-rice-src-2.6.0/src/RSP_Parser.cpp000066400000000000000000002137301464507324400220240ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include "Config.h" #include "ConvertImage.h" #include "Debugger.h" #include "GraphicsContext.h" #include "RSP_Parser.h" #include "RSP_S2DEX.h" #include "Render.h" #include "RenderBase.h" #include "RenderTexture.h" #include "TextureManager.h" #include "Timing.h" #include "UcodeDefs.h" #include "VectorMath.h" #include "Video.h" #include "m64p_plugin.h" #include "osal_preproc.h" #include "typedefs.h" #include "ucode.h" #undef min #undef max ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// // uCode Config // ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// #define MAX_UCODE_INFO 16 UcodeInfo ucodeInfo[MAX_UCODE_INFO]; RDPInstruction LoadedUcodeMap[256]; char* LoadedUcodeNameMap[256]; OSTask *g_pOSTask = NULL; UcodeInfo lastUcodeInfo; UcodeInfo UsedUcodes[MAX_UCODE_INFO]; const uint32 maxUsedUcodes = sizeof(UsedUcodes)/sizeof(UcodeInfo); ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// // Ucodes // ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// UcodeMap *ucodeMaps[] = { &ucodeMap0, // ucode 0 - Mario &ucodeMap1, // ucode 1 - GBI1 NULL, // ucode 2 - Golden Eye &ucodeMap3, // ucode 3 - S2DEX GBI2 NULL, // ucode 4 - Wave Racer &ucodeMap5, // ucode 5 - BGI2 NULL, // ucode 6 - DKR &ucodeMap7, // ucode 7 - S2DEX NULL, // ucode 8 - ucode 0 with sprite2D, for Demo Puzzle Master 64 NULL, // ucode 9 - Perfect Dark NULL, // ucode 10 - Conker NULL, // ucode 11 - Gemini NULL, // ucode 12 - Silicon Valley, Spacestation NULL, // ucode 13 - modified ucode S2DEX NULL, // ucode 14 - OgreBattle Background NULL, // ucode 15 - ucode 0 with sprite2D NULL, // ucode 16 - Star War, Shadow of Empire NULL, // ucode 17 - Star Wars - Rogue Squadron, NULL, // ucode 18 - World Driver Championship NULL, // ucode 19 - Last Legion UX &ucodeMap1, // ucode 20 - ZSortp }; uint32 vertexMultVals[] = { 10, // ucode 0 - Mario 2, // ucode 1 - GBI1 10, // ucode 2 - Golden Eye 2, // ucode 3 - S2DEX GBI2 5, // ucode 4 - Wave Racer 2, // ucode 5 - BGI2 10, // ucode 6 - DKR 2, // ucode 7 - S2DEX 10, // ucode 8 - ucode 0 with sprite2D, for Demo Puzzle Master 64 10, // ucode 9 - Perfect Dark 2, // ucode 10 - Conker 10, // ucode 11 - Gemini 2, // ucode 12 - Silicon Valley, Spacestation 2, // ucode 13 - modified ucode S2DEX 2, // ucode 14 - OgreBattle Background 10, // ucode 15 - ucode 0 with sprite2D 5, // ucode 16 - Star War, Shadow of Empire 2, // ucode 17 - Star Wars - Rogue Squadron, 2, // ucode 18 - World Driver Championship, check me here 2, // ucode 19 - Last Legion UX, check me here 2, // ucode 20 - ZSortp }; unsigned char gLastMicrocodeString[ 300 ] = ""; //***************************************************************************** // //***************************************************************************** static UcodeData g_UcodeData[] = { //crc_size, crc_800; {0, 0x150c3ce8, 0x150c3ce8, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Super Mario 64 {4, 0x2b94276f, 0x2b94276f, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Wave Race 64 (v1.0) {16,0xb1870454, 0xb1870454, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Star Wars - Shadows of the Empire (v1.0), {0, 0x51671ae4, 0x51671ae4, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Pilot Wings 64, {0, 0x67b5ac55, 0x67b5ac55, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Wibble, {0, 0x64dc8104, 0x64dc8104, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Dark Rift, {0, 0x309f363d, 0x309f363d, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Killer Instinct Gold, {0, 0xfcb57e57, 0xfcb57e57, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Blast Corps, {0, 0xb420f35a, 0xb420f35a, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, // Blast Corps, {0, 0x6e26c1df, 0x7c98e9c2, (unsigned char*)"RSP SW Version: 2.0D, 04-01-96",}, {2, 0xc02ac7bc, 0xc02ac7bc, (unsigned char*)"RSP SW Version: 2.0G, 09-30-96",}, // GoldenEye 007, {0, 0xe5fee3bc, 0xe5fee3bc, (unsigned char*)"RSP SW Version: 2.0G, 09-30-96",}, // Aero Fighters Assault, {8, 0xe4bb5ad8, 0x80129845, (unsigned char*)"RSP SW Version: 2.0G, 09-30-96",}, // Puzzle Master 64, {0, 0x72109ec6, 0x72109ec6, (unsigned char*)"RSP SW Version: 2.0H, 02-12-97",}, // Duke Nukem 64, {0, 0xf24a9a04, 0xf24a9a04, (unsigned char*)"RSP SW Version: 2.0H, 02-12-97",}, // Tetrisphere, {15,0x700de42e, 0x700de42e, (unsigned char*)"RSP SW Version: 2.0H, 02-12-97",}, // Wipeout 64 (uses GBI1 too!), {15,0x1b304a74, 0x1b304a74, (unsigned char*)"RSP SW Version: 2.0H, 02-12-97",}, // Flying Dragon, {15,0xe4bb5ad8, 0xa7b2f704, (unsigned char*)"RSP SW Version: 2.0H, 02-12-97",}, // Silicon Valley, {15,0xe4bb5ad8, 0x88202781, (unsigned char*)"RSP SW Version: 2.0H, 02-12-97",}, // Glover, {0, 0xe466b5bd, 0xe466b5bd, (unsigned char*)"Unknown 0xe466b5bd, 0xe466b5bd",}, // Dark Rift, {9, 0x7064a163, 0x7064a163, (unsigned char*)"Unknown 0x7064a163, 0x7064a163",}, // Perfect Dark (v1.0), {0, 0x6522df69, 0x71bd078d, (unsigned char*)"Unknown 0x6522df69, 0x71bd078d",}, // Tetris {0, 0x6522df69, 0x1b0c23a8, (unsigned char*)"Unknown 0x6522df69, 0x1b0c23a8",}, // Pachinko Nichi // GBI1 {1, 0x45ca328e, 0x45ca328e, (unsigned char*)"RSP Gfx ucode F3DLX 0.95 Yoshitaka Yasumoto Nintendo.",}, // Mario Kart 64, {1, 0x98e3b909, 0x98e3b909, (unsigned char*)"RSP Gfx ucode F3DEX 0.95 Yoshitaka Yasumoto Nintendo.",}, // Mario Kart 64 {1, 0x5d446090, 0x5d446090, (unsigned char*)"RSP Gfx ucode F3DLP.Rej 0.96 Yoshitaka Yasumoto Nintendo.",0,1}, // Jikkyou J. League Perfect Striker, {1, 0x244f5ca3, 0x244f5ca3, (unsigned char*)"RSP Gfx ucode F3DEX 1.00 Yoshitaka Yasumoto Nintendo.",}, // F-1 Pole Position 64, {1, 0x6a022585, 0x6a022585, (unsigned char*)"RSP Gfx ucode F3DEX.NoN 1.00 Yoshitaka Yasumoto Nintendo.",1}, // Turok - The Dinosaur Hunter (v1.0), {1, 0x150706be, 0x150706be, (unsigned char*)"RSP Gfx ucode F3DLX.NoN 1.00 Yoshitaka Yasumoto Nintendo.",1}, // Extreme-G, {1, 0x503f2c53, 0x503f2c53, (unsigned char*)"RSP Gfx ucode F3DEX.NoN 1.21 Yoshitaka Yasumoto Nintendo.",1}, // Bomberman 64, {1, 0xc705c37c, 0xc705c37c, (unsigned char*)"RSP Gfx ucode F3DLX 1.21 Yoshitaka Yasumoto Nintendo.",}, // Fighting Force 64, Wipeout 64 {1, 0xa2146075, 0xa2146075, (unsigned char*)"RSP Gfx ucode F3DLX.NoN 1.21 Yoshitaka Yasumoto Nintendo.",1}, // San Francisco Rush - Extreme Racing, {1, 0xb65aa2da, 0xb65aa2da, (unsigned char*)"RSP Gfx ucode L3DEX 1.21 Yoshitaka Yasumoto Nintendo.",}, // Wipeout 64, {1, 0x0c8e5ec9, 0x0c8e5ec9, (unsigned char*)"RSP Gfx ucode F3DEX 1.21 Yoshitaka Yasumoto Nintendo.",}, // {1, 0xe30795f2, 0xa53df3c4, (unsigned char*)"RSP Gfx ucode F3DLP.Rej 1.21 Yoshitaka Yasumoto Nintendo.",0,1}, {1, 0xaebeda7d, 0xaebeda7d, (unsigned char*)"RSP Gfx ucode F3DLX.Rej 1.21 Yoshitaka Yasumoto Nintendo.",0,1}, // Jikkyou World Soccer 3, {1, 0x0c8e5ec9, 0x0c8e5ec9, (unsigned char*)"RSP Gfx ucode F3DEX 1.23 Yoshitaka Yasumoto Nintendo" ,}, // Wave Race 64 (Rev. 2) - Shindou Rumble Edition (JAP) {1, 0xc705c37c, 0xc705c37c, (unsigned char*)"RSP Gfx ucode F3DLX 1.23 Yoshitaka Yasumoto Nintendo.",}, // GT {1, 0x2a61350d, 0x2a61350d, (unsigned char*)"RSP Gfx ucode F3DLX 1.23 Yoshitaka Yasumoto Nintendo.",}, // Toy Story2 {1, 0x0c8e5ec9, 0x0c8e5ec9, (unsigned char*)"RSP Gfx ucode F3DEX 1.23 Yoshitaka Yasumoto Nintendo.",}, // Wave Race 64 Shindou Edition {12,0xfc6529aa, 0xfc6529aa, (unsigned char*)"RSP Gfx ucode F3DEX 1.23 Yoshitaka Yasumoto Nintendo.",}, // Superman - The Animated Series, {1, 0xa56cf996, 0xa56cf996, (unsigned char*)"RSP Gfx ucode L3DEX 1.23 Yoshitaka Yasumoto Nintendo.",}, // Flying Dragon, {1, 0xcc83b43f, 0xcc83b43f, (unsigned char*)"RSP Gfx ucode F3DEX.NoN 1.23 Yoshitaka Yasumoto Nintendo.",1}, // AeroGauge, {1, 0xca8927a0, 0xca8927a0, (unsigned char*)"RSP Gfx ucode F3DLX.Rej 1.23 Yoshitaka Yasumoto Nintendo.",0,1}, // Puzzle Bobble 64, {1, 0x25689c75, 0xbe481ae8, (unsigned char*)"RSP Gfx ucode F3DLP.Rej 1.23 Yoshitaka Yasumoto Nintendo.",0,1}, {1, 0xd2d747b7, 0xd2d747b7, (unsigned char*)"RSP Gfx ucode F3DLX.NoN 1.23 Yoshitaka Yasumoto Nintendo.",1}, // Penny Racers, {1, 0xa849c858, 0x5bd32b5a, (unsigned char*)"RSP Gfx ucode F3DTEX/A 1.23 Yoshitaka Yasumoto Nintendo.",}, // Tamagotchi {7, 0xecd8b772, 0xecd8b772, (unsigned char*)"RSP Gfx ucode S2DEX 1.06 Yoshitaka Yasumoto Nintendo.",}, // Yoshi's Story, {7, 0xf59132f5, 0xf59132f5, (unsigned char*)"RSP Gfx ucode S2DEX 1.07 Yoshitaka Yasumoto Nintendo.",}, // Bakuretsu Muteki Bangaioh, {7, 0x961dd811, 0x961dd811, (unsigned char*)"RSP Gfx ucode S2DEX 1.03 Yoshitaka Yasumoto Nintendo.",}, // GT {5, 0x3e083afa, 0x722f97cc, (unsigned char*)"RSP Gfx ucode F3DEX.NoN fifo 2.03 Yoshitaka Yasumoto 1998 Nintendo.",1}, // F-Zero X, {5, 0xa8050bd1, 0xa8050bd1, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.03 Yoshitaka Yasumoto 1998 Nintendo.",}, // F-Zero X, {5, 0x4e8055f0, 0x4e8055f0, (unsigned char*)"RSP Gfx ucode F3DLX.Rej fifo 2.03 Yoshitaka Yasumoto 1998 Nintendo.",0,1}, // F-Zero X, {5, 0xabf001f5, 0xabf001f5, (unsigned char*)"RSP Gfx ucode F3DFLX.Rej fifo 2.03F Yoshitaka Yasumoto 1998 Nintendo.",0,1}, // F-Zero X, {5, 0xadb4b686, 0xadb4b686, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.04 Yoshitaka Yasumoto 1998 Nintendo.",}, // Top Gear Rally 2, {5, 0x779e2a9b, 0x779e2a9b, (unsigned char*)"RSP Gfx ucode F3DEX.NoN fifo 2.04 Yoshitaka Yasumoto 1998 Nintendo.",1}, // California Speed, {5, 0xa8cb3e09, 0xa8cb3e09, (unsigned char*)"RSP Gfx ucode L3DEX fifo 2.04 Yoshitaka Yasumoto 1998 Nintendo.",}, // In-Fisherman Bass Hunter 64, {5, 0x2a1341d6, 0x2a1341d6, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.04H Yoshitaka Yasumoto 1998 Nintendo.",}, // Kirby 64 - The Crystal Shards, {5, 0x3e083afa, 0x89a8e0ed, (unsigned char*)"RSP Gfx ucode F3DEX.NoN fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo.",1}, // Carmageddon 64 (uncensored), {5, 0x4964b75d, 0x4964b75d, (unsigned char*)"RSP Gfx ucode F3DEX.NoN fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo.",1}, {5, 0x39e3e95a, 0x39e3e95a, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo."}, // Knife Edge - Nose Gunner, {5, 0xd2913522, 0xd2913522, (unsigned char*)"RSP Gfx ucode F3DAM fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo."}, // Hey You, Pikachu!, {5, 0x3e083afa, 0xc998443f, (unsigned char*)"RSP Gfx ucode F3DEX xbus 2.05 Yoshitaka Yasumoto 1998 Nintendo."}, //Triple play {5, 0xf4184a7d, 0xf4184a7d, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.06 Yoshitaka Yasumoto 1998 Nintendo.",}, // Hey You, Pikachu!, {5, 0x595a88de, 0x595a88de, (unsigned char*)"RSP Gfx ucode F3DEX.Rej fifo 2.06 Yoshitaka Yasumoto 1998 Nintendo.",0,1}, // Bio Hazard 2, {5, 0x0259f764, 0x0259f764, (unsigned char*)"RSP Gfx ucode F3DLX.Rej fifo 2.06 Yoshitaka Yasumoto 1998 Nintendo.",0,1}, // Mario Party, {5, 0xe1a5477a, 0xe1a5477a, (unsigned char*)"RSP Gfx ucode F3DEX.NoN xbus 2.06 Yoshitaka Yasumoto 1998 Nintendo.",1}, // Command & Conquer, {5, 0x4cfa0a19, 0x4cfa0a19, (unsigned char*)"RSP Gfx ucode F3DZEX.NoN fifo 2.06H Yoshitaka Yasumoto 1998 Nintendo.",1}, // The Legend of Zelda - Ocarina of Time (v1.0), {5, 0x2cbd9514, 0x5f40b9f5, (unsigned char*)"RSP Gfx ucode F3DZEX.NoN fifo 2.06H Yoshitaka Yasumoto 1998 Nintendo.",1}, {5, 0x3e083afa, 0x882680f4, (unsigned char*)"RSP Gfx ucode L3DEX fifo 2.07 Yoshitaka Yasumoto 1998 Nintendo."}, // Polaris Sno {5, 0xdeb1cac0, 0xdeb1cac0, (unsigned char*)"RSP Gfx ucode F3DEX.NoN fifo 2.07 Yoshitaka Yasumoto 1998 Nintendo.",1}, // Knockout Kings 2000, {5, 0xf4184a7d, 0xf4184a7d, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.07 Yoshitaka Yasumoto 1998 Nintendo.",}, // Xena Warrior Princess - Talisman of Fate, Army Men - Air Combat, Destruction Derby {5, 0x4b013e60, 0x4b013e60, (unsigned char*)"RSP Gfx ucode F3DEX xbus 2.07 Yoshitaka Yasumoto 1998 Nintendo.",}, // Lode Runner 3-D, {5, 0xd1a63836, 0xd1a63836, (unsigned char*)"RSP Gfx ucode L3DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // Hey You, Pikachu!, {5, 0x97193667, 0x97193667, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // Top Gear Hyper-Bike, {5, 0x92149ba8, 0x92149ba8, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.08 Yoshitaka Yasumoto/Kawasedo 1999.",}, // Paper Mario, {5, 0xae0fb88f, 0xae0fb88f, (unsigned char*)"RSP Gfx ucode F3DEX xbus 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // WWF WrestleMania 2000, {5, 0xc572f368, 0xc572f368, (unsigned char*)"RSP Gfx ucode F3DLX.Rej xbus 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // WWF No Mercy, {5, 0x3e083afa, 0x74252492, (unsigned char*)"RSP Gfx ucode F3DEX.NoN xbus 2.08 Yoshitaka Yasumoto 1999 Nintendo.",1}, {5, 0x9c2edb70, 0xea98e740, (unsigned char*)"RSP Gfx ucode F3DEX.NoN fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",1}, // LEGO Racers, {5, 0x79e004a6, 0x79e004a6, (unsigned char*)"RSP Gfx ucode F3DLX.Rej fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",0,1}, // Mario Party 2, {5, 0xaa6ab3ca, 0xaa6ab3ca, (unsigned char*)"RSP Gfx ucode F3DEX.Rej fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",0,1}, // V-Rally Edition 99, {5, 0x2c597e0f, 0x2c597e0f, (unsigned char*)"RSP Gfx ucode F3DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // Cruis'n Exotica, {10, 0x4e5f3e3b, 0x4e5f3e3b,(unsigned char*)"RSP Gfx ucode F3DEXBG.NoN fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",1}, // Conker The Bad Fur Day {5, 0x61f31862, 0x61f31862, (unsigned char*)"RSP Gfx ucode F3DEX.NoN fifo 2.08H Yoshitaka Yasumoto 1999 Nintendo.",1}, // Pokemon Snap, {5, 0x005f5b71, 0x005f5b71, (unsigned char*)"RSP Gfx ucode F3DZEX.NoN fifo 2.08I Yoshitaka Yasumoto/Kawasedo 1999.",1}, // The Legend of Zelda 2 - Majora's Mask, {3, 0x41839d1e, 0x41839d1e, (unsigned char*)"RSP Gfx ucode S2DEX fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo.",}, // Chou Snobow Kids, {3, 0x2cbd9514, 0xc639dbb9, (unsigned char*)"RSP Gfx ucode S2DEX xbus 2.06 Yoshitaka Yasumoto 1998 Nintendo.",}, {3, 0xec89e273, 0xec89e273, (unsigned char*)"RSP Gfx ucode S2DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // V-Rally Edition 99, {3, 0x9429b7d6, 0x9429b7d6, (unsigned char*)"RSP Gfx ucode S2DEX xbus 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // Star Craft, //{14,0x5a72397b, 0xec89e273, "RSP Gfx ucode S2DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // OgreBattle Background, {3, 0x2cbd9514, 0xec89e273, (unsigned char*)"RSP Gfx ucode S2DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",}, // Zelda MM, {6, 0x6aef74f8, 0x6aef74f8, (unsigned char*)"Unknown 0x6aef74f8, 0x6aef74f8",}, // Diddy Kong Racing (v1.0), {6, 0x4c4eead8, 0x4c4eead8, (unsigned char*)"Unknown 0x4c4eead8, 0x4c4eead8",}, // Diddy Kong Racing (v1.1), {1, 0xed421e9a, 0xed421e9a, (unsigned char*)"Unknown 0xed421e9a, 0xed421e9a",}, // Kuiki Uhabi Suigo, {5, 0x37751932, 0x55c0fd25, (unsigned char*)"Unknown 0x37751932, 0x55c0fd25",}, // Bio Hazard 2, {11,0xbe0b83e7, 0xbe0b83e7,(unsigned char*)"Unknown 0xbe0b83e7, 0xbe0b83e7",}, // Jet Force Gemini, {17, 0x02e882cf, 0x2ad17281, (unsigned char*)"Unknown 0x02e882cf, 0x2ad17281",}, // Indiana Jones, {17, 0x1f7d9118, 0xdab2199b, (unsigned char*)"Unknown 0x1f7d9118, 0xdab2199b",}, // Battle Naboo, {17, 0x74583614, 0x74583614, (unsigned char*)"Unknown 0x74583614, 0x74583614",}, // Star Wars - Rogue Squadron, {17, 0xe37e2f49, 0x1eb63fd8, (unsigned char*)"Unknown 0xe37e2f49, 0x1eb63fd8",}, // Star Wars - Rogue Squadron, {17, 0x8ce1af3d, 0xb2760ea2, (unsigned char*)"Unknown 0x8ce1af3d, 0xb2760ea2",}, // Star Wars - Rogue Squadron, {18, 0x7b685972, 0x57b8095a, (unsigned char*)"Unknown 0x7b685972, 0x57b8095a",}, // World Driver Championship {18, 0xe92dbb9b, 0x57b8095a, (unsigned char*)"Unknown 0xe92dbb9b, 0x57b8095a",}, // World Driver Championship {18, 0xe6c9acc1, 0x65f80845, (unsigned char*)"Unknown 0xe6c9acc1, 0x65f80845",}, // World Driver Championship {18, 0x6522df69, 0x720b88a0, (unsigned char*)"Unknown 0x6522df69, 0x720b88a0",}, // World Driver Championship {18, 0x6522df69, 0xf1e8ba9e, (unsigned char*)"Unknown 0x6522df69, 0xf1e8ba9e",}, // World Driver Championship {19, 0xa486bed3, 0xa486bed3, (unsigned char*)"Unknown 0xa486bed3, 0xa486bed3",}, // Last Legion UX, {19, 0x6b519381, 0xfebacfd8, (unsigned char*)"Unknown in Toukan Road",}, // I don't know which ucode {20, 0x6d2a01b1, 0x6d2a01b1, (unsigned char*)"RSP Gfx ucode ZSortp 0.33 Yoshitaka Yasumoto Nintendo.",}, // Mia Hamm Soccer 64, }; FiddledVtx * g_pVtxBase=NULL; SetImgInfo g_TI = { TXT_FMT_RGBA, TXT_SIZE_16b, 1, 0 }; SetImgInfo g_CI = { TXT_FMT_RGBA, TXT_SIZE_16b, 1, 0 }; SetImgInfo g_ZI = { TXT_FMT_RGBA, TXT_SIZE_16b, 1, 0 }; RenderTextureInfo g_ZI_saves[2]; DListStack gDlistStack[MAX_DL_STACK_SIZE]; int gDlistStackPointer= -1; TMEMLoadMapInfo g_tmemLoadAddrMap[0x200]; // Totally 4KB TMEM TMEMLoadMapInfo g_tmemInfo0; // Info for Tmem=0 TMEMLoadMapInfo g_tmemInfo1; // Info for Tmem=0x100 const char *pszImgSize[4] = {"4", "8", "16", "32"}; const char *textluttype[4] = {"RGB16", "I16?", "RGBA16", "IA16"}; uint16 g_wRDPTlut[0x200]; uint32 g_dwRDPPalCrc[16]; #include "FrameBuffer.h" #include "RDP_Texture.h" #include "RSP_GBI0.h" #include "RSP_GBI1.h" #include "RSP_GBI2.h" #include "RSP_GBI2_ext.h" #include "RSP_GBI_Others.h" #include "RSP_GBI_Sprite2D.h" ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// // Init and Reset // ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// void DLParser_Init() { int i; status.gRDPTime = 0; status.gDlistCount = 0; status.gUcodeCount = 0; status.frameReadByCPU = FALSE; status.frameWriteByCPU = FALSE; status.SPCycleCount = 0; status.DPCycleCount = 0; status.bN64IsDrawingTextureBuffer = false; status.bDirectWriteIntoRDRAM = false; status.bHandleN64RenderTexture = false; status.bUcodeIsKnown = FALSE; status.lastPurgeTimeTime = status.gRDPTime; status.curRenderBuffer = 0; status.curDisplayBuffer = 0; status.curVIOriginReg = 0; status.primitiveType = PRIM_TRI1; status.lastPurgeTimeTime = 0; // Time textures were last purged status.UseLargerTile[0] = false; status.LargerTileRealLeft[0] = status.LargerTileRealLeft[1] = 0; memset(&g_ZI_saves, 0, sizeof(RenderTextureInfo)*2); for( i=0; i<8; i++ ) { memset(&gRDP.tiles[i], 0, sizeof(Tile)); } memset(g_tmemLoadAddrMap, 0, sizeof(g_tmemLoadAddrMap)); for( i=0; iCloseRenderTexture(false); } } void RDP_SetUcodeMap(int ucode) { status.bUseModifiedUcodeMap = false; switch( ucode ) { case 0: // Mario and demos break; case 1: // F3DEX GBI1 case 20: break; case 2: // Golden Eye memcpy( &LoadedUcodeMap, &ucodeMap0, sizeof(UcodeMap)); //LoadedUcodeMap[9]=RSP_GBI1_Sprite2DBase; //LoadedUcodeMap[0xaf]=RSP_GBI1_LoadUCode; //LoadedUcodeMap[0xb0]=RSP_GBI1_BranchZ; LoadedUcodeMap[0xb4]=DLParser_RDPHalf_1_0xb4_GoldenEye; status.bUseModifiedUcodeMap = true; break; case 3: // S2DEX GBI2 break; case 4: memcpy( &LoadedUcodeMap, &ucodeMap0, sizeof(UcodeMap)); LoadedUcodeMap[4]=RSP_Vtx_WRUS; LoadedUcodeMap[0xb1]=RSP_GBI1_Tri2; //LoadedUcodeMap[9]=RSP_GBI1_Sprite2DBase; //LoadedUcodeMap[0xaf]=RSP_GBI1_LoadUCode; //LoadedUcodeMap[0xb0]=RSP_GBI1_BranchZ; //LoadedUcodeMap[0xb2]=RSP_GBI1_ModifyVtx; status.bUseModifiedUcodeMap = true; break; case 5: // F3DEX GBI2 break; case 6: // DKR, Jet Force Gemini, Mickey case 11: // DKR, Jet Force Gemini, Mickey memcpy( &LoadedUcodeMap, &ucodeMap0, sizeof(UcodeMap)); LoadedUcodeMap[1]=RSP_Mtx_DKR; LoadedUcodeMap[4]=RSP_Vtx_DKR; if( ucode == 11 ) LoadedUcodeMap[4]=RSP_Vtx_Gemini; LoadedUcodeMap[5]=RSP_DMA_Tri_DKR; LoadedUcodeMap[7]=RSP_DL_In_MEM_DKR; LoadedUcodeMap[0xbc]=RSP_MoveWord_DKR; LoadedUcodeMap[0xbf]=DLParser_Set_Addr_Ucode6; //LoadedUcodeMap[9]=RSP_GBI1_Sprite2DBase; //LoadedUcodeMap[0xb0]=RSP_GBI1_BranchZ; //LoadedUcodeMap[0xb2]=RSP_GBI1_ModifyVtx; status.bUseModifiedUcodeMap = true; break; case 7: // S2DEX GBI1 break; case 8: // Ucode 0 with Sprite2D, Puzzle Master 64 memcpy( &LoadedUcodeMap, &ucodeMap0, sizeof(UcodeMap)); LoadedUcodeMap[RSP_SPRITE2D_BASE] = RSP_GBI_Sprite2D_PuzzleMaster64; LoadedUcodeMap[RSP_SPRITE2D_SCALEFLIP] = RSP_GBI1_Sprite2DScaleFlip; LoadedUcodeMap[RSP_SPRITE2D_DRAW] = RSP_GBI0_Sprite2DDraw; status.bUseModifiedUcodeMap = true; break; case 9: // Perfect Dark memcpy( &LoadedUcodeMap, &ucodeMap0, sizeof(UcodeMap)); LoadedUcodeMap[4]=RSP_Vtx_PD; LoadedUcodeMap[7]=RSP_Set_Vtx_CI_PD; LoadedUcodeMap[0xb1]=RSP_Tri4_PD; LoadedUcodeMap[0xb4]=DLParser_RDPHalf_1_0xb4_GoldenEye; status.bUseModifiedUcodeMap = true; break; case 10: // Conker BFD memcpy( &LoadedUcodeMap, &ucodeMap5, sizeof(UcodeMap)); LoadedUcodeMap[1]=RSP_Vtx_Conker; LoadedUcodeMap[0x10]=DLParser_Tri4_Conker; LoadedUcodeMap[0x11]=DLParser_Tri4_Conker; LoadedUcodeMap[0x12]=DLParser_Tri4_Conker; LoadedUcodeMap[0x13]=DLParser_Tri4_Conker; LoadedUcodeMap[0x14]=DLParser_Tri4_Conker; LoadedUcodeMap[0x15]=DLParser_Tri4_Conker; LoadedUcodeMap[0x16]=DLParser_Tri4_Conker; LoadedUcodeMap[0x17]=DLParser_Tri4_Conker; LoadedUcodeMap[0x18]=DLParser_Tri4_Conker; LoadedUcodeMap[0x19]=DLParser_Tri4_Conker; LoadedUcodeMap[0x1a]=DLParser_Tri4_Conker; LoadedUcodeMap[0x1b]=DLParser_Tri4_Conker; LoadedUcodeMap[0x1c]=DLParser_Tri4_Conker; LoadedUcodeMap[0x1d]=DLParser_Tri4_Conker; LoadedUcodeMap[0x1e]=DLParser_Tri4_Conker; LoadedUcodeMap[0x1f]=DLParser_Tri4_Conker; LoadedUcodeMap[0xdb]=DLParser_MoveWord_Conker; LoadedUcodeMap[0xdc]=DLParser_MoveMem_Conker; status.bUseModifiedUcodeMap = true; break; case 12: // Silicon Velley, Space Station memcpy( &LoadedUcodeMap, &ucodeMap1, sizeof(UcodeMap)); LoadedUcodeMap[0x01]=RSP_GBI0_Mtx; status.bUseModifiedUcodeMap = true; break; case 13: // modified S2DEX memcpy( &LoadedUcodeMap, &ucodeMap7, sizeof(UcodeMap)); //LoadedUcodeMap[S2DEX_BG_1CYC] = ucodeMap1[S2DEX_BG_1CYC]; LoadedUcodeMap[S2DEX_OBJ_RECTANGLE] = ucodeMap1[S2DEX_OBJ_RECTANGLE]; LoadedUcodeMap[S2DEX_OBJ_SPRITE] = ucodeMap1[S2DEX_OBJ_SPRITE]; //LoadedUcodeMap[S2DEX_OBJ_RENDERMODE] = ucodeMap1[S2DEX_OBJ_RENDERMODE]; //LoadedUcodeMap[S2DEX_OBJ_RECTANGLE_R] = ucodeMap1[S2DEX_OBJ_RECTANGLE_R]; LoadedUcodeMap[S2DEX_RDPHALF_0] = ucodeMap1[S2DEX_RDPHALF_0]; status.bUseModifiedUcodeMap = true; break; case 14: // OgreBattle Background memcpy( &LoadedUcodeMap, &ucodeMap5, sizeof(UcodeMap)); LoadedUcodeMap[0xda] = DLParser_OgreBatter64BG; LoadedUcodeMap[0xdc] = RSP_S2DEX_OBJ_MOVEMEM; status.bUseModifiedUcodeMap = true; break; case 15: // Ucode 0 with Sprite2D memcpy( &LoadedUcodeMap, &ucodeMap0, sizeof(UcodeMap)); LoadedUcodeMap[RSP_SPRITE2D_BASE] = RSP_GBI_Sprite2DBase; LoadedUcodeMap[RSP_SPRITE2D_SCALEFLIP] = RSP_GBI1_Sprite2DScaleFlip; LoadedUcodeMap[RSP_SPRITE2D_DRAW] = RSP_GBI0_Sprite2DDraw; status.bUseModifiedUcodeMap = true; break; case 16: // Star War, Shadow Of Empire memcpy( &LoadedUcodeMap, &ucodeMap0, sizeof(UcodeMap)); LoadedUcodeMap[4]=RSP_Vtx_ShadowOfEmpire; status.bUseModifiedUcodeMap = true; break; case 17: //Indiana Jones, does not work anyway memcpy( &LoadedUcodeMap, &ucodeMap1, sizeof(UcodeMap)); LoadedUcodeMap[0]=DLParser_Ucode8_0x0; //LoadedUcodeMap[1]=RSP_RDP_Nothing; LoadedUcodeMap[2]=DLParser_RS_Color_Buffer; LoadedUcodeMap[3]=DLParser_RS_MoveMem; LoadedUcodeMap[4]=DLParser_RS_Vtx_Buffer; LoadedUcodeMap[5]=DLParser_Ucode8_0x05; LoadedUcodeMap[6]=DLParser_Ucode8_DL; LoadedUcodeMap[7]=DLParser_Ucode8_JUMP; LoadedUcodeMap[8]=RSP_RDP_Nothing; LoadedUcodeMap[9]=RSP_RDP_Nothing; LoadedUcodeMap[10]=RSP_RDP_Nothing; LoadedUcodeMap[11]=RSP_RDP_Nothing; LoadedUcodeMap[0x80]=DLParser_RS_Block; LoadedUcodeMap[0xb4]=DLParser_Ucode8_0xb4; LoadedUcodeMap[0xb5]=DLParser_Ucode8_0xb5; LoadedUcodeMap[0xb8]=DLParser_Ucode8_EndDL; LoadedUcodeMap[0xbc]=DLParser_Ucode8_0xbc; LoadedUcodeMap[0xbd]=DLParser_Ucode8_0xbd; LoadedUcodeMap[0xbe]=DLParser_RS_0xbe; LoadedUcodeMap[0xbF]=DLParser_Ucode8_0xbf; LoadedUcodeMap[0xe4]=DLParser_TexRect_Last_Legion; status.bUseModifiedUcodeMap = true; break; case 18: // World Driver Championship memcpy( &LoadedUcodeMap, &ucodeMap1, sizeof(UcodeMap)); LoadedUcodeMap[0xe]=DLParser_RSP_DL_WorldDriver; LoadedUcodeMap[0x2]=DLParser_RSP_Pop_DL_WorldDriver; LoadedUcodeMap[0xdf]=DLParser_RSP_Pop_DL_WorldDriver; LoadedUcodeMap[0x6]=RSP_RDP_Nothing; status.bUseModifiedUcodeMap = true; break; case 19: // Last Legion UX memcpy( &LoadedUcodeMap, &ucodeMap1, sizeof(UcodeMap)); LoadedUcodeMap[0x80]=DLParser_RSP_Last_Legion_0x80; LoadedUcodeMap[0x00]=DLParser_RSP_Last_Legion_0x00; LoadedUcodeMap[0xe4]=DLParser_TexRect_Last_Legion; status.bUseModifiedUcodeMap = true; break; default: memcpy( &LoadedUcodeMap, &ucodeMap5, sizeof(UcodeMap)); status.bUseModifiedUcodeMap = true; break; } #ifdef DEBUGGER if( logMicrocode ) TRACE1("Using ucode %d", ucode); #endif } void RSP_SetUcode(int ucode, uint32 ucStart, uint32 ucDStart, uint32 ucSize) { if( status.ucodeHasBeenSet && gRSP.ucode == ucode ) return; status.ucodeHasBeenSet = true; if( ucode < 0 ) ucode = 5; RDP_SetUcodeMap(ucode); if( status.bUseModifiedUcodeMap ) { currentUcodeMap = &LoadedUcodeMap[0]; } else { currentUcodeMap = *ucodeMaps[ucode]; } gRSP.vertexMult = vertexMultVals[ucode]; //if( gRSP.ucode != ucode ) DebuggerAppendMsg("Set to ucode: %d", ucode); gRSP.ucode = ucode; lastUcodeInfo.used = true; if( ucStart == 0 ) { lastUcodeInfo.ucStart = g_pOSTask->t.ucode; lastUcodeInfo.ucDStart = g_pOSTask->t.ucode_data; lastUcodeInfo.ucSize = g_pOSTask->t.ucode_size; } else { lastUcodeInfo.ucStart = ucStart; lastUcodeInfo.ucDStart = ucDStart; lastUcodeInfo.ucSize = ucSize; } } //***************************************************************************** // //***************************************************************************** static uint32 DLParser_IdentifyUcodeFromString( const unsigned char * str_ucode ) { const unsigned char str_ucode0[] = "RSP SW Version: 2.0"; const unsigned char str_ucode1[] = "RSP Gfx ucode "; if ( strncasecmp( (char*)str_ucode, (char*)str_ucode0, strlen((char*)str_ucode0) ) == 0 ) { return 0; } if ( strncasecmp( (char*)str_ucode, (char*)str_ucode1, strlen((char*)str_ucode1) ) == 0 ) { if( strstr((char*)str_ucode,"1.") != 0 ) { if( strstr((char*)str_ucode,"S2DEX") != 0 ) { return 7; } else return 1; } else if( strstr((char*)str_ucode,"2.") != 0 ) { if( strstr((char*)str_ucode,"S2DEX") != 0 ) { return 3; } else return 5; } } return 5; } //***************************************************************************** // //***************************************************************************** static uint32 DLParser_IdentifyUcode( uint32 crc_size, uint32 crc_800, char* str ) { for ( uint32 i = 0; i < sizeof(g_UcodeData)/sizeof(UcodeData); i++ ) { #ifdef DEBUGGER if ( crc_800 == g_UcodeData[i].crc_800 ) { if( strlen(str)==0 || strcmp((const char *) g_UcodeData[i].ucode_name, str) == 0 ) { TRACE0((const char *) g_UcodeData[i].ucode_name); } else { DebuggerAppendMsg("Incorrect description for this ucode:\n%x, %x, %s",crc_800, crc_size, str); } status.bUcodeIsKnown = TRUE; gRSP.bNearClip = !g_UcodeData[i].non_nearclip; gRSP.bRejectVtx = g_UcodeData[i].reject; DebuggerAppendMsg("Identify ucode = %d, crc = %08X, %s", g_UcodeData[i].ucode, crc_800, str); return g_UcodeData[i].ucode; } #else if ( crc_800 == g_UcodeData[i].crc_800 ) { status.bUcodeIsKnown = TRUE; gRSP.bNearClip = !g_UcodeData[i].non_nearclip; gRSP.bRejectVtx = g_UcodeData[i].reject; return g_UcodeData[i].ucode; } #endif } #ifdef DEBUGGER { static bool warned = false; if( warned == false ) { warned = true; TRACE0("Can not identify ucode for this game"); } } #endif gRSP.bNearClip = false; gRSP.bRejectVtx = false; status.bUcodeIsKnown = FALSE; return ~0; } uint32 DLParser_CheckUcode(uint32 ucStart, uint32 ucDStart, uint32 ucSize, uint32 ucDSize) { if( options.enableHackForGames == HACK_FOR_ROGUE_SQUADRON ) { return 17; } // Check the used ucode table first int usedUcodeIndex = 0; for( usedUcodeIndex=0; (unsigned int)usedUcodeIndex= ' ') { *p++ = g_pRDRAMs8[ base + (i ^ 3) ]; i++; } *p++ = 0; break; } } } //if ( strcmp( str, gLastMicrocodeString ) != 0 ) { //uint32 size = ucDSize; base = ucStart & 0x1fffffff; uint32 crc_size = ComputeCRC32( 0, &g_pRDRAMu8[ base ], 8);//size ); uint32 crc_800 = ComputeCRC32( 0, &g_pRDRAMu8[ base ], 0x800 ); uint32 ucode; ucode = DLParser_IdentifyUcode( crc_size, crc_800, (char*)str ); if ( (int)ucode == ~0 ) { #ifdef DEBUGGER static bool warned=false; //if( warned == false ) { char message[300]; sprintf(message, "Unable to find ucode to use for '%s' CRCSize: 0x%08x CRC800: 0x%08x", str, crc_size, crc_800); TRACE0(message); DebugMessage(M64MSG_ERROR, message); warned = true; } #endif ucode = DLParser_IdentifyUcodeFromString(str); if ( (int)ucode == ~0 ) { ucode=5; } } //DLParser_SetuCode( ucode ); #ifdef DEBUGGER { static bool warned=false; if( warned == false ) { warned = true; if( strlen((char *) str) == 0 ) DebuggerAppendMsg("Can not find RSP string in the DLIST, CRC800: 0x%08x, CRCSize: 0x%08x", crc_800, crc_size); else TRACE0((char *) str); } } #endif strcpy( (char*)gLastMicrocodeString, (char*)str ); if( usedUcodeIndex >= MAX_UCODE_INFO ) { usedUcodeIndex = rand()%MAX_UCODE_INFO; } UsedUcodes[usedUcodeIndex].ucStart = ucStart; UsedUcodes[usedUcodeIndex].ucSize = ucSize; UsedUcodes[usedUcodeIndex].ucDStart = ucDStart; UsedUcodes[usedUcodeIndex].ucDSize = ucDSize; UsedUcodes[usedUcodeIndex].ucode = ucode; UsedUcodes[usedUcodeIndex].crc_800 = crc_800; UsedUcodes[usedUcodeIndex].crc_size = crc_size; UsedUcodes[usedUcodeIndex].used = true; strcpy( UsedUcodes[usedUcodeIndex].rspstr, (char*)str ); TRACE2("New ucode has been detected:\n%s, ucode=%d", str, ucode); return ucode; } } extern int dlistMtxCount; extern bool bHalfTxtScale; void DLParser_Process(OSTask * pTask) { static int skipframe=0; //BOOL menuWaiting = FALSE; dlistMtxCount = 0; bHalfTxtScale = false; if ( CRender::g_pRender == NULL) { TriggerDPInterrupt(); TriggerSPInterrupt(); return; } status.bScreenIsDrawn = true; if( options.bSkipFrame ) { skipframe++; if(skipframe%2) { TriggerDPInterrupt(); TriggerSPInterrupt(); return; } } if( currentRomOptions.N64RenderToTextureEmuType != TXT_BUF_NONE && defaultRomOptions.bSaveVRAM ) { g_pFrameBufferManager->CheckRenderTextureCRCInRDRAM(); } g_pOSTask = pTask; DebuggerPauseCountN( NEXT_DLIST ); status.gRDPTime = (uint32) SDL_GetTicks(); status.gDlistCount++; if ( lastUcodeInfo.ucStart != (uint32)(pTask->t.ucode) ) { uint32 ucode = DLParser_CheckUcode(pTask->t.ucode, pTask->t.ucode_data, pTask->t.ucode_size, pTask->t.ucode_data_size); RSP_SetUcode(ucode, pTask->t.ucode, pTask->t.ucode_data, pTask->t.ucode_size); DEBUGGER_PAUSE_AND_DUMP(NEXT_SWITCH_UCODE,{DebuggerAppendMsg("Pause at switching ucode");}); } // Initialize stack status.bN64FrameBufferIsUsed = false; gDlistStackPointer=0; gDlistStack[gDlistStackPointer].pc = (uint32)pTask->t.data_ptr; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((gDlistStack[gDlistStackPointer].pc == 0 && pauseAtNext && eventToPause==NEXT_UNKNOWN_OP), {DebuggerAppendMsg("Start Task without DLIST: ucode=%08X, data=%08X", (uint32)pTask->t.ucode, (uint32)pTask->t.ucode_data);}); // Check if we need to purge (every 5 milliseconds) if (status.gRDPTime - status.lastPurgeTimeTime > 5) { gTextureManager.PurgeOldTextures(); status.lastPurgeTimeTime = status.gRDPTime; } status.dwNumDListsCulled = 0; status.dwNumTrisRendered = 0; status.dwNumTrisClipped = 0; status.dwNumVertices = 0; status.dwBiggestVertexIndex = 0; if( g_curRomInfo.bForceScreenClear && CGraphicsContext::needCleanScene ) { CRender::g_pRender->ClearBuffer(true,true); CGraphicsContext::needCleanScene = false; } SetVIScales(); CRender::g_pRender->RenderReset(); CRender::g_pRender->BeginRendering(); CRender::g_pRender->SetViewport(0, 0, windowSetting.uViWidth, windowSetting.uViHeight, 0x3FF); CRender::g_pRender->SetFillMode(options.bWinFrameMode? RICE_FILLMODE_WINFRAME : RICE_FILLMODE_SOLID); try { // The main loop while( gDlistStackPointer >= 0 ) { #ifdef DEBUGGER DEBUGGER_PAUSE_COUNT_N(NEXT_UCODE); if( debuggerPause ) { DebuggerPause(); CRender::g_pRender->SetFillMode(options.bWinFrameMode? RICE_FILLMODE_WINFRAME : RICE_FILLMODE_SOLID); } if (gDlistStack[gDlistStackPointer].pc > g_dwRamSize) { DebuggerAppendMsg("Error: dwPC is %08X", gDlistStack[gDlistStackPointer].pc ); break; } #endif status.gUcodeCount++; Gfx *pgfx = (Gfx*)&g_pRDRAMu32[(gDlistStack[gDlistStackPointer].pc>>2)]; #ifdef DEBUGGER LOG_UCODE("0x%08x: %08x %08x %-10s", gDlistStack[gDlistStackPointer].pc, pgfx->words.w0, pgfx->words.w1, (gRSP.ucode!=5&&gRSP.ucode!=10)?ucodeNames_GBI1[(pgfx->words.w0>>24)]:ucodeNames_GBI2[(pgfx->words.w0>>24)]); #endif gDlistStack[gDlistStackPointer].pc += 8; currentUcodeMap[pgfx->words.w0 >>24](pgfx); if ( gDlistStackPointer >= 0 && --gDlistStack[gDlistStackPointer].countdown < 0 ) { LOG_UCODE("**EndDLInMem"); gDlistStackPointer--; } } } catch(...) { TRACE0("Unknown exception happens in ProcessDList"); TriggerDPInterrupt(); } CRender::g_pRender->EndRendering(); if( gRSP.ucode >= 17) TriggerDPInterrupt(); TriggerSPInterrupt(); } ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// // Util Functions // ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// void RDP_NOIMPL_Real(const char* op, uint32 word0, uint32 word1) { #ifdef DEBUGGER if( logWarning ) { TRACE0("Stack Trace"); for( int i=0; iSetCullMode(bCullFront, bCullBack); BOOL bShade = (gRDP.geometryMode & G_SHADE) ? TRUE : FALSE; BOOL bShadeSmooth = (gRDP.geometryMode & G_SHADING_SMOOTH) ? TRUE : FALSE; if (bShade && bShadeSmooth) CRender::g_pRender->SetShadeMode( SHADE_SMOOTH ); else CRender::g_pRender->SetShadeMode( SHADE_FLAT ); CRender::g_pRender->SetFogEnable( gRDP.geometryMode & G_FOG ? true : false ); SetTextureGen((gRDP.geometryMode & G_TEXTURE_GEN) ? true : false ); SetLighting( (gRDP.geometryMode & G_LIGHTING ) ? true : false ); CRender::g_pRender->ZBufferEnable( gRDP.geometryMode & G_ZBUFFER ); } ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// // DP Ucodes // ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// void DLParser_SetKeyGB(Gfx *gfx) { DP_Timing(DLParser_SetKeyGB); gRDP.keyB = ((gfx->words.w1)>>8)&0xFF; gRDP.keyG = ((gfx->words.w1)>>24)&0xFF; gRDP.keyA = (gRDP.keyR+gRDP.keyG+gRDP.keyB)/3; gRDP.fKeyA = gRDP.keyA/255.0f; gRDP.keyScaleB = (gfx->words.w1)&0xFF; gRDP.keyCenterB = (gfx->words.w1>>8)&0xFF; gRDP.keyScaleG = (gfx->words.w1>>16)&0xFF; gRDP.keyCenterG = (gfx->words.w1>>24)&0xFF; gRDP.keyWidthB = (gfx->words.w0)&0xFFF; gRDP.keyWidthG = (gfx->words.w0>>12)&0xFFF; } void DLParser_SetKeyR(Gfx *gfx) { DP_Timing(DLParser_SetKeyR); gRDP.keyR = ((gfx->words.w1)>>8)&0xFF; gRDP.keyA = (gRDP.keyR+gRDP.keyG+gRDP.keyB)/3; gRDP.fKeyA = gRDP.keyA/255.0f; gRDP.keyScaleR = (gfx->words.w1)&0xFF; gRDP.keyCenterR = (gfx->words.w1>>8)&0xFF; gRDP.keyWidthR = (gfx->words.w1>>16)&0xFFF; } int g_convk0,g_convk1,g_convk2,g_convk3,g_convk4,g_convk5; float g_convc0,g_convc1,g_convc2,g_convc3,g_convc4,g_convc5; void DLParser_SetConvert(Gfx *gfx) { DP_Timing(DLParser_SetConvert); int temp; temp = ((gfx->words.w0)>>13)&0x1FF; g_convk0 = temp>0xFF ? -(temp-0x100) : temp; temp = ((gfx->words.w0)>>4)&0x1FF; g_convk1 = temp>0xFF ? -(temp-0x100) : temp; temp = (gfx->words.w0)&0xF; temp = (temp<<5)|(((gfx->words.w1)>>27)&0x1F); g_convk2 = temp>0xFF ? -(temp-0x100) : temp; temp = ((gfx->words.w1)>>18)&0x1FF; g_convk3 = temp>0xFF ? -(temp-0x100) : temp; temp = ((gfx->words.w1)>>9)&0x1FF; g_convk4 = temp>0xFF ? -(temp-0x100) : temp; temp = (gfx->words.w1)&0x1FF; g_convk5 = temp>0xFF ? -(temp-0x100) : temp; g_convc0 = g_convk5/255.0f+1.0f; g_convc1 = g_convk0/255.0f*g_convc0; g_convc2 = g_convk1/255.0f*g_convc0; g_convc3 = g_convk2/255.0f*g_convc0; g_convc4 = g_convk3/255.0f*g_convc0; gRDP.K5 = (uint8)(gfx->words.w1)&0x1FF; gRDP.K4 = (uint8)(gfx->words.w1>>9)&0x1FF; } void DLParser_SetPrimDepth(Gfx *gfx) { DP_Timing(DLParser_SetPrimDepth); uint32 dwZ = ((gfx->words.w1) >> 16) & 0xFFFF; uint32 dwDZ = ((gfx->words.w1) ) & 0xFFFF; LOG_UCODE("SetPrimDepth: 0x%08x 0x%08x - z: 0x%04x dz: 0x%04x", gfx->words.w0, gfx->words.w1, dwZ, dwDZ); SetPrimitiveDepth(dwZ, dwDZ); DEBUGGER_PAUSE(NEXT_SET_PRIM_COLOR); } void DLParser_RDPSetOtherMode(Gfx *gfx) { DP_Timing(DLParser_RDPSetOtherMode); gRDP.otherMode._u32[1] = (gfx->words.w0); // High gRDP.otherMode._u32[0] = (gfx->words.w1); // Low if( gRDP.otherModeH != ((gfx->words.w0) & 0x0FFFFFFF) ) { gRDP.otherModeH = ((gfx->words.w0) & 0x0FFFFFFF); uint32 dwTextFilt = (gRDP.otherModeH>>RSP_SETOTHERMODE_SHIFT_TEXTFILT)&0x3; CRender::g_pRender->SetTextureFilter(dwTextFilt<words.w1) ) { if( (gRDP.otherModeL&ZMODE_DEC) != ((gfx->words.w1)&ZMODE_DEC) ) { if( ((gfx->words.w1)&ZMODE_DEC) == ZMODE_DEC ) CRender::g_pRender->SetZBias( 2 ); else CRender::g_pRender->SetZBias( 0 ); } gRDP.otherModeL = (gfx->words.w1); BOOL bZCompare = (gRDP.otherModeL & Z_COMPARE) ? TRUE : FALSE; BOOL bZUpdate = (gRDP.otherModeL & Z_UPDATE) ? TRUE : FALSE; CRender::g_pRender->SetZCompare( bZCompare ); CRender::g_pRender->SetZUpdate( bZUpdate ); uint32 dwAlphaTestMode = (gRDP.otherModeL >> RSP_SETOTHERMODE_SHIFT_ALPHACOMPARE) & 0x3; if ((dwAlphaTestMode) != 0) CRender::g_pRender->SetAlphaTestEnable( TRUE ); else CRender::g_pRender->SetAlphaTestEnable( FALSE ); } uint16 blender = gRDP.otherMode.blender; RDP_BlenderSetting &bl = *(RDP_BlenderSetting*)(&(blender)); if( bl.c1_m1a==3 || bl.c1_m2a == 3 || bl.c2_m1a == 3 || bl.c2_m2a == 3 ) { gRDP.bFogEnableInBlender = true; } else { gRDP.bFogEnableInBlender = false; } } void DLParser_RDPLoadSync(Gfx *gfx) { DP_Timing(DLParser_RDPLoadSync); LOG_UCODE("LoadSync: (Ignored)"); } void DLParser_RDPPipeSync(Gfx *gfx) { DP_Timing(DLParser_RDPPipeSync); LOG_UCODE("PipeSync: (Ignored)"); } void DLParser_RDPTileSync(Gfx *gfx) { DP_Timing(DLParser_RDPTileSync); LOG_UCODE("TileSync: (Ignored)"); } void DLParser_RDPFullSync(Gfx *gfx) { DP_Timing(DLParser_RDPFullSync); TriggerDPInterrupt(); } void DLParser_SetScissor(Gfx *gfx) { DP_Timing(DLParser_SetScissor); ScissorType tempScissor; // The coords are all in 8:2 fixed point tempScissor.x0 = ((gfx->words.w0)>>12)&0xFFF; tempScissor.y0 = ((gfx->words.w0)>>0 )&0xFFF; tempScissor.mode = ((gfx->words.w1)>>24)&0x03; tempScissor.x1 = ((gfx->words.w1)>>12)&0xFFF; tempScissor.y1 = ((gfx->words.w1)>>0 )&0xFFF; tempScissor.left = tempScissor.x0/4; tempScissor.top = tempScissor.y0/4; tempScissor.right = tempScissor.x1/4; tempScissor.bottom = tempScissor.y1/4; if( options.bEnableHacks ) { if( g_CI.dwWidth == 0x200 && tempScissor.right == 0x200 ) { uint32 width = *g_GraphicsInfo.VI_WIDTH_REG & 0xFFF; if( width != 0x200 ) { // Hack for RE2 tempScissor.bottom = tempScissor.right*tempScissor.bottom/width; tempScissor.right = width; } } } if( gRDP.scissor.left != tempScissor.left || gRDP.scissor.top != tempScissor.top || gRDP.scissor.right != tempScissor.right || gRDP.scissor.bottom != tempScissor.bottom || gRSP.real_clip_scissor_left != tempScissor.left || gRSP.real_clip_scissor_top != tempScissor.top || gRSP.real_clip_scissor_right != tempScissor.right || gRSP.real_clip_scissor_bottom != tempScissor.bottom) { memcpy(&(gRDP.scissor), &tempScissor, sizeof(ScissorType) ); if( !status.bHandleN64RenderTexture ) SetVIScales(); if( options.enableHackForGames == HACK_FOR_SUPER_BOWLING && g_CI.dwAddr%0x100 != 0 ) { // right half screen gRDP.scissor.left += 160; gRDP.scissor.right += 160; CRender::g_pRender->SetViewport(160, 0, 320, 240, 0xFFFF); } CRender::g_pRender->UpdateClipRectangle(); CRender::g_pRender->UpdateScissor(); CRender::g_pRender->SetViewportRender(); } LOG_UCODE("SetScissor: x0=%d y0=%d x1=%d y1=%d mode=%d", gRDP.scissor.left, gRDP.scissor.top, gRDP.scissor.right, gRDP.scissor.bottom, gRDP.scissor.mode); ///TXTRBUF_DETAIL_DUMP(DebuggerAppendMsg("SetScissor: x0=%d y0=%d x1=%d y1=%d mode=%d", gRDP.scissor.left, gRDP.scissor.top, //gRDP.scissor.right, gRDP.scissor.bottom, gRDP.scissor.mode);); } void DLParser_FillRect(Gfx *gfx) { DP_Timing(DLParser_FillRect); // fix me status.primitiveType = PRIM_FILLRECT; if( status.bN64IsDrawingTextureBuffer && frameBufferOptions.bIgnore ) { return; } if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS ) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction uint32 w2 = *(uint32 *)(g_pRDRAMu8 + dwPC); if( (w2>>24) == RDP_FILLRECT ) { // Mario Tennis, a lot of FillRect ucodes, skip all of them while( (w2>>24) == RDP_FILLRECT ) { dwPC += 8; w2 = *(uint32 *)(g_pRDRAMu8 + dwPC); } gDlistStack[gDlistStackPointer].pc = dwPC; return; } } uint32 x0 = (((gfx->words.w1)>>12)&0xFFF)/4; uint32 y0 = (((gfx->words.w1)>>0 )&0xFFF)/4; uint32 x1 = (((gfx->words.w0)>>12)&0xFFF)/4; uint32 y1 = (((gfx->words.w0)>>0 )&0xFFF)/4; // Note, in some modes, the right/bottom lines aren't drawn LOG_UCODE(" (%d,%d) (%d,%d)", x0, y0, x1, y1); if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY ) { x1++; y1++; } //TXTRBUF_DETAIL_DUMP(DebuggerAppendMsg("FillRect: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%08X", x0, y0, x1, y1, gRDP.originalFillColor);); if( status.bHandleN64RenderTexture && options.enableHackForGames == HACK_FOR_BANJO_TOOIE ) { // Skip this return; } if (IsUsedAsDI(g_CI.dwAddr)) { // Clear the Z Buffer if( x0!=0 || y0!=0 || windowSetting.uViWidth-x1>1 || windowSetting.uViHeight-y1>1) { if( options.enableHackForGames == HACK_FOR_GOLDEN_EYE ) { // GoldenEye is using double zbuffer if( g_CI.dwAddr == g_ZI.dwAddr ) { // The zbuffer is the upper screen COORDRECT rect={int(x0*windowSetting.fMultX),int(y0*windowSetting.fMultY),int(x1*windowSetting.fMultX),int(y1*windowSetting.fMultY)}; CRender::g_pRender->ClearBuffer(false,true,rect); //Check me LOG_UCODE(" Clearing ZBuffer"); } else { // The zbuffer is the lower screen int h = (g_CI.dwAddr-g_ZI.dwAddr)/g_CI.dwWidth/2; COORDRECT rect={int(x0*windowSetting.fMultX),int((y0+h)*windowSetting.fMultY),int(x1*windowSetting.fMultX),int((y1+h)*windowSetting.fMultY)}; CRender::g_pRender->ClearBuffer(false,true,rect); //Check me LOG_UCODE(" Clearing ZBuffer"); } } else { COORDRECT rect={int(x0*windowSetting.fMultX),int(y0*windowSetting.fMultY),int(x1*windowSetting.fMultX),int(y1*windowSetting.fMultY)}; CRender::g_pRender->ClearBuffer(false,true,rect); //Check me LOG_UCODE(" Clearing ZBuffer"); } } else { CRender::g_pRender->ClearBuffer(false,true); //Check me LOG_UCODE(" Clearing ZBuffer"); } DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FLUSH_TRI,{TRACE0("Pause after FillRect: ClearZbuffer\n");}); DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FILLRECT, {DebuggerAppendMsg("ClearZbuffer: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%08X", x0, y0, x1, y1, gRDP.originalFillColor); DebuggerAppendMsg("Pause after ClearZbuffer: Color=%08X\n", gRDP.originalFillColor);}); if( g_curRomInfo.bEmulateClear ) { // Emulating Clear, by write the memory in RDRAM uint16 color = (uint16)gRDP.originalFillColor; uint32 pitch = g_CI.dwWidth<<1; long long base = (long long) (g_pRDRAMu8 + g_CI.dwAddr); for( uint32 i =y0; iActiveTextureBuffer(); status.leftRendered = status.leftRendered<0 ? x0 : std::min((int)x0,status.leftRendered); status.topRendered = status.topRendered<0 ? y0 : std::min((int)y0,status.topRendered); status.rightRendered = status.rightRendered<0 ? x1 : std::max((int)x1,status.rightRendered); status.bottomRendered = status.bottomRendered<0 ? y1 : std::max((int)y1,status.bottomRendered); g_pRenderTextureInfo->maxUsedHeight = std::max(g_pRenderTextureInfo->maxUsedHeight,(int)y1); if( status.bDirectWriteIntoRDRAM || ( x0==0 && y0==0 && (x1 == g_pRenderTextureInfo->N64Width || x1 == g_pRenderTextureInfo->N64Width-1 ) ) ) { if( g_pRenderTextureInfo->CI_Info.dwSize == TXT_SIZE_16b ) { uint16 color = (uint16)gRDP.originalFillColor; uint32 pitch = g_pRenderTextureInfo->N64Width<<1; long long base = (long long) (g_pRDRAMu8 + g_pRenderTextureInfo->CI_Info.dwAddr); for( uint32 i =y0; iN64Width; long long base = (long long) (g_pRDRAMu8 + g_pRenderTextureInfo->CI_Info.dwAddr); for( uint32 i=y0; iN64Width || x1 == g_pRenderTextureInfo->N64Width-1 ) && gRDP.fillColor == 0) //{ // CRender::g_pRender->ClearBuffer(true,false); //} //else { if( gRDP.otherMode.cycle_type == CYCLE_TYPE_FILL ) { CRender::g_pRender->FillRect(x0, y0, x1, y1, gRDP.fillColor); } else { COLOR primColor = GetPrimitiveColor(); CRender::g_pRender->FillRect(x0, y0, x1, y1, primColor); } } } DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FLUSH_TRI,{TRACE0("Pause after FillRect\n");}); DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FILLRECT, {DebuggerAppendMsg("FillRect: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%08X", x0, y0, x1, y1, gRDP.originalFillColor); DebuggerAppendMsg("Pause after FillRect: Color=%08X\n", gRDP.originalFillColor);}); } else { LOG_UCODE(" Filling Rectangle"); if( frameBufferOptions.bSupportRenderTextures || frameBufferOptions.bCheckBackBufs ) { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); status.leftRendered = status.leftRendered<0 ? x0 : std::min((int)x0,status.leftRendered); status.topRendered = status.topRendered<0 ? y0 : std::min((int)y0,status.topRendered); status.rightRendered = status.rightRendered<0 ? x1 : std::max((int)x1,status.rightRendered); status.bottomRendered = status.bottomRendered<0 ? y1 : std::max((int)y1,status.bottomRendered); } if( !status.bHandleN64RenderTexture || g_pRenderTextureInfo->CI_Info.dwSize == TXT_SIZE_16b ) { CRender::g_pRender->FillRect(x0, y0, x1, y1, gRDP.fillColor); } DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FLUSH_TRI,{TRACE0("Pause after FillRect\n");}); DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FILLRECT, {DebuggerAppendMsg("FillRect: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%08X", x0, y0, x1, y1, gRDP.originalFillColor); DebuggerAppendMsg("Pause after FillRect: Color=%08X\n", gRDP.originalFillColor);}); } } #define STORE_CI {g_CI.dwAddr = dwNewAddr;g_CI.dwFormat = dwFmt;g_CI.dwSize = dwSiz;g_CI.dwWidth = dwWidth;g_CI.bpl=dwBpl;} void DLParser_SetCImg(Gfx *gfx) { uint32 dwFmt = gfx->setimg.fmt; uint32 dwSiz = gfx->setimg.siz; uint32 dwWidth = gfx->setimg.width + 1; uint32 dwNewAddr = RSPSegmentAddr((gfx->setimg.addr)) & 0x00FFFFFF ; uint32 dwBpl = dwWidth << dwSiz >> 1; TXTRBUF_DETAIL_DUMP(DebuggerAppendMsg("SetCImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", dwNewAddr, pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth);); if( dwFmt == TXT_FMT_YUV || dwFmt == TXT_FMT_IA ) { WARNING(TRACE4("Check me: SetCImg Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_CI.dwAddr, pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth)); } LOG_UCODE(" Image: 0x%08x", RSPSegmentAddr(gfx->words.w1)); LOG_UCODE(" Fmt: %s Size: %s Width: %d", pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth); if( g_CI.dwAddr == dwNewAddr && g_CI.dwFormat == dwFmt && g_CI.dwSize == dwSiz && g_CI.dwWidth == dwWidth ) { TXTRBUF_OR_CI_DETAIL_DUMP({ TRACE0("Set CIMG to the same address, no change, skipped"); DebuggerAppendMsg("Pause after SetCImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_CI.dwAddr, pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth); }); return; } if( status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_1ST_CI_CHANGE ) { status.bVIOriginIsUpdated=false; CGraphicsContext::Get()->UpdateFrame(); TXTRBUF_OR_CI_DETAIL_DUMP(TRACE0("Screen Update at 1st CI change");); } if( options.enableHackForGames == HACK_FOR_SUPER_BOWLING ) { if( dwNewAddr%0x100 == 0 ) { if( dwWidth < 320 ) { // Left half screen gRDP.scissor.left = 0; gRDP.scissor.right = 160; CRender::g_pRender->SetViewport(0, 0, 160, 240, 0xFFFF); CRender::g_pRender->UpdateClipRectangle(); CRender::g_pRender->UpdateScissor(); } else { gRDP.scissor.left = 0; gRDP.scissor.right = 320; CRender::g_pRender->SetViewport(0, 0, 320, 240, 0xFFFF); CRender::g_pRender->UpdateClipRectangle(); CRender::g_pRender->UpdateScissor(); } } else { // right half screen gRDP.scissor.left = 160; gRDP.scissor.right = 320; gRSP.nVPLeftN = 160; gRSP.nVPRightN = 320; CRender::g_pRender->UpdateClipRectangle(); CRender::g_pRender->UpdateScissor(); CRender::g_pRender->SetViewport(160, 0, 320, 240, 0xFFFF); } } if( !frameBufferOptions.bUpdateCIInfo ) { STORE_CI; status.bCIBufferIsRendered = false; status.bN64IsDrawingTextureBuffer = false; TXTRBUF_DUMP(TRACE4("SetCImg : Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_CI.dwAddr, pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth)); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG, { DebuggerAppendMsg("Pause after SetCImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", dwNewAddr, pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth); } ); return; } SetImgInfo newCI; newCI.bpl = dwBpl; newCI.dwAddr = dwNewAddr; newCI.dwFormat = dwFmt; newCI.dwSize = dwSiz; newCI.dwWidth = dwWidth; g_pFrameBufferManager->Set_CI_addr(newCI); } void DLParser_SetZImg(Gfx *gfx) { DP_Timing(DLParser_SetZImg); LOG_UCODE(" Image: 0x%08x", RSPSegmentAddr(gfx->words.w1)); uint32 dwFmt = gfx->setimg.fmt; uint32 dwSiz = gfx->setimg.siz; uint32 dwWidth = gfx->setimg.width + 1; uint32 dwAddr = RSPSegmentAddr((gfx->setimg.addr)); if( dwAddr != g_ZI_saves[0].CI_Info.dwAddr ) { g_ZI_saves[1].CI_Info.dwAddr = g_ZI.dwAddr; g_ZI_saves[1].CI_Info.dwFormat = g_ZI.dwFormat; g_ZI_saves[1].CI_Info.dwSize = g_ZI.dwSize; g_ZI_saves[1].CI_Info.dwWidth = g_ZI.dwWidth; g_ZI_saves[1].updateAtFrame = g_ZI_saves[0].updateAtFrame; g_ZI_saves[0].CI_Info.dwAddr = g_ZI.dwAddr = dwAddr; g_ZI_saves[0].CI_Info.dwFormat = g_ZI.dwFormat = dwFmt; g_ZI_saves[0].CI_Info.dwSize = g_ZI.dwSize = dwSiz; g_ZI_saves[0].CI_Info.dwWidth = g_ZI.dwWidth = dwWidth; g_ZI_saves[0].updateAtFrame = status.gDlistCount; } else { g_ZI.dwAddr = dwAddr; g_ZI.dwFormat = dwFmt; g_ZI.dwSize = dwSiz; g_ZI.dwWidth = dwWidth; } DEBUGGER_IF_DUMP((pauseAtNext) , {DebuggerAppendMsg("SetZImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_ZI.dwAddr, pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth);} ); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG, { DebuggerAppendMsg("Pause after SetZImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", g_ZI.dwAddr, pszImgFormat[dwFmt], pszImgSize[dwSiz], dwWidth); } ); } bool IsUsedAsDI(uint32 addr) { if( addr == g_ZI_saves[0].CI_Info.dwAddr ) return true; else if( addr == g_ZI_saves[1].CI_Info.dwAddr && status.gDlistCount - g_ZI_saves[1].updateAtFrame < 10 && g_ZI_saves[1].CI_Info.dwAddr != 0 ) return true; else return false; } void DLParser_SetCombine(Gfx *gfx) { DP_Timing(DLParser_SetCombine); uint32 dwMux0 = (gfx->words.w0)&0x00FFFFFF; uint32 dwMux1 = (gfx->words.w1); CRender::g_pRender->SetCombineMode(dwMux0, dwMux1); } void DLParser_SetFillColor(Gfx *gfx) { DP_Timing(DLParser_SetFillColor); gRDP.fillColor = Convert555ToRGBA(gfx->setcolor.fillcolor); gRDP.originalFillColor = (gfx->setcolor.color); LOG_UCODE(" Color5551=0x%04x = 0x%08x", (uint16)gfx->words.w1, gRDP.fillColor); } void DLParser_SetFogColor(Gfx *gfx) { DP_Timing(DLParser_SetFogColor); CRender::g_pRender->SetFogColor( gfx->setcolor.r, gfx->setcolor.g, gfx->setcolor.b, gfx->setcolor.a ); FOG_DUMP(TRACE1("Set Fog color: %08X", gfx->setcolor.color)); } void DLParser_SetBlendColor(Gfx *gfx) { DP_Timing(DLParser_SetBlendColor); gRDP.blendColor = gfx->setcolor.color; gRDP.fvBlendColor[0] = gfx->setcolor.r/255.0f; gRDP.fvBlendColor[1] = gfx->setcolor.g/255.0f; gRDP.fvBlendColor[2] = gfx->setcolor.b/255.0f; gRDP.fvBlendColor[3] = gfx->setcolor.a/255.0f; } void DLParser_SetPrimColor(Gfx *gfx) { DP_Timing(DLParser_SetPrimColor); gRDP.primitiveColor = gfx->setcolor.color; gRDP.primLODMin = gfx->setcolor.prim_min_level; gRDP.primLODFrac = gfx->setcolor.prim_level; if( gRDP.primLODFrac < gRDP.primLODMin ) { gRDP.primLODFrac = gRDP.primLODMin; } gRDP.fvPrimitiveColor[0] = gfx->setcolor.r/255.0f; gRDP.fvPrimitiveColor[1] = gfx->setcolor.g/255.0f; gRDP.fvPrimitiveColor[2] = gfx->setcolor.b/255.0f; gRDP.fvPrimitiveColor[3] = gfx->setcolor.a/255.0f; } void DLParser_SetEnvColor(Gfx *gfx) { DP_Timing(DLParser_SetEnvColor); gRDP.envColor = gfx->setcolor.color; gRDP.fvEnvColor[0] = gfx->setcolor.r/255.0f; gRDP.fvEnvColor[1] = gfx->setcolor.g/255.0f; gRDP.fvEnvColor[2] = gfx->setcolor.b/255.0f; gRDP.fvEnvColor[3] = gfx->setcolor.a/255.0f; } void RDP_DLParser_Process(void) { status.gRDPTime = (uint32) SDL_GetTicks(); status.gDlistCount++; uint32 start = *(g_GraphicsInfo.DPC_START_REG); uint32 end = *(g_GraphicsInfo.DPC_END_REG); gDlistStackPointer=0; gDlistStack[gDlistStackPointer].pc = start; gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT; // Check if we need to purge (every 5 milliseconds) if (status.gRDPTime - status.lastPurgeTimeTime > 5) { gTextureManager.PurgeOldTextures(); status.lastPurgeTimeTime = status.gRDPTime; } // Lock the graphics context here. CRender::g_pRender->SetFillMode(RICE_FILLMODE_SOLID); SetVIScales(); CRender::g_pRender->RenderReset(); CRender::g_pRender->BeginRendering(); CRender::g_pRender->SetViewport(0, 0, windowSetting.uViWidth, windowSetting.uViHeight, 0x3FF); while( gDlistStack[gDlistStackPointer].pc < end ) { Gfx *pgfx = (Gfx*)&g_pRDRAMu32[(gDlistStack[gDlistStackPointer].pc>>2)]; gDlistStack[gDlistStackPointer].pc += 8; currentUcodeMap[pgfx->words.w0 >>24](pgfx); } CRender::g_pRender->EndRendering(); } void RDP_TriFill(Gfx *gfx) { } void RDP_TriFillZ(Gfx *gfx) { } void RDP_TriTxtr(Gfx *gfx) { } void RDP_TriTxtrZ(Gfx *gfx) { } void RDP_TriShade(Gfx *gfx) { } void RDP_TriShadeZ(Gfx *gfx) { } void RDP_TriShadeTxtr(Gfx *gfx) { } void RDP_TriShadeTxtrZ(Gfx *gfx) { } static int crc_table_empty = 1; static unsigned int crc_table[256]; static void make_crc_table(void); static void make_crc_table() { unsigned int c; int n, k; unsigned int poly; /* polynomial exclusive-or pattern */ /* terms of polynomial defining this crc (except x^32): */ static const uint8 p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; /* make exclusive-or pattern from polynomial (0xedb88320L) */ poly = 0L; for (n = 0; (unsigned int)n < sizeof(p)/sizeof(uint8); n++) poly |= 1L << (31 - p[n]); for (n = 0; n < 256; n++) { c = (unsigned int)n; for (k = 0; k < 8; k++) c = (c & 1) ? (poly ^ (c >> 1)) : c >> 1; crc_table[n] = c; } crc_table_empty = 0; } /* ========================================================================= */ #define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); #define DO2(buf) DO1(buf); DO1(buf); #define DO4(buf) DO2(buf); DO2(buf); #define DO8(buf) DO4(buf); DO4(buf); /* ========================================================================= */ unsigned int ComputeCRC32(unsigned int crc, const uint8 *buf, unsigned int len) { if (buf == NULL) return 0L; if (crc_table_empty) make_crc_table(); crc = crc ^ 0xffffffffL; while (len >= 8) { DO8(buf); len -= 8; } if (len) do { DO1(buf); } while (--len); return crc ^ 0xffffffffL; } Matrix matToLoad; void LoadMatrix(uint32 addr) { const float fRecip = 1.0f / 65536.0f; if (addr + 64 > g_dwRamSize) { TRACE1("Mtx: Address invalid (0x%08x)", addr); return; } for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { int hi = *(short *)(g_pRDRAMu8 + ((addr+(i<<3)+(j<<1) )^0x2)); int lo = *(unsigned short *)(g_pRDRAMu8 + ((addr+(i<<3)+(j<<1) + 32)^0x2)); matToLoad.m[i][j] = (float)((hi<<16) | lo) * fRecip; } } #ifdef DEBUGGER LOG_UCODE( " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n" " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n", matToLoad.m[0][0], matToLoad.m[0][1], matToLoad.m[0][2], matToLoad.m[0][3], matToLoad.m[1][0], matToLoad.m[1][1], matToLoad.m[1][2], matToLoad.m[1][3], matToLoad.m[2][0], matToLoad.m[2][1], matToLoad.m[2][2], matToLoad.m[2][3], matToLoad.m[3][0], matToLoad.m[3][1], matToLoad.m[3][2], matToLoad.m[3][3]); #endif // DEBUGGER } mupen64plus-video-rice-src-2.6.0/src/RSP_Parser.h000066400000000000000000000466611464507324400215000ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __RICE_RDP_GFX_H__ #define __RICE_RDP_GFX_H__ #if defined(__GNUC__) #define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos))) #else #define ATTR_FMT(fmtpos, attrpos) #endif #include "typedefs.h" #define RSP_SPNOOP 0 // handle 0 gracefully #define RSP_MTX 1 #define RSP_RESERVED0 2 // unknown #define RSP_MOVEMEM 3 // move a block of memory (up to 4 words) to dmem #define RSP_VTX 4 #define RSP_RESERVED1 5 // unknown #define RSP_DL 6 #define RSP_RESERVED2 7 // unknown #define RSP_RESERVED3 8 // unknown #define RSP_SPRITE2D 9 // sprite command #define RSP_SPRITE2D_BASE 9 // sprite command #define RSP_1ST 0xBF #define RSP_TRI1 (RSP_1ST-0) #define RSP_CULLDL (RSP_1ST-1) #define RSP_POPMTX (RSP_1ST-2) #define RSP_MOVEWORD (RSP_1ST-3) #define RSP_TEXTURE (RSP_1ST-4) #define RSP_SETOTHERMODE_H (RSP_1ST-5) #define RSP_SETOTHERMODE_L (RSP_1ST-6) #define RSP_ENDDL (RSP_1ST-7) #define RSP_SETGEOMETRYMODE (RSP_1ST-8) #define RSP_CLEARGEOMETRYMODE (RSP_1ST-9) #define RSP_LINE3D (RSP_1ST-10) #define RSP_RDPHALF_1 (RSP_1ST-11) #define RSP_RDPHALF_2 (RSP_1ST-12) #define RSP_RDPHALF_CONT (RSP_1ST-13) #define RSP_MODIFYVTX (RSP_1ST-13) #define RSP_TRI2 (RSP_1ST-14) #define RSP_BRANCH_Z (RSP_1ST-15) #define RSP_LOAD_UCODE (RSP_1ST-16) #define RSP_SPRITE2D_SCALEFLIP (RSP_1ST-1) #define RSP_SPRITE2D_DRAW (RSP_1ST-2) #define RSP_ZELDAVTX 1 #define RSP_ZELDAMODIFYVTX 2 #define RSP_ZELDACULLDL 3 #define RSP_ZELDABRANCHZ 4 #define RSP_ZELDATRI1 5 #define RSP_ZELDATRI2 6 #define RSP_ZELDALINE3D 7 #define RSP_ZELDARDPHALF_2 0xf1 #define RSP_ZELDASETOTHERMODE_H 0xe3 #define RSP_ZELDASETOTHERMODE_L 0xe2 #define RSP_ZELDARDPHALF_1 0xe1 #define RSP_ZELDASPNOOP 0xe0 #define RSP_ZELDAENDDL 0xdf #define RSP_ZELDADL 0xde #define RSP_ZELDALOAD_UCODE 0xdd #define RSP_ZELDAMOVEMEM 0xdc #define RSP_ZELDAMOVEWORD 0xdb #define RSP_ZELDAMTX 0xda #define RSP_ZELDAGEOMETRYMODE 0xd9 #define RSP_ZELDAPOPMTX 0xd8 #define RSP_ZELDATEXTURE 0xd7 #define RSP_ZELDASUBMODULE 0xd6 // 4 is something like a conditional DL #define RSP_DMATRI 0x05 #define G_DLINMEM 0x07 // RDP commands: #define RDP_NOOP 0xc0 #define RDP_SETCIMG 0xff #define RDP_SETZIMG 0xfe #define RDP_SETTIMG 0xfd #define RDP_SETCOMBINE 0xfc #define RDP_SETENVCOLOR 0xfb #define RDP_SETPRIMCOLOR 0xfa #define RDP_SETBLENDCOLOR 0xf9 #define RDP_SETFOGCOLOR 0xf8 #define RDP_SETFILLCOLOR 0xf7 #define RDP_FILLRECT 0xf6 #define RDP_SETTILE 0xf5 #define RDP_LOADTILE 0xf4 #define RDP_LOADBLOCK 0xf3 #define RDP_SETTILESIZE 0xf2 #define RDP_LOADTLUT 0xf0 #define RDP_RDPSETOTHERMODE 0xef #define RDP_SETPRIMDEPTH 0xee #define RDP_SETSCISSOR 0xed #define RDP_SETCONVERT 0xec #define RDP_SETKEYR 0xeb #define RDP_SETKEYGB 0xea #define RDP_FULLSYNC 0xe9 #define RDP_TILESYNC 0xe8 #define RDP_PIPESYNC 0xe7 #define RDP_LOADSYNC 0xe6 #define RDP_TEXRECT_FLIP 0xe5 #define RDP_TEXRECT 0xe4 #define RSP_ZELDA_MTX_MODELVIEW 0x00 #define RSP_ZELDA_MTX_PROJECTION 0x04 #define RSP_ZELDA_MTX_MUL 0x00 #define RSP_ZELDA_MTX_LOAD 0x02 #define RSP_ZELDA_MTX_PUSH 0x00 #define RSP_ZELDA_MTX_NOPUSH 0x01 // // RSP_SETOTHERMODE_L sft: shift count #define RSP_SETOTHERMODE_SHIFT_ALPHACOMPARE 0 #define RSP_SETOTHERMODE_SHIFT_ZSRCSEL 2 #define RSP_SETOTHERMODE_SHIFT_RENDERMODE 3 #define RSP_SETOTHERMODE_SHIFT_BLENDER 16 // // RSP_SETOTHERMODE_H sft: shift count #define RSP_SETOTHERMODE_SHIFT_BLENDMASK 0 // unsupported #define RSP_SETOTHERMODE_SHIFT_ALPHADITHER 4 #define RSP_SETOTHERMODE_SHIFT_RGBDITHER 6 #define RSP_SETOTHERMODE_SHIFT_COMBKEY 8 #define RSP_SETOTHERMODE_SHIFT_TEXTCONV 9 #define RSP_SETOTHERMODE_SHIFT_TEXTFILT 12 #define RSP_SETOTHERMODE_SHIFT_TEXTLUT 14 #define RSP_SETOTHERMODE_SHIFT_TEXTLOD 16 #define RSP_SETOTHERMODE_SHIFT_TEXTDETAIL 17 #define RSP_SETOTHERMODE_SHIFT_TEXTPERSP 19 #define RSP_SETOTHERMODE_SHIFT_CYCLETYPE 20 #define RSP_SETOTHERMODE_SHIFT_COLORDITHER 22 // unsupported in HW 2.0 #define RSP_SETOTHERMODE_SHIFT_PIPELINE 23 // RSP_SETOTHERMODE_H gPipelineMode #define RSP_PIPELINE_MODE_1PRIMITIVE (1 << RSP_SETOTHERMODE_SHIFT_PIPELINE) #define RSP_PIPELINE_MODE_NPRIMITIVE (0 << RSP_SETOTHERMODE_SHIFT_PIPELINE) // RSP_SETOTHERMODE_H gSetCycleType #define CYCLE_TYPE_1 0 #define CYCLE_TYPE_2 1 #define CYCLE_TYPE_COPY 2 #define CYCLE_TYPE_FILL 3 // RSP_SETOTHERMODE_H gSetTextureLUT #define TLUT_FMT_NONE (0 << RSP_SETOTHERMODE_SHIFT_TEXTLUT) #define TLUT_FMT_UNKNOWN (1 << RSP_SETOTHERMODE_SHIFT_TEXTLUT) #define TLUT_FMT_RGBA16 (2 << RSP_SETOTHERMODE_SHIFT_TEXTLUT) #define TLUT_FMT_IA16 (3 << RSP_SETOTHERMODE_SHIFT_TEXTLUT) // RSP_SETOTHERMODE_H gSetTextureFilter #define RDP_TFILTER_POINT (0 << RSP_SETOTHERMODE_SHIFT_TEXTFILT) #define RDP_TFILTER_AVERAGE (3 << RSP_SETOTHERMODE_SHIFT_TEXTFILT) #define RDP_TFILTER_BILERP (2 << RSP_SETOTHERMODE_SHIFT_TEXTFILT) /* G_SETOTHERMODE_H gSetCombineKey */ #define RDP_COMBKEY_NONE (0 << RSP_SETOTHERMODE_SHIFT_COMBKEY) #define RDP_COMBKEY_KEY (1 << RSP_SETOTHERMODE_SHIFT_COMBKEY) // RSP_SETOTHERMODE_L gSetAlphaCompare #define RDP_ALPHA_COMPARE_NONE (0 << RSP_SETOTHERMODE_SHIFT_ALPHACOMPARE) #define RDP_ALPHA_COMPARE_THRESHOLD (1 << RSP_SETOTHERMODE_SHIFT_ALPHACOMPARE) #define RDP_ALPHA_COMPARE_DITHER (3 << RSP_SETOTHERMODE_SHIFT_ALPHACOMPARE) // RSP_SETOTHERMODE_L gSetRenderMode #define Z_COMPARE 0x0010 #define Z_UPDATE 0x0020 #define ZMODE_DEC 0x0c00 // // flags for RSP_SETGEOMETRYMODE // #define G_ZBUFFER 0x00000001 #define G_TEXTURE_ENABLE 0x00000002 // Microcode use only #define G_SHADE 0x00000004 // enable Gouraud interp // #define G_SHADING_SMOOTH 0x00000200 // flat or smooth shaded #define G_CULL_FRONT 0x00001000 #define G_CULL_BACK 0x00002000 #define G_CULL_BOTH 0x00003000 // To make code cleaner #define G_FOG 0x00010000 #define G_LIGHTING 0x00020000 #define G_TEXTURE_GEN 0x00040000 #define G_TEXTURE_GEN_LINEAR 0x00080000 #define G_LOD 0x00100000 // NOT IMPLEMENTED // // G_SETIMG fmt: set image formats // #define TXT_FMT_RGBA 0 #define TXT_FMT_YUV 1 #define TXT_FMT_CI 2 #define TXT_FMT_IA 3 #define TXT_FMT_I 4 // // G_SETIMG siz: set image pixel size // #define TXT_SIZE_4b 0 #define TXT_SIZE_8b 1 #define TXT_SIZE_16b 2 #define TXT_SIZE_32b 3 // // Texturing macros // #define RDP_TXT_LOADTILE 7 #define RDP_TXT_RENDERTILE 0 #define RDP_TXT_NOMIRROR 0 #define RDP_TXT_WRAP 0 #define RDP_TXT_MIRROR 0x1 #define RDP_TXT_CLAMP 0x2 #define RDP_TXT_NOMASK 0 #define RDP_TXT_NOLOD 0 // // MOVEMEM indices // // Each of these indexes an entry in a dmem table // which points to a 1-4 word block of dmem in // which to store a 1-4 word DMA. // // #define RSP_GBI1_MV_MEM_VIEWPORT 0x80 #define RSP_GBI1_MV_MEM_LOOKATY 0x82 #define RSP_GBI1_MV_MEM_LOOKATX 0x84 #define RSP_GBI1_MV_MEM_L0 0x86 #define RSP_GBI1_MV_MEM_L1 0x88 #define RSP_GBI1_MV_MEM_L2 0x8a #define RSP_GBI1_MV_MEM_L3 0x8c #define RSP_GBI1_MV_MEM_L4 0x8e #define RSP_GBI1_MV_MEM_L5 0x90 #define RSP_GBI1_MV_MEM_L6 0x92 #define RSP_GBI1_MV_MEM_L7 0x94 #define RSP_GBI1_MV_MEM_TXTATT 0x96 #define RSP_GBI1_MV_MEM_MATRIX_1 0x9e // NOTE: this is in moveword table #define RSP_GBI1_MV_MEM_MATRIX_2 0x98 #define RSP_GBI1_MV_MEM_MATRIX_3 0x9a #define RSP_GBI1_MV_MEM_MATRIX_4 0x9c # define RSP_GBI2_MV_MEM__VIEWPORT 8 # define RSP_GBI2_MV_MEM__LIGHT 10 # define RSP_GBI2_MV_MEM__POINT 12 # define RSP_GBI2_MV_MEM__MATRIX 14 /* NOTE: this is in moveword table */ # define RSP_GBI2_MV_MEM_O_LOOKATX (0*24) # define RSP_GBI2_MV_MEM_O_LOOKATY (1*24) # define RSP_GBI2_MV_MEM_O_L0 (2*24) # define RSP_GBI2_MV_MEM_O_L1 (3*24) # define RSP_GBI2_MV_MEM_O_L2 (4*24) # define RSP_GBI2_MV_MEM_O_L3 (5*24) # define RSP_GBI2_MV_MEM_O_L4 (6*24) # define RSP_GBI2_MV_MEM_O_L5 (7*24) # define RSP_GBI2_MV_MEM_O_L6 (8*24) # define RSP_GBI2_MV_MEM_O_L7 (9*24) // // MOVEWORD indices // // Each of these indexes an entry in a dmem table // which points to a word in dmem in dmem where // an immediate word will be stored. // // #define RSP_MOVE_WORD_MATRIX 0x00 // NOTE: also used by movemem #define RSP_MOVE_WORD_NUMLIGHT 0x02 #define RSP_MOVE_WORD_CLIP 0x04 #define RSP_MOVE_WORD_SEGMENT 0x06 #define RSP_MOVE_WORD_FOG 0x08 #define RSP_MOVE_WORD_LIGHTCOL 0x0a #define RSP_MOVE_WORD_POINTS 0x0c #define RSP_MOVE_WORD_PERSPNORM 0x0e // // These are offsets from the address in the dmem table // #define RSP_MV_WORD_OFFSET_NUMLIGHT 0x00 #define RSP_MV_WORD_OFFSET_CLIP_RNX 0x04 #define RSP_MV_WORD_OFFSET_CLIP_RNY 0x0c #define RSP_MV_WORD_OFFSET_CLIP_RPX 0x14 #define RSP_MV_WORD_OFFSET_CLIP_RPY 0x1c #define RSP_MV_WORD_OFFSET_FOG 0x00 #define RSP_MV_WORD_OFFSET_POINT_RGBA 0x10 #define RSP_MV_WORD_OFFSET_POINT_ST 0x14 #define RSP_MV_WORD_OFFSET_POINT_XYSCREEN 0x18 #define RSP_MV_WORD_OFFSET_POINT_ZSCREEN 0x1c // flags to inhibit pushing of the display list (on branch) #define RSP_DLIST_PUSH 0x00 #define RSP_DLIST_NOPUSH 0x01 // // RSP_MTX: parameter flags // #define RSP_MATRIX_MODELVIEW 0x00 #define RSP_MATRIX_PROJECTION 0x01 #define RSP_MATRIX_MUL 0x00 #define RSP_MATRIX_LOAD 0x02 #define RSP_MATRIX_NOPUSH 0x00 #define RSP_MATRIX_PUSH 0x04 typedef struct { uint32 type; uint32 flags; uint32 ucode_boot; uint32 ucode_boot_size; uint32 ucode; uint32 ucode_size; uint32 ucode_data; uint32 ucode_data_size; uint32 dram_stack; uint32 dram_stack_size; uint32 output_buff; uint32 output_buff_size; uint32 data_ptr; uint32 data_size; uint32 yield_data_ptr; uint32 yield_data_size; } OSTask_t; typedef union { OSTask_t t; uint64 force_structure_alignment; } OSTask; #define MAX_DL_STACK_SIZE 32 #define MAX_DL_COUNT 1000000 typedef struct { bool used; uint32 crc_size; uint32 crc_800; uint32 ucode; uint32 minor_ver; uint32 variant; char rspstr[200]; uint32 ucStart; uint32 ucSize; uint32 ucDStart; uint32 ucDSize; uint32 ucCRC; uint32 ucDWORD1; uint32 ucDWORD2; uint32 ucDWORD3; uint32 ucDWORD4; } UcodeInfo; typedef struct { uint32 ucode; uint32 crc_size; uint32 crc_800; const unsigned char * ucode_name; bool non_nearclip; bool reject; } UcodeData; struct TileDescriptor { // Set by SetTile unsigned int dwFormat :3; // e.g. RGBA, YUV etc unsigned int dwSize :2; // e.g 4/8/16/32bpp unsigned int dwLine :9; // Ummm... unsigned int dwPalette :4; // 0..15 - a palette index? uint32 dwTMem; // Texture memory location unsigned int bClampS :1; unsigned int bClampT :1; unsigned int bMirrorS :1; unsigned int bMirrorT :1; unsigned int dwMaskS :4; unsigned int dwMaskT :4; unsigned int dwShiftS :4; unsigned int dwShiftT :4; // Set by SetTileSize unsigned int sl :10; // Upper left S - 8:3 unsigned int tl :10; // Upper Left T - 8:3 unsigned int sh :10; // Lower Right S unsigned int th :10; // Lower Right T }; enum LoadType { BY_NEVER_SET, BY_LOAD_BLOCK, BY_LOAD_TILE, BY_LOAD_TLUT, }; struct LoadCmdInfo { LoadType loadtype; unsigned int sl :10; // Upper left S - 8:3 unsigned int tl :10; // Upper Left T - 8:3 unsigned int sh :10; // Lower Right S unsigned int th :10; // Lower Right T unsigned int dxt :12; }; typedef struct { // This is in Intel format uint32 SourceImagePointer; uint32 TlutPointer; short SubImageWidth; short Stride; char SourceImageBitSize; char SourceImageType; short SubImageHeight; short SourceImageOffsetT; short SourceImageOffsetS; char dummy[4]; } SpriteStruct; //Converted Sprint struct in Intel format typedef struct{ short px; short py; float scaleX; float scaleY; uint8 flipX; uint8 flipY; SpriteStruct *spritePtr; } Sprite2DInfo; // Blender equation: (A*P+B*M)/(A+B) typedef struct { unsigned int c2_m2b:2; // M (cycle 2) unsigned int c1_m2b:2; // M (cycle 1) unsigned int c2_m2a:2; // B (cycle 2) unsigned int c1_m2a:2; // B (cycle 1) unsigned int c2_m1b:2; // P (cycle 2) unsigned int c1_m1b:2; // P (cycle 1) unsigned int c2_m1a:2; // A (cycle 2) unsigned int c1_m1a:2; // A (cycle 1) } RDP_BlenderSetting; typedef struct { union { struct { // Low bits unsigned int alpha_compare : 2; // 0..1 unsigned int depth_source : 1; // 2..2 // unsigned int render_mode : 13; // 3..15 unsigned int aa_en : 1; // 3 unsigned int z_cmp : 1; // 4 unsigned int z_upd : 1; // 5 unsigned int im_rd : 1; // 6 unsigned int clr_on_cvg : 1; // 7 unsigned int cvg_dst : 2; // 8..9 unsigned int zmode : 2; // 10..11 unsigned int cvg_x_alpha : 1; // 12 unsigned int alpha_cvg_sel : 1; // 13 unsigned int force_bl : 1; // 14 unsigned int tex_edge : 1; // 15 - Not used unsigned int blender : 16; // 16..31 (Defined in RDP_BlenderSetting) // High bits unsigned int blend_mask : 4; // 0..3 - not supported unsigned int alpha_dither : 2; // 4..5 unsigned int rgb_dither : 2; // 6..7 unsigned int key_en : 1; // 8..8 unsigned int text_conv : 3; // 9..11 unsigned int text_filt : 2; // 12..13 unsigned int text_tlut : 2; // 14..15 unsigned int text_lod : 1; // 16..16 unsigned int text_sharpen : 1; // 17..18 unsigned int text_detail : 1; // 17..18 unsigned int text_persp : 1; // 19..19 unsigned int cycle_type : 2; // 20..21 unsigned int reserved : 1; // 22..22 - not supported unsigned int atomic_prim : 1; // 23..23 unsigned int pad : 8; // 24..31 - padding }; uint64 _u64; uint32 _u32[2]; }; } RDP_OtherMode; typedef enum { CMD_SETTILE, CMD_SETTILE_SIZE, CMD_LOADBLOCK, CMD_LOADTILE, CMD_LOADTLUT, CMD_SET_TEXTURE, CMD_LOAD_OBJ_TXTR, } SetTileCmdType; // The display list PC stack. Before this was an array of 10 // items, but this way we can nest as deeply as necessary. typedef struct { uint32 pc; int countdown; } DListStack; typedef struct { int x0, y0, x1, y1, mode; int left, top, right, bottom; } ScissorType; // Mask down to 0x003FFFFF? #define RSPSegmentAddr(seg) ( gRSP.segments[((seg)>>24)&0x0F] + ((seg)&0x00FFFFFF) ) #define RDRAM_UWORD(addr) (*(uint32 *)((addr)+g_pRDRAMu8)) #define RDRAM_SWORD(addr) (*(s32 *)((addr)+g_pRDRAMu8)) #define RDRAM_UHALF(addr) (*(uint16 *)(((addr)^2)+g_pRDRAMu8)) #define RDRAM_SHALF(addr) (*(short *)(((addr)^2)+g_pRDRAMu8)) #define RDRAM_UBYTE(addr) (*(uint8 *)(((addr)^3)+g_pRDRAMu8)) #define RDRAM_SBYTE(addr) (*(s8 *)(((addr)^3)+g_pRDRAMu8)) #define pRDRAM_UWORD(addr) ((uint32 *)((addr)+g_pRDRAMu8)) #define pRDRAM_SWORD(addr) ((s32 *)((addr)+g_pRDRAMu8)) #define pRDRAM_UHALF(addr) ((uint16 *)(((addr)^2)+g_pRDRAMu8)) #define pRDRAM_SHALF(addr) ((short *)(((addr)^2)+g_pRDRAMu8)) #define pRDRAM_UBYTE(addr) ((uint8 *)(((addr)^3)+g_pRDRAMu8)) #define pRDRAM_SBYTE(addr) ((s8 *)(((addr)^3)+g_pRDRAMu8)) extern uint16 g_wRDPTlut[]; extern const char *textluttype[4]; extern const char *pszImgFormat[8]; extern const char *pszImgSize[4]; extern uint8 pnImgSize[4]; extern const char *textlutname[4]; extern SetImgInfo g_CI; extern SetImgInfo g_ZI; extern SetImgInfo g_TI; extern TmemType g_Tmem; extern DListStack gDlistStack[MAX_DL_STACK_SIZE]; extern int gDlistStackPointer; void DLParser_Init(); void RDP_GFX_Reset(); void RDP_Cleanup(); void DLParser_Process(OSTask * pTask); void RDP_DLParser_Process(void); void PrepareTextures(); void RDP_InitRenderState(); void DisplayVertexInfo(uint32 dwAddr, uint32 dwV0, uint32 dwN); void RSP_MoveMemLight(uint32 dwLight, uint32 dwAddr); void RSP_MoveMemViewport(uint32 dwAddr); void RDP_NOIMPL_WARN(const char* op); void RSP_GFX_Force_Matrix(uint32 dwAddr); void RSP_GFX_InitGeometryMode(); void RSP_SetUcode(int ucode, uint32 ucStart=0, uint32 ucDStart=0, uint32 cdSize=0); uint32 CalcalateCRC(uint32* srcPtr, uint32 srcSize); void RDP_GFX_PopDL(); extern Matrix matToLoad; void LoadMatrix(uint32 addr); unsigned int ComputeCRC32(unsigned int crc, const uint8 *buf, unsigned int len); void TriggerDPInterrupt(); void TriggerSPInterrupt(); uint32 DLParser_CheckUcode(uint32 ucStart, uint32 ucDStart, uint32 ucSize, uint32 ucDSize); bool IsUsedAsDI(uint32 addr); #if defined(DEBUGGER) void __cdecl LOG_UCODE(const char* szFormat, ...) ATTR_FMT(1,2); #else inline void LOG_UCODE(...) {} #endif #endif // __RICE_RDP_GFX_H__ mupen64plus-video-rice-src-2.6.0/src/RSP_S2DEX.cpp000066400000000000000000000436251464507324400214210ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // This file implements the S2DEX ucode, Yoshi story is using this ucodes #include #include "Debugger.h" #include "RSP_Parser.h" #include "RSP_S2DEX.h" #include "Render.h" #include "RenderBase.h" #include "Timing.h" #include "UcodeDefs.h" #include "VectorMath.h" #include "Video.h" #include "typedefs.h" uObjTxtr *gObjTxtr = NULL; uObjTxtrTLUT *gObjTlut = NULL; uint32 gObjTlutAddr = 0; uObjMtx *gObjMtx = NULL; uObjSubMtx *gSubObjMtx = NULL; uObjMtxReal gObjMtxReal = {1, 0, 0, 1, 0, 0, 0, 0}; Matrix g_MtxReal(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1); uint32 g_TxtLoadBy = CMD_LOAD_OBJ_TXTR; // Yoshi's Story uses this - 0x02 void RSP_S2DEX_BG_COPY(Gfx *gfx) { SP_Timing(DP_Minimal16); DP_Timing(DP_Minimal16); uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjBg *sbgPtr = (uObjBg*)(g_pRDRAMu8+dwAddr); CRender::g_pRender->LoadObjBGCopy(*sbgPtr); CRender::g_pRender->DrawObjBGCopy(*sbgPtr); } // Yoshi's Story uses this - 0x03 void RSP_S2DEX_OBJ_RECTANGLE(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjSprite *ptr = (uObjSprite*)(g_pRDRAMu8+dwAddr); uObjTxSprite objtx; memcpy(&objtx.sprite,ptr,sizeof(uObjSprite)); if( g_TxtLoadBy == CMD_LOAD_OBJ_TXTR ) { memcpy(&(objtx.txtr.block),&(gObjTxtr->block),sizeof(uObjTxtr)); CRender::g_pRender->LoadObjSprite(objtx,true); } else { PrepareTextures(); } CRender::g_pRender->DrawSprite(objtx, false); #ifdef DEBUGGER if( (pauseAtNext && (eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI)) || logTextures ) { if( debuggerPauseCount > 0 ) debuggerPauseCount--; if( debuggerPauseCount == 0 ) { eventToPause = false; debuggerPause = true; TRACE3("Paused at RSP_S2DEX_OBJ_RECTANGLE\nptr=%08X, img=%08X, Tmem=%08X", dwAddr,objtx.txtr.block.image, ptr->imageAdrs); CGraphicsContext::Get()->UpdateFrame(); } } #endif } // Yoshi's Story uses this - 0x04 void RSP_S2DEX_OBJ_SPRITE(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjSprite *info = (uObjSprite*)(g_pRDRAMu8+dwAddr); uint32 dwTile = gRSP.curTile; status.bAllowLoadFromTMEM = false; // Because we need to use TLUT loaded by ObjTlut cmd PrepareTextures(); status.bAllowLoadFromTMEM = true; uObjTxSprite drawinfo; memcpy( &(drawinfo.sprite), info, sizeof(uObjSprite)); CRender::g_pRender->DrawSpriteR(drawinfo, false, dwTile, 0, 0, drawinfo.sprite.imageW/32, drawinfo.sprite.imageH/32); /* static BOOL bWarned = FALSE; //if (!bWarned) { RSP_RDP_NOIMPL("RDP: RSP_S2DEX_OBJ_SPRITE (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); bWarned = TRUE; } */ #ifdef DEBUGGER if( (pauseAtNext && (eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI)) || logTextures ) { eventToPause = false; debuggerPause = true; TRACE0("Paused at RSP_S2DEX_OBJ_SPRITE"); CGraphicsContext::Get()->UpdateFrame(); } #endif } // Yoshi's Story uses this - 0xb0 void RSP_S2DEX_SELECT_DL(Gfx *gfx) { //static BOOL bWarned = FALSE; //if (!bWarned) { RSP_RDP_NOIMPL("RDP: RSP_S2DEX_SELECT_DL (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); //bWarned = TRUE; } DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_OBJ_TXT_CMD, {DebuggerAppendMsg("Paused at RSP_S2DEX_SELECT_DL");}); } void RSP_S2DEX_OBJ_RENDERMODE(Gfx *gfx) { /* static BOOL bWarned = FALSE; //if (!bWarned) { RSP_RDP_NOIMPL("RDP: RSP_S2DEX_OBJ_RENDERMODE (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); bWarned = TRUE; } */ } // Yoshi's Story uses this - 0xb1 void RSP_GBI1_Tri2(Gfx *gfx); void RSP_S2DEX_OBJ_RENDERMODE_2(Gfx *gfx) { if( ((gfx->words.w0)&0xFFFFFF) != 0 || ((gfx->words.w1)&0xFFFFFF00) != 0 ) { // This is a TRI2 cmd RSP_GBI1_Tri2(gfx); return; } RSP_S2DEX_OBJ_RENDERMODE(gfx); } #ifdef DEBUGGER void DumpBlockParameters(uObjTxtrBlock &ptr) { /* typedef struct { //Intel format uint32 type; // S2DEX_OBJLT_TXTRBLOCK divided into types. uint64 *image; // The texture source address on DRAM. uint16 tsize; // The Texture size. Specified by the macro GS_TB_TSIZE(). uint16 tmem; // The transferred TMEM word address. (8byteWORD) uint16 sid; // STATE ID Multipled by 4. Either one of 0,4,8 and 12. uint16 tline; // The width of the Texture 1-line. Specified by the macro GS_TB_TLINE() uint32 flag; // STATE flag uint32 mask; // STATE mask } uObjTxtrBlock; // 24 bytes */ DebuggerAppendMsg("uObjTxtrBlock Header in RDRAM: 0x%08X", (uint32) ((char *) &ptr - (char *) g_pRDRAMu8)); DebuggerAppendMsg("ImgAddr=0x%08X(0x%08X), tsize=0x%X, \nTMEM=0x%X, sid=%d, tline=%d, flag=0x%X, mask=0x%X\n\n", RSPSegmentAddr(ptr.image), ptr.image, ptr.tsize, ptr.tmem, ptr.sid/4, ptr.tline, ptr.flag, ptr.mask); } void DumpSpriteParameters(uObjSprite &ptr) { /* typedef struct { // Intel format uint16 scaleW; // Scaling of the u5.10 width direction. short objX; // The x-coordinate of the upper-left end. s10.2 OBJ uint16 paddingX; // Unused. Always 0. uint16 imageW; // The width of the u10.5 texture. (The length of the S-direction.) uint16 scaleH; // Scaling of the u5.10 height direction. short objY; // The y-coordinate of the s10.2 OBJ upper-left end. uint16 paddingY; // Unused. Always 0. uint16 imageH; // The height of the u10.5 texture. (The length of the T-direction.) uint16 imageAdrs; // The texture header position in TMEM. (In units of 64bit word.) uint16 imageStride; // The folding width of the texel. (In units of 64bit word.) uint8 imageFlags; // The display flag. S2DEX_OBJ_FLAG_FLIP* uint8 imagePal; //The pallet number. 0-7 uint8 imageSiz; // The size of the texel. TXT_SIZE_* uint8 imageFmt; // The format of the texel. TXT_FMT_* } uObjSprite; // 24 bytes */ if( logTextures || (pauseAtNext && eventToPause == NEXT_OBJ_TXT_CMD) ) { DebuggerAppendMsg("uObjSprite Header in RDRAM: 0x%08X", (uint32) ((char *) &ptr - (char *) g_pRDRAMu8)); DebuggerAppendMsg("X=%d, Y=%d, W=%d, H=%d, scaleW=%f, scaleH=%f\n" "TAddr=0x%X, Stride=%d, Flag=0x%X, Pal=%d, Fmt=%s-%db\n\n", ptr.objX/4, ptr.objY/4, ptr.imageW/32, ptr.imageH/32, ptr.scaleW/1024.0f, ptr.scaleH/1024.0f, ptr.imageAdrs, ptr.imageStride, ptr.imageFlags, ptr.imagePal, pszImgFormat[ptr.imageFmt], pnImgSize[ptr.imageSiz]); } } void DumpTileParameters(uObjTxtrTile &tile) { } void DumpTlutParameters(uObjTxtrTLUT &tlut) { /* typedef struct { // Intel Format uint32 type; // S2DEX_OBJLT_TLUT divided into types. uint32 image; uint16 pnum; // The loading pallet number -1. uint16 phead; // The pallet number of the load header. Between 256 and 511. uint16 sid; // STATE ID Multiplied by 4. Either one of 0,4,8 and 12. uint16 zero; // Assign 0 all the time. uint32 flag; // STATE flag uint32 mask; // STATE mask } uObjTxtrTLUT; // 24 bytes */ DebuggerAppendMsg("ImgAddr=0x%08X(0x%08X), pnum=%d, phead=%d, sid=%d, flag=0x%X, mask=0x%X\n\n", RSPSegmentAddr(tlut.image), tlut.image, tlut.pnum+1, tlut.phead, tlut.sid/4, tlut.flag, tlut.mask); } void DumpTxtrInfo(uObjTxtr *ptr) { if( logTextures || (pauseAtNext && eventToPause == NEXT_OBJ_TXT_CMD) ) { DebuggerAppendMsg("uObjTxtr Header in RDRAM: 0x%08X", (uint32) ((char *) ptr - (char *) g_pRDRAMu8)); switch( ptr->block.type ) { case S2DEX_OBJLT_TXTRBLOCK: TRACE0("Loading ObjTxtr: type=BLOCK"); DumpBlockParameters(ptr->block); break; case S2DEX_OBJLT_TXTRTILE: TRACE0("Loading ObjTxtr: type=TILE"); DumpTileParameters(ptr->tile); break; case S2DEX_OBJLT_TLUT: TRACE0("Loading ObjTxtr: type=TLUT"); DumpTlutParameters(ptr->tlut); break; } } } void DumpObjMtx(bool fullmtx = true) { if( logTextures || (pauseAtNext && eventToPause == NEXT_OBJ_TXT_CMD) ) { if( fullmtx ) DebuggerAppendMsg("A=%X, B=%X, C=%X, D=%X, X=%X, Y=%X, BaseX=%X, BaseY=%X", gObjMtx->A, gObjMtx->B, gObjMtx->C, gObjMtx->D, gObjMtx->X, gObjMtx->Y, gObjMtx->BaseScaleX, gObjMtx->BaseScaleY); else DebuggerAppendMsg("SubMatrix: X=%X, Y=%X, BaseX=%X, BaseY=%X", gSubObjMtx->X, gSubObjMtx->Y, gSubObjMtx->BaseScaleX, gSubObjMtx->BaseScaleY); DebuggerAppendMsg("A=%f, B=%f, C=%f, D=%f, X=%f, Y=%f, BaseX=%f, BaseY=%f", gObjMtxReal.A, gObjMtxReal.B, gObjMtxReal.C, gObjMtxReal.D, gObjMtxReal.X, gObjMtxReal.Y, gObjMtxReal.BaseScaleX, gObjMtxReal.BaseScaleY); } } #endif void ObjMtxTranslate(float &x, float &y) { float x1 = gObjMtxReal.A*x + gObjMtxReal.B*y + gObjMtxReal.X; float y1 = gObjMtxReal.C*x + gObjMtxReal.D*y + gObjMtxReal.Y; x = x1; y = y1; } void RSP_S2DEX_SPObjLoadTxtr(Gfx *gfx) { gObjTxtr = (uObjTxtr*)(g_pRDRAMu8+(RSPSegmentAddr((gfx->words.w1))&(g_dwRamSize-1))); if( gObjTxtr->block.type == S2DEX_OBJLT_TLUT ) { gObjTlut = (uObjTxtrTLUT*)gObjTxtr; gObjTlutAddr = (uint32)(RSPSegmentAddr(gObjTlut->image)); // Copy tlut int size = gObjTlut->pnum+1; int offset = gObjTlut->phead-0x100; if( offset+size>0x100) { size = 0x100 - offset; } uint32 addr = (gObjTlutAddr);//&0xFFFFFFFC); //if( addr & 3 ) addr = (addr&0xFFFFFFF0)+8;; //uint16 *srcPal = (uint16*)(g_pRDRAMu8 + (addr& (g_dwRamSize-1)) ); for( int i=offset; iwords.w1))&(g_dwRamSize-1))); gObjTxtr = (uObjTxtr*)ptr; //Now draw the sprite CRender::g_pRender->LoadObjSprite(*ptr); CRender::g_pRender->DrawSpriteR(*ptr); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI), { DumpTxtrInfo(gObjTxtr); DumpSpriteParameters(ptr->sprite); TRACE0("Paused at RSP_S2DEX_SPObjLoadTxSprite"); } ); } // Yoshi's Story uses this - 0xc3 void RSP_S2DEX_SPObjLoadTxRect(Gfx *gfx) { uObjTxSprite* ptr = (uObjTxSprite*)(g_pRDRAMu8+(RSPSegmentAddr((gfx->words.w1))&(g_dwRamSize-1))); gObjTxtr = (uObjTxtr*)ptr; //Now draw the sprite CRender::g_pRender->LoadObjSprite(*ptr); CRender::g_pRender->DrawSprite(*ptr, false); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI), { DumpTxtrInfo(gObjTxtr); DumpSpriteParameters(ptr->sprite); TRACE0("Paused at RSP_S2DEX_SPObjLoadTxRect"); } ); } // Yoshi's Story uses this - 0xc4 void RSP_S2DEX_SPObjLoadTxRectR(Gfx *gfx) { uObjTxSprite* ptr = (uObjTxSprite*)(g_pRDRAMu8+(RSPSegmentAddr((gfx->words.w1))&(g_dwRamSize-1))); gObjTxtr = (uObjTxtr*)ptr; //Now draw the sprite CRender::g_pRender->LoadObjSprite(*ptr); CRender::g_pRender->DrawSprite(*ptr, true); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI), { DumpTxtrInfo(gObjTxtr); DumpSpriteParameters(ptr->sprite); TRACE0("Paused at RSP_S2DEX_SPObjLoadTxRect"); } ); } void DLParser_TexRect(Gfx *gfx); // Yoshi's Story uses this - 0xe4 void RSP_S2DEX_RDPHALF_0(Gfx *gfx) { //RDP: RSP_S2DEX_RDPHALF_0 (0xe449c0a8 0x003b40a4) //0x001d3c88: e449c0a8 003b40a4 RDP_TEXRECT //0x001d3c90: b4000000 00000000 RSP_RDPHALF_1 //0x001d3c98: b3000000 04000400 RSP_RDPHALF_2 uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction uint32 dwNextUcode = *(uint32 *)(g_pRDRAMu8 + dwPC); if( (dwNextUcode>>24) != S2DEX_SELECT_DL ) { // Pokemom Puzzle League if( (dwNextUcode>>24) == 0xB4 ) { DLParser_TexRect(gfx); } else { RSP_RDP_NOIMPL("RDP: RSP_S2DEX_RDPHALF_0 (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); } } else { RSP_RDP_NOIMPL("RDP: RSP_S2DEX_RDPHALF_0 (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); DEBUGGER_PAUSE_COUNT_N(NEXT_OBJ_TXT_CMD); } } // Yoshi's Story uses this - 0x05 void RSP_S2DEX_OBJ_MOVEMEM(Gfx *gfx) { uint32 dwCommand = ((gfx->words.w0)>>16)&0xFF; uint32 dwLength = ((gfx->words.w0)) &0xFFFF; uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); if( dwAddr >= g_dwRamSize ) { TRACE0("ObjMtx: memory ptr is invalid"); } if( dwLength == 0 && dwCommand == 23 ) { gObjMtx = (uObjMtx *)(dwAddr+g_pRDRAMu8); gObjMtxReal.A = gObjMtx->A/65536.0f; gObjMtxReal.B = gObjMtx->B/65536.0f; gObjMtxReal.C = gObjMtx->C/65536.0f; gObjMtxReal.D = gObjMtx->D/65536.0f; gObjMtxReal.X = float(gObjMtx->X>>2); gObjMtxReal.Y = float(gObjMtx->Y>>2); gObjMtxReal.BaseScaleX = gObjMtx->BaseScaleX/1024.0f; gObjMtxReal.BaseScaleY = gObjMtx->BaseScaleY/1024.0f; #ifdef DEBUGGER DumpObjMtx(); #endif } else if( dwLength == 2 && dwCommand == 7 ) { gSubObjMtx = (uObjSubMtx*)(dwAddr+g_pRDRAMu8); gObjMtxReal.X = float(gSubObjMtx->X>>2); gObjMtxReal.Y = float(gSubObjMtx->Y>>2); gObjMtxReal.BaseScaleX = gSubObjMtx->BaseScaleX/1024.0f; gObjMtxReal.BaseScaleY = gSubObjMtx->BaseScaleY/1024.0f; #ifdef DEBUGGER DumpObjMtx(false); #endif } g_MtxReal._11 = gObjMtxReal.A; g_MtxReal._12 = gObjMtxReal.C; g_MtxReal._13 = 0; g_MtxReal._14 = 0;//gObjMtxReal.X; g_MtxReal._21 = gObjMtxReal.B; g_MtxReal._22 = gObjMtxReal.D; g_MtxReal._23 = 0; g_MtxReal._24 = 0;//gObjMtxReal.Y; g_MtxReal._31 = 0; g_MtxReal._32 = 0; g_MtxReal._33 = 1.0; g_MtxReal._34 = 0; g_MtxReal._41 = gObjMtxReal.X; g_MtxReal._42 = gObjMtxReal.Y; g_MtxReal._43 = 0; g_MtxReal._44 = 1.0; DEBUGGER_PAUSE_COUNT_N(NEXT_OBJ_TXT_CMD); } // Yoshi's Story uses this - 0x01 extern void RSP_GBI0_Mtx(Gfx *gfx); void RSP_S2DEX_BG_1CYC(Gfx *gfx) { SP_Timing(DP_Minimal16); DP_Timing(DP_Minimal16); uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjScaleBg *sbgPtr = (uObjScaleBg *)(dwAddr+g_pRDRAMu8); CRender::g_pRender->LoadObjBG1CYC(*sbgPtr); CRender::g_pRender->DrawObjBG1CYC(*sbgPtr); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI||eventToPause == NEXT_OBJ_BG), { DebuggerAppendMsg("S2DEX BG 1CYC: %08X-%08X\n", (gfx->words.w0), (gfx->words.w1) ); TRACE0("Paused at RSP_S2DEX_BG_1CYC"); } ); } void RSP_S2DEX_BG_1CYC_2(Gfx *gfx) { if( ((gfx->words.w0)&0x00FFFFFF) != 0 ) { RSP_GBI0_Mtx(gfx); return; } RSP_S2DEX_BG_1CYC(gfx); } // Yoshi's Story uses this - 0xb2 void RSP_S2DEX_OBJ_RECTANGLE_R(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjSprite *ptr = (uObjSprite*)(g_pRDRAMu8+dwAddr); uObjTxSprite objtx; memcpy(&objtx.sprite,ptr,sizeof(uObjSprite)); //uObjTxSprite* ptr = (uObjTxSprite*)(g_pRDRAMu8+(RSPSegmentAddr((gfx->words.w1))&(g_dwRamSize-1))); //gObjTxtr = (uObjTxtr*)ptr; //Now draw the sprite if( g_TxtLoadBy == CMD_LOAD_OBJ_TXTR ) { memcpy(&(objtx.txtr.block),&(gObjTxtr->block),sizeof(uObjTxtr)); //CRender::g_pRender->LoadObjSprite(*ptr,true); CRender::g_pRender->LoadObjSprite(objtx,true); } else { PrepareTextures(); } //CRender::g_pRender->DrawSprite(*ptr, true); CRender::g_pRender->DrawSprite(objtx, true); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI), { DumpTxtrInfo(gObjTxtr); DumpSpriteParameters(*ptr); TRACE0("Paused at RSP_S2DEX_OBJ_RECTANGLE_R"); } ); } mupen64plus-video-rice-src-2.6.0/src/RSP_S2DEX.h000066400000000000000000000104771464507324400210650ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _RSP_S2DEX_H_ #define _RSP_S2DEX_H_ #include "typedefs.h" #define S2DEX_BG_1CYC 0x01 #define S2DEX_BG_COPY 0x02 #define S2DEX_OBJ_RECTANGLE 0x03 #define S2DEX_OBJ_SPRITE 0x04 #define S2DEX_OBJ_MOVEMEM 0x05 #define S2DEX_SELECT_DL 0xb0 #define S2DEX_OBJ_RENDERMODE 0xb1 #define S2DEX_OBJ_RECTANGLE_R 0xb2 #define S2DEX_OBJ_LOADTXTR 0xc1 #define S2DEX_OBJ_LDTX_SPRITE 0xc2 #define S2DEX_OBJ_LDTX_RECT 0xc3 #define S2DEX_OBJ_LDTX_RECT_R 0xc4 #define S2DEX_RDPHALF_0 0xe4 #define S2DEX_OBJLT_TXTRBLOCK 0x00001033 #define S2DEX_OBJLT_TXTRTILE 0x00fc1034 #define S2DEX_OBJLT_TLUT 0x00000030 #define S2DEX_BGLT_LOADBLOCK 0x0033 #define S2DEX_BGLT_LOADTILE 0xfff4 typedef struct { //Intel format uint32 type; uint32 image; uint16 tsize; uint16 tmem; uint16 sid; uint16 tline; uint32 flag; uint32 mask; } uObjTxtrBlock; typedef struct { //Intel Format uint32 type; uint32 image; uint16 twidth; uint16 tmem; uint16 sid; uint16 theight; uint32 flag; uint32 mask; } uObjTxtrTile; // 24 bytes typedef struct { // Intel Format uint32 type; uint32 image; uint16 pnum; uint16 phead; uint16 sid; uint16 zero; uint32 flag; uint32 mask; } uObjTxtrTLUT; typedef union { uObjTxtrBlock block; uObjTxtrTile tile; uObjTxtrTLUT tlut; } uObjTxtr; typedef struct { // Intel format uint16 scaleW; short objX; uint16 paddingX; uint16 imageW; uint16 scaleH; short objY; uint16 paddingY; uint16 imageH; uint16 imageAdrs; uint16 imageStride; uint8 imageFlags; uint8 imagePal; uint8 imageSiz; uint8 imageFmt; } uObjSprite; typedef struct { uObjTxtr txtr; uObjSprite sprite; } uObjTxSprite; /* 48 bytes */ typedef struct { // Intel format s32 A, B, C, D; short Y; short X; uint16 BaseScaleY; uint16 BaseScaleX; } uObjMtx; typedef struct { float A, B, C, D; float X; float Y; float BaseScaleX; float BaseScaleY; } uObjMtxReal; typedef struct { //Intel format short Y; short X; uint16 BaseScaleY; uint16 BaseScaleX; } uObjSubMtx; typedef struct { // Intel Format uint16 imageW; uint16 imageX; uint16 frameW; short frameX; uint16 imageH; uint16 imageY; uint16 frameH; short frameY; uint32 imagePtr; uint8 imageSiz; uint8 imageFmt; uint16 imageLoad; uint16 imageFlip; uint16 imagePal; uint16 tmemH; uint16 tmemW; uint16 tmemLoadTH; uint16 tmemLoadSH; uint16 tmemSize; uint16 tmemSizeW; } uObjBg; typedef struct { // Intel Format uint16 imageW; uint16 imageX; uint16 frameW; short frameX; uint16 imageH; uint16 imageY; uint16 frameH; short frameY; uint32 imagePtr; uint8 imageSiz; uint8 imageFmt; uint16 imageLoad; uint16 imageFlip; uint16 imagePal; uint16 scaleH; uint16 scaleW; s32 imageYorig; uint8 padding[4]; } uObjScaleBg; #endif mupen64plus-video-rice-src-2.6.0/src/Render.cpp000066400000000000000000002074001464507324400212600ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define M64P_PLUGIN_PROTOTYPES 1 #include #include #include #include #include "Blender.h" #include "ConvertImage.h" #include "DeviceBuilder.h" #include "FrameBuffer.h" #include "GraphicsContext.h" #include "Render.h" #include "RenderTexture.h" #include "Texture.h" #include "VectorMath.h" #include "Video.h" #include "liblinux/BMGImage.h" #include "liblinux/BMGLibPNG.h" #include "liblinux/pngrw.h" #include "m64p_plugin.h" #include "m64p_types.h" #include "osal_preproc.h" #undef min #undef max extern FiddledVtx * g_pVtxBase; CRender * CRender::g_pRender=NULL; int CRender::gRenderReferenceCount=0; XMATRIX reverseXY(-1,0,0,0,0,-1,0,0,0,0,1,0,0,0,0,1); XMATRIX reverseY(1,0,0,0,0,-1,0,0,0,0,1,0,0,0,0,1); extern char* right (const char * src, int nchars); #if defined(WIN32) #define strcasecmp _stricmp #endif //======================================================================== CRender * CRender::GetRender(void) { if( CRender::g_pRender == NULL ) { DebugMessage(M64MSG_ERROR, "g_pRender is NULL"); exit(0); } else return CRender::g_pRender; } bool CRender::IsAvailable() { return CRender::g_pRender != NULL; } CRender::CRender() : m_fScreenViewportMultX(2.0f), m_fScreenViewportMultY(2.0f), m_dwTexturePerspective(FALSE), m_bAlphaTestEnable(FALSE), m_bZUpdate(FALSE), m_bZCompare(FALSE), m_dwZBias(0), m_dwMinFilter(FILTER_POINT), m_dwMagFilter(FILTER_POINT), m_dwAlpha(0xFF), m_modes64(0) { int i; InitRenderBase(); for( i=0; iCreateColorCombiner(this); m_pColorCombiner->Initialize(); m_pAlphaBlender = CDeviceBuilder::GetBuilder()->CreateAlphaBlender(this); } CRender::~CRender() { if( m_pColorCombiner != NULL ) { CDeviceBuilder::GetBuilder()->DeleteColorCombiner(); m_pColorCombiner = NULL; } if( m_pAlphaBlender != NULL ) { CDeviceBuilder::GetBuilder()->DeleteAlphaBlender(); m_pAlphaBlender = NULL; } } void CRender::ResetMatrices() { Matrix mat; mat.m[0][1] = mat.m[0][2] = mat.m[0][3] = mat.m[1][0] = mat.m[1][2] = mat.m[1][3] = mat.m[2][0] = mat.m[2][1] = mat.m[2][3] = mat.m[3][0] = mat.m[3][1] = mat.m[3][2] = 0.0f; mat.m[0][0] = mat.m[1][1] = mat.m[2][2] = mat.m[3][3] = 1.0f; gRSP.projectionMtxTop = 0; gRSP.modelViewMtxTop = 0; gRSP.projectionMtxs[0] = mat; gRSP.modelviewMtxs[0] = mat; gRSP.bMatrixIsUpdated = true; gRSP.bWorldMatrixIsUpdated = true; UpdateCombinedMatrix(); } void CRender::SetProjection(const Matrix & mat, bool bPush, bool bReplace) { if (bPush) { if (gRSP.projectionMtxTop >= (RICE_MATRIX_STACK-1)) { TRACE0("Pushing past proj stack limits!"); } else gRSP.projectionMtxTop++; if (bReplace) { // Load projection matrix gRSP.projectionMtxs[gRSP.projectionMtxTop] = mat; } else { gRSP.projectionMtxs[gRSP.projectionMtxTop] = mat * gRSP.projectionMtxs[gRSP.projectionMtxTop-1]; } } else { if (bReplace) { // Load projection matrix gRSP.projectionMtxs[gRSP.projectionMtxTop] = mat; } else { gRSP.projectionMtxs[gRSP.projectionMtxTop] = mat * gRSP.projectionMtxs[gRSP.projectionMtxTop]; } } gRSP.bMatrixIsUpdated = true; DumpMatrix(mat,"Set Projection Matrix"); } bool mtxPopUpError = false; void CRender::SetWorldView(const Matrix & mat, bool bPush, bool bReplace) { if (bPush) { if (gRSP.modelViewMtxTop >= (RICE_MATRIX_STACK-1)) DebuggerAppendMsg("Pushing past modelview stack limits! %s", bReplace?"Load":"Mul"); else gRSP.modelViewMtxTop++; // We should store the current projection matrix... if (bReplace) { // Load projection matrix gRSP.modelviewMtxs[gRSP.modelViewMtxTop] = mat; } else // Multiply projection matrix { gRSP.modelviewMtxs[gRSP.modelViewMtxTop] = mat * gRSP.modelviewMtxs[gRSP.modelViewMtxTop-1]; } } else // NoPush { if (bReplace) { // Load projection matrix gRSP.modelviewMtxs[gRSP.modelViewMtxTop] = mat; // Hack needed to show flashing last heart and map arrows in Zelda OoT & MM // It renders at Z cordinate = 0.0f that gets clipped away // So we translate them a bit along Z to make them stick if( options.enableHackForGames == HACK_FOR_ZELDA || options.enableHackForGames == HACK_FOR_ZELDA_MM) { if(gRSP.modelviewMtxs[gRSP.modelViewMtxTop]._43 == 0.0f && gRSP.modelviewMtxs[gRSP.modelViewMtxTop]._42 != 0.0f && gRSP.modelviewMtxs[gRSP.modelViewMtxTop]._42 <= 94.5f && gRSP.modelviewMtxs[gRSP.modelViewMtxTop]._42 >= -94.5f) { gRSP.modelviewMtxs[gRSP.modelViewMtxTop]._43 -= 10.1f; } } } else { // Multiply projection matrix gRSP.modelviewMtxs[gRSP.modelViewMtxTop] = mat * gRSP.modelviewMtxs[gRSP.modelViewMtxTop]; } } gRSPmodelViewTop = gRSP.modelviewMtxs[gRSP.modelViewMtxTop]; if( options.enableHackForGames == HACK_REVERSE_XY_COOR ) { gRSPmodelViewTop = gRSPmodelViewTop * reverseXY; } if( options.enableHackForGames == HACK_REVERSE_Y_COOR ) { gRSPmodelViewTop = gRSPmodelViewTop * reverseY; } MatrixTranspose(&gRSPmodelViewTopTranspose, &gRSPmodelViewTop); gRSP.bMatrixIsUpdated = true; gRSP.bWorldMatrixIsUpdated = true; DumpMatrix(mat,"Set WorldView Matrix"); } void CRender::PopWorldView() { if (gRSP.modelViewMtxTop > 0) { gRSP.modelViewMtxTop--; gRSPmodelViewTop = gRSP.modelviewMtxs[gRSP.modelViewMtxTop]; if( options.enableHackForGames == HACK_REVERSE_XY_COOR ) { gRSPmodelViewTop = gRSPmodelViewTop * reverseXY; } if( options.enableHackForGames == HACK_REVERSE_Y_COOR ) { gRSPmodelViewTop = gRSPmodelViewTop * reverseY; } MatrixTranspose(&gRSPmodelViewTopTranspose, &gRSPmodelViewTop); gRSP.bMatrixIsUpdated = true; gRSP.bWorldMatrixIsUpdated = true; } else { #ifdef DEBUGGER if( pauseAtNext ) TRACE0("Popping past worldview stack limits"); #endif mtxPopUpError = true; } } Matrix & CRender::GetWorldProjectMatrix(void) { return gRSPworldProject; } void CRender::SetWorldProjectMatrix(Matrix &mtx) { #ifdef DEBUGGER if( pauseAtNext && (eventToPause == NEXT_TRIANGLE || eventToPause == NEXT_FLUSH_TRI || eventToPause == NEXT_MATRIX_CMD ) ) { uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8; DebuggerAppendMsg("Force Matrix: pc=%08X", dwPC); DumpMatrix(mtx, "Force Matrix, loading new world-project matrix"); } #endif gRSPworldProject = mtx; gRSP.bMatrixIsUpdated = false; gRSP.bCombinedMatrixIsUpdated = true; } void CRender::SetCombineMode(uint32 dwMux0, uint32 dwMux1) { uint64 tempModes64 = (((uint64)dwMux0) << 32) | (uint64)dwMux1; if( m_modes64 != tempModes64 ) { m_modes64 = tempModes64; m_pColorCombiner->SetCombineMode(dwMux0, dwMux1); } } void CRender::SetCombinerAndBlender() { InitOtherModes(); if( g_curRomInfo.bDisableBlender ) m_pAlphaBlender->DisableAlphaBlender(); else if( currentRomOptions.bNormalBlender ) m_pAlphaBlender->NormalAlphaBlender(); else m_pAlphaBlender->InitBlenderMode(); m_pColorCombiner->InitCombinerMode(); ApplyTextureFilter(); } void CRender::RenderReset() { UpdateClipRectangle(); ResetMatrices(); SetZBias(0); gRSP.numVertices = 0; gRSP.maxVertexID = 0; gRSP.curTile = 0; gRSP.fTexScaleX = 1/32.0f;; gRSP.fTexScaleY = 1/32.0f; } bool CRender::FillRect(int nX0, int nY0, int nX1, int nY1, uint32 dwColor) { LOG_UCODE("FillRect: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%8X", nX0, nY0, nX1, nY1, dwColor); if (g_CI.dwSize != TXT_SIZE_16b && frameBufferOptions.bIgnore) return true; if (status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM) status.bFrameBufferIsDrawn = true; if(status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_1ST_PRIMITIVE) { status.bVIOriginIsUpdated=false; CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG, {DebuggerAppendMsg("Screen Update at 1st FillRectangle");}); } if (status.bCIBufferIsRendered && status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_BEFORE_SCREEN_CLEAR ) { if ((nX0==0 && nY0 == 0 && (nX1 == (int) g_CI.dwWidth || nX1 == (int) g_CI.dwWidth-1)) || (nX0==gRDP.scissor.left && nY0 == gRDP.scissor.top && (nX1 == gRDP.scissor.right || nX1 == gRDP.scissor.right-1)) || ((nX0+nX1 == (int)g_CI.dwWidth || nX0+nX1 == (int)g_CI.dwWidth-1 || nX0+nX1 == gRDP.scissor.left+gRDP.scissor.right || nX0+nX1 == gRDP.scissor.left+gRDP.scissor.right-1) && (nY0 == gRDP.scissor.top || nY0 == 0 || nY0+nY1 == gRDP.scissor.top+gRDP.scissor.bottom || nY0+nY1 == gRDP.scissor.top+gRDP.scissor.bottom-1))) { status.bVIOriginIsUpdated=false; CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG,{DebuggerAppendMsg("Screen Update Before Screen Clear");}); } } SetFillMode(RICE_FILLMODE_SOLID); bool res=true; /* // I don't know why this does not work for OpenGL if( gRDP.otherMode.cycle_type == CYCLE_TYPE_FILL && nX0 == 0 && nY0 == 0 && ((nX1==windowSetting.uViWidth && nY1==windowSetting.uViHeight)||(nX1==windowSetting.uViWidth-1 && nY1==windowSetting.uViHeight-1)) ) { CGraphicsContext::Get()->Clear(CLEAR_COLOR_BUFFER,dwColor); } else */ { //BOOL m_savedZBufferFlag = gRSP.bZBufferEnabled; // Save ZBuffer state ZBufferEnable( FALSE ); m_fillRectVtx[0].x = ViewPortTranslatei_x(nX0); m_fillRectVtx[0].y = ViewPortTranslatei_y(nY0); m_fillRectVtx[1].x = ViewPortTranslatei_x(nX1); m_fillRectVtx[1].y = ViewPortTranslatei_y(nY1); SetCombinerAndBlender(); if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY ) { ZBufferEnable(FALSE); } float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0 ); ApplyRDPScissor(); res = RenderFillRect(dwColor, depth); if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY ) { ZBufferEnable(gRSP.bZBufferEnabled); } } if( options.bWinFrameMode ) SetFillMode(RICE_FILLMODE_WINFRAME ); DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FILLRECT, {DebuggerAppendMsg("FillRect: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%08X", nX0, nY0, nX1, nY1, dwColor); DebuggerAppendMsg("Pause after FillRect: Color=%08X\n", dwColor);}); DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_FLUSH_TRI, {DebuggerAppendMsg("FillRect: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%08X", nX0, nY0, nX1, nY1, dwColor); DebuggerAppendMsg("Pause after FillRect: Color=%08X\n", dwColor);}); return res; } bool CRender::Line3D(uint32 dwV0, uint32 dwV1, uint32 dwWidth) { LOG_UCODE("Line3D: Vtx0=%d, Vtx1=%d, Width=%d", dwV0, dwV1, dwWidth); if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); m_line3DVtx[0].z = (g_vecProjected[dwV0].z + 1.0f) * 0.5f; m_line3DVtx[1].z = (g_vecProjected[dwV1].z + 1.0f) * 0.5f; if( m_line3DVtx[0].z != m_line3DVtx[1].z ) return false; if( status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM ) status.bFrameBufferIsDrawn = true; if( status.bHandleN64RenderTexture ) { g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height; if( status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } } m_line3DVtx[0].x = ViewPortTranslatef_x(g_vecProjected[dwV0].x); m_line3DVtx[0].y = ViewPortTranslatef_y(g_vecProjected[dwV0].y); m_line3DVtx[0].rhw = g_vecProjected[dwV0].w; m_line3DVtx[0].dcDiffuse = g_dwVtxDifColor[dwV0]; m_line3DVtx[1].x = ViewPortTranslatef_x(g_vecProjected[dwV1].x); m_line3DVtx[1].y = ViewPortTranslatef_y(g_vecProjected[dwV1].y); m_line3DVtx[1].rhw = g_vecProjected[dwV1].w; m_line3DVtx[1].dcDiffuse = g_dwVtxDifColor[dwV1]; float width = dwWidth*0.5f+1.5f; if( m_line3DVtx[0].y == m_line3DVtx[1].y ) { m_line3DVector[0].x = m_line3DVector[1].x = m_line3DVtx[0].x; m_line3DVector[2].x = m_line3DVector[3].x = m_line3DVtx[1].x; m_line3DVector[0].y = m_line3DVector[2].y = m_line3DVtx[0].y-width/2*windowSetting.fMultY; m_line3DVector[1].y = m_line3DVector[3].y = m_line3DVtx[0].y+width/2*windowSetting.fMultY; } else { m_line3DVector[0].y = m_line3DVector[1].y = m_line3DVtx[0].y; m_line3DVector[2].y = m_line3DVector[3].y = m_line3DVtx[1].y; m_line3DVector[0].x = m_line3DVector[2].x = m_line3DVtx[0].x-width/2*windowSetting.fMultX; m_line3DVector[1].x = m_line3DVector[3].x = m_line3DVtx[0].x+width/2*windowSetting.fMultX; } SetCombinerAndBlender(); bool res=RenderLine3D(); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_FLUSH_TRI, { DebuggerAppendMsg("Pause after Line3D: v%d(%f,%f,%f), v%d(%f,%f,%f), Width=%d\n", dwV0, m_line3DVtx[0].x, m_line3DVtx[0].y, m_line3DVtx[0].z, dwV1, m_line3DVtx[1].x, m_line3DVtx[1].y, m_line3DVtx[1].z, dwWidth); }); DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_OBJ_TXT_CMD, { DebuggerAppendMsg("Pause after Line3D: v%d(%f,%f,%f), v%d(%f,%f,%f), Width=%d\n", dwV0, m_line3DVtx[0].x, m_line3DVtx[0].y, m_line3DVtx[0].z, dwV1, m_line3DVtx[1].x, m_line3DVtx[1].y, m_line3DVtx[1].z, dwWidth); }); return res; } bool CRender::RemapTextureCoordinate (float t0, float t1, uint32 tileWidth, uint32 mask, float textureWidth, float &u0, float &u1) { int s0 = (int)t0; int s1 = (int)t1; int width = mask>0 ? (1< s0 ) divs0--; int divs1 = s1/width; if( divs1*width > s1 ) divs1--; if( divs0 == divs1 ) { s0 -= divs0*width; s1 -= divs1*width; //if( s0 > s1 ) // s0++; //else if( s1 > s0 ) // s1++; u0 = s0/textureWidth; u1 = s1/textureWidth; return true; } else if( divs0+1 == divs1 && s0%width==0 && s1%width == 0 ) { u0 = 0; u1 = tileWidth/textureWidth; return true; } else if( divs0 == divs1+1 && s0%width==0 && s1%width == 0 ) { u1 = 0; u0 = tileWidth/textureWidth; return true; } else { //if( s0 > s1 ) //{ //s0++; // u0 = s0/textureWidth; //} //else if( s1 > s0 ) //{ //s1++; // u1 = s1/textureWidth; //} return false; } } bool CRender::TexRect(int nX0, int nY0, int nX1, int nY1, float fS0, float fT0, float fScaleS, float fScaleT, bool colorFlag, uint32 diffuseColor) { if( options.enableHackForGames == HACK_FOR_DUKE_NUKEM ) { colorFlag = true; diffuseColor = 0; } if( status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_1ST_PRIMITIVE ) { status.bVIOriginIsUpdated=false; CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG,{DebuggerAppendMsg("Screen Update at 1st textRect");}); } if( options.enableHackForGames == HACK_FOR_BANJO_TOOIE ) { // Hack for Banjo shadow in Banjo Tooie if( g_TI.dwWidth == g_CI.dwWidth && g_TI.dwFormat == TXT_FMT_CI && g_TI.dwSize == TXT_SIZE_8b ) { if( nX0 == fS0 && nY0 == fT0 )//&& nX0 > 90 && nY0 > 130 && nX1-nX0 > 80 && nY1-nY0 > 20 ) { // Skip the text rect return true; } } } if( status.bN64IsDrawingTextureBuffer ) { if( frameBufferOptions.bIgnore || ( frameBufferOptions.bIgnoreRenderTextureIfHeightUnknown && newRenderTextureInfo.knownHeight == 0 ) ) { return true; } } PrepareTextures(); if( status.bHandleN64RenderTexture && g_pRenderTextureInfo->CI_Info.dwSize == TXT_SIZE_8b ) { return true; } if( !IsTextureEnabled() && gRDP.otherMode.cycle_type != CYCLE_TYPE_COPY ) { FillRect(nX0, nY0, nX1, nY1, gRDP.primitiveColor); return true; } if( IsUsedAsDI(g_CI.dwAddr) && !status.bHandleN64RenderTexture ) { status.bFrameBufferIsDrawn = true; } if( status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM ) status.bFrameBufferIsDrawn = true; LOG_UCODE("TexRect: X0=%d, Y0=%d, X1=%d, Y1=%d,\n\t\tfS0=%f, fT0=%f, ScaleS=%f, ScaleT=%f ", nX0, nY0, nX1, nY1, fS0, fT0, fScaleS, fScaleT); if( options.bEnableHacks ) { // Goldeneye HACK if( nY1 - nY0 < 2 ) nY1 = nY1+2; //// Text edge hack else if( gRDP.otherMode.cycle_type == CYCLE_TYPE_1 && fScaleS == 1 && fScaleT == 1 && (int)g_textures[gRSP.curTile].m_dwTileWidth == nX1-nX0+1 && (int)g_textures[gRSP.curTile].m_dwTileHeight == nY1-nY0+1 && g_textures[gRSP.curTile].m_dwTileWidth%2 == 0 && g_textures[gRSP.curTile].m_dwTileHeight%2 == 0 ) { nY1++; nX1++; } else if( g_curRomInfo.bIncTexRectEdge ) { nX1++; nY1++; } } // Scale to Actual texture coords // The two cases are to handle the oversized textures hack on voodoos SetCombinerAndBlender(); if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY || !gRDP.otherMode.z_cmp ) { ZBufferEnable(FALSE); } BOOL accurate = currentRomOptions.bAccurateTextureMapping; RenderTexture &tex0 = g_textures[gRSP.curTile]; Tile &tile0 = gRDP.tiles[gRSP.curTile]; float widthDiv = tex0.m_fTexWidth; float heightDiv = tex0.m_fTexHeight; float t0u0; if( options.enableHackForGames == HACK_FOR_ALL_STAR_BASEBALL || options.enableHackForGames == HACK_FOR_MLB ) { t0u0 = (fS0 -tile0.fhilite_sl); } else { t0u0 = (fS0 * tile0.fShiftScaleS -tile0.fhilite_sl); } float t0u1; if( accurate && gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY ) { t0u1 = t0u0 + (fScaleS * (nX1 - nX0 - 1))*tile0.fShiftScaleS; } else { t0u1 = t0u0 + (fScaleS * (nX1 - nX0))*tile0.fShiftScaleS; } if( status.UseLargerTile[0] ) { m_texRectTex1UV[0].u = (t0u0+status.LargerTileRealLeft[0])/widthDiv; m_texRectTex1UV[1].u = (t0u1+status.LargerTileRealLeft[0])/widthDiv; } else { m_texRectTex1UV[0].u = t0u0/widthDiv; m_texRectTex1UV[1].u = t0u1/widthDiv; if( accurate && !tile0.bMirrorS && RemapTextureCoordinate(t0u0, t0u1, tex0.m_dwTileWidth, tile0.dwMaskS, widthDiv, m_texRectTex1UV[0].u, m_texRectTex1UV[1].u) ) SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile); } float t0v0; if( options.enableHackForGames == HACK_FOR_ALL_STAR_BASEBALL || options.enableHackForGames == HACK_FOR_MLB ) { t0v0 = (fT0 -tile0.fhilite_tl); } else { t0v0 = (fT0 * tile0.fShiftScaleT -tile0.fhilite_tl); } float t0v1; if ( accurate && gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY) { t0v1 = t0v0 + (fScaleT * (nY1 - nY0-1))*tile0.fShiftScaleT; } else { t0v1 = t0v0 + (fScaleT * (nY1 - nY0))*tile0.fShiftScaleT; } m_texRectTex1UV[0].v = t0v0/heightDiv; m_texRectTex1UV[1].v = t0v1/heightDiv; if( accurate && !tile0.bMirrorT && RemapTextureCoordinate(t0v0, t0v1, tex0.m_dwTileHeight, tile0.dwMaskT, heightDiv, m_texRectTex1UV[0].v, m_texRectTex1UV[1].v) ) SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile); COLOR difColor; if( colorFlag ) difColor = diffuseColor; else difColor = gRDP.primitiveColor; g_texRectTVtx[0].x = ViewPortTranslatei_x(nX0); g_texRectTVtx[0].y = ViewPortTranslatei_y(nY0); g_texRectTVtx[0].dcDiffuse = difColor; g_texRectTVtx[1].x = ViewPortTranslatei_x(nX1); g_texRectTVtx[1].y = ViewPortTranslatei_y(nY0); g_texRectTVtx[1].dcDiffuse = difColor; g_texRectTVtx[2].x = ViewPortTranslatei_x(nX1); g_texRectTVtx[2].y = ViewPortTranslatei_y(nY1); g_texRectTVtx[2].dcDiffuse = difColor; g_texRectTVtx[3].x = ViewPortTranslatei_x(nX0); g_texRectTVtx[3].y = ViewPortTranslatei_y(nY1); g_texRectTVtx[3].dcDiffuse = difColor; float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0 ); // -0.02 : hack here (arbitrary value...). I guess this offset has do be found "somewhere" if( depth > 0.02f ) { depth -= 0.02f; } g_texRectTVtx[0].z = g_texRectTVtx[1].z = g_texRectTVtx[2].z = g_texRectTVtx[3].z = depth; g_texRectTVtx[0].rhw = g_texRectTVtx[1].rhw = g_texRectTVtx[2].rhw = g_texRectTVtx[3].rhw = 1; if( IsTexel1Enable() ) { RenderTexture &tex1 = g_textures[(gRSP.curTile+1)&7]; Tile &tile1 = gRDP.tiles[(gRSP.curTile+1)&7]; widthDiv = tex1.m_fTexWidth; heightDiv = tex1.m_fTexHeight; //if( tile1.dwMaskS == 0 ) widthDiv = tile1.dwWidth; //if( tile1.dwMaskT == 0 ) heightDiv = tile1.dwHeight; float t0u0 = fS0 * tile1.fShiftScaleS -tile1.fhilite_sl; float t0v0 = fT0 * tile1.fShiftScaleT -tile1.fhilite_tl; float t0u1; float t0v1; if ( accurate && gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY) { t0u1 = t0u0 + (fScaleS * (nX1 - nX0 - 1))*tile1.fShiftScaleS; t0v1 = t0v0 + (fScaleT * (nY1 - nY0 - 1))*tile1.fShiftScaleT; } else { t0u1 = t0u0 + (fScaleS * (nX1 - nX0))*tile1.fShiftScaleS; t0v1 = t0v0 + (fScaleT * (nY1 - nY0))*tile1.fShiftScaleT; } if( status.UseLargerTile[1] ) { m_texRectTex2UV[0].u = (t0u0+status.LargerTileRealLeft[1])/widthDiv; m_texRectTex2UV[1].u = (t0u1+status.LargerTileRealLeft[1])/widthDiv; } else { m_texRectTex2UV[0].u = t0u0/widthDiv; m_texRectTex2UV[1].u = t0u1/widthDiv; if( accurate && !tile1.bMirrorS && RemapTextureCoordinate(t0u0, t0u1, tex1.m_dwTileWidth, tile1.dwMaskS, widthDiv, m_texRectTex2UV[0].u, m_texRectTex2UV[1].u) ) SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, (gRSP.curTile+1)&7); } m_texRectTex2UV[0].v = t0v0/heightDiv; m_texRectTex2UV[1].v = t0v1/heightDiv; if( accurate && !tile1.bMirrorT && RemapTextureCoordinate(t0v0, t0v1, tex1.m_dwTileHeight, tile1.dwMaskT, heightDiv, m_texRectTex2UV[0].v, m_texRectTex2UV[1].v) ) SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, (gRSP.curTile+1)&7); SetVertexTextureUVCoord(g_texRectTVtx[0], m_texRectTex1UV[0].u, m_texRectTex1UV[0].v, m_texRectTex2UV[0].u, m_texRectTex2UV[0].v); SetVertexTextureUVCoord(g_texRectTVtx[1], m_texRectTex1UV[1].u, m_texRectTex1UV[0].v, m_texRectTex2UV[1].u, m_texRectTex2UV[0].v); SetVertexTextureUVCoord(g_texRectTVtx[2], m_texRectTex1UV[1].u, m_texRectTex1UV[1].v, m_texRectTex2UV[1].u, m_texRectTex2UV[1].v); SetVertexTextureUVCoord(g_texRectTVtx[3], m_texRectTex1UV[0].u, m_texRectTex1UV[1].v, m_texRectTex2UV[0].u, m_texRectTex2UV[1].v); } else { SetVertexTextureUVCoord(g_texRectTVtx[0], m_texRectTex1UV[0].u, m_texRectTex1UV[0].v); SetVertexTextureUVCoord(g_texRectTVtx[1], m_texRectTex1UV[1].u, m_texRectTex1UV[0].v); SetVertexTextureUVCoord(g_texRectTVtx[2], m_texRectTex1UV[1].u, m_texRectTex1UV[1].v); SetVertexTextureUVCoord(g_texRectTVtx[3], m_texRectTex1UV[0].u, m_texRectTex1UV[1].v); } bool res; if( TileUFlags[gRSP.curTile]==TEXTURE_UV_FLAG_CLAMP && TileVFlags[gRSP.curTile]==TEXTURE_UV_FLAG_CLAMP && options.forceTextureFilter == FORCE_DEFAULT_FILTER ) { TextureFilter dwFilter = m_dwMagFilter; m_dwMagFilter = m_dwMinFilter = FILTER_LINEAR; ApplyTextureFilter(); ApplyRDPScissor(); res = RenderTexRect(); m_dwMagFilter = m_dwMinFilter = dwFilter; ApplyTextureFilter(); } else if( fScaleS >= 1 && fScaleT >= 1 && options.forceTextureFilter == FORCE_DEFAULT_FILTER ) { TextureFilter dwFilter = m_dwMagFilter; m_dwMagFilter = m_dwMinFilter = FILTER_POINT; ApplyTextureFilter(); ApplyRDPScissor(); res = RenderTexRect(); m_dwMagFilter = m_dwMinFilter = dwFilter; ApplyTextureFilter(); } else { ApplyRDPScissor(); res = RenderTexRect(); } if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY || !gRDP.otherMode.z_cmp ) { ZBufferEnable(gRSP.bZBufferEnabled); } DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_FLUSH_TRI || eventToPause == NEXT_TEXTRECT), { DebuggerAppendMsg("TexRect: tile=%d, X0=%d, Y0=%d, X1=%d, Y1=%d,\nfS0=%f, fT0=%f, ScaleS=%f, ScaleT=%f\n", gRSP.curTile, nX0, nY0, nX1, nY1, fS0, fT0, fScaleS, fScaleT); DebuggerAppendMsg(" : x0=%f, y0=%f, x1=%f, y1=%f\n", g_texRectTVtx[0].x, g_texRectTVtx[0].y, g_texRectTVtx[2].x, g_texRectTVtx[2].y); DebuggerAppendMsg(" Tex0: u0=%f, v0=%f, u1=%f, v1=%f\n", m_texRectTex1UV[0].u, m_texRectTex1UV[0].v, m_texRectTex1UV[1].u, m_texRectTex1UV[1].v); if( IsTexel1Enable() ) { DebuggerAppendMsg(" Tex1: u0=%f, v0=%f, u1=%f, v1=%f\n", m_texRectTex2UV[0].u, m_texRectTex2UV[0].v, m_texRectTex2UV[1].u, m_texRectTex2UV[1].v); } DebuggerAppendMsg("color=%08X\n", g_texRectTVtx[0].dcDiffuse); DebuggerAppendMsg("Pause after TexRect\n"); }); return res; } bool CRender::TexRectFlip(int nX0, int nY0, int nX1, int nY1, float fS0, float fT0, float fS1, float fT1) { LOG_UCODE("TexRectFlip: X0=%d, Y0=%d, X1=%d, Y1=%d,\n\t\tfS0=%f, fT0=%f, fS1=%f, fT1=%f ", nX0, nY0, nX1, nY1, fS0, fT0, fS1, fT1); if( status.bHandleN64RenderTexture && !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } PrepareTextures(); // Save ZBuffer state m_savedZBufferFlag = gRSP.bZBufferEnabled; if( gRDP.otherMode.depth_source == 0 ) ZBufferEnable( FALSE ); float widthDiv = g_textures[gRSP.curTile].m_fTexWidth; float heightDiv = g_textures[gRSP.curTile].m_fTexHeight; //Tile &tile0 = gRDP.tiles[gRSP.curTile]; float t0u0 = fS0 / widthDiv; float t0v0 = fT0 / heightDiv; float t0u1 = (fS1 - fS0)/ widthDiv + t0u0; float t0v1 = (fT1 - fT0)/ heightDiv + t0v0; float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0 ); if( t0u0 >= 0 && t0u1 <= 1 && t0u1 >= t0u0 ) SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile); if( t0v0 >= 0 && t0v1 <= 1 && t0v1 >= t0v0 ) SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile); SetCombinerAndBlender(); COLOR difColor = gRDP.primitiveColor; // Same as TexRect, but with texcoords 0,2 swapped g_texRectTVtx[0].x = ViewPortTranslatei_x(nX0); g_texRectTVtx[0].y = ViewPortTranslatei_y(nY0); g_texRectTVtx[0].dcDiffuse = difColor; g_texRectTVtx[1].x = ViewPortTranslatei_x(nX1); g_texRectTVtx[1].y = ViewPortTranslatei_y(nY0); g_texRectTVtx[1].dcDiffuse = difColor; g_texRectTVtx[2].x = ViewPortTranslatei_x(nX1); g_texRectTVtx[2].y = ViewPortTranslatei_y(nY1); g_texRectTVtx[2].dcDiffuse = difColor; g_texRectTVtx[3].x = ViewPortTranslatei_x(nX0); g_texRectTVtx[3].y = ViewPortTranslatei_y(nY1); g_texRectTVtx[3].dcDiffuse = difColor; g_texRectTVtx[0].z = g_texRectTVtx[1].z = g_texRectTVtx[2].z = g_texRectTVtx[3].z = depth; g_texRectTVtx[0].rhw = g_texRectTVtx[1].rhw = g_texRectTVtx[2].rhw = g_texRectTVtx[3].rhw = 1.0f; SetVertexTextureUVCoord(g_texRectTVtx[0], t0u0, t0v0); SetVertexTextureUVCoord(g_texRectTVtx[1], t0u0, t0v1); SetVertexTextureUVCoord(g_texRectTVtx[2], t0u1, t0v1); SetVertexTextureUVCoord(g_texRectTVtx[3], t0u1, t0v0); ApplyRDPScissor(); bool res = RenderTexRect(); // Restore state ZBufferEnable( m_savedZBufferFlag ); DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_FLUSH_TRI || eventToPause == NEXT_TEXTRECT), { DebuggerAppendMsg("TexRectFlip: tile=%d, X0=%d, Y0=%d, X1=%d, Y1=%d,\nfS0=%f, fT0=%f, nfS1=%f, fT1=%f\n", gRSP.curTile, nX0, nY0, nX1, nY1, fS0, fT0, fS1, fT1); DebuggerAppendMsg(" : x0=%f, y0=%f, x1=%f, y1=%f\n", g_texRectTVtx[0].x, g_texRectTVtx[0].y, g_texRectTVtx[2].x, g_texRectTVtx[2].y); DebuggerAppendMsg(" Tex0: u0=%f, v0=%f, u1=%f, v1=%f\n", g_texRectTVtx[0].tcord[0].u, g_texRectTVtx[0].tcord[0].v, g_texRectTVtx[2].tcord[0].u, g_texRectTVtx[2].tcord[0].v); TRACE0("Pause after TexRectFlip\n"); }); return res; } void CRender::StartDrawSimple2DTexture(float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, COLOR dif, float z, float rhw) { g_texRectTVtx[0].x = ViewPortTranslatei_x(x0); // << Error here, shouldn't divid by 4 g_texRectTVtx[0].y = ViewPortTranslatei_y(y0); g_texRectTVtx[0].dcDiffuse = dif; g_texRectTVtx[0].tcord[0].u = u0; g_texRectTVtx[0].tcord[0].v = v0; g_texRectTVtx[1].x = ViewPortTranslatei_x(x1); g_texRectTVtx[1].y = ViewPortTranslatei_y(y0); g_texRectTVtx[1].dcDiffuse = dif; g_texRectTVtx[1].tcord[0].u = u1; g_texRectTVtx[1].tcord[0].v = v0; g_texRectTVtx[2].x = ViewPortTranslatei_x(x1); g_texRectTVtx[2].y = ViewPortTranslatei_y(y1); g_texRectTVtx[2].dcDiffuse = dif; g_texRectTVtx[2].tcord[0].u = u1; g_texRectTVtx[2].tcord[0].v = v1; g_texRectTVtx[3].x = ViewPortTranslatei_x(x0); g_texRectTVtx[3].y = ViewPortTranslatei_y(y1); g_texRectTVtx[3].dcDiffuse = dif; g_texRectTVtx[3].tcord[0].u = u0; g_texRectTVtx[3].tcord[0].v = v1; RenderTexture &txtr = g_textures[0]; if( txtr.pTextureEntry && txtr.pTextureEntry->txtrBufIdx > 0 ) { RenderTextureInfo &info = gRenderTextureInfos[txtr.pTextureEntry->txtrBufIdx-1]; g_texRectTVtx[0].tcord[0].u *= info.scaleX; g_texRectTVtx[0].tcord[0].v *= info.scaleY; g_texRectTVtx[1].tcord[0].u *= info.scaleX; g_texRectTVtx[1].tcord[0].v *= info.scaleY; g_texRectTVtx[2].tcord[0].u *= info.scaleX; g_texRectTVtx[2].tcord[0].v *= info.scaleY; g_texRectTVtx[3].tcord[0].u *= info.scaleX; g_texRectTVtx[3].tcord[0].v *= info.scaleY; } g_texRectTVtx[0].z = g_texRectTVtx[1].z = g_texRectTVtx[2].z = g_texRectTVtx[3].z = z; g_texRectTVtx[0].rhw = g_texRectTVtx[1].rhw = g_texRectTVtx[2].rhw = g_texRectTVtx[3].rhw = rhw; } void CRender::StartDrawSimpleRect(int nX0, int nY0, int nX1, int nY1, uint32 dwColor, float depth, float rhw) { m_simpleRectVtx[0].x = ViewPortTranslatei_x(nX0); m_simpleRectVtx[1].x = ViewPortTranslatei_x(nX1); m_simpleRectVtx[0].y = ViewPortTranslatei_y(nY0); m_simpleRectVtx[1].y = ViewPortTranslatei_y(nY1); } void CRender::SetAddressUAllStages(uint32 dwTile, TextureUVFlag dwFlag) { } void CRender::SetAddressVAllStages(uint32 dwTile, TextureUVFlag dwFlag) { } void CRender::SetAllTexelRepeatFlag() { if( IsTextureEnabled() ) { if( IsTexel0Enable() || gRDP.otherMode.cycle_type == CYCLE_TYPE_COPY ) SetTexelRepeatFlags(gRSP.curTile); if( IsTexel1Enable() ) SetTexelRepeatFlags((gRSP.curTile+1)&7); } } void CRender::SetTexelRepeatFlags(uint32 dwTile) { Tile &tile = gRDP.tiles[dwTile]; if( tile.bForceClampS ) SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, dwTile); else if( tile.bForceWrapS ) SetTextureUFlag(TEXTURE_UV_FLAG_WRAP, dwTile); else if( tile.dwMaskS == 0 || tile.bClampS ) { if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY ) SetTextureUFlag(TEXTURE_UV_FLAG_WRAP, dwTile); // Can not clamp in COPY/FILL mode else SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, dwTile); } else if (tile.bMirrorS ) SetTextureUFlag(TEXTURE_UV_FLAG_MIRROR, dwTile); else SetTextureUFlag(TEXTURE_UV_FLAG_WRAP, dwTile); if( tile.bForceClampT ) SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, dwTile); else if( tile.bForceWrapT ) SetTextureVFlag(TEXTURE_UV_FLAG_WRAP, dwTile); else if( tile.dwMaskT == 0 || tile.bClampT) { if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY ) SetTextureVFlag(TEXTURE_UV_FLAG_WRAP, dwTile); // Can not clamp in COPY/FILL mode else SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, dwTile); } else if (tile.bMirrorT ) SetTextureVFlag(TEXTURE_UV_FLAG_MIRROR, dwTile); else SetTextureVFlag(TEXTURE_UV_FLAG_WRAP, dwTile); } void CRender::Initialize(void) { ClearDeviceObjects(); InitDeviceObjects(); } void CRender::CleanUp(void) { m_pColorCombiner->CleanUp(); ClearDeviceObjects(); } void myVec3Transform(float *vecout, float *vecin, float* m) { float w = m[3]*vecin[0]+m[7]*vecin[1]+m[11]*vecin[2]+m[15]; vecout[0] = (m[0]*vecin[0]+m[4]*vecin[1]+m[8]*vecin[2]+m[12])/w; vecout[1] = (m[1]*vecin[0]+m[5]*vecin[1]+m[9]*vecin[2]+m[13])/w; vecout[2] = (m[2]*vecin[0]+m[6]*vecin[1]+m[10]*vecin[2]+m[14])/w; } void CRender::SetTextureEnableAndScale(int dwTile, bool bEnable, float fScaleX, float fScaleY) { gRSP.bTextureEnabled = bEnable; if( bEnable ) { if( gRSP.curTile != (unsigned int)dwTile ) gRDP.textureIsChanged = true; gRSP.curTile = dwTile; gRSP.fTexScaleX = fScaleX; gRSP.fTexScaleY = fScaleY; if( fScaleX == 0 || fScaleY == 0 ) { gRSP.fTexScaleX = 1/32.0f; gRSP.fTexScaleY = 1/32.0f; } } } void CRender::SetViewport(int nLeft, int nTop, int nRight, int nBottom, int maxZ) { if( status.bHandleN64RenderTexture ) return; static float MultX=0, MultY=0; if( gRSP.nVPLeftN == nLeft && gRSP.nVPTopN == nTop && gRSP.nVPRightN == nRight && gRSP.nVPBottomN == nBottom && MultX==windowSetting.fMultX && MultY==windowSetting.fMultY) { // no changes return; } MultX=windowSetting.fMultX; MultY=windowSetting.fMultY; gRSP.maxZ = maxZ; gRSP.nVPLeftN = nLeft; gRSP.nVPTopN = nTop; gRSP.nVPRightN = nRight; gRSP.nVPBottomN = nBottom; gRSP.nVPWidthN = nRight - nLeft + 1; gRSP.nVPHeightN = nBottom - nTop + 1; UpdateClipRectangle(); SetViewportRender(); LOG_UCODE("SetViewport (%d,%d - %d,%d)",gRSP.nVPLeftN, gRSP.nVPTopN, gRSP.nVPRightN, gRSP.nVPBottomN); } extern bool bHalfTxtScale; bool CRender::DrawTriangles() { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); DEBUGGER_ONLY_IF( (!debuggerEnableZBuffer), {ZBufferEnable( FALSE );} ); if( status.bVIOriginIsUpdated == true && currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_1ST_PRIMITIVE ) { status.bVIOriginIsUpdated=false; CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG,{DebuggerAppendMsg("Screen Update at 1st triangle");}); } // Hack for Pilotwings 64 (U) [!].v64 static bool skipNext=false; if( options.enableHackForGames == HACK_FOR_PILOT_WINGS ) { if( IsUsedAsDI(g_CI.dwAddr) && gRDP.otherMode.z_cmp+gRDP.otherMode.z_upd > 0 ) { TRACE0("Warning: using Flushtris to write Zbuffer" ); gRSP.numVertices = 0; gRSP.maxVertexID = 0; skipNext = true; return true; } else if( skipNext ) { skipNext = false; gRSP.numVertices = 0; gRSP.maxVertexID = 0; return true; } } if( status.bN64IsDrawingTextureBuffer && frameBufferOptions.bIgnore ) { gRSP.numVertices = 0; gRSP.maxVertexID = 0; return true; } extern bool bConkerHideShadow; if( options.enableHackForGames == HACK_FOR_CONKER && bConkerHideShadow ) { gRSP.numVertices = 0; gRSP.maxVertexID = 0; return true; } if( IsUsedAsDI(g_CI.dwAddr) && !status.bHandleN64RenderTexture ) { status.bFrameBufferIsDrawn = true; } /* if( status.bHandleN64RenderTexture && g_pRenderTextureInfo->CI_Info.dwSize == TXT_SIZE_8b ) { gRSP.numVertices = 0; gRSP.maxVertexID = 0; return true; } */ if (gRSP.numVertices == 0) return true; if( status.bHandleN64RenderTexture ) { g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height; if( !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } } for( int t=0; t<2; t++ ) { float halfscaleS = 1; // This will get rid of the thin black lines if( t==0 && !(m_pColorCombiner->m_bTex0Enabled) ) continue; else { if( ( gRDP.tiles[gRSP.curTile].dwSize == TXT_SIZE_32b && options.enableHackForGames == HACK_FOR_RUMBLE ) || (bHalfTxtScale && g_curRomInfo.bTextureScaleHack ) || (options.enableHackForGames == HACK_FOR_POLARISSNOCROSS && gRDP.tiles[7].dwFormat == TXT_FMT_CI && gRDP.tiles[7].dwSize == TXT_SIZE_8b && gRDP.tiles[0].dwFormat == TXT_FMT_CI && gRDP.tiles[0].dwSize == TXT_SIZE_8b && gRSP.curTile == 0 )) { halfscaleS = 0.5; } } if( t==1 && !(m_pColorCombiner->m_bTex1Enabled) ) break; if( halfscaleS < 1 ) { for( uint32 i=0; i 1.0 || g_vtxBuffer[i].tcord[t].u < 0.0 ) { clampS = false; break; } } for( uint32 i=0; i 1.0 || g_vtxBuffer[i].tcord[t].v < 0.0 ) { clampT = false; break; } } if( clampS ) { SetTextureUFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile+t); } if( clampT ) { SetTextureVFlag(TEXTURE_UV_FLAG_CLAMP, gRSP.curTile+t); } */ } if( status.bHandleN64RenderTexture && g_pRenderTextureInfo->CI_Info.dwSize == TXT_SIZE_8b ) { ZBufferEnable(FALSE); } ApplyScissorWithClipRatio(); if( g_curRomInfo.bZHack ) { extern void HackZAll(); HackZAll(); } bool res = RenderFlushTris(); g_clippedVtxCount = 0; LOG_UCODE("DrawTriangles: Draw %d Triangles", gRSP.numVertices/3); gRSP.numVertices = 0; // Reset index gRSP.maxVertexID = 0; DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_FLUSH_TRI, { TRACE0("Pause after DrawTriangles\n"); }); return res; } inline int ReverseCITableLookup(uint32 *pTable, int size, uint32 val) { for( int i=0; i=2 || entry.ti.Format == TXT_FMT_CI || entry.ti.Format == TXT_FMT_RGBA) && entry.ti.Size <= TXT_SIZE_8b ) ) { // No a CI texture return false; } if ( entry.ti.TLutFmt != TLUT_FMT_RGBA16 && entry.ti.TLutFmt != TLUT_FMT_IA16 ) { TRACE0("Invalid Tlut format"); return false; } if( !entry.pTexture ) { TRACE0("Null texture"); return false; } uint32 *pTable = NULL; int tableSize; uint16 * pPal = (uint16 *)entry.ti.PalAddress; // Create the pallette table if( entry.ti.Size == TXT_SIZE_4b ) { // 4-bit table tableSize = 16; pTable = new uint32[16]; for( int i=0; i<16; i++ ) { pTable[i] = entry.ti.TLutFmt == TLUT_FMT_RGBA16 ? Convert555ToRGBA(pPal[i^1]) : ConvertIA16ToRGBA(pPal[i^1]); } } else { // 8-bit table tableSize = 256; pTable = new uint32[256]; for( int i=0; i<256; i++ ) { pTable[i] = entry.ti.TLutFmt == TLUT_FMT_RGBA16 ? Convert555ToRGBA(pPal[i^1]) : ConvertIA16ToRGBA(pPal[i^1]); } } // Reversely convert current texture to indexed textures CTexture &texture = *entry.pTexture; //int width = bWholeTexture ? texture.m_dwCreatedTextureWidth : texture.m_dwWidth; //int height = bWholeTexture ? texture.m_dwCreatedTextureHeight : texture.m_dwHeight; int width = bWholeTexture ? texture.m_dwCreatedTextureWidth : entry.ti.WidthToLoad; int height = bWholeTexture ? texture.m_dwCreatedTextureHeight : entry.ti.HeightToLoad; int bufSizePerLine = (((((width << entry.ti.Size) + 1 ) >> 1)+3) >> 2)*4; // pad to 32bit boundary int bufSize = bufSizePerLine*height; unsigned char *pbuf = new unsigned char[bufSize]; DrawInfo srcInfo; if( texture.StartUpdate(&srcInfo) ) { int idx = 0; for( int i=height-1; i>=0; i--) { uint32 *pSrc = (uint32*)((unsigned char*)srcInfo.lpSurface+srcInfo.lPitch * i); for( int j=0; j>1] = (pbuf[idx>>1]<<4) | val; idx++; } else { // 0 pbuf[idx>>1] = (unsigned char)val; idx++; } } else { // 8 bits pbuf[idx++] = (unsigned char)val; } } if( entry.ti.Size == TXT_SIZE_4b ) { if( idx%8 ) idx = (idx/8+1)*8; } else { if( idx%4 ) idx = (idx/4+1)*4; } } texture.EndUpdate(&srcInfo); } // Create BMP color indexed file if( strcasecmp(right(filename,4),".bmp") != 0 ) strcat(filename,".bmp"); BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; infoHeader.biSize = sizeof( BITMAPINFOHEADER ); infoHeader.biWidth = width; infoHeader.biHeight = height; infoHeader.biPlanes = 1; infoHeader.biBitCount = entry.ti.Size == TXT_SIZE_4b ? 4 : 8; infoHeader.biCompression = BI_RGB; infoHeader.biSizeImage = bufSize; infoHeader.biXPelsPerMeter = 0; infoHeader.biYPelsPerMeter = 0; infoHeader.biClrUsed = 0; infoHeader.biClrImportant = 0; fileHeader.bfType = 19778; fileHeader.bfSize = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) + infoHeader.biSizeImage + tableSize*4; fileHeader.bfReserved1 = fileHeader.bfReserved2 = 0; fileHeader.bfOffBits = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) + tableSize*4; FILE *f; f = fopen(filename, "wb"); if(f != NULL) { if (fwrite(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f) != 1 || fwrite(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f) != 1 || fwrite(pTable, tableSize*4, 1, f) != 1 || fwrite(pbuf, infoHeader.biSizeImage, 1, f) != 1) printf("failed to write out texture data to image file '%s'", filename); fclose(f); } else { // Do something TRACE1("Fail to create file %s", filename); } // Clean up delete [] pTable; delete [] pbuf; return true; } void CRender::SaveTextureToFile(CTexture &texture, char *filename, TextureChannel channel, bool bShow, bool bWholeTexture, int width, int height) { if( width < 0 || height < 0 ) { width = bWholeTexture ? texture.m_dwCreatedTextureWidth : texture.m_dwWidth; height = bWholeTexture ? texture.m_dwCreatedTextureHeight : texture.m_dwHeight; } unsigned char *pbuf = new unsigned char[width*height* (channel == TXT_RGBA ? 4 : 3)]; if( pbuf ) { DrawInfo srcInfo; if( texture.StartUpdate(&srcInfo) ) { if( channel == TXT_RGBA ) { uint32 *pbuf2 = (uint32*)pbuf; for( int i=height-1; i>=0; i--) { uint32 *pSrc = (uint32*)((unsigned char*)srcInfo.lpSurface+srcInfo.lPitch * i); for( int j=0; j=0; i--) { unsigned char *pSrc = (unsigned char*)srcInfo.lpSurface+srcInfo.lPitch * i; for( int j=0; j=2 || g_textures[tex].pTextureEntry->ti.Format == TXT_FMT_CI || g_textures[tex].pTextureEntry->ti.Format == TXT_FMT_RGBA) && g_textures[tex].pTextureEntry->ti.Size <= TXT_SIZE_8b ) { sprintf(filename, "\\%s#%08X#%d#%d_ci", g_curRomInfo.szGameName, g_textures[tex].pTextureEntry->dwCRC, g_textures[tex].pTextureEntry->ti.Format, g_textures[tex].pTextureEntry->ti.Size); SaveCITextureToFile(*(g_textures[tex].pTextureEntry), filename, bShow && bInWhole, false); sprintf(filename, "\\%s#%08X#%d#%d#%08X_ci", g_curRomInfo.szGameName, g_textures[tex].pTextureEntry->dwCRC, g_textures[tex].pTextureEntry->ti.Format, g_textures[tex].pTextureEntry->ti.Size, g_textures[tex].pTextureEntry->dwPalCRC); SaveCITextureToFile(*(g_textures[tex].pTextureEntry), filename, false, false); sprintf(filename, "\\%s#%08X#%d#%d#%08X_ciByRGBA", g_curRomInfo.szGameName, g_textures[tex].pTextureEntry->dwCRC, g_textures[tex].pTextureEntry->ti.Format, g_textures[tex].pTextureEntry->ti.Size, g_textures[tex].pTextureEntry->dwPalCRC); SaveTextureToFile(*pBaseTexture, filename, TXT_RGBA, false, false, g_textures[tex].pTextureEntry->ti.WidthToLoad, g_textures[tex].pTextureEntry->ti.HeightToLoad); DebuggerAppendMsg("Base texture is stored at: %s", filename); if( !bInWhole && bShow ) { sprintf(filename, "\\%s#%08X#%d#%d_ci_%s_debugger", g_curRomInfo.szGameName, g_textures[tex].pTextureEntry->dwCRC, g_textures[tex].pTextureEntry->ti.Format, g_textures[tex].pTextureEntry->ti.Size, channel == TXT_ALPHA ? "a" : channel == TXT_RGBA ? "all" : "rgb"); SaveTextureToFile(*pEnhancedTexture, filename, channel, true, true); DebuggerAppendMsg("Whole texture is stored at: %s", filename); } } else { sprintf(filename, "\\%s#%08X#%d#%d_%s", g_curRomInfo.szGameName, g_textures[tex].pTextureEntry->dwCRC, g_textures[tex].pTextureEntry->ti.Format, g_textures[tex].pTextureEntry->ti.Size, channel == TXT_ALPHA ? "a" : channel == TXT_RGBA ? "all" : "rgb"); SaveTextureToFile(*pBaseTexture, filename, channel, bShow && bInWhole, false,g_textures[tex].pTextureEntry->ti.WidthToLoad, g_textures[tex].pTextureEntry->ti.HeightToLoad); DebuggerAppendMsg("Base texture is stored at: %s", filename); if( !bInWhole && bShow ) { sprintf(filename, "\\%s#%08X#%d#%d_%s_debugger", g_curRomInfo.szGameName, g_textures[tex].pTextureEntry->dwCRC, g_textures[tex].pTextureEntry->ti.Format, g_textures[tex].pTextureEntry->ti.Size, channel == TXT_ALPHA ? "a" : channel == TXT_RGBA ? "all" : "rgb"); SaveTextureToFile(*pEnhancedTexture, filename, channel, true, true); DebuggerAppendMsg("Whole texture is stored at: %s", filename); } } } #endif extern RenderTextureInfo gRenderTextureInfos[]; void SetVertexTextureUVCoord(TexCord &dst, float s, float t, int tile, TxtrCacheEntry *pEntry) { RenderTexture &txtr = g_textures[tile]; RenderTextureInfo &info = gRenderTextureInfos[pEntry->txtrBufIdx-1]; uint32 addrOffset = g_TI.dwAddr-info.CI_Info.dwAddr; uint32 extraTop = (addrOffset>>(info.CI_Info.dwSize-1)) /info.CI_Info.dwWidth; uint32 extraLeft = (addrOffset>>(info.CI_Info.dwSize-1))%info.CI_Info.dwWidth; if( pEntry->txtrBufIdx > 0 ) { // Loading from render_texture or back buffer s += (extraLeft+pEntry->ti.LeftToLoad)/txtr.m_fTexWidth; t += (extraTop+pEntry->ti.TopToLoad)/txtr.m_fTexHeight; s *= info.scaleX; t *= info.scaleY; } dst.u = s; dst.v = t; } void CRender::SetVertexTextureUVCoord(TLITVERTEX &v, float fTex0S, float fTex0T) { RenderTexture &txtr = g_textures[0]; if( txtr.pTextureEntry && txtr.pTextureEntry->txtrBufIdx > 0 ) { ::SetVertexTextureUVCoord(v.tcord[0], fTex0S, fTex0T, 0, txtr.pTextureEntry); } else { v.tcord[0].u = fTex0S; v.tcord[0].v = fTex0T; } } void CRender::SetVertexTextureUVCoord(TLITVERTEX &v, float fTex0S, float fTex0T, float fTex1S, float fTex1T) { if( (options.enableHackForGames == HACK_FOR_ZELDA||options.enableHackForGames == HACK_FOR_ZELDA_MM) && m_modes64 == 0x00262a60150c937fLL && gRSP.curTile == 0 ) { // Hack for Zelda Sun Tile &t0 = gRDP.tiles[0]; Tile &t1 = gRDP.tiles[1]; if( t0.dwFormat == TXT_FMT_I && t0.dwSize == TXT_SIZE_8b && t0.dwWidth == 64 && t1.dwFormat == TXT_FMT_I && t1.dwSize == TXT_SIZE_8b && t1.dwWidth == 64 && t0.dwHeight == t1.dwHeight ) { fTex0S /= 2; fTex0T /= 2; fTex1S /= 2; fTex1T /= 2; } } RenderTexture &txtr0 = g_textures[0]; if( txtr0.pTextureEntry && txtr0.pTextureEntry->txtrBufIdx > 0 ) { ::SetVertexTextureUVCoord(v.tcord[0], fTex0S, fTex0T, 0, txtr0.pTextureEntry); } else { v.tcord[0].u = fTex0S; v.tcord[0].v = fTex0T; } RenderTexture &txtr1 = g_textures[1]; if( txtr1.pTextureEntry && txtr1.pTextureEntry->txtrBufIdx > 0 ) { ::SetVertexTextureUVCoord(v.tcord[1], fTex1S, fTex1T, 1, txtr1.pTextureEntry); } else { v.tcord[1].u = fTex1S; v.tcord[1].v = fTex1T; } } void CRender::SetClipRatio(uint32 type, uint32 w1) { bool modified = false; switch(type) { case RSP_MV_WORD_OFFSET_CLIP_RNX: LOG_UCODE(" RSP_MOVE_WORD_CLIP NegX: %d", (int)(short)w1); if( gRSP.clip_ratio_negx != (short)w1 ) { gRSP.clip_ratio_negx = (short)w1; modified = true; } break; case RSP_MV_WORD_OFFSET_CLIP_RNY: LOG_UCODE(" RSP_MOVE_WORD_CLIP NegY: %d", (int)(short)w1); if( gRSP.clip_ratio_negy != (short)w1 ) { gRSP.clip_ratio_negy = (short)w1; modified = true; } break; case RSP_MV_WORD_OFFSET_CLIP_RPX: LOG_UCODE(" RSP_MOVE_WORD_CLIP PosX: %d", (int)(short)w1); if( gRSP.clip_ratio_posx != -(short)w1 ) { gRSP.clip_ratio_posx = -(short)w1; modified = true; } break; case RSP_MV_WORD_OFFSET_CLIP_RPY: LOG_UCODE(" RSP_MOVE_WORD_CLIP PosY: %d", (int)(short)w1); if( gRSP.clip_ratio_posy != -(short)w1 ) { gRSP.clip_ratio_posy = -(short)w1; modified = true; } break; } if( modified ) { UpdateClipRectangle(); } } void CRender::UpdateClipRectangle() { if( status.bHandleN64RenderTexture ) { //windowSetting.fMultX = windowSetting.fMultY = 1; windowSetting.vpLeftW = 0; windowSetting.vpTopW = 0; windowSetting.vpRightW = newRenderTextureInfo.bufferWidth; windowSetting.vpBottomW = newRenderTextureInfo.bufferHeight; windowSetting.vpWidthW = newRenderTextureInfo.bufferWidth; windowSetting.vpHeightW = newRenderTextureInfo.bufferHeight; gRSP.vtxXMul = windowSetting.vpWidthW/2.0f; gRSP.vtxXAdd = gRSP.vtxXMul + windowSetting.vpLeftW; gRSP.vtxYMul = -windowSetting.vpHeightW/2.0f; gRSP.vtxYAdd = windowSetting.vpHeightW/2.0f + windowSetting.vpTopW+windowSetting.toolbarHeightToUse; // Update clip rectangle by setting scissor int halfx = newRenderTextureInfo.bufferWidth/2; int halfy = newRenderTextureInfo.bufferHeight/2; int centerx = halfx; int centery = halfy; gRSP.clip_ratio_left = centerx - halfx * gRSP.clip_ratio_negx; gRSP.clip_ratio_top = centery - halfy * gRSP.clip_ratio_negy; gRSP.clip_ratio_right = centerx + halfx * gRSP.clip_ratio_posx; gRSP.clip_ratio_bottom = centery + halfy * gRSP.clip_ratio_posy; } else { windowSetting.vpLeftW = int(gRSP.nVPLeftN * windowSetting.fMultX); windowSetting.vpTopW = int(gRSP.nVPTopN * windowSetting.fMultY); windowSetting.vpRightW = int(gRSP.nVPRightN* windowSetting.fMultX); windowSetting.vpBottomW = int(gRSP.nVPBottomN* windowSetting.fMultY); windowSetting.vpWidthW = int((gRSP.nVPRightN - gRSP.nVPLeftN + 1) * windowSetting.fMultX); windowSetting.vpHeightW = int((gRSP.nVPBottomN - gRSP.nVPTopN + 1) * windowSetting.fMultY); gRSP.vtxXMul = windowSetting.vpWidthW/2.0f; gRSP.vtxXAdd = gRSP.vtxXMul + windowSetting.vpLeftW; gRSP.vtxYMul = -windowSetting.vpHeightW/2.0f; gRSP.vtxYAdd = windowSetting.vpHeightW/2.0f + windowSetting.vpTopW+windowSetting.toolbarHeightToUse; // Update clip rectangle by setting scissor int halfx = gRSP.nVPWidthN/2; int halfy = gRSP.nVPHeightN/2; int centerx = gRSP.nVPLeftN+halfx; int centery = gRSP.nVPTopN+halfy; gRSP.clip_ratio_left = centerx - halfx * gRSP.clip_ratio_negx; gRSP.clip_ratio_top = centery - halfy * gRSP.clip_ratio_negy; gRSP.clip_ratio_right = centerx + halfx * gRSP.clip_ratio_posx; gRSP.clip_ratio_bottom = centery + halfy * gRSP.clip_ratio_posy; } UpdateScissorWithClipRatio(); } void CRender::UpdateScissorWithClipRatio() { gRSP.real_clip_scissor_left = std::max(gRDP.scissor.left, gRSP.clip_ratio_left); gRSP.real_clip_scissor_top = std::max(gRDP.scissor.top, gRSP.clip_ratio_top); gRSP.real_clip_scissor_right = std::min(gRDP.scissor.right,gRSP.clip_ratio_right); gRSP.real_clip_scissor_bottom = std::min(gRDP.scissor.bottom, gRSP.clip_ratio_bottom); gRSP.real_clip_scissor_left = std::max(gRSP.real_clip_scissor_left, 0); gRSP.real_clip_scissor_top = std::max(gRSP.real_clip_scissor_top, 0); gRSP.real_clip_scissor_right = std::min(gRSP.real_clip_scissor_right,windowSetting.uViWidth-1); gRSP.real_clip_scissor_bottom = std::min(gRSP.real_clip_scissor_bottom, windowSetting.uViHeight-1); WindowSettingStruct &w = windowSetting; w.clipping.left = (uint32)(gRSP.real_clip_scissor_left*windowSetting.fMultX); w.clipping.top = (uint32)(gRSP.real_clip_scissor_top*windowSetting.fMultY); w.clipping.bottom = (uint32)(gRSP.real_clip_scissor_bottom*windowSetting.fMultY); w.clipping.right = (uint32)(gRSP.real_clip_scissor_right*windowSetting.fMultX); if( w.clipping.left > 0 || w.clipping.top > 0 || w.clipping.right < (uint32)windowSetting.uDisplayWidth-1 || w.clipping.bottom < (uint32)windowSetting.uDisplayHeight-1 ) { w.clipping.needToClip = true; } else { w.clipping.needToClip = false; } // CF63 return real_clip_scissor_left bigger than real_clip_scissor_right // bringing to negative width. We use max to ensure the value is always 0+ w.clipping.width = (uint32)std::max((gRSP.real_clip_scissor_right-gRSP.real_clip_scissor_left+1)*windowSetting.fMultX, 0.0f); w.clipping.height = (uint32)std::max((gRSP.real_clip_scissor_bottom-gRSP.real_clip_scissor_top+1)*windowSetting.fMultY, 0.0f); float halfx = gRSP.nVPWidthN/2.0f; float halfy = gRSP.nVPHeightN/2.0f; float centerx = gRSP.nVPLeftN+halfx; float centery = gRSP.nVPTopN+halfy; gRSP.real_clip_ratio_negx = (gRSP.real_clip_scissor_left - centerx)/halfx; gRSP.real_clip_ratio_negy = (gRSP.real_clip_scissor_top - centery)/halfy; gRSP.real_clip_ratio_posx = (gRSP.real_clip_scissor_right - centerx)/halfx; gRSP.real_clip_ratio_posy = (gRSP.real_clip_scissor_bottom - centery)/halfy; ApplyScissorWithClipRatio(true); } // Set other modes not covered by color combiner or alpha blender void CRender::InitOtherModes(void) { // // I can't think why the hand in mario's menu screen is rendered with an opaque rendermode, // and no alpha threshold. We set the alpha reference to 1 to ensure that the transparent pixels // don't get rendered. I hope this doesn't fuck anything else up. // if ( gRDP.otherMode.alpha_compare == 0 ) { if ( gRDP.otherMode.cvg_x_alpha && (gRDP.otherMode.alpha_cvg_sel || gRDP.otherMode.aa_en ) ) { ForceAlphaRef(128); // Strange, I have to use value=2 for pixel shader combiner for Nvidia FX5200 // for other video cards, value=1 is good enough. SetAlphaTestEnable(TRUE); } else { SetAlphaTestEnable(FALSE); } } else if ( gRDP.otherMode.alpha_compare == 3 ) { //RDP_ALPHA_COMPARE_DITHER SetAlphaTestEnable(FALSE); } else { if( (gRDP.otherMode.alpha_cvg_sel ) && !gRDP.otherMode.cvg_x_alpha ) { // Use CVG for pixel alpha SetAlphaTestEnable(FALSE); } else { // RDP_ALPHA_COMPARE_THRESHOLD || RDP_ALPHA_COMPARE_DITHER if( m_dwAlpha==0 ) ForceAlphaRef(1); else ForceAlphaRef(m_dwAlpha); SetAlphaTestEnable(TRUE); } } if( options.enableHackForGames == HACK_FOR_SOUTH_PARK_RALLY && m_modes64 == 0x00121824ff33ffffLL && gRSP.bCullFront && gRDP.otherMode.aa_en && gRDP.otherMode.z_cmp && gRDP.otherMode.z_upd ) { SetZCompare(FALSE); } if( gRDP.otherMode.cycle_type >= CYCLE_TYPE_COPY ) { // Disable zbuffer for COPY and FILL mode SetZCompare(FALSE); } else { SetZCompare(gRDP.otherMode.z_cmp); SetZUpdate(gRDP.otherMode.z_upd); } /* if( options.enableHackForGames == HACK_FOR_SOUTH_PARK_RALLY && m_modes64 == 0x00121824ff33ffff && gRSP.bCullFront && gRDP.otherMode.z_cmp && gRDP.otherMode.z_upd )//&& gRDP.otherMode.aa_en ) { SetZCompare(FALSE); SetZUpdate(FALSE); } */ } void CRender::SetTextureFilter(uint32 dwFilter) { if( options.forceTextureFilter == FORCE_DEFAULT_FILTER ) { switch(dwFilter) { case RDP_TFILTER_AVERAGE: //? case RDP_TFILTER_BILERP: m_dwMinFilter = m_dwMagFilter = FILTER_LINEAR; break; default: m_dwMinFilter = m_dwMagFilter = FILTER_POINT; break; } } else { switch( options.forceTextureFilter ) { case FORCE_POINT_FILTER: m_dwMinFilter = m_dwMagFilter = FILTER_POINT; break; case FORCE_LINEAR_FILTER: m_dwMinFilter = m_dwMagFilter = FILTER_LINEAR; break; } } ApplyTextureFilter(); } bool SaveRGBBufferToFile(char *filename, unsigned char *buf, int width, int height, int pitch) { if( pitch == -1 ) pitch = width*3; if( strcasecmp(right(filename,3),"bmp") == 0 ) { BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; infoHeader.biSize = sizeof( BITMAPINFOHEADER ); infoHeader.biWidth = width; infoHeader.biHeight = height; infoHeader.biPlanes = 1; infoHeader.biBitCount = 24; infoHeader.biCompression = BI_RGB; infoHeader.biSizeImage = width * height * 3; infoHeader.biXPelsPerMeter = 0; infoHeader.biYPelsPerMeter = 0; infoHeader.biClrUsed = 0; infoHeader.biClrImportant = 0; fileHeader.bfType = 19778; fileHeader.bfSize = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) + infoHeader.biSizeImage; fileHeader.bfReserved1 = fileHeader.bfReserved2 = 0; fileHeader.bfOffBits = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ); FILE *f; f = fopen(filename, "wb"); if(f != NULL) { if (fwrite(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f) != 1 || fwrite(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f) != 1 || fwrite(buf, infoHeader.biSizeImage, 1, f) != 1) printf("failed to write out texture data to image file '%s'", filename); fclose(f); return true; } else { // Do something TRACE1("Fail to create file %s", filename); return false; } } else { if( strcasecmp(right(filename,4),".png") != 0 ) strcat(filename,".png"); struct BMGImageStruct img; memset(&img, 0, sizeof(BMGImageStruct)); InitBMGImage(&img); img.bits = buf; img.bits_per_pixel = 24; img.height = height; img.width = width; img.scan_width = pitch; BMG_Error code = WritePNG(filename, img); if( code == BMG_OK ) return true; else return false; } } bool SaveRGBABufferToPNGFile(char *filename, unsigned char *buf, int width, int height, int pitch) { if( pitch == -1 ) pitch = width*4; if( strcasecmp(right(filename,4),".png") != 0 ) strcat(filename,".png"); struct BMGImageStruct img; memset(&img, 0, sizeof(BMGImageStruct)); InitBMGImage(&img); img.bits = buf; img.bits_per_pixel = 32; img.height = height; img.width = width; img.scan_width = pitch; BMG_Error code = WritePNG(filename, img); if( code == BMG_OK ) return true; else return false; } mupen64plus-video-rice-src-2.6.0/src/Render.h000066400000000000000000000230211464507324400207200ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _RICE_RENDER_H #define _RICE_RENDER_H #include "Blender.h" #include "Combiner.h" #include "Config.h" #include "Debugger.h" #include "ExtendedRender.h" #include "RSP_Parser.h" #include "RSP_S2DEX.h" #include "RenderBase.h" #include "TextureManager.h" #include "osal_preproc.h" #include "typedefs.h" class CBlender; class CTexture; enum TextureChannel { TXT_RGB, TXT_ALPHA, TXT_RGBA, }; class CRender : public CExtendedRender { protected: CRender(); TextureUVFlag TileUFlags[8]; TextureUVFlag TileVFlags[8]; public: float m_fScreenViewportMultX; float m_fScreenViewportMultY; uint32 m_dwTexturePerspective; BOOL m_bAlphaTestEnable; BOOL m_bZUpdate; BOOL m_bZCompare; uint32 m_dwZBias; TextureFilter m_dwMinFilter; TextureFilter m_dwMagFilter; uint32 m_dwAlpha; uint64 m_modes64; // used to find hacks CColorCombiner *m_pColorCombiner; CBlender *m_pAlphaBlender; virtual ~CRender(); inline bool IsTexel0Enable() {return m_pColorCombiner->m_bTex0Enabled;} inline bool IsTexel1Enable() {return m_pColorCombiner->m_bTex1Enabled;} inline bool IsTextureEnabled() { return (m_pColorCombiner->m_bTexelsEnable); } inline RenderTexture& GetCurrentTexture() { return g_textures[gRSP.curTile]; } inline RenderTexture& GetTexture(uint32 dwTile) { return g_textures[dwTile]; } void SetViewport(int nLeft, int nTop, int nRight, int nBottom, int maxZ); virtual void SetViewportRender() {} virtual void SetClipRatio(uint32 type, uint32 value); virtual void UpdateScissor() {} virtual void ApplyRDPScissor(bool force=false) {} virtual void UpdateClipRectangle(); virtual void UpdateScissorWithClipRatio(); virtual void ApplyScissorWithClipRatio(bool force=false) {} void SetTextureEnableAndScale(int dwTile, bool enable, float fScaleX, float fScaleY); virtual void SetFogEnable(bool bEnable) { DEBUGGER_IF_DUMP( (gRSP.bFogEnabled != bEnable && logFog ), TRACE1("Set Fog %s", bEnable? "enable":"disable")); gRSP.bFogEnabled = bEnable&&(options.fogMethod > 0); } virtual void SetFogColor(uint32 r, uint32 g, uint32 b, uint32 a) { gRDP.fogColor = COLOR_RGBA(r, g, b, a); } uint32 GetFogColor() { return gRDP.fogColor; } void SetProjection(const Matrix & mat, bool bPush, bool bReplace); void SetWorldView(const Matrix & mat, bool bPush, bool bReplace); inline int GetProjectMatrixLevel(void) { return gRSP.projectionMtxTop; } inline int GetWorldViewMatrixLevel(void) { return gRSP.modelViewMtxTop; } inline void PopProjection() { if (gRSP.projectionMtxTop > 0) gRSP.projectionMtxTop--; else TRACE0("Popping past projection stack limits"); } void PopWorldView(); Matrix & GetWorldProjectMatrix(void); void SetWorldProjectMatrix(Matrix &mtx); void ResetMatrices(); inline RenderShadeMode GetShadeMode() { return gRSP.shadeMode; } void SetVtxTextureCoord(uint32 dwV, float tu, float tv) { g_fVtxTxtCoords[dwV].x = tu; g_fVtxTxtCoords[dwV].y = tv; } virtual void RenderReset(); virtual void SetCombinerAndBlender(); void SetCombineMode(uint32 dwMux0, uint32 dwMux1); virtual void SetCullMode(bool bCullFront, bool bCullBack) { gRSP.bCullFront = bCullFront; gRSP.bCullBack = bCullBack; } virtual void BeginRendering(void) {CRender::gRenderReferenceCount++;} // For DirectX only virtual void EndRendering(void) { if( CRender::gRenderReferenceCount > 0 ) CRender::gRenderReferenceCount--; } virtual void ClearBuffer(bool cbuffer, bool zbuffer)=0; virtual void ClearZBuffer(float depth)=0; virtual void ClearBuffer(bool cbuffer, bool zbuffer, COORDRECT &rect) { ClearBuffer(cbuffer, zbuffer); } virtual void ZBufferEnable(BOOL bZBuffer)=0; virtual void SetZCompare(BOOL bZCompare)=0; virtual void SetZUpdate(BOOL bZUpdate)=0; virtual void SetZBias(int bias)=0; virtual void SetAlphaTestEnable(BOOL bAlphaTestEnable)=0; void SetTextureFilter(uint32 dwFilter); virtual void ApplyTextureFilter() {} virtual void SetShadeMode(RenderShadeMode mode)=0; virtual void SetAlphaRef(uint32 dwAlpha)=0; virtual void ForceAlphaRef(uint32 dwAlpha)=0; virtual void InitOtherModes(void); void SetVertexTextureUVCoord(TLITVERTEX &v, float fTex0S, float fTex0T, float fTex1S, float fTex1T); void SetVertexTextureUVCoord(TLITVERTEX &v, float fTex0S, float fTex0T); bool DrawTriangles(); virtual bool RenderFlushTris()=0; bool TexRect(int nX0, int nY0, int nX1, int nY1, float fS0, float fT0, float fScaleS, float fScaleT, bool colorFlag=false, uint32 difcolor=0xFFFFFFFF); bool TexRectFlip(int nX0, int nY0, int nX1, int nY1, float fS0, float fT0, float fS1, float fT1); bool FillRect(int nX0, int nY0, int nX1, int nY1, uint32 dwColor); bool Line3D(uint32 dwV0, uint32 dwV1, uint32 dwWidth); virtual void SetAddressUAllStages(uint32 dwTile, TextureUVFlag dwFlag); // For DirectX only, fix me virtual void SetAddressVAllStages(uint32 dwTile, TextureUVFlag dwFlag); // For DirectX only, fix me virtual void SetTextureUFlag(TextureUVFlag dwFlag, uint32 tile)=0; virtual void SetTextureVFlag(TextureUVFlag dwFlag, uint32 tile)=0; virtual void SetTexelRepeatFlags(uint32 dwTile); virtual void SetAllTexelRepeatFlag(); virtual bool SetCurrentTexture(int tile, TxtrCacheEntry *pTextureEntry)=0; virtual bool SetCurrentTexture(int tile, CTexture *handler, uint32 dwTileWidth, uint32 dwTileHeight, TxtrCacheEntry *pTextureEntry) = 0; virtual bool InitDeviceObjects()=0; virtual bool ClearDeviceObjects()=0; virtual void Initialize(void); virtual void CleanUp(void); virtual void SetFillMode(FillMode mode)=0; #ifdef DEBUGGER virtual bool DrawTexture(int tex, TextureChannel channel = TXT_RGB ); virtual void SaveTextureToFile(int tex, TextureChannel channel = TXT_RGB, bool bShow = false); #endif virtual void SaveTextureToFile(CTexture &texture, char *filename, TextureChannel channel = TXT_RGB, bool bShow = false, bool bWholeTexture = true, int width = -1, int height = -1); void LoadSprite2D(Sprite2DInfo &info, uint32 ucode); void LoadObjBGCopy(uObjBg &info); void LoadObjBG1CYC(uObjScaleBg &info); void LoadObjSprite(uObjTxSprite &info, bool useTIAddr=false); void LoadFrameBuffer(bool useVIreg=false, uint32 left=0, uint32 top=0, uint32 width=0, uint32 height=0); void LoadTextureFromMemory(void *buf, uint32 left, uint32 top, uint32 width, uint32 height, uint32 pitch, uint32 format); void LoadTxtrBufIntoTexture(void); void DrawSprite2D(Sprite2DInfo &info, uint32 ucode); void DrawSpriteR(uObjTxSprite &sprite, bool initCombiner=true, uint32 tile=0, uint32 left=0, uint32 top=0, uint32 width=0, uint32 height=0); void DrawSprite(uObjTxSprite &sprite, bool rectR = true); void DrawObjBGCopy(uObjBg &info); virtual void DrawSpriteR_Render(){}; virtual void DrawSimple2DTexture(float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, COLOR dif, float z, float rhw)=0; void DrawFrameBuffer(bool useVIreg=false, uint32 left=0, uint32 top=0, uint32 width=0, uint32 height=0); void DrawObjBG1CYC(uObjScaleBg &bg, bool scaled=true); static CRender * g_pRender; static int gRenderReferenceCount; static CRender * GetRender(void); static bool IsAvailable(); protected: BOOL m_savedZBufferFlag; uint32 m_savedMinFilter; uint32 m_savedMagFilter; // FillRect virtual bool RenderFillRect(uint32 dwColor, float depth)=0; VECTOR2 m_fillRectVtx[2]; // Line3D virtual bool RenderLine3D()=0; LITVERTEX m_line3DVtx[2]; VECTOR2 m_line3DVector[4]; // TexRect virtual bool RenderTexRect()=0; TexCord m_texRectTex1UV[2]; TexCord m_texRectTex2UV[2]; // DrawSimple2DTexture virtual void StartDrawSimple2DTexture(float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, COLOR dif, float z, float rhw); // DrawSimpleRect virtual void StartDrawSimpleRect(int nX0, int nY0, int nX1, int nY1, uint32 dwColor, float depth, float rhw); VECTOR2 m_simpleRectVtx[2]; bool RemapTextureCoordinate(float s0, float s1, uint32 tileWidth, uint32 mask, float textureWidth, float &u0, float &u1); }; #define ffloor(a) (((int(a))<=(a))?(float)(int(a)):((float)(int(a))-1)) bool SaveRGBBufferToFile(char *filename, unsigned char *buf, int width, int height, int pitch = -1); bool SaveRGBABufferToPNGFile(char *filename, unsigned char *buf, int width, int height, int pitch = -1); #endif //_RICE_RENDER_H mupen64plus-video-rice-src-2.6.0/src/RenderBase.cpp000066400000000000000000002373201464507324400220570ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include "Combiner.h" #include "CombinerDefs.h" #include "Config.h" #include "Debugger.h" #include "DeviceBuilder.h" #include "RSP_Parser.h" #include "Render.h" #include "RenderBase.h" #include "Timing.h" #include "VectorMath.h" #include "Video.h" #include "float.h" #include "m64p_plugin.h" #include "osal_preproc.h" #include "typedefs.h" #undef min #undef max extern FiddledVtx * g_pVtxBase; #define ENABLE_CLIP_TRI #define X_CLIP_MAX 0x1 #define X_CLIP_MIN 0x2 #define Y_CLIP_MAX 0x4 #define Y_CLIP_MIN 0x8 #define Z_CLIP_MAX 0x10 #define Z_CLIP_MIN 0x20 #ifdef ENABLE_CLIP_TRI inline void RSP_Vtx_Clipping(int i) { g_clipFlag[i] = 0; g_clipFlag2[i] = 0; if( g_vecProjected[i].w > 0 ) { /* if( gRSP.bRejectVtx ) { if( g_vecProjected[i].x > 1 ) { g_clipFlag2[i] |= X_CLIP_MAX; if( g_vecProjected[i].x > gRSP.real_clip_ratio_posx ) g_clipFlag[i] |= X_CLIP_MAX; } if( g_vecProjected[i].x < -1 ) { g_clipFlag2[i] |= X_CLIP_MIN; if( g_vecProjected[i].x < gRSP.real_clip_ratio_negx ) g_clipFlag[i] |= X_CLIP_MIN; } if( g_vecProjected[i].y > 1 ) { g_clipFlag2[i] |= Y_CLIP_MAX; if( g_vecProjected[i].y > gRSP.real_clip_ratio_posy ) g_clipFlag[i] |= Y_CLIP_MAX; } if( g_vecProjected[i].y < -1 ) { g_clipFlag2[i] |= Y_CLIP_MIN; if( g_vecProjected[i].y < gRSP.real_clip_ratio_negy ) g_clipFlag[i] |= Y_CLIP_MIN; } //if( g_vecProjected[i].z > 1.0f ) //{ // g_clipFlag2[i] |= Z_CLIP_MAX; // g_clipFlag[i] |= Z_CLIP_MAX; //} //if( gRSP.bNearClip && g_vecProjected[i].z < -1.0f ) //{ // g_clipFlag2[i] |= Z_CLIP_MIN; // g_clipFlag[i] |= Z_CLIP_MIN; //} } else */ { if( g_vecProjected[i].x > 1 ) g_clipFlag2[i] |= X_CLIP_MAX; if( g_vecProjected[i].x < -1 ) g_clipFlag2[i] |= X_CLIP_MIN; if( g_vecProjected[i].y > 1 ) g_clipFlag2[i] |= Y_CLIP_MAX; if( g_vecProjected[i].y < -1 ) g_clipFlag2[i] |= Y_CLIP_MIN; //if( g_vecProjected[i].z > 1.0f ) g_clipFlag2[i] |= Z_CLIP_MAX; //if( gRSP.bNearClip && g_vecProjected[i].z < -1.0f ) g_clipFlag2[i] |= Z_CLIP_MIN; } } } #else inline void RSP_Vtx_Clipping(int i) {} #endif /* * Global variables */ ALIGN(16,RSP_Options gRSP) ALIGN(16,RDP_Options gRDP) static ALIGN(16,XVECTOR4 g_normal) //static int norms[3]; ALIGN(16,XVECTOR4 g_vtxNonTransformed[MAX_VERTS]) ALIGN(16,XVECTOR4 g_vecProjected[MAX_VERTS]) ALIGN(16,XVECTOR4 g_vtxTransformed[MAX_VERTS]) float g_vtxProjected5[1000][5]; float g_vtxProjected5Clipped[2000][5]; //uint32 g_dwVtxFlags[MAX_VERTS]; // Z_POS Z_NEG etc VECTOR2 g_fVtxTxtCoords[MAX_VERTS]; uint32 g_dwVtxDifColor[MAX_VERTS]; uint32 g_clipFlag[MAX_VERTS]; uint32 g_clipFlag2[MAX_VERTS]; RenderTexture g_textures[MAX_TEXTURES]; float g_fFogCoord[MAX_VERTS]; EXTERNAL_VERTEX g_vtxForExternal[MAX_VERTS]; TLITVERTEX g_vtxBuffer[1000]; TLITVERTEX g_clippedVtxBuffer[2000]; uint8 g_oglVtxColors[1000][4]; int g_clippedVtxCount=0; TLITVERTEX g_texRectTVtx[4]; unsigned short g_vtxIndex[1000]; unsigned int g_minIndex, g_maxIndex; float gRSPfFogMin; float gRSPfFogMax; float gRSPfFogDivider; uint32 gRSPnumLights; Light gRSPlights[16]; ALIGN(16,Matrix gRSPworldProjectTransported) ALIGN(16,Matrix gRSPworldProject) ALIGN(16,Matrix gRSPmodelViewTop) ALIGN(16,Matrix gRSPmodelViewTopTranspose) ALIGN(16,Matrix dkrMatrixTransposed) N64Light gRSPn64lights[16]; void (*ProcessVertexData)(uint32 dwAddr, uint32 dwV0, uint32 dwNum)=NULL; /* * */ /*n.x = (g_normal.x * matWorld.m00) + (g_normal.y * matWorld.m10) + (g_normal.z * matWorld.m20); n.y = (g_normal.x * matWorld.m01) + (g_normal.y * matWorld.m11) + (g_normal.z * matWorld.m21); n.z = (g_normal.x * matWorld.m02) + (g_normal.y * matWorld.m12) + (g_normal.z * matWorld.m22);*/ // Multiply (x,y,z,0) by matrix m, then normalize #if defined(__INTEL_COMPILER) && !defined(NO_ASM) #define Vec3TransformNormal(vec, m) __asm \ { \ __asm fld dword ptr [vec + 0] \ __asm fmul dword ptr [m + 0] \ /* x m00*/ __asm fld dword ptr [vec + 0] \ __asm fmul dword ptr [m + 4] \ /* x m01 x m00*/ __asm fld dword ptr [vec + 0] \ __asm fmul dword ptr [m + 8] \ /* x m02 x m01 x m00*/ \ __asm fld dword ptr [vec + 4] \ __asm fmul dword ptr [m + 16] \ /* y m10 x m02 x m01 x m00*/ __asm fld dword ptr [vec + 4] \ __asm fmul dword ptr [m + 20] \ /* y m11 y m10 x m02 x m01 x m00*/ __asm fld dword ptr [vec + 4] \ __asm fmul dword ptr [m + 24] \ /* y m12 y m11 y m10 x m02 x m01 x m00*/ \ __asm fxch st(2) \ /* y m10 y m11 y m12 x m02 x m01 x m00*/ __asm faddp st(5), st(0) \ /* y m11 y m12 x m02 x m01 (x m00 + y m10)*/ __asm faddp st(3), st(0) \ /* y m12 x m02 (x m01 + ym11) (x m00 + y m10)*/ __asm faddp st(1), st(0) \ /* (x m02 + y m12) (x m01 + ym11) (x m00 + y m10)*/ \ __asm fld dword ptr [vec + 8] \ __asm fmul dword ptr [m + 32] \ /* z m20 (x m02 + y m12) (x m01 + ym11) (x m00 + y m10)*/ __asm fld dword ptr [vec + 8] \ __asm fmul dword ptr [m + 36] \ /* z m21 z m20 (x m02 + y m12) (x m01 + ym11) (x m00 + y m10)*/ __asm fld dword ptr [vec + 8] \ __asm fmul dword ptr [m + 40] \ /* z m22 z m21 z m20 (x m02 + y m12) (x m01 + ym11) (x m00 + y m10)*/ \ __asm fxch st(2) \ /* z m20 z m21 z m22 (x m02 + y m12) (x m01 + ym11) (x m00 + y m10)*/ __asm faddp st(5), st(0) \ /* z m21 z m22 (x m02 + y m12) (x m01 + ym11) (x m00 + y m10 + z m20)*/ __asm faddp st(3), st(0) \ /* z m22 (x m02 + y m12) (x m01 + ym11 + z m21) (x m00 + y m10 + z m20)*/ __asm faddp st(1), st(0) \ /* (x m02 + y m12 + z m 22) (x m01 + ym11 + z m21) (x m00 + y m10 + z m20)*/ \ __asm fxch st(2) \ /* (x m00 + y m10 + z m20) (x m01 + ym11 + z m21) (x m02 + y m12 + z m 22) */ \ __asm fld1 \ /* 1 x y z */ __asm fld st(1) \ /* x 1 x y z */ __asm fmul st(0),st(0) \ /* xx 1 x y z */ __asm fld st(3) \ /* y xx 1 x y z */ __asm fmul st(0),st(0) \ /* yy xx 1 x y z */ __asm fld st(5) \ /* z yy xx 1 x y z */ __asm fmul st(0),st(0) \ /* zz yy xx 1 x y z */ \ __asm fxch st(2) \ /* xx yy zz 1 x y z */ \ __asm faddp st(1),st(0) \ /* (xx+yy) zz 1 x y z */ __asm faddp st(1),st(0) \ /* (xx+yy+zz) 1 x y z */ \ __asm ftst \ /* Compare ST to 0 */ __asm fstsw ax \ /* Store FPU status word in a */ __asm sahf \ /* Transfer ax to flags register */ __asm jz l2 \ /* Skip if length is zero */ \ __asm fsqrt \ /* l 1 x y z */ \ __asm fdivp st(1),st(0) \ /* (1/l) x y z */ \ __asm fmul st(3),st(0) \ /* f x y fz */ __asm fmul st(2),st(0) \ /* f x fy fz */ __asm fmulp st(1),st(0) \ /* fx fy fz */ \ __asm fstp dword ptr [vec + 0] \ /* fy fz*/ __asm fstp dword ptr [vec + 4] \ /* fz */ __asm fstp dword ptr [vec + 8] \ /* done */ __asm jmp l3 \ __asm l2: \ __asm mov dword ptr [vec + 0], 0 \ __asm mov dword ptr [vec + 4], 0 \ __asm mov dword ptr [vec + 8], 0 \ __asm l3: \ } \ #else // use C code in other cases, this is probably faster anyway #define Vec3TransformNormal(vec, m) \ VECTOR3 temp; \ temp.x = (vec.x * m._11) + (vec.y * m._21) + (vec.z * m._31); \ temp.y = (vec.x * m._12) + (vec.y * m._22) + (vec.z * m._32); \ temp.z = (vec.x * m._13) + (vec.y * m._23) + (vec.z * m._33); \ float norm = sqrt(temp.x*temp.x+temp.y*temp.y+temp.z*temp.z); \ if (norm == 0.0) { vec.x = 0.0; vec.y = 0.0; vec.z = 0.0;} else \ { vec.x = temp.x/norm; vec.y = temp.y/norm; vec.z = temp.z/norm; } #endif #if !defined(__GNUC__) && !defined(NO_ASM) __declspec( naked ) void __fastcall SSEVec3Transform(int i) { __asm { shl ecx,4; // ecx = i movaps xmm1, DWORD PTR g_vtxNonTransformed [ecx]; // xmm1 as original vector movaps xmm4, DWORD PTR gRSPworldProjectTransported; // row1 movaps xmm5, DWORD PTR gRSPworldProjectTransported[0x10]; // row2 movaps xmm6, DWORD PTR gRSPworldProjectTransported[0x20]; // row3 movaps xmm7, DWORD PTR gRSPworldProjectTransported[0x30]; // row4 mulps xmm4, xmm1; // row 1 mulps xmm5, xmm1; // row 2 mulps xmm6, xmm1; // row 3 mulps xmm7, xmm1; // row 4 movhlps xmm0, xmm4; // xmm4 high to xmm0 low movlhps xmm0, xmm5; // xmm5 low to xmm0 high addps xmm4, xmm0; // result of add are in xmm4 low addps xmm5, xmm0; // result of add are in xmm5 high shufps xmm0, xmm4, 0x44; // move xmm4 low DWORDs to xmm0 high shufps xmm4, xmm5, 0xe4; // move xmm5 high DWORS to xmm4 movhlps xmm5, xmm0; // xmm4, xmm5 are mirrored shufps xmm4, xmm4, 0x08; // move xmm4's 3rd uint32 to its 2nd uint32 shufps xmm5, xmm5, 0x0d; // move xmm5's 4th uint32 to its 2nd uint32, // and move its 2nd uint32 to its 1st uint32 addps xmm4, xmm5; // results are in 1st and 2nd uint32 movhlps xmm0, xmm6; // xmm6 high to xmm0 low movlhps xmm0, xmm7; // xmm7 low to xmm0 high addps xmm6, xmm0; // result of add are in xmm6 low addps xmm7, xmm0; // result of add are in xmm7 high shufps xmm0, xmm6, 0x44; // move xmm6 low DWORDs to xmm0 high shufps xmm6, xmm7, 0xe4; // move xmm7 high DWORS to xmm6 movhlps xmm7, xmm0; // xmm6, xmm7 are mirrored shufps xmm6, xmm6, 0x08; // move xmm6's 3rd uint32 to its 2nd uint32 shufps xmm7, xmm7, 0x0d; // move xmm7's 4th uint32 to its 2nd uint32, // and move its 2nd uint32 to its 1st uint32 addps xmm6, xmm7; // results are in 1st and 2nd uint32 movlhps xmm4, xmm6; // final result is in xmm4 movaps DWORD PTR g_vtxTransformed [ecx], xmm4; movaps xmm0,xmm4; shufps xmm0,xmm0,0xff; divps xmm4,xmm0; rcpps xmm0,xmm0; movhlps xmm0,xmm4; shufps xmm0,xmm0,0xe8; movlhps xmm4,xmm0; movaps DWORD PTR g_vecProjected [ecx], xmm4; emms; ret; } } // Only used by DKR __declspec( naked ) void __fastcall SSEVec3TransformDKR(XVECTOR4 &pOut, const XVECTOR4 &pV) { __asm { movaps xmm1, DWORD PTR [edx]; // xmm1 as original vector movaps xmm4, DWORD PTR dkrMatrixTransposed; // row1 movaps xmm5, DWORD PTR dkrMatrixTransposed[0x10]; // row2 movaps xmm6, DWORD PTR dkrMatrixTransposed[0x20]; // row3 movaps xmm7, DWORD PTR dkrMatrixTransposed[0x30]; // row4 mulps xmm4, xmm1; // row 1 mulps xmm5, xmm1; // row 2 mulps xmm6, xmm1; // row 3 mulps xmm7, xmm1; // row 4 movhlps xmm0, xmm4; // xmm4 high to xmm0 low movlhps xmm0, xmm5; // xmm5 low to xmm0 high addps xmm4, xmm0; // result of add are in xmm4 low addps xmm5, xmm0; // result of add are in xmm5 high shufps xmm0, xmm4, 0x44; // move xmm4 low DWORDs to xmm0 high shufps xmm4, xmm5, 0xe4; // move xmm5 high DWORS to xmm4 movhlps xmm5, xmm0; // xmm4, xmm5 are mirrored shufps xmm4, xmm4, 0x08; // move xmm4's 3rd uint32 to its 2nd uint32 shufps xmm5, xmm5, 0x0d; // move xmm5's 4th uint32 to its 2nd uint32, // and move its 2nd uint32 to its 1st uint32 addps xmm4, xmm5; // results are in 1st and 2nd uint32 movhlps xmm0, xmm6; // xmm6 high to xmm0 low movlhps xmm0, xmm7; // xmm7 low to xmm0 high addps xmm6, xmm0; // result of add are in xmm6 low addps xmm7, xmm0; // result of add are in xmm7 high shufps xmm0, xmm6, 0x44; // move xmm6 low DWORDs to xmm0 high shufps xmm6, xmm7, 0xe4; // move xmm7 high DWORS to xmm6 movhlps xmm7, xmm0; // xmm6, xmm7 are mirrored shufps xmm6, xmm6, 0x08; // move xmm6's 3rd uint32 to its 2nd uint32 shufps xmm7, xmm7, 0x0d; // move xmm7's 4th uint32 to its 2nd uint32, // and move its 2nd uint32 to its 1st uint32 addps xmm6, xmm7; // results are in 1st and 2nd uint32 movlhps xmm4, xmm6; // final result is in xmm4 movaps DWORD PTR [ecx], xmm4; emms; ret; } } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) void SSEVec3Transform(int i) { asm volatile(" shl $4, %0 \n" " movslq %k0, %q0 \n" " movaps (%1,%q0), %%xmm1 \n" " movaps 0(%2), %%xmm4 \n" " movaps 16(%2), %%xmm5 \n" " movaps 32(%2), %%xmm6 \n" " movaps 48(%2), %%xmm7 \n" " mulps %%xmm1, %%xmm4 \n" " mulps %%xmm1, %%xmm5 \n" " mulps %%xmm1, %%xmm6 \n" " mulps %%xmm1, %%xmm7 \n" " movhlps %%xmm4, %%xmm0 \n" " movlhps %%xmm5, %%xmm0 \n" " addps %%xmm0, %%xmm4 \n" " addps %%xmm0, %%xmm5 \n" " shufps $0x44, %%xmm4, %%xmm0 \n" " shufps $0xe4, %%xmm5, %%xmm4 \n" " movhlps %%xmm0, %%xmm5 \n" " shufps $0x08, %%xmm4, %%xmm4 \n" " shufps $0x0d, %%xmm5, %%xmm5 \n" " addps %%xmm5, %%xmm4 \n" " movhlps %%xmm6, %%xmm0 \n" " movlhps %%xmm7, %%xmm0 \n" " addps %%xmm0, %%xmm6 \n" " addps %%xmm0, %%xmm7 \n" " shufps $0x44, %%xmm6, %%xmm0 \n" " shufps $0xe4, %%xmm7, %%xmm6 \n" " movhlps %%xmm0, %%xmm7 \n" " shufps $0x08, %%xmm6, %%xmm6 \n" " shufps $0x0d, %%xmm7, %%xmm7 \n" " addps %%xmm7, %%xmm6 \n" " movlhps %%xmm6, %%xmm4 \n" " movaps %%xmm4, (%3,%q0) \n" " movaps %%xmm4, %%xmm0 \n" " shufps $0xff, %%xmm0, %%xmm0 \n" " divps %%xmm0, %%xmm4 \n" " rcpps %%xmm0, %%xmm0 \n" " movhlps %%xmm4, %%xmm0 \n" " shufps $0xe8, %%xmm0, %%xmm0 \n" " movlhps %%xmm0, %%xmm4 \n" " movaps %%xmm4, (%4,%q0) \n" : "+r"(i) : "r"(g_vtxNonTransformed), "r"(&gRSPworldProjectTransported.m[0][0]), "r"(g_vtxTransformed), "r"(g_vecProjected) : "memory", "%xmm0", "%xmm1", "%xmm4", "%xmm5", "%xmm6", "%xmm7" ); } #elif !defined(NO_ASM) // 32-bit GCC assumed void SSEVec3Transform(int i) { asm volatile(" shl $4, %0 \n" " movaps (%1,%0), %%xmm1 \n" " movaps 0(%2), %%xmm4 \n" " movaps 16(%2), %%xmm5 \n" " movaps 32(%2), %%xmm6 \n" " movaps 48(%2), %%xmm7 \n" " mulps %%xmm1, %%xmm4 \n" " mulps %%xmm1, %%xmm5 \n" " mulps %%xmm1, %%xmm6 \n" " mulps %%xmm1, %%xmm7 \n" " movhlps %%xmm4, %%xmm0 \n" " movlhps %%xmm5, %%xmm0 \n" " addps %%xmm0, %%xmm4 \n" " addps %%xmm0, %%xmm5 \n" " shufps $0x44, %%xmm4, %%xmm0 \n" " shufps $0xe4, %%xmm5, %%xmm4 \n" " movhlps %%xmm0, %%xmm5 \n" " shufps $0x08, %%xmm4, %%xmm4 \n" " shufps $0x0d, %%xmm5, %%xmm5 \n" " addps %%xmm5, %%xmm4 \n" " movhlps %%xmm6, %%xmm0 \n" " movlhps %%xmm7, %%xmm0 \n" " addps %%xmm0, %%xmm6 \n" " addps %%xmm0, %%xmm7 \n" " shufps $0x44, %%xmm6, %%xmm0 \n" " shufps $0xe4, %%xmm7, %%xmm6 \n" " movhlps %%xmm0, %%xmm7 \n" " shufps $0x08, %%xmm6, %%xmm6 \n" " shufps $0x0d, %%xmm7, %%xmm7 \n" " addps %%xmm7, %%xmm6 \n" " movlhps %%xmm6, %%xmm4 \n" " movaps %%xmm4, (%3,%0) \n" " movaps %%xmm4, %%xmm0 \n" " shufps $0xff, %%xmm0, %%xmm0 \n" " divps %%xmm0, %%xmm4 \n" " rcpps %%xmm0, %%xmm0 \n" " movhlps %%xmm4, %%xmm0 \n" " shufps $0xe8, %%xmm0, %%xmm0 \n" " movlhps %%xmm0, %%xmm4 \n" " movaps %%xmm4, (%4,%0) \n" : "+r"(i) : "r"(g_vtxNonTransformed), "r"(&gRSPworldProjectTransported.m[0][0]), "r"(g_vtxTransformed), "r"(g_vecProjected) : "memory", "%xmm0", "%xmm1", "%xmm4", "%xmm5", "%xmm6", "%xmm7" ); } #endif float real255 = 255.0f; float real128 = 128.0f; #if !defined(__GNUC__) && !defined(NO_ASM) __declspec( naked ) void __fastcall SSEVec3TransformNormal() { __asm { mov DWORD PTR [g_normal][12], 0; movaps xmm4, DWORD PTR gRSPmodelViewTopTranspose; // row1 movaps xmm5, DWORD PTR gRSPmodelViewTopTranspose[0x10]; // row2 movaps xmm1, DWORD PTR [g_normal]; // xmm1 as the normal vector movaps xmm6, DWORD PTR gRSPmodelViewTopTranspose[0x20]; // row3 mulps xmm4, xmm1; // row 1 mulps xmm5, xmm1; // row 2 mulps xmm6, xmm1; // row 3 movhlps xmm0, xmm4; // xmm4 high to xmm0 low movlhps xmm0, xmm5; // xmm5 low to xmm0 high addps xmm4, xmm0; // result of add are in xmm4 low addps xmm5, xmm0; // result of add are in xmm5 high shufps xmm0, xmm4, 0x44; // move xmm4 low DWORDs to xmm0 high shufps xmm4, xmm5, 0xe4; // move xmm5 high DWORS to xmm4 movhlps xmm5, xmm0; // xmm4, xmm5 are mirrored shufps xmm4, xmm4, 0x08; // move xmm4's 3rd uint32 to its 2nd uint32 shufps xmm5, xmm5, 0x0d; // move xmm5's 4th uint32 to its 2nd uint32, addps xmm4, xmm5; // results are in 1st and 2nd uint32 movaps xmm1,xmm4; mulps xmm1,xmm1; //square movlhps xmm7, xmm1; shufps xmm7, xmm7,0x03; addss xmm7, xmm1; movhlps xmm0, xmm6; // xmm6 high to xmm0 low addps xmm6, xmm0; // result of add are in xmm6 low movlhps xmm0, xmm6; shufps xmm0, xmm0, 0x03; addss xmm0, xmm6; // result of add is at xmm0's 1st uint32 movlhps xmm4, xmm0; mulss xmm0,xmm0; addss xmm7,xmm0; // xmm7 1st uint32 is the sum of squares #ifdef DEBUGGER movaps DWORD PTR [g_normal], xmm4; movss DWORD PTR [g_normal][12], xmm7; #endif xorps xmm0,xmm0; ucomiss xmm0,xmm7; jz l2 rsqrtss xmm7,xmm7; shufps xmm7,xmm7,0; #ifdef DEBUGGER movss DWORD PTR [g_normal][12], xmm7; #endif mulps xmm4,xmm7; movaps DWORD PTR [g_normal], xmm4; // Normalized mov DWORD PTR [g_normal][12], 0; emms; ret; l2: movss DWORD PTR [g_normal], xmm0; movss DWORD PTR [g_normal][12], xmm0; emms; ret; } } #elif defined(__GNUC__) && !defined(NO_ASM) // this code should compile for both 64-bit and 32-bit architectures void SSEVec3TransformNormal(void) { asm volatile(" movl $0, 12(%0) \n" " movaps (%1), %%xmm4 \n" " movaps 16(%1), %%xmm5 \n" " movaps (%0), %%xmm1 \n" " movaps 32(%1), %%xmm6 \n" " mulps %%xmm1, %%xmm4 \n" " mulps %%xmm1, %%xmm5 \n" " mulps %%xmm1, %%xmm6 \n" " movhlps %%xmm4, %%xmm0 \n" " movlhps %%xmm5, %%xmm0 \n" " addps %%xmm0, %%xmm4 \n" " addps %%xmm0, %%xmm5 \n" " shufps $0x44, %%xmm4, %%xmm0 \n" " shufps $0xe4, %%xmm5, %%xmm4 \n" " movhlps %%xmm0, %%xmm5 \n" " shufps $0x08, %%xmm4, %%xmm4 \n" " shufps $0x0d, %%xmm5, %%xmm5 \n" " addps %%xmm5, %%xmm4 \n" " movaps %%xmm4, %%xmm1 \n" " mulps %%xmm1, %%xmm1 \n" " movlhps %%xmm1, %%xmm7 \n" " shufps $0x03, %%xmm7, %%xmm7 \n" " addss %%xmm1, %%xmm7 \n" " movhlps %%xmm6, %%xmm0 \n" " addps %%xmm0, %%xmm6 \n" " movlhps %%xmm6, %%xmm0 \n" " shufps $0x03, %%xmm0, %%xmm0 \n" " addss %%xmm6, %%xmm0 \n" " movlhps %%xmm0, %%xmm4 \n" " mulss %%xmm0, %%xmm0 \n" " addss %%xmm0, %%xmm7 \n" #ifdef DEBUGGER " movaps %%xmm4, (%0) \n" " movss %%xmm7, 12(%0) \n" #endif " xorps %%xmm0, %%xmm0 \n" " ucomiss %%xmm7, %%xmm0 \n" " jz 0f \n" " rsqrtss %%xmm7, %%xmm7 \n" " shufps $0x00, %%xmm7, %%xmm7 \n" #ifdef DEBUGGER " movss %%xmm7, 12(%0) \n" #endif " mulps %%xmm7, %%xmm4 \n" " movaps %%xmm4, (%0) \n" " movl $0, 12(%0) \n" " jmp 1f \n" "0: \n" " movss %%xmm0, (%0) \n" " movss %%xmm0, 12(%0) \n" "1: \n" : : "r"(&g_normal.x), "r"(&gRSPmodelViewTopTranspose.m[0][0]) : "memory", "cc", "%xmm0", "%xmm1", "%xmm4", "%xmm5", "%xmm6", "%xmm7" ); } #endif void NormalizeNormalVec() { float w = 1/sqrtf(g_normal.x*g_normal.x + g_normal.y*g_normal.y + g_normal.z*g_normal.z); g_normal.x *= w; g_normal.y *= w; g_normal.z *= w; } void InitRenderBase() { #if !defined(NO_ASM) if( status.isSSEEnabled && !g_curRomInfo.bPrimaryDepthHack && options.enableHackForGames != HACK_FOR_NASCAR) { ProcessVertexData = ProcessVertexDataSSE; } else #endif { ProcessVertexData = ProcessVertexDataNoSSE; } gRSPfFogMin = gRSPfFogMax = 0.0f; windowSetting.fMultX = windowSetting.fMultY = 2.0f; windowSetting.vpLeftW = windowSetting.vpTopW = 0; windowSetting.vpRightW = windowSetting.vpWidthW = 640; windowSetting.vpBottomW = windowSetting.vpHeightW = 480; gRSP.maxZ = 0; gRSP.nVPLeftN = gRSP.nVPTopN = 0; gRSP.nVPRightN = 640; gRSP.nVPBottomN = 640; gRSP.nVPWidthN = 640; gRSP.nVPHeightN = 640; gRDP.scissor.left=gRDP.scissor.top=0; gRDP.scissor.right=gRDP.scissor.bottom=640; gRSP.bLightingEnable = gRSP.bTextureGen = false; gRSP.curTile=gRSPnumLights=gRSP.ambientLightColor=gRSP.ambientLightIndex= 0; gRSP.fAmbientLightR=gRSP.fAmbientLightG=gRSP.fAmbientLightB=0; gRSP.projectionMtxTop = gRSP.modelViewMtxTop = 0; gRDP.fogColor = gRDP.primitiveColor = gRDP.envColor = gRDP.primitiveDepth = gRDP.primLODMin = gRDP.primLODFrac = gRDP.LODFrac = 0; gRDP.fPrimitiveDepth = 0; gRSP.numVertices = 0; gRSP.maxVertexID = 0; gRSP.bCullFront=false; gRSP.bCullBack=true; gRSP.bFogEnabled=gRDP.bFogEnableInBlender=false; gRSP.bZBufferEnabled=true; gRSP.shadeMode=SHADE_SMOOTH; gRDP.keyR=gRDP.keyG=gRDP.keyB=gRDP.keyA=gRDP.keyRGB=gRDP.keyRGBA = 0; gRDP.fKeyA = 0; gRSP.DKRCMatrixIndex = gRSP.dwDKRVtxAddr = gRSP.dwDKRMatrixAddr = 0; gRSP.DKRBillBoard = false; gRSP.fTexScaleX = 1/32.0f; gRSP.fTexScaleY = 1/32.0f; gRSP.bTextureEnabled = FALSE; gRSP.clip_ratio_left = 0; gRSP.clip_ratio_top = 0; gRSP.clip_ratio_right = 640; gRSP.clip_ratio_bottom = 480; gRSP.clip_ratio_negx = 1; gRSP.clip_ratio_negy = 1; gRSP.clip_ratio_posx = 1; gRSP.clip_ratio_posy = 1; gRSP.real_clip_scissor_left = 0; gRSP.real_clip_scissor_top = 0; gRSP.real_clip_scissor_right = 640; gRSP.real_clip_scissor_bottom = 480; windowSetting.clipping.left = 0; windowSetting.clipping.top = 0; windowSetting.clipping.right = 640; windowSetting.clipping.bottom = 480; windowSetting.clipping.width = 640; windowSetting.clipping.height = 480; windowSetting.clipping.needToClip = false; gRSP.real_clip_ratio_negx = 1; gRSP.real_clip_ratio_negy = 1; gRSP.real_clip_ratio_posx = 1; gRSP.real_clip_ratio_posy = 1; gRSP.DKRCMatrixIndex=0; gRSP.DKRVtxCount=0; gRSP.DKRBillBoard = false; gRSP.dwDKRVtxAddr=0; gRSP.dwDKRMatrixAddr=0; gRDP.geometryMode = 0; gRDP.otherModeL = 0; gRDP.otherModeH = 0; gRDP.fillColor = 0xFFFFFFFF; gRDP.originalFillColor =0; gRSP.ucode = 1; gRSP.vertexMult = 10; gRSP.bNearClip = false; gRSP.bRejectVtx = false; gRDP.textureIsChanged = false; memset(&gRDP.otherMode,0,sizeof(RDP_OtherMode)); memset(&gRDP.tiles,0,sizeof(Tile)*8); for( int i=0; i fMax ) { float temp = fMin; fMin = fMax; fMax = temp; } { gRSPfFogMin = std::max(0.f,fMin/500-1); gRSPfFogMax = fMax/500-1; } gRSPfFogDivider = 255/(gRSPfFogMax-gRSPfFogMin); } void InitVertexTextureConstants() { float scaleX; float scaleY; RenderTexture &tex0 = g_textures[gRSP.curTile]; //CTexture *surf = tex0.m_pCTexture; Tile &tile0 = gRDP.tiles[gRSP.curTile]; scaleX = gRSP.fTexScaleX; scaleY = gRSP.fTexScaleY; gRSP.tex0scaleX = scaleX * tile0.fShiftScaleS/tex0.m_fTexWidth; gRSP.tex0scaleY = scaleY * tile0.fShiftScaleT/tex0.m_fTexHeight; gRSP.tex0OffsetX = tile0.fhilite_sl/tex0.m_fTexWidth; gRSP.tex0OffsetY = tile0.fhilite_tl/tex0.m_fTexHeight; if( CRender::g_pRender->IsTexel1Enable() ) { RenderTexture &tex1 = g_textures[(gRSP.curTile+1)&7]; //CTexture *surf = tex1.m_pCTexture; Tile &tile1 = gRDP.tiles[(gRSP.curTile+1)&7]; gRSP.tex1scaleX = scaleX * tile1.fShiftScaleS/tex1.m_fTexWidth; gRSP.tex1scaleY = scaleY * tile1.fShiftScaleT/tex1.m_fTexHeight; gRSP.tex1OffsetX = tile1.fhilite_sl/tex1.m_fTexWidth; gRSP.tex1OffsetY = tile1.fhilite_tl/tex1.m_fTexHeight; } gRSP.texGenXRatio = tile0.fShiftScaleS; gRSP.texGenYRatio = gRSP.fTexScaleX/gRSP.fTexScaleY*tex0.m_fTexWidth/tex0.m_fTexHeight*tile0.fShiftScaleT; } void TexGen(float &s, float &t) { if (gRDP.geometryMode & G_TEXTURE_GEN_LINEAR) { s = acosf(g_normal.x) / 3.14159f; t = acosf(g_normal.y) / 3.14159f; } else { s = 0.5f * ( 1.0f + g_normal.x); t = 0.5f * ( 1.0f - g_normal.y); } } void ComputeLOD() { TLITVERTEX &v0 = g_vtxBuffer[0]; TLITVERTEX &v1 = g_vtxBuffer[1]; RenderTexture &tex0 = g_textures[gRSP.curTile]; float d,dt; float x = g_vtxProjected5[0][0] / g_vtxProjected5[0][4] - g_vtxProjected5[1][0] / g_vtxProjected5[1][4]; float y = g_vtxProjected5[0][1] / g_vtxProjected5[0][4] - g_vtxProjected5[1][1] / g_vtxProjected5[1][4]; x = windowSetting.vpWidthW*x/windowSetting.fMultX/2; y = windowSetting.vpHeightW*y/windowSetting.fMultY/2; d = sqrtf(x*x+y*y); float s0 = v0.tcord[0].u * tex0.m_fTexWidth; float t0 = v0.tcord[0].v * tex0.m_fTexHeight; float s1 = v1.tcord[0].u * tex0.m_fTexWidth; float t1 = v1.tcord[0].v * tex0.m_fTexHeight; dt = sqrtf((s0-s1)*(s0-s1)+(t0-t1)*(t0-t1)); float lod = dt/d; float frac = log10f(lod)/log10f(2.0f); //DEBUGGER_IF_DUMP(pauseAtNext,{DebuggerAppendMsg("LOD frac = %f", frac);}); frac = (lod / powf(2.0f,floorf(frac))); frac = frac - floorf(frac); //DEBUGGER_IF_DUMP(pauseAtNext,{DebuggerAppendMsg("LOD = %f, frac = %f", lod, frac);}); gRDP.LODFrac = (uint32)(frac*255); CRender::g_pRender->SetCombinerAndBlender(); } bool bHalfTxtScale=false; extern uint32 lastSetTile; void InitVertex(uint32 dwV, uint32 vtxIndex, bool bTexture) { VTX_DUMP(TRACE2("Init vertex (%d) to vtx buf[%d]:", dwV, vtxIndex)); TLITVERTEX &v = g_vtxBuffer[vtxIndex]; VTX_DUMP(TRACE4(" Trans: x=%f, y=%f, z=%f, w=%f", g_vtxTransformed[dwV].x,g_vtxTransformed[dwV].y,g_vtxTransformed[dwV].z,g_vtxTransformed[dwV].w)); g_vtxProjected5[vtxIndex][0] = g_vtxTransformed[dwV].x; g_vtxProjected5[vtxIndex][1] = g_vtxTransformed[dwV].y; g_vtxProjected5[vtxIndex][2] = g_vtxTransformed[dwV].z; g_vtxProjected5[vtxIndex][3] = g_vtxTransformed[dwV].w; g_vtxProjected5[vtxIndex][4] = g_fFogCoord[dwV]; g_vtxIndex[vtxIndex] = vtxIndex; if( options.bOGLVertexClipper == TRUE ) { v.x = g_vecProjected[dwV].x*gRSP.vtxXMul+gRSP.vtxXAdd; v.y = g_vecProjected[dwV].y*gRSP.vtxYMul+gRSP.vtxYAdd; v.z = (g_vecProjected[dwV].z + 1.0f) * 0.5f; // DirectX minZ=0, maxZ=1 //v.z = g_vecProjected[dwV].z; // DirectX minZ=0, maxZ=1 v.rhw = g_vecProjected[dwV].w; VTX_DUMP(TRACE4(" Proj : x=%f, y=%f, z=%f, rhw=%f", v.x,v.y,v.z,v.rhw)); } VTX_DUMP(TRACE2(" (U,V): %f, %f", g_fVtxTxtCoords[dwV].x,g_fVtxTxtCoords[dwV].y)); v.dcDiffuse = g_dwVtxDifColor[dwV]; if( gRDP.otherMode.key_en ) { v.dcDiffuse &= 0x00FFFFFF; v.dcDiffuse |= (gRDP.keyA<<24); } else if( gRDP.otherMode.aa_en && gRDP.otherMode.clr_on_cvg==0 ) { v.dcDiffuse |= 0xFF000000; } if( options.bWinFrameMode ) { v.dcDiffuse = g_dwVtxDifColor[dwV]; } g_oglVtxColors[vtxIndex][0] = v.r; g_oglVtxColors[vtxIndex][1] = v.g; g_oglVtxColors[vtxIndex][2] = v.b; g_oglVtxColors[vtxIndex][3] = v.a; if( bTexture ) { // If the vert is already lit, then there is no normal (and hence we can't generate tex coord) // Only scale if not generated automatically if (gRSP.bTextureGen && gRSP.bLightingEnable) { // Correction for texGen result float u0,u1,v0,v1; RenderTexture &tex0 = g_textures[gRSP.curTile]; u0 = g_fVtxTxtCoords[dwV].x * 32 * 1024 * gRSP.fTexScaleX / tex0.m_fTexWidth; v0 = g_fVtxTxtCoords[dwV].y * 32 * 1024 * gRSP.fTexScaleY / tex0.m_fTexHeight; u0 *= (gRDP.tiles[gRSP.curTile].fShiftScaleS); v0 *= (gRDP.tiles[gRSP.curTile].fShiftScaleT); if( CRender::g_pRender->IsTexel1Enable() ) { RenderTexture &tex1 = g_textures[(gRSP.curTile+1)&7]; u1 = g_fVtxTxtCoords[dwV].x * 32 * 1024 * gRSP.fTexScaleX / tex1.m_fTexWidth; v1 = g_fVtxTxtCoords[dwV].y * 32 * 1024 * gRSP.fTexScaleY / tex1.m_fTexHeight; u1 *= gRDP.tiles[(gRSP.curTile+1)&7].fShiftScaleS; v1 *= gRDP.tiles[(gRSP.curTile+1)&7].fShiftScaleT; CRender::g_pRender->SetVertexTextureUVCoord(v, u0, v0, u1, v1); } else { CRender::g_pRender->SetVertexTextureUVCoord(v, u0, v0); } } else { float tex0u = g_fVtxTxtCoords[dwV].x *gRSP.tex0scaleX - gRSP.tex0OffsetX ; float tex0v = g_fVtxTxtCoords[dwV].y *gRSP.tex0scaleY - gRSP.tex0OffsetY ; if( CRender::g_pRender->IsTexel1Enable() ) { float tex1u = g_fVtxTxtCoords[dwV].x *gRSP.tex1scaleX - gRSP.tex1OffsetX ; float tex1v = g_fVtxTxtCoords[dwV].y *gRSP.tex1scaleY - gRSP.tex1OffsetY ; CRender::g_pRender->SetVertexTextureUVCoord(v, tex0u, tex0v, tex1u, tex1v); VTX_DUMP(TRACE2(" (tex0): %f, %f", tex0u,tex0v)); VTX_DUMP(TRACE2(" (tex1): %f, %f", tex1u,tex1v)); } else { CRender::g_pRender->SetVertexTextureUVCoord(v, tex0u, tex0v); VTX_DUMP(TRACE2(" (tex0): %f, %f", tex0u,tex0v)); } } // Check for txt scale hack if( !bHalfTxtScale && g_curRomInfo.bTextureScaleHack && (gRDP.tiles[lastSetTile].dwSize == TXT_SIZE_32b || gRDP.tiles[lastSetTile].dwSize == TXT_SIZE_4b ) ) { int width = ((gRDP.tiles[lastSetTile].sh-gRDP.tiles[lastSetTile].sl+1)<<1); int height = ((gRDP.tiles[lastSetTile].th-gRDP.tiles[lastSetTile].tl+1)<<1); if( g_fVtxTxtCoords[dwV].x*gRSP.fTexScaleX == width || g_fVtxTxtCoords[dwV].y*gRSP.fTexScaleY == height ) { bHalfTxtScale=true; } } } if( g_curRomInfo.bEnableTxtLOD && vtxIndex == 1 && gRDP.otherMode.text_lod ) { if( CRender::g_pRender->IsTexel1Enable() && CRender::g_pRender->m_pColorCombiner->m_bLODFracEnabled ) { ComputeLOD(); } else { gRDP.LODFrac = 0; } } VTX_DUMP(TRACE2(" DIF(%08X)", v.dcDiffuse)); VTX_DUMP(TRACE0("")); } uint32 LightVert(XVECTOR4 & norm, int vidx) { float fCosT; // Do ambient float r = gRSP.fAmbientLightR; float g = gRSP.fAmbientLightG; float b = gRSP.fAmbientLightB; if( options.enableHackForGames != HACK_FOR_ZELDA_MM ) { for (unsigned int l=0; l < gRSPnumLights; l++) { fCosT = norm.x*gRSPlights[l].x + norm.y*gRSPlights[l].y + norm.z*gRSPlights[l].z; if (fCosT > 0 ) { r += gRSPlights[l].fr * fCosT; g += gRSPlights[l].fg * fCosT; b += gRSPlights[l].fb * fCosT; } } } else { XVECTOR4 v; bool transformed = false; for (unsigned int l=0; l < gRSPnumLights; l++) { if( gRSPlights[l].range == 0 ) { // Regular directional light fCosT = norm.x*gRSPlights[l].x + norm.y*gRSPlights[l].y + norm.z*gRSPlights[l].z; if (fCosT > 0 ) { r += gRSPlights[l].fr * fCosT; g += gRSPlights[l].fg * fCosT; b += gRSPlights[l].fb * fCosT; } } else //if( (gRSPlights[l].col&0x00FFFFFF) != 0x00FFFFFF ) { // Point light if( !transformed ) { Vec3Transform(&v, (XVECTOR3*)&g_vtxNonTransformed[vidx], &gRSPmodelViewTop); // Convert to w=1 transformed = true; } XVECTOR3 dir(gRSPlights[l].x - v.x, gRSPlights[l].y - v.y, gRSPlights[l].z - v.z); //XVECTOR3 dir(v.x-gRSPlights[l].x, v.y-gRSPlights[l].y, v.z-gRSPlights[l].z); float d2 = sqrtf(dir.x*dir.x+dir.y*dir.y+dir.z*dir.z); dir.x /= d2; dir.y /= d2; dir.z /= d2; fCosT = norm.x*dir.x + norm.y*dir.y + norm.z*dir.z; if (fCosT > 0 ) { //float f = d2/gRSPlights[l].range*50; float f = d2/15000*50; f = 1 - std::min(f,1.f); fCosT *= f*f; r += gRSPlights[l].fr * fCosT; g += gRSPlights[l].fg * fCosT; b += gRSPlights[l].fb * fCosT; } } } } if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; return ((0xff000000)|(((uint32)r)<<16)|(((uint32)g)<<8)|((uint32)b)); } uint32 LightVertNew(XVECTOR4 & norm) { float fCosT; // Do ambient float r = gRSP.fAmbientLightR; float g = gRSP.fAmbientLightG; float b = gRSP.fAmbientLightB; for (unsigned int l=0; l < gRSPnumLights; l++) { fCosT = norm.x*gRSPlights[l].tx + norm.y*gRSPlights[l].ty + norm.z*gRSPlights[l].tz; if (fCosT > 0 ) { r += gRSPlights[l].fr * fCosT; g += gRSPlights[l].fg * fCosT; b += gRSPlights[l].fb * fCosT; } } if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; return ((0xff000000)|(((uint32)r)<<16)|(((uint32)g)<<8)|((uint32)b)); } float zero = 0.0f; float onef = 1.0f; float fcosT; #if !defined(__GNUC__) && !defined(NO_ASM) __declspec( naked ) uint32 __fastcall SSELightVert() { __asm { movaps xmm3, DWORD PTR gRSP; // loading Ambient colors, xmm3 is the result color movaps xmm4, DWORD PTR [g_normal]; // xmm4 is the normal mov ecx, 0; loopback: cmp ecx, DWORD PTR gRSPnumLights; jae breakout; mov eax,ecx; imul eax,0x44; movups xmm5, DWORD PTR gRSPlights[eax]; // Light Dir movups xmm1, DWORD PTR gRSPlights[0x14][eax]; // Light color mulps xmm5, xmm4; // Lightdir * normals movhlps xmm0,xmm5; addps xmm0,xmm5; shufps xmm5,xmm0,0x01; addps xmm0,xmm5; comiss xmm0,zero; jc endloop shufps xmm0,xmm0,0; // fcosT mulps xmm1,xmm0; addps xmm3,xmm1; endloop: inc ecx; jmp loopback; breakout: movss xmm0,DWORD PTR real255; shufps xmm0,xmm0,0; minps xmm0,xmm3; // Without using a memory cvtss2si eax,xmm0; // move the 1st uint32 to eax shl eax,10h; or eax,0FF000000h; shufps xmm0,xmm0,0E5h; // move the 2nd uint32 to the 1st uint32 cvtss2si ecx,xmm0; // move the 1st uint32 to ecx shl ecx,8; or eax,ecx; shufps xmm0,xmm0,0E6h; // Move the 3rd uint32 to the 1st uint32 cvtss2si ecx,xmm0; or eax,ecx; ret; } } #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM) uint32 SSELightVert(void) { uint32 rval; float f255 = 255.0, fZero = 0.0; asm volatile(" movaps %1, %%xmm3 \n" // xmm3 == gRSP.fAmbientLight{RGBA} " movaps %2, %%xmm4 \n" // xmm4 == g_normal.{xyz} " xor %%rcx, %%rcx \n" "0: \n" " cmpl %3, %%ecx \n" " jae 2f \n" " mov %%rcx, %%rax \n" " imul $0x44, %%rax, %%rax \n" " movups (%4,%%rax,), %%xmm5 \n" // xmm5 == gRSPlights[l].{xyzr} " movups 20(%4,%%rax,), %%xmm1 \n" // xmm1 == gRSPlights[l].{frfgfbfa} " mulps %%xmm4, %%xmm5 \n" " movhlps %%xmm5, %%xmm0 \n" " addps %%xmm5, %%xmm0 \n" " shufps $0x01, %%xmm0, %%xmm5 \n" " addps %%xmm5, %%xmm0 \n" " comiss %6, %%xmm0 \n" " jc 1f \n" " shufps $0x00, %%xmm0, %%xmm0 \n" " mulps %%xmm0, %%xmm1 \n" " addps %%xmm1, %%xmm3 \n" "1: \n" " inc %%rcx \n" " jmp 0b \n" "2: \n" " movss %5, %%xmm0 \n" " shufps $0x00, %%xmm0, %%xmm0 \n" " minps %%xmm3, %%xmm0 \n" " cvtss2si %%xmm0, %%eax \n" " shll $0x10, %%eax \n" " orl $0xff000000, %%eax \n" " shufps $0xe5, %%xmm0, %%xmm0 \n" " cvtss2si %%xmm0, %%ecx \n" " shll $8, %%ecx \n" " orl %%ecx, %%eax \n" " shufps $0xe6, %%xmm0, %%xmm0 \n" " cvtss2si %%xmm0, %%ecx \n" " orl %%ecx, %%eax \n" : "=&a"(rval) : "m"(gRSP), "m"(g_normal), "m"(gRSPnumLights), "r"(gRSPlights), "m"(f255), "m"(fZero) : "%rcx", "memory", "cc", "%xmm0", "%xmm1", "%xmm3", "%xmm4", "%xmm5" ); return rval; } #elif !defined(NO_ASM) // 32-bit GCC assumed uint32 SSELightVert(void) { uint32 rval; float f255 = 255.0, fZero = 0.0; asm volatile(" movaps %1, %%xmm3 \n" " movaps %2, %%xmm4 \n" " xor %%ecx, %%ecx \n" "0: \n" " cmpl %3, %%ecx \n" " jae 2f \n" " mov %%ecx, %%eax \n" " imul $0x44, %%eax, %%eax \n" " movups (%4,%%eax,), %%xmm5 \n" " movups 20(%4,%%eax,), %%xmm1 \n" " mulps %%xmm4, %%xmm5 \n" " movhlps %%xmm5, %%xmm0 \n" " addps %%xmm5, %%xmm0 \n" " shufps $0x01, %%xmm0, %%xmm5 \n" " addps %%xmm5, %%xmm0 \n" " comiss %6, %%xmm0 \n" " jc 1f \n" " shufps $0x00, %%xmm0, %%xmm0 \n" " mulps %%xmm0, %%xmm1 \n" " addps %%xmm1, %%xmm3 \n" "1: \n" " inc %%ecx \n" " jmp 0b \n" "2: \n" " movss %5, %%xmm0 \n" " shufps $0x00, %%xmm0, %%xmm0 \n" " minps %%xmm3, %%xmm0 \n" " cvtss2si %%xmm0, %%eax \n" " shll $0x10, %%eax \n" " orl $0xff000000, %%eax \n" " shufps $0xe5, %%xmm0, %%xmm0 \n" " cvtss2si %%xmm0, %%ecx \n" " shll $8, %%ecx \n" " orl %%ecx, %%eax \n" " shufps $0xe6, %%xmm0, %%xmm0 \n" " cvtss2si %%xmm0, %%ecx \n" " orl %%ecx, %%eax \n" : "=&a"(rval) : "m"(gRSP), "m"(g_normal), "m"(gRSPnumLights), "r"(gRSPlights), "m"(f255), "m"(fZero) : "%rcx", "memory", "cc", "%xmm0", "%xmm1", "%xmm3", "%xmm4", "%xmm5" ); return rval; } #endif inline void ReplaceAlphaWithFogFactor(int i) { if( gRDP.geometryMode & G_FOG ) { // Use fog factor to replace vertex alpha if( g_vecProjected[i].z > 1 ) *(((uint8*)&(g_dwVtxDifColor[i]))+3) = 0xFF; if( g_vecProjected[i].z < 0 ) *(((uint8*)&(g_dwVtxDifColor[i]))+3) = 0; else *(((uint8*)&(g_dwVtxDifColor[i]))+3) = (uint8)(g_vecProjected[i].z*255); } } // Bits // +-+-+- // xxyyzz #define Z_NEG 0x01 #define Z_POS 0x02 #define Y_NEG 0x04 #define Y_POS 0x08 #define X_NEG 0x10 #define X_POS 0x20 // Assumes dwAddr has already been checked! // Don't inline - it's too big with the transform macros #if !defined(NO_ASM) void ProcessVertexDataSSE(uint32 dwAddr, uint32 dwV0, uint32 dwNum) { UpdateCombinedMatrix(); // This function is called upon SPvertex // - do vertex matrix transform // - do vertex lighting // - do texture cooridinate transform if needed // - calculate normal vector // Output: - g_vecProjected[i] -> transformed vertex x,y,z // - g_vecProjected[i].w -> saved vertex 1/w // - g_dwVtxFlags[i] -> flags // - g_dwVtxDifColor[i] -> vertex color // - g_fVtxTxtCoords[i] -> vertex texture cooridinates FiddledVtx * pVtxBase = (FiddledVtx*)(g_pRDRAMu8 + dwAddr); g_pVtxBase = pVtxBase; for (uint32 i = dwV0; i < dwV0 + dwNum; i++) { SP_Timing(RSP_GBI0_Vtx); FiddledVtx & vert = pVtxBase[i - dwV0]; g_vtxNonTransformed[i].x = (float)vert.x; g_vtxNonTransformed[i].y = (float)vert.y; g_vtxNonTransformed[i].z = (float)vert.z; SSEVec3Transform(i); if( gRSP.bFogEnabled ) { g_fFogCoord[i] = g_vecProjected[i].z; if( g_vecProjected[i].w < 0 || g_vecProjected[i].z < 0 || g_fFogCoord[i] < gRSPfFogMin ) g_fFogCoord[i] = gRSPfFogMin; } ReplaceAlphaWithFogFactor(i); VTX_DUMP( { uint32 *dat = (uint32*)(&vert); DebuggerAppendMsg("vtx %d: %08X %08X %08X %08X", i, dat[0],dat[1],dat[2],dat[3]); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vtxTransformed[i].x,g_vtxTransformed[i].y,g_vtxTransformed[i].z,g_vtxTransformed[i].w); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vecProjected[i].x,g_vecProjected[i].y,g_vecProjected[i].z,g_vecProjected[i].w); }); RSP_Vtx_Clipping(i); if( gRSP.bLightingEnable ) { g_normal.x = (float)vert.norma.nx; g_normal.y = (float)vert.norma.ny; g_normal.z = (float)vert.norma.nz; SSEVec3TransformNormal(); if( options.enableHackForGames != HACK_FOR_ZELDA_MM ) g_dwVtxDifColor[i] = SSELightVert(); else g_dwVtxDifColor[i] = LightVert(g_normal, i); *(((uint8*)&(g_dwVtxDifColor[i]))+3) = vert.rgba.a; // still use alpha from the vertex } else { if( (gRDP.geometryMode & G_SHADE) == 0 && gRSP.ucode < 5 ) //Shade is disabled { //FLAT shade g_dwVtxDifColor[i] = gRDP.primitiveColor; } else { g_dwVtxDifColor[i] = COLOR_RGBA(vert.rgba.r, vert.rgba.g, vert.rgba.b, vert.rgba.a); } } if( options.bWinFrameMode ) { g_dwVtxDifColor[i] = COLOR_RGBA(vert.rgba.r, vert.rgba.g, vert.rgba.b, vert.rgba.a); } // Update texture coords n.b. need to divide tu/tv by bogus scale on addition to buffer // If the vert is already lit, then there is no normal (and hence we // can't generate tex coord) if (gRSP.bTextureGen && gRSP.bLightingEnable ) { TexGen(g_fVtxTxtCoords[i].x, g_fVtxTxtCoords[i].y); } else { g_fVtxTxtCoords[i].x = (float)vert.tu; g_fVtxTxtCoords[i].y = (float)vert.tv; } } VTX_DUMP(TRACE2("Setting Vertexes: %d - %d\n", dwV0, dwV0+dwNum-1)); DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{TRACE0("Paused at Vertex Cmd");}); } #endif void ProcessVertexDataNoSSE(uint32 dwAddr, uint32 dwV0, uint32 dwNum) { UpdateCombinedMatrix(); // This function is called upon SPvertex // - do vertex matrix transform // - do vertex lighting // - do texture cooridinate transform if needed // - calculate normal vector // Output: - g_vecProjected[i] -> transformed vertex x,y,z // - g_vecProjected[i].w -> saved vertex 1/w // - g_dwVtxFlags[i] -> flags // - g_dwVtxDifColor[i] -> vertex color // - g_fVtxTxtCoords[i] -> vertex texture cooridinates FiddledVtx * pVtxBase = (FiddledVtx*)(g_pRDRAMu8 + dwAddr); g_pVtxBase = pVtxBase; for (uint32 i = dwV0; i < dwV0 + dwNum; i++) { SP_Timing(RSP_GBI0_Vtx); FiddledVtx & vert = pVtxBase[i - dwV0]; g_vtxNonTransformed[i].x = (float)vert.x; g_vtxNonTransformed[i].y = (float)vert.y; g_vtxNonTransformed[i].z = (float)vert.z; Vec3Transform(&g_vtxTransformed[i], (XVECTOR3*)&g_vtxNonTransformed[i], &gRSPworldProject); // Convert to w=1 g_vecProjected[i].w = 1.0f / g_vtxTransformed[i].w; g_vecProjected[i].x = g_vtxTransformed[i].x * g_vecProjected[i].w; g_vecProjected[i].y = g_vtxTransformed[i].y * g_vecProjected[i].w; if ((g_curRomInfo.bPrimaryDepthHack || options.enableHackForGames == HACK_FOR_NASCAR ) && gRDP.otherMode.depth_source ) { g_vecProjected[i].z = gRDP.fPrimitiveDepth; g_vtxTransformed[i].z = gRDP.fPrimitiveDepth*g_vtxTransformed[i].w; } else { g_vecProjected[i].z = g_vtxTransformed[i].z * g_vecProjected[i].w; } if( gRSP.bFogEnabled ) { g_fFogCoord[i] = g_vecProjected[i].z; if( g_vecProjected[i].w < 0 || g_vecProjected[i].z < 0 || g_fFogCoord[i] < gRSPfFogMin ) g_fFogCoord[i] = gRSPfFogMin; } VTX_DUMP( { uint32 *dat = (uint32*)(&vert); DebuggerAppendMsg("vtx %d: %08X %08X %08X %08X", i, dat[0],dat[1],dat[2],dat[3]); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vtxTransformed[i].x,g_vtxTransformed[i].y,g_vtxTransformed[i].z,g_vtxTransformed[i].w); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vecProjected[i].x,g_vecProjected[i].y,g_vecProjected[i].z,g_vecProjected[i].w); }); RSP_Vtx_Clipping(i); if( gRSP.bLightingEnable ) { g_normal.x = (float)vert.norma.nx; g_normal.y = (float)vert.norma.ny; g_normal.z = (float)vert.norma.nz; Vec3TransformNormal(g_normal, gRSPmodelViewTop); g_dwVtxDifColor[i] = LightVert(g_normal, i); *(((uint8*)&(g_dwVtxDifColor[i]))+3) = vert.rgba.a; // still use alpha from the vertex } else { if( (gRDP.geometryMode & G_SHADE) == 0 && gRSP.ucode < 5 ) //Shade is disabled { //FLAT shade g_dwVtxDifColor[i] = gRDP.primitiveColor; } else { g_dwVtxDifColor[i] = COLOR_RGBA(vert.rgba.r, vert.rgba.g, vert.rgba.b, vert.rgba.a); } } if( options.bWinFrameMode ) { g_dwVtxDifColor[i] = COLOR_RGBA(vert.rgba.r, vert.rgba.g, vert.rgba.b, vert.rgba.a); } ReplaceAlphaWithFogFactor(i); // Update texture coords n.b. need to divide tu/tv by bogus scale on addition to buffer // If the vert is already lit, then there is no normal (and hence we // can't generate tex coord) if (gRSP.bTextureGen && gRSP.bLightingEnable ) { TexGen(g_fVtxTxtCoords[i].x, g_fVtxTxtCoords[i].y); } else { g_fVtxTxtCoords[i].x = (float)vert.tu; g_fVtxTxtCoords[i].y = (float)vert.tv; } } VTX_DUMP(TRACE2("Setting Vertexes: %d - %d\n", dwV0, dwV0+dwNum-1)); DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{TRACE0("Paused at Vertex Cmd");}); } bool PrepareTriangle(uint32 dwV0, uint32 dwV1, uint32 dwV2) { SP_Timing(SP_Each_Triangle); bool textureFlag = (CRender::g_pRender->IsTextureEnabled() || gRSP.ucode == 6 ); InitVertex(dwV0, gRSP.numVertices, textureFlag); InitVertex(dwV1, gRSP.numVertices+1, textureFlag); InitVertex(dwV2, gRSP.numVertices+2, textureFlag); gRSP.numVertices += 3; status.dwNumTrisRendered++; return true; } // Returns TRUE if it thinks the triangle is visible // Returns FALSE if it is clipped bool IsTriangleVisible(uint32 dwV0, uint32 dwV1, uint32 dwV2) { //return true; //fix me DEBUGGER_ONLY_IF( (!debuggerEnableTestTris || !debuggerEnableCullFace), {return TRUE;}); #ifdef DEBUGGER // Check vertices are valid! if (dwV0 >= MAX_VERTS || dwV1 >= MAX_VERTS || dwV2 >= MAX_VERTS) return false; #endif // Here we AND all the flags. If any of the bits is set for all // 3 vertices, it means that all three x, y or z lie outside of // the current viewing volume. // Currently disabled - still seems a bit dodgy if ((gRSP.bCullFront || gRSP.bCullBack) && gRDP.otherMode.zmode != 3) { XVECTOR4 & v0 = g_vecProjected[dwV0]; XVECTOR4 & v1 = g_vecProjected[dwV1]; XVECTOR4 & v2 = g_vecProjected[dwV2]; // Only try to clip if the tri is onscreen. For some reason, this // method doesnt' work well when the z value is outside of screenspace //if (v0.z < 1 && v1.z < 1 && v2.z < 1) { float V1 = v2.x - v0.x; float V2 = v2.y - v0.y; float W1 = v2.x - v1.x; float W2 = v2.y - v1.y; float fDirection = (V1 * W2) - (V2 * W1); fDirection = fDirection * v1.w * v2.w * v0.w; //float fDirection = v0.x*v1.y-v1.x*v0.y+v1.x*v2.y-v2.x*v1.y+v2.x*v0.y-v0.x*v2.y; if (fDirection < 0 && gRSP.bCullBack) { status.dwNumTrisClipped++; return false; } else if (fDirection > 0 && gRSP.bCullFront) { status.dwNumTrisClipped++; return false; } } } #ifdef ENABLE_CLIP_TRI //if( gRSP.bRejectVtx && (g_clipFlag[dwV0]|g_clipFlag[dwV1]|g_clipFlag[dwV2]) ) // return; if( g_clipFlag2[dwV0]&g_clipFlag2[dwV1]&g_clipFlag2[dwV2] ) { //DebuggerAppendMsg("Clipped"); return false; } #endif return true; } void SetPrimitiveDepth(uint32 z, uint32 dwDZ) { gRDP.primitiveDepth = z & 0x7FFF; gRDP.fPrimitiveDepth = (float)(gRDP.primitiveDepth)/(float)0x8000; //gRDP.fPrimitiveDepth = gRDP.fPrimitiveDepth*2-1; /* z=0xFFFF -> 1 the farest z=0 -> -1 the nearest */ //how to use dwDZ? #ifdef DEBUGGER if( (pauseAtNext && (eventToPause == NEXT_VERTEX_CMD || eventToPause == NEXT_FLUSH_TRI )) )//&& logTriangles ) { DebuggerAppendMsg("Set prim Depth: %f, (%08X, %08X)", gRDP.fPrimitiveDepth, z, dwDZ); } #endif } void SetVertexXYZ(uint32 vertex, float x, float y, float z) { g_vecProjected[vertex].x = x; g_vecProjected[vertex].y = y; g_vecProjected[vertex].z = z; g_vtxTransformed[vertex].x = x*g_vtxTransformed[vertex].w; g_vtxTransformed[vertex].y = y*g_vtxTransformed[vertex].w; g_vtxTransformed[vertex].z = z*g_vtxTransformed[vertex].w; } void ModifyVertexInfo(uint32 where, uint32 vertex, uint32 val) { switch (where) { case RSP_MV_WORD_OFFSET_POINT_RGBA: // Modify RGBA { uint32 r = (val>>24)&0xFF; uint32 g = (val>>16)&0xFF; uint32 b = (val>>8)&0xFF; uint32 a = val&0xFF; g_dwVtxDifColor[vertex] = COLOR_RGBA(r, g, b, a); LOG_UCODE("Modify vert %d color, 0x%08x", vertex, g_dwVtxDifColor[vertex]); } break; case RSP_MV_WORD_OFFSET_POINT_XYSCREEN: // Modify X,Y { uint16 nX = (uint16)(val>>16); short x = *((short*)&nX); x /= 4; uint16 nY = (uint16)(val&0xFFFF); short y = *((short*)&nY); y /= 4; // Should do viewport transform. x -= windowSetting.uViWidth/2; y = windowSetting.uViHeight/2-y; if( options.bEnableHacks && ((*g_GraphicsInfo.VI_X_SCALE_REG)&0xF) != 0 ) { // Tarzan // I don't know why Tarzan is different SetVertexXYZ(vertex, x/windowSetting.fViWidth, y/windowSetting.fViHeight, g_vecProjected[vertex].z); } else { // Toy Story 2 and other games SetVertexXYZ(vertex, x*2/windowSetting.fViWidth, y*2/windowSetting.fViHeight, g_vecProjected[vertex].z); } LOG_UCODE("Modify vert %d: x=%d, y=%d", vertex, x, y); VTX_DUMP(TRACE3("Modify vert %d: (%d,%d)", vertex, x, y)); } break; case RSP_MV_WORD_OFFSET_POINT_ZSCREEN: // Modify C { int z = val>>16; SetVertexXYZ(vertex, g_vecProjected[vertex].x, g_vecProjected[vertex].y, (((float)z/0x03FF)+0.5f)/2.0f ); LOG_UCODE("Modify vert %d: z=%d", vertex, z); VTX_DUMP(TRACE2("Modify vert %d: z=%d", vertex, z)); } break; case RSP_MV_WORD_OFFSET_POINT_ST: // Texture { short tu = short(val>>16); short tv = short(val & 0xFFFF); float ftu = tu / 32.0f; float ftv = tv / 32.0f; LOG_UCODE(" Setting vertex %d tu/tv to %f, %f", vertex, (float)tu, (float)tv); CRender::g_pRender->SetVtxTextureCoord(vertex, ftu/gRSP.fTexScaleX, ftv/gRSP.fTexScaleY); } break; } DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{TRACE0("Paused at ModVertex Cmd");}); } void ProcessVertexDataDKR(uint32 dwAddr, uint32 dwV0, uint32 dwNum) { UpdateCombinedMatrix(); long long pVtxBase = (long long) (g_pRDRAMu8 + dwAddr); g_pVtxBase = (FiddledVtx*)pVtxBase; Matrix &matWorldProject = gRSP.DKRMatrixes[gRSP.DKRCMatrixIndex]; int nOff; bool addbase=false; if ((!gRSP.DKRBillBoard) || (gRSP.DKRCMatrixIndex != 2) ) addbase = false; else addbase = true; if( addbase && gRSP.DKRVtxCount == 0 && dwNum > 1 ) { gRSP.DKRVtxCount++; } LOG_UCODE(" ProcessVertexDataDKR, CMatrix = %d, Add base=%s", gRSP.DKRCMatrixIndex, gRSP.DKRBillBoard?"true":"false"); VTX_DUMP(TRACE2("DKR Setting Vertexes\nCMatrix = %d, Add base=%s", gRSP.DKRCMatrixIndex, gRSP.DKRBillBoard?"true":"false")); nOff = 0; uint32 end = dwV0 + dwNum; for (uint32 i = dwV0; i < end; i++) { XVECTOR3 w; g_vtxNonTransformed[i].x = (float)*(short*)((pVtxBase+nOff + 0) ^ 2); g_vtxNonTransformed[i].y = (float)*(short*)((pVtxBase+nOff + 2) ^ 2); g_vtxNonTransformed[i].z = (float)*(short*)((pVtxBase+nOff + 4) ^ 2); //if( status.isSSEEnabled ) // SSEVec3TransformDKR(g_vtxTransformed[i], g_vtxNonTransformed[i]); //else Vec3Transform(&g_vtxTransformed[i], (XVECTOR3*)&g_vtxNonTransformed[i], &matWorldProject); // Convert to w=1 if( gRSP.DKRVtxCount == 0 && dwNum==1 ) { gRSP.DKRBaseVec.x = g_vtxTransformed[i].x; gRSP.DKRBaseVec.y = g_vtxTransformed[i].y; gRSP.DKRBaseVec.z = g_vtxTransformed[i].z; gRSP.DKRBaseVec.w = g_vtxTransformed[i].w; } else if( addbase ) { g_vtxTransformed[i].x += gRSP.DKRBaseVec.x; g_vtxTransformed[i].y += gRSP.DKRBaseVec.y; g_vtxTransformed[i].z += gRSP.DKRBaseVec.z; g_vtxTransformed[i].w = gRSP.DKRBaseVec.w; } g_vecProjected[i].w = 1.0f / g_vtxTransformed[i].w; g_vecProjected[i].x = g_vtxTransformed[i].x * g_vecProjected[i].w; g_vecProjected[i].y = g_vtxTransformed[i].y * g_vecProjected[i].w; g_vecProjected[i].z = g_vtxTransformed[i].z * g_vecProjected[i].w; gRSP.DKRVtxCount++; VTX_DUMP(TRACE5("vtx %d: %f, %f, %f, %f", i, g_vtxTransformed[i].x,g_vtxTransformed[i].y,g_vtxTransformed[i].z,g_vtxTransformed[i].w)); if( gRSP.bFogEnabled ) { g_fFogCoord[i] = g_vecProjected[i].z; if( g_vecProjected[i].w < 0 || g_vecProjected[i].z < 0 || g_fFogCoord[i] < gRSPfFogMin ) g_fFogCoord[i] = gRSPfFogMin; } RSP_Vtx_Clipping(i); short wA = *(short*)((pVtxBase+nOff + 6) ^ 2); short wB = *(short*)((pVtxBase+nOff + 8) ^ 2); s8 r = (s8)(wA >> 8); s8 g = (s8)(wA); s8 b = (s8)(wB >> 8); s8 a = (s8)(wB); if (gRSP.bLightingEnable) { g_normal.x = (char)r; //norma.nx; g_normal.y = (char)g; //norma.ny; g_normal.z = (char)b; //norma.nz; Vec3TransformNormal(g_normal, matWorldProject) #if !defined(NO_ASM) if( status.isSSEEnabled ) g_dwVtxDifColor[i] = SSELightVert(); else #endif g_dwVtxDifColor[i] = LightVert(g_normal, i); } else { int nR, nG, nB, nA; nR = r; nG = g; nB = b; nA = a; // Assign true vert colour after lighting/fogging g_dwVtxDifColor[i] = COLOR_RGBA(nR, nG, nB, nA); } ReplaceAlphaWithFogFactor(i); g_fVtxTxtCoords[i].x = g_fVtxTxtCoords[i].y = 1; nOff += 10; } DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{DebuggerAppendMsg("Paused at DKR Vertex Cmd, v0=%d, vn=%d, addr=%08X", dwV0, dwNum, dwAddr);}); } extern uint32 dwPDCIAddr; void ProcessVertexDataPD(uint32 dwAddr, uint32 dwV0, uint32 dwNum) { UpdateCombinedMatrix(); N64VtxPD * pVtxBase = (N64VtxPD*)(g_pRDRAMu8 + dwAddr); g_pVtxBase = (FiddledVtx*)pVtxBase; // Fix me for (uint32 i = dwV0; i < dwV0 + dwNum; i++) { N64VtxPD &vert = pVtxBase[i - dwV0]; g_vtxNonTransformed[i].x = (float)vert.x; g_vtxNonTransformed[i].y = (float)vert.y; g_vtxNonTransformed[i].z = (float)vert.z; #if !defined(NO_ASM) if( status.isSSEEnabled ) SSEVec3Transform(i); else #endif { Vec3Transform(&g_vtxTransformed[i], (XVECTOR3*)&g_vtxNonTransformed[i], &gRSPworldProject); // Convert to w=1 g_vecProjected[i].w = 1.0f / g_vtxTransformed[i].w; g_vecProjected[i].x = g_vtxTransformed[i].x * g_vecProjected[i].w; g_vecProjected[i].y = g_vtxTransformed[i].y * g_vecProjected[i].w; g_vecProjected[i].z = g_vtxTransformed[i].z * g_vecProjected[i].w; } g_fFogCoord[i] = g_vecProjected[i].z; if( g_vecProjected[i].w < 0 || g_vecProjected[i].z < 0 || g_fFogCoord[i] < gRSPfFogMin ) g_fFogCoord[i] = gRSPfFogMin; RSP_Vtx_Clipping(i); uint8 *addr = g_pRDRAMu8+dwPDCIAddr+ (vert.cidx&0xFF); uint32 a = addr[0]; uint32 r = addr[3]; uint32 g = addr[2]; uint32 b = addr[1]; if( gRSP.bLightingEnable ) { g_normal.x = (char)r; g_normal.y = (char)g; g_normal.z = (char)b; #if !defined(NO_ASM) if( status.isSSEEnabled ) { SSEVec3TransformNormal(); g_dwVtxDifColor[i] = SSELightVert(); } else #endif { Vec3TransformNormal(g_normal, gRSPmodelViewTop); g_dwVtxDifColor[i] = LightVert(g_normal, i); } *(((uint8*)&(g_dwVtxDifColor[i]))+3) = (uint8)a; // still use alpha from the vertex } else { if( (gRDP.geometryMode & G_SHADE) == 0 && gRSP.ucode < 5 ) //Shade is disabled { g_dwVtxDifColor[i] = gRDP.primitiveColor; } else //FLAT shade { g_dwVtxDifColor[i] = COLOR_RGBA(r, g, b, a); } } if( options.bWinFrameMode ) { g_dwVtxDifColor[i] = COLOR_RGBA(r, g, b, a); } ReplaceAlphaWithFogFactor(i); VECTOR2 & t = g_fVtxTxtCoords[i]; if (gRSP.bTextureGen && gRSP.bLightingEnable ) { // Not sure if we should transform the normal here //Matrix & matWV = gRSP.projectionMtxs[gRSP.projectionMtxTop]; //Vec3TransformNormal(g_normal, matWV); TexGen(g_fVtxTxtCoords[i].x, g_fVtxTxtCoords[i].y); } else { t.x = vert.s; t.y = vert.t; } VTX_DUMP( { DebuggerAppendMsg("vtx %d: %d %d %d", i, vert.x,vert.y,vert.z); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vtxTransformed[i].x,g_vtxTransformed[i].y,g_vtxTransformed[i].z,g_vtxTransformed[i].w); DebuggerAppendMsg(" : %X, %X, %X, %X", r,g,b,a); DebuggerAppendMsg(" : u=%f, v=%f", t.x, t.y); }); } VTX_DUMP(TRACE2("Setting Vertexes: %d - %d\n", dwV0, dwV0+dwNum-1)); DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{TRACE0("Paused at Vertex Cmd");}); } extern uint32 dwConkerVtxZAddr; void ProcessVertexDataConker(uint32 dwAddr, uint32 dwV0, uint32 dwNum) { UpdateCombinedMatrix(); FiddledVtx * pVtxBase = (FiddledVtx*)(g_pRDRAMu8 + dwAddr); g_pVtxBase = pVtxBase; //short *vertexColoraddr = (short*)(g_pRDRAMu8+dwConkerVtxZAddr); for (uint32 i = dwV0; i < dwV0 + dwNum; i++) { SP_Timing(RSP_GBI0_Vtx); FiddledVtx & vert = pVtxBase[i - dwV0]; g_vtxNonTransformed[i].x = (float)vert.x; g_vtxNonTransformed[i].y = (float)vert.y; g_vtxNonTransformed[i].z = (float)vert.z; #if !defined(NO_ASM) if( status.isSSEEnabled ) SSEVec3Transform(i); else #endif { Vec3Transform(&g_vtxTransformed[i], (XVECTOR3*)&g_vtxNonTransformed[i], &gRSPworldProject); // Convert to w=1 g_vecProjected[i].w = 1.0f / g_vtxTransformed[i].w; g_vecProjected[i].x = g_vtxTransformed[i].x * g_vecProjected[i].w; g_vecProjected[i].y = g_vtxTransformed[i].y * g_vecProjected[i].w; g_vecProjected[i].z = g_vtxTransformed[i].z * g_vecProjected[i].w; } g_fFogCoord[i] = g_vecProjected[i].z; if( g_vecProjected[i].w < 0 || g_vecProjected[i].z < 0 || g_fFogCoord[i] < gRSPfFogMin ) g_fFogCoord[i] = gRSPfFogMin; VTX_DUMP( { uint32 *dat = (uint32*)(&vert); DebuggerAppendMsg("vtx %d: %08X %08X %08X %08X", i, dat[0],dat[1],dat[2],dat[3]); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vtxTransformed[i].x,g_vtxTransformed[i].y,g_vtxTransformed[i].z,g_vtxTransformed[i].w); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vecProjected[i].x,g_vecProjected[i].y,g_vecProjected[i].z,g_vecProjected[i].w); }); RSP_Vtx_Clipping(i); if( gRSP.bLightingEnable ) { { uint32 r= ((gRSP.ambientLightColor>>16)&0xFF); uint32 g= ((gRSP.ambientLightColor>> 8)&0xFF); uint32 b= ((gRSP.ambientLightColor )&0xFF); for( uint32 k=1; k<=gRSPnumLights; k++) { r += gRSPlights[k].r; g += gRSPlights[k].g; b += gRSPlights[k].b; } if( r>255 ) r=255; if( g>255 ) g=255; if( b>255 ) b=255; r *= vert.rgba.r ; g *= vert.rgba.g ; b *= vert.rgba.b ; r >>= 8; g >>= 8; b >>= 8; g_dwVtxDifColor[i] = 0xFF000000; g_dwVtxDifColor[i] |= (r<<16); g_dwVtxDifColor[i] |= (g<< 8); g_dwVtxDifColor[i] |= (b ); } *(((uint8*)&(g_dwVtxDifColor[i]))+3) = vert.rgba.a; // still use alpha from the vertex } else { if( (gRDP.geometryMode & G_SHADE) == 0 && gRSP.ucode < 5 ) //Shade is disabled { g_dwVtxDifColor[i] = gRDP.primitiveColor; } else //FLAT shade { g_dwVtxDifColor[i] = COLOR_RGBA(vert.rgba.r, vert.rgba.g, vert.rgba.b, vert.rgba.a); } } if( options.bWinFrameMode ) { //g_vecProjected[i].z = 0; g_dwVtxDifColor[i] = COLOR_RGBA(vert.rgba.r, vert.rgba.g, vert.rgba.b, vert.rgba.a); } ReplaceAlphaWithFogFactor(i); // Update texture coords n.b. need to divide tu/tv by bogus scale on addition to buffer //VECTOR2 & t = g_fVtxTxtCoords[i]; // If the vert is already lit, then there is no normal (and hence we // can't generate tex coord) if (gRSP.bTextureGen && gRSP.bLightingEnable ) { g_normal.x = (float)*(char*)(g_pRDRAMu8+ (((i<<1)+0)^3)+dwConkerVtxZAddr); g_normal.y = (float)*(char*)(g_pRDRAMu8+ (((i<<1)+1)^3)+dwConkerVtxZAddr); g_normal.z = (float)*(char*)(g_pRDRAMu8+ (((i<<1)+2)^3)+dwConkerVtxZAddr); Vec3TransformNormal(g_normal, gRSPmodelViewTop); TexGen(g_fVtxTxtCoords[i].x, g_fVtxTxtCoords[i].y); } else { g_fVtxTxtCoords[i].x = (float)vert.tu; g_fVtxTxtCoords[i].y = (float)vert.tv; } } VTX_DUMP(TRACE2("Setting Vertexes: %d - %d\n", dwV0, dwV0+dwNum-1)); DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{DebuggerAppendMsg("Paused at Vertex Cmd");}); } typedef struct{ short y; short x; short flag; short z; } RS_Vtx_XYZ; typedef union { struct { uint8 a; uint8 b; uint8 g; uint8 r; }; struct { char na; //a char nz; //b char ny; //g char nx; //r }; } RS_Vtx_Color; void ProcessVertexData_Rogue_Squadron(uint32 dwXYZAddr, uint32 dwColorAddr, uint32 dwXYZCmd, uint32 dwColorCmd) { UpdateCombinedMatrix(); uint32 dwV0 = 0; uint32 dwNum = (dwXYZCmd&0xFF00)>>10; RS_Vtx_XYZ * pVtxXYZBase = (RS_Vtx_XYZ*)(g_pRDRAMu8 + dwXYZAddr); RS_Vtx_Color * pVtxColorBase = (RS_Vtx_Color*)(g_pRDRAMu8 + dwColorAddr); uint32 i; for (i = dwV0; i < dwV0 + dwNum; i++) { RS_Vtx_XYZ & vertxyz = pVtxXYZBase[i - dwV0]; RS_Vtx_Color & vertcolors = pVtxColorBase[i - dwV0]; g_vtxNonTransformed[i].x = (float)vertxyz.x; g_vtxNonTransformed[i].y = (float)vertxyz.y; g_vtxNonTransformed[i].z = (float)vertxyz.z; #if !defined(NO_ASM) if( status.isSSEEnabled ) SSEVec3Transform(i); else #endif { Vec3Transform(&g_vtxTransformed[i], (XVECTOR3*)&g_vtxNonTransformed[i], &gRSPworldProject); // Convert to w=1 g_vecProjected[i].w = 1.0f / g_vtxTransformed[i].w; g_vecProjected[i].x = g_vtxTransformed[i].x * g_vecProjected[i].w; g_vecProjected[i].y = g_vtxTransformed[i].y * g_vecProjected[i].w; g_vecProjected[i].z = g_vtxTransformed[i].z * g_vecProjected[i].w; } VTX_DUMP( { DebuggerAppendMsg(" : %f, %f, %f, %f", g_vtxTransformed[i].x,g_vtxTransformed[i].y,g_vtxTransformed[i].z,g_vtxTransformed[i].w); DebuggerAppendMsg(" : %f, %f, %f, %f", g_vecProjected[i].x,g_vecProjected[i].y,g_vecProjected[i].z,g_vecProjected[i].w); }); g_fFogCoord[i] = g_vecProjected[i].z; if( g_vecProjected[i].w < 0 || g_vecProjected[i].z < 0 || g_fFogCoord[i] < gRSPfFogMin ) g_fFogCoord[i] = gRSPfFogMin; RSP_Vtx_Clipping(i); if( gRSP.bLightingEnable ) { g_normal.x = (float)vertcolors.nx; g_normal.y = (float)vertcolors.ny; g_normal.z = (float)vertcolors.nz; #if !defined(NO_ASM) if( status.isSSEEnabled ) { SSEVec3TransformNormal(); g_dwVtxDifColor[i] = SSELightVert(); } else #endif { Vec3TransformNormal(g_normal, gRSPmodelViewTop); g_dwVtxDifColor[i] = LightVert(g_normal, i); } *(((uint8*)&(g_dwVtxDifColor[i]))+3) = vertcolors.a; // still use alpha from the vertex } else { if( (gRDP.geometryMode & G_SHADE) == 0 && gRSP.ucode < 5 ) //Shade is disabled { g_dwVtxDifColor[i] = gRDP.primitiveColor; } else //FLAT shade { g_dwVtxDifColor[i] = COLOR_RGBA(vertcolors.r, vertcolors.g, vertcolors.b, vertcolors.a); } } if( options.bWinFrameMode ) { g_dwVtxDifColor[i] = COLOR_RGBA(vertcolors.r, vertcolors.g, vertcolors.b, vertcolors.a); } ReplaceAlphaWithFogFactor(i); /* // Update texture coords n.b. need to divide tu/tv by bogus scale on addition to buffer VECTOR2 & t = g_fVtxTxtCoords[i]; // If the vert is already lit, then there is no normal (and hence we // can't generate tex coord) if (gRSP.bTextureGen && gRSP.bLightingEnable && g_textures[gRSP.curTile].m_bTextureEnable ) { TexGen(g_fVtxTxtCoords[i].x, g_fVtxTxtCoords[i].y); } else { t.x = (float)vert.tu; t.y = (float)vert.tv; } */ } VTX_DUMP(TRACE2("Setting Vertexes: %d - %d\n", dwV0, dwV0+dwNum-1)); DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{TRACE0("Paused at Vertex Cmd");}); } void SetLightCol(uint32 dwLight, uint32 dwCol) { gRSPlights[dwLight].r = (uint8)((dwCol >> 24)&0xFF); gRSPlights[dwLight].g = (uint8)((dwCol >> 16)&0xFF); gRSPlights[dwLight].b = (uint8)((dwCol >> 8)&0xFF); gRSPlights[dwLight].a = 255; // Ignore light alpha gRSPlights[dwLight].fr = (float)gRSPlights[dwLight].r; gRSPlights[dwLight].fg = (float)gRSPlights[dwLight].g; gRSPlights[dwLight].fb = (float)gRSPlights[dwLight].b; gRSPlights[dwLight].fa = 255; // Ignore light alpha //TRACE1("Set light %d color", dwLight); LIGHT_DUMP(TRACE2("Set Light %d color: %08X", dwLight, dwCol)); } void SetLightDirection(uint32 dwLight, float x, float y, float z, float range) { //gRSP.bLightIsUpdated = true; //gRSPlights[dwLight].ox = x; //gRSPlights[dwLight].oy = y; //gRSPlights[dwLight].oz = z; float w = range == 0 ? (float)sqrt(x*x+y*y+z*z) : 1; gRSPlights[dwLight].x = x/w; gRSPlights[dwLight].y = y/w; gRSPlights[dwLight].z = z/w; gRSPlights[dwLight].range = range; DEBUGGER_PAUSE_AND_DUMP(NEXT_SET_LIGHT,TRACE5("Set Light %d dir: %.4f, %.4f, %.4f, %.4f", dwLight, x, y, z, range)); } static float maxS0, maxT0; static float maxS1, maxT1; static bool validS0, validT0; static bool validS1, validT1; void LogTextureCoords(float fTex0S, float fTex0T, float fTex1S, float fTex1T) { if( validS0 ) { if( fTex0S<0 || fTex0S>maxS0 ) validS0 = false; } if( validT0 ) { if( fTex0T<0 || fTex0T>maxT0 ) validT0 = false; } if( validS1 ) { if( fTex1S<0 || fTex1S>maxS1 ) validS1 = false; } if( validT1 ) { if( fTex1T<0 || fTex1T>maxT1 ) validT1 = false; } } bool CheckTextureCoords(int tex) { if( tex==0 ) { return validS0&&validT0; } else { return validS1&&validT1; } } void ResetTextureCoordsLog(float maxs0, float maxt0, float maxs1, float maxt1) { maxS0 = maxs0; maxT0 = maxt0; maxS1 = maxs1; maxT1 = maxt1; validS0 = validT0 = true; validS1 = validT1 = true; } void ForceMainTextureIndex(int dwTile) { if( dwTile == 1 && !(CRender::g_pRender->IsTexel0Enable()) && CRender::g_pRender->IsTexel1Enable() ) { // Hack gRSP.curTile = 0; } else { gRSP.curTile = dwTile; } } float HackZ2(float z) { z = (z+9)/10; return z; } float HackZ(float z) { return HackZ2(z); if( z < 0.1 && z >= 0 ) z = (.1f+z)/2; else if( z < 0 ) //return (10+z)/100; z = (expf(z)/20); return z; } void HackZ(std::vector& points) { int size = points.size(); for( int i=0; i VIwidth*2 ) { gti.Format = 0; gti.Size = 2; gti.Address = (*g_GraphicsInfo.VI_ORIGIN_REG & (g_dwRamSize-1) ) - VIwidth*2; gti.LeftToLoad = 0; gti.TopToLoad = 0; gti.PalAddress = (uchar *) &g_wRDPTlut[0]; gti.WidthToCreate = windowSetting.uViWidth;; gti.HeightToCreate = windowSetting.uViHeight; if( gti.WidthToCreate == 0 || gti.HeightToCreate == 0 ) { TRACE0("Loading frame buffer: size = 0 x 0"); return; } gti.Pitch = VIwidth << gti.Size >> 1; } else { gti.Format = g_CI.dwFormat; gti.Size = g_CI.dwSize; gti.PalAddress = (uchar *) &g_wRDPTlut[0]; gti.Address = RSPSegmentAddr(g_CI.dwAddr); if( width == 0 || height == 0 ) { gti.LeftToLoad = 0; gti.TopToLoad = 0; gti.WidthToCreate = g_CI.dwWidth; gti.HeightToCreate = g_CI.dwWidth*3/4; } else { gti.LeftToLoad = left; gti.TopToLoad = top; gti.WidthToCreate = width; gti.HeightToCreate = height; } if( gti.Size == TXT_SIZE_4b ) { gti.Pitch = g_CI.dwWidth >> 1; } else { gti.Pitch = g_CI.dwWidth << (gti.Size-1); } } if( gti.Address + gti.Pitch*gti.HeightToCreate > g_dwRamSize ) { TRACE0("Skip frame buffer loading, memory out of bound"); return; } #ifdef DEBUGGER if( pauseAtNext ) { DebuggerAppendMsg("Load Frame Buffer Imag at: %08X, (%d, %d) - (%d, %d)", gti.Address, gti.LeftToLoad, gti.TopToLoad, gti.WidthToCreate, gti.HeightToCreate ); } #endif gti.HeightToLoad = gti.HeightToCreate; gti.WidthToLoad = gti.WidthToCreate; gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address; gti.tileNo = -1; TxtrCacheEntry *pEntry = gTextureManager.GetTexture(>i, false, true, false); if( pEntry ) SetCurrentTexture( 0, pEntry->pTexture, pEntry->ti.WidthToCreate, pEntry->ti.HeightToCreate, pEntry); } void CRender::LoadTextureFromMemory(void *buf, uint32 left, uint32 top, uint32 width, uint32 height, uint32 pitch, uint32 format) { TxtrInfo gti; gti.Format = g_CI.dwFormat; gti.Size = g_CI.dwSize; gti.Palette = 0; gti.TLutFmt = TLUT_FMT_RGBA16; //RGBA16 gti.PalAddress = 0; gti.bSwapped = FALSE; gti.Address = 0; gti.LeftToLoad = 0; gti.TopToLoad = 0; gti.WidthToCreate = width; gti.HeightToCreate = height; gti.Pitch = pitch; gti.HeightToLoad = height; gti.WidthToLoad = width; gti.pPhysicalAddress = (uint8*)buf; gti.tileNo = -1; TxtrCacheEntry *pEntry = gTextureManager.GetTexture(>i, false); //Upto here, the texture is loaded wrong because the format is wrong DrawInfo info; if( pEntry->pTexture->StartUpdate(&info) ) { for( uint32 i=0; ipTexture->EndUpdate(&info); } SetCurrentTexture( 0, pEntry->pTexture, width, height, pEntry); } void CRender::LoadObjBGCopy(uObjBg &info) { TxtrInfo gti; gti.Format = info.imageFmt; gti.Size = info.imageSiz; gti.Address = RSPSegmentAddr(info.imagePtr); gti.LeftToLoad = 0; gti.TopToLoad = 0; gti.Palette = info.imagePal; gti.PalAddress = (uchar *) &g_wRDPTlut[0]; gti.bSwapped = FALSE; gti.TLutFmt = TLUT_FMT_RGBA16; //RGBA16 gti.WidthToCreate = info.imageW/4; gti.HeightToCreate = info.imageH/4; if( options.bEnableHacks ) { if( g_CI.dwWidth == 0x200 && gti.Format == g_CI.dwFormat && gti.Size == g_CI.dwSize && gti.WidthToCreate == 0x200 ) { // Hack for RE2 uint32 w = *g_GraphicsInfo.VI_WIDTH_REG & 0xFFF; gti.HeightToCreate = (gti.WidthToCreate*gti.HeightToCreate)/w; gti.WidthToCreate = w; } } gti.Pitch = gti.WidthToCreate << gti.Size >> 1; gti.Pitch = (gti.Pitch>>3)<<3; // Align to 8 bytes if( gti.Address + gti.Pitch*gti.HeightToCreate > g_dwRamSize ) { TRACE0("Skip BG copy loading, memory out of bound"); return; } gti.HeightToLoad = gti.HeightToCreate; gti.WidthToLoad = gti.WidthToCreate; gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address; gti.tileNo = -1; TxtrCacheEntry *pEntry = gTextureManager.GetTexture(>i, false); SetCurrentTexture(0,pEntry); DEBUGGER_IF_DUMP((pauseAtNext && (eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI||eventToPause == NEXT_OBJ_BG)), { TRACE0("Load Obj BG Copy:\n"); DebuggerAppendMsg("Addr=0x%08X, W=%d, H=%d, Left=%d, Top=%d\n", gti.Address, gti.WidthToCreate, gti.HeightToCreate, gti.LeftToLoad, gti.TopToLoad); DebuggerAppendMsg("Fmt=%s-%db, Pal=%d\n", pszImgFormat[gti.Format], pnImgSize[gti.Size], gti.Palette); } ); } void CRender::LoadTxtrBufIntoTexture(void) { TxtrInfo gti; gti.Format = g_pRenderTextureInfo->CI_Info.dwFormat; gti.Size = g_pRenderTextureInfo->CI_Info.dwSize; gti.Address = RSPSegmentAddr(g_pRenderTextureInfo->CI_Info.dwAddr); gti.LeftToLoad = 0; gti.TopToLoad = 0; gti.Palette = 0; gti.PalAddress = (uchar *) &g_wRDPTlut[0]; gti.bSwapped = FALSE; gti.WidthToCreate = g_pRenderTextureInfo->N64Width; gti.HeightToCreate = g_pRenderTextureInfo->N64Height; gti.TLutFmt = TLUT_FMT_RGBA16; //RGBA16 gti.Pitch = gti.WidthToCreate << (gti.Size-1); gti.HeightToLoad = gti.HeightToCreate; gti.WidthToLoad = gti.WidthToCreate; gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address; gti.tileNo = -1; TxtrCacheEntry *pEntry = gTextureManager.GetTexture(>i, false); SetCurrentTexture(0,pEntry); } void CRender::LoadSprite2D(Sprite2DInfo &info, uint32 ucode) { TxtrInfo gti; gti.Format = info.spritePtr->SourceImageType; gti.Size = info.spritePtr->SourceImageBitSize; gti.Address = RSPSegmentAddr(info.spritePtr->SourceImagePointer); gti.Palette = 0; gti.PalAddress = (uchar *) (g_pRDRAMu8 + RSPSegmentAddr(info.spritePtr->TlutPointer)); if( options.enableHackForGames == HACK_FOR_NITRO ) { gti.WidthToCreate = (uint32)(info.spritePtr->SubImageWidth/info.scaleX); gti.HeightToCreate = (uint32)(info.spritePtr->SubImageHeight/info.scaleY); gti.LeftToLoad = (uint32)(info.spritePtr->SourceImageOffsetS/info.scaleX); gti.TopToLoad = (uint32)(info.spritePtr->SourceImageOffsetT/info.scaleY); gti.Pitch = info.spritePtr->Stride << gti.Size >> 1; gti.Pitch = (uint32)(gti.Pitch*info.scaleY); } else { gti.WidthToCreate = info.spritePtr->SubImageWidth; gti.HeightToCreate = info.spritePtr->SubImageHeight; gti.LeftToLoad = info.spritePtr->SourceImageOffsetS; gti.TopToLoad = info.spritePtr->SourceImageOffsetT; gti.Pitch = info.spritePtr->Stride << gti.Size >> 1; } if( gti.Address + gti.Pitch*gti.HeightToCreate > g_dwRamSize ) { TRACE0("Skip Sprite image decompress, memory out of bound"); return; } gti.HeightToLoad = gti.HeightToCreate; gti.WidthToLoad = gti.WidthToCreate; gti.TLutFmt = TLUT_FMT_RGBA16; //RGBA16 gti.bSwapped = FALSE; gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address; gti.tileNo = -1; TxtrCacheEntry *pEntry = gTextureManager.GetTexture(>i, false); SetCurrentTexture(0,pEntry); DEBUGGER_IF_DUMP((pauseAtNext && (eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI||eventToPause == NEXT_SPRITE_2D)), { TRACE0("Load Sprite 2D\n"); DebuggerAppendMsg("Addr=0x%08X, W=%d, H=%d, Left=%d, Top=%d\n", gti.Address, gti.WidthToCreate, gti.HeightToCreate, gti.LeftToLoad, gti.TopToLoad); DebuggerAppendMsg("Fmt=%s-%db, Pal=%d, Pitch=%d\n", pszImgFormat[gti.Format], pnImgSize[gti.Size], gti.Palette, gti.Pitch); } ); } void CRender::DrawSprite2D(Sprite2DInfo &info, uint32 ucode) { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); if( status.bHandleN64RenderTexture ) { g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height; if( !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } } LoadSprite2D(info, ucode); info.scaleX = 1/info.scaleX; info.scaleY = 1/info.scaleY; int x0, y0, x1, y1; float t0, s0, t1, s1; if( info.flipX ) { //x0 = info.px*info.scaleX + info.spritePtr->SubImageWidth*info.scaleX; //x1 = info.px*info.scaleX; x0 = info.px + int(info.spritePtr->SubImageWidth*info.scaleX); x1 = info.px; } else { //x0 = info.px*info.scaleX; //x1 = info.px*info.scaleX + info.spritePtr->SubImageWidth*info.scaleX; x0 = info.px; x1 = info.px + int(info.spritePtr->SubImageWidth*info.scaleX); } if( info.flipY ) { //y0 = info.py*info.scaleY + info.spritePtr->SubImageHeight*info.scaleY; //y1 = info.py*info.scaleY; y0 = info.py + int(info.spritePtr->SubImageHeight*info.scaleY); y1 = info.py; } else { //y0 = info.py*info.scaleY; //y1 = info.py*info.scaleY + info.spritePtr->SubImageHeight*info.scaleY; y0 = info.py; y1 = info.py + int(info.spritePtr->SubImageHeight*info.scaleY); } t0 = s0 = 0; if( options.enableHackForGames == HACK_FOR_NITRO ) { t1 = info.spritePtr->SubImageWidth*info.scaleX/g_textures[0].m_fTexWidth; s1 = info.spritePtr->SubImageHeight*info.scaleY/g_textures[0].m_fTexHeight; } else { t1 = info.spritePtr->SubImageWidth/g_textures[0].m_fTexWidth; s1 = info.spritePtr->SubImageHeight/g_textures[0].m_fTexHeight; } //InitCombinerBlenderForSimpleTextureDraw(); SetCombinerAndBlender(); SetAddressUAllStages( 0, TEXTURE_UV_FLAG_CLAMP ); SetAddressVAllStages( 0, TEXTURE_UV_FLAG_CLAMP ); COLOR difColor = 0xffffffff; float depth = ( gRDP.otherMode.depth_source == 1 ) ? gRDP.fPrimitiveDepth : 0; DrawSimple2DTexture((float)x0, (float)y0, (float)x1, (float)y1, t0, s0, t1, s1, difColor, depth, 1.0f); } void CRender::DrawSpriteR(uObjTxSprite &sprite, bool initCombiner, uint32 tile, uint32 left, uint32 top, uint32 width, uint32 height) // With Rotation { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); if( status.bHandleN64RenderTexture ) { g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height; if( !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } } SetCombinerAndBlender(); float scaleX = sprite.sprite.scaleW/1024.0f; float scaleY = sprite.sprite.scaleH/1024.0f; if( width == 0 || height == 0 ) { width = g_textures[tile].m_dwTileWidth; height = g_textures[tile].m_dwTileHeight; } //RECT src = {left,top,width, height}; float depth = 0.0; if (gRDP.otherMode.depth_source==1) depth = gRDP.fPrimitiveDepth; float x0 = sprite.sprite.objX/4.0f; float y0 = sprite.sprite.objY/4.0f; float x1 = sprite.sprite.imageW / 32.0f / scaleX + x0; float y1 = sprite.sprite.imageH / 32.0f / scaleY + y0; if( sprite.sprite.imageFlags&1 ) { float temp = x0; x0 = x1; x1 = temp; } // flip X if( sprite.sprite.imageFlags&0x10 ) { float temp = y0; y0 = y1; y1 = temp; } // flip Y g_texRectTVtx[0].x = (gObjMtxReal.A*x0 + gObjMtxReal.B*y0 + gObjMtxReal.X)*windowSetting.fMultX; g_texRectTVtx[0].y = (gObjMtxReal.C*x0 + gObjMtxReal.D*y0 + gObjMtxReal.Y)*windowSetting.fMultY; g_texRectTVtx[0].z = depth; g_texRectTVtx[0].rhw = 1; g_texRectTVtx[1].x = (gObjMtxReal.A*x1 + gObjMtxReal.B*y0 + gObjMtxReal.X)*windowSetting.fMultX; g_texRectTVtx[1].y = (gObjMtxReal.C*x1 + gObjMtxReal.D*y0 + gObjMtxReal.Y)*windowSetting.fMultY; g_texRectTVtx[1].z = depth; g_texRectTVtx[1].rhw = 1; g_texRectTVtx[2].x = (gObjMtxReal.A*x1 + gObjMtxReal.B*y1 + gObjMtxReal.X)*windowSetting.fMultX; g_texRectTVtx[2].y = (gObjMtxReal.C*x1 + gObjMtxReal.D*y1 + gObjMtxReal.Y)*windowSetting.fMultY; g_texRectTVtx[2].z = depth; g_texRectTVtx[2].rhw = 1; g_texRectTVtx[3].x = (gObjMtxReal.A*x0 + gObjMtxReal.B*y1 + gObjMtxReal.X)*windowSetting.fMultX; g_texRectTVtx[3].y = (gObjMtxReal.C*x0 + gObjMtxReal.D*y1 + gObjMtxReal.Y)*windowSetting.fMultY; g_texRectTVtx[3].z = depth; g_texRectTVtx[3].rhw = 1; g_texRectTVtx[0].tcord[0].u = left/g_textures[tile].m_fTexWidth; g_texRectTVtx[0].tcord[0].v = top/g_textures[tile].m_fTexHeight; g_texRectTVtx[1].tcord[0].u = (left+width)/g_textures[tile].m_fTexWidth; g_texRectTVtx[1].tcord[0].v = top/g_textures[tile].m_fTexHeight; g_texRectTVtx[2].tcord[0].u = (left+width)/g_textures[tile].m_fTexWidth; g_texRectTVtx[2].tcord[0].v = (top+height)/g_textures[tile].m_fTexHeight; g_texRectTVtx[3].tcord[0].u = left/g_textures[tile].m_fTexWidth; g_texRectTVtx[3].tcord[0].v = (top+height)/g_textures[tile].m_fTexHeight; COLOR difColor = 0xffffffff; g_texRectTVtx[0].dcDiffuse = g_texRectTVtx[1].dcDiffuse = g_texRectTVtx[2].dcDiffuse = g_texRectTVtx[3].dcDiffuse = difColor; DrawSpriteR_Render(); } void CRender::DrawFrameBuffer(bool useVIreg, uint32 left, uint32 top, uint32 width, uint32 height) { BeginRendering(); LoadFrameBuffer(useVIreg, left, top, width, height); m_pColorCombiner->InitCombinerBlenderForSimpleTextureDraw(0); ZBufferEnable(FALSE); SetZUpdate(FALSE); if( left == 0 ) SetAlphaTestEnable(FALSE); else SetAlphaTestEnable(TRUE); // use Alpha Test for partial frame buffer draw, for Dr. Mario 64 m_pAlphaBlender->Disable(); CTexture *pTexture = g_textures[0].m_pCTexture; if( pTexture ) { if( useVIreg ) { // Draw the whole frame buffer DrawSimple2DTexture(0, 0, windowSetting.uViWidth, windowSetting.uViHeight, 0, 0, 1/pTexture->m_fXScale, 1/pTexture->m_fYScale, 0xFFFFFFFF, 0, 1); } else { // Draw a small texture in frame buffer DrawSimple2DTexture((float)left, (float)top, (float)(left+width), (float)(top+height), 0, 0, 1/pTexture->m_fXScale, 1/pTexture->m_fYScale, 0xFFFFFFFF, 0, 1); } } TXTRBUF_OR_CI_DUMP(TRACE0("Draw Frame Buffer Img")); #ifdef DEBUGGER if( pauseAtNext && ( eventToPause == NEXT_FRAME || eventToPause == NEXT_FLUSH_TRI ) ) { TRACE0("Draw Frame Buffer Img"); debuggerPause = true; DebuggerPause(); } #endif EndRendering(); } void CRender::DrawObjBGCopy(uObjBg &info) { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); if( status.bHandleN64RenderTexture ) { g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height; if( !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } } SetCombinerAndBlender(); uint32 frameH = info.frameH; uint32 frameW = info.frameW; uint32 imageH = info.imageH; uint32 imageW = info.imageW; if( options.bEnableHacks ) { if( g_CI.dwWidth == 0x200 && info.imageFmt == g_CI.dwFormat && info.imageSiz == g_CI.dwSize && frameW == 0x800 ) { // Hack for RE2 uint32 width = *g_GraphicsInfo.VI_WIDTH_REG & 0xFFF; imageH = frameH = (frameW/4*frameH/4)/width*4; imageW = frameW = width*4; } } float x0 = info.frameX / 4.0f; float y0 = info.frameY / 4.0f; float x1 = frameW / 4.0f + x0; float y1 = frameH / 4.0f + y0; float s0 = info.imageX / 32.0f; float t0 = info.imageY / 32.0f; float texwidth = imageW/4.0f; float texheight = imageH/4.0f; float u0 = s0/g_textures[0].m_fTexWidth; float v0 = t0/g_textures[0].m_fTexHeight; float maxu = texwidth/g_textures[0].m_fTexWidth; float maxv = texheight/g_textures[0].m_fTexHeight; float x2 = x0 + (texwidth-s0); float y2 = y0 + (texheight-t0); float u1 = (x1-x2)/g_textures[0].m_fTexWidth; float v1 = (y1-y2)/g_textures[0].m_fTexHeight; float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0.0f); COLOR difColor = 0xffffffff; if( options.enableHackForGames == HACK_FOR_COMMANDCONQUER ) { float s1 = (x1-x0) + s0; float t1 = (y1-y0) + t0; DrawSimple2DTexture(x0, y0, x1, y1, u0, v0, s1/g_textures[0].m_fTexWidth, t1/g_textures[0].m_fTexHeight, difColor, depth, 1); } else if( x2 >= x1 ) { float s1 = (x1-x0) + s0; if( y2 >= y1 ) { float t1 = (y1-y0) + t0; DrawSimple2DTexture(x0, y0, x1, y1, u0, v0, s1/g_textures[0].m_fTexWidth, t1/g_textures[0].m_fTexHeight, difColor, depth, 1); } else { DrawSimple2DTexture(x0, y0, x1, y2, u0, v0, s1/g_textures[0].m_fTexWidth, maxv, difColor, depth, 1); DrawSimple2DTexture(x0, y2, x1, y1, u0, 0, s1/g_textures[0].m_fTexWidth, v1, difColor, depth, 1); } } else { if( y2 >= y1 ) { float t1 = (y1-y0) + t0; DrawSimple2DTexture(x0, y0, x2, y1, u0, v0, maxu, t1/g_textures[0].m_fTexHeight, difColor, depth, 1); DrawSimple2DTexture(x2, y0, x1, y1, 0, v0, u1, t1/g_textures[0].m_fTexHeight, difColor, depth, 1); } else { DrawSimple2DTexture(x0, y0, x2, y2, u0, v0, maxu, maxv, difColor, depth, 1); DrawSimple2DTexture(x2, y0, x1, y2, 0, v0, u1, maxv, difColor, depth, 1); DrawSimple2DTexture(x0, y2, x2, y1, u0, 0, maxu, v1, difColor, depth, 1); DrawSimple2DTexture(x2, y2, x1, y1, 0, 0, u1, v1, difColor, depth, 1); } } DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N( (pauseAtNext&&(eventToPause==NEXT_OBJ_BG||eventToPause==NEXT_FLUSH_TRI||eventToPause==NEXT_OBJ_TXT_CMD)), { TRACE0("Pause ObjBG Copy"); } ); } void CRender::DrawObjBG1CYC(uObjScaleBg &bg, bool scaled) //Without Ratation { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); if( g_curRomInfo.bDisableObjBG ) return; if( status.bHandleN64RenderTexture ) { g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height; if( !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } } SetCombinerAndBlender(); float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0.0f); float x0 = bg.frameX / 4.0f; float y0 = bg.frameY / 4.0f; float x1 = bg.frameW / 4.0f + x0; float y1 = bg.frameH / 4.0f + y0; float s0 = bg.imageX / 32.0f; float t0 = bg.imageY / 32.0f; float scaleX = bg.scaleW/1024.0f; float scaleY = bg.scaleH/1024.0f; float texwidth = bg.imageW/4.0f; float texheight = bg.imageH/4.0f; float u0 = s0/g_textures[0].m_fTexWidth; float v0 = t0/g_textures[0].m_fTexHeight; float maxu = texwidth/g_textures[0].m_fTexWidth; float maxv = texheight/g_textures[0].m_fTexHeight; float x2 = x0 + (texwidth-s0)/scaleX; float y2 = y0 + (texheight-t0)/scaleY; float u1 = (x1-x2)*scaleX/g_textures[0].m_fTexWidth; float v1 = (y1-y2)*scaleY/g_textures[0].m_fTexHeight; COLOR difColor = 0xffffffff; SetAlphaTestEnable(FALSE); if( options.enableHackForGames != HACK_FOR_YOSHI ) { float s1 = (x1-x0)*scaleX + s0; float t1 = (y1-y0)*scaleY + t0; DrawSimple2DTexture(x0, y0, x1, y1, u0, v0, s1/g_textures[0].m_fTexWidth, t1/g_textures[0].m_fTexHeight, difColor, depth, 1); } else if( x2 >= x1 ) { float s1 = (x1-x0)*scaleX + s0; if( y2 >= y1 ) { float t1 = (y1-y0)*scaleY + t0; DrawSimple2DTexture(x0, y0, x1, y1, u0, v0, s1/g_textures[0].m_fTexWidth, t1/g_textures[0].m_fTexHeight, difColor, depth, 1); } else { DrawSimple2DTexture(x0, y0, x1, y2, u0, v0, s1/g_textures[0].m_fTexWidth, maxv, difColor, depth, 1); DrawSimple2DTexture(x0, y2, x1, y1, u0, 0, s1/g_textures[0].m_fTexWidth, v1, difColor, depth, 1); } } else { if( y2 >= y1 ) { float t1 = (y1-y0)*scaleY + t0; DrawSimple2DTexture(x0, y0, x2, y1, u0, v0, maxu, t1/g_textures[0].m_fTexHeight, difColor, depth, 1); DrawSimple2DTexture(x2, y0, x1, y1, 0, v0, u1, t1/g_textures[0].m_fTexHeight, difColor, depth, 1); } else { DrawSimple2DTexture(x0, y0, x2, y2, u0, v0, maxu, maxv, difColor, depth, 1); DrawSimple2DTexture(x2, y0, x1, y2, 0, v0, u1, maxv, difColor, depth, 1); DrawSimple2DTexture(x0, y2, x2, y1, u0, 0, maxu, v1, difColor, depth, 1); DrawSimple2DTexture(x2, y2, x1, y1, 0, 0, u1, v1, difColor, depth, 1); } } DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N( (pauseAtNext&&(eventToPause==NEXT_OBJ_BG||eventToPause==NEXT_FLUSH_TRI||eventToPause==NEXT_OBJ_TXT_CMD)), { DebuggerAppendMsg("Pause BG 1CYC: (%.0f,%.0f - %.0f,%.0f), \ntex (%.2f,%.2f), scale (%.2f,%.2f)",x0,y0,x1,y1,s0,t0,scaleX,scaleY); } ); } void CRender::DrawSprite(uObjTxSprite &sprite, bool rectR) //Without Ratation { if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer(); if( status.bHandleN64RenderTexture ) { g_pRenderTextureInfo->maxUsedHeight = g_pRenderTextureInfo->N64Height; if( !status.bDirectWriteIntoRDRAM ) { status.bFrameBufferIsDrawn = true; status.bFrameBufferDrawnByTriangles = true; } } SetCombinerAndBlender(); COLOR difColor = 0xffffffff; float objX = sprite.sprite.objX/4.0f; float objY = sprite.sprite.objY/4.0f; float width = sprite.sprite.imageW / 32.0f; float high = sprite.sprite.imageH / 32.0f; float scaleW = sprite.sprite.scaleW/1024.0f; float scaleH = sprite.sprite.scaleH/1024.0f; if( g_curRomInfo.bIncTexRectEdge ) { width++; high++; } float x0, y0, x1, y1; if( rectR ) { // Upper-left coordinate // ( X + objX / BaseScaleX, Y+objY/BaseScaleY ) // Lower-right coordinate // ( X + (objX + imageW / scaleW) / BaseScaleX - 1, Y + (objY + imageH / scaleH) / BaseScaleY - 1 ) x0 = gObjMtxReal.X + objX/gObjMtxReal.BaseScaleX; y0 = gObjMtxReal.Y + objY/gObjMtxReal.BaseScaleY; x1 = gObjMtxReal.X + (objX + width / scaleW) / gObjMtxReal.BaseScaleX; y1 = gObjMtxReal.Y + (objY + high / scaleH) / gObjMtxReal.BaseScaleY; } else { // (objX, objY) - ( objX+imageW/scaleW-1, objY+imageH/scaleH-1) x0 = objX; y0 = objY; x1 = objX + width / scaleW; y1 = objY + high / scaleH; if( (sprite.sprite.imageFlags&1) ) // flipX { float temp = x0; x0 = x1; x1 = temp; } if( (sprite.sprite.imageFlags&0x10) ) // flipY { float temp = y0; y0 = y1; y1 = temp; } } // save the current clamp type GLint iClampS, iClampT; glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &iClampS); OPENGL_CHECK_ERRORS; glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, &iClampT); OPENGL_CHECK_ERRORS; // force clamp type to CLAMP_EDGE (experiments show sometimes this is set to hex 0x2901 - invalid value) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); OPENGL_CHECK_ERRORS; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); OPENGL_CHECK_ERRORS; // draw the 2D sprite as 2 triangles float depth = (gRDP.otherMode.depth_source == 1 ? gRDP.fPrimitiveDepth : 0.0f); CTexture *pTexture = g_textures[0].m_pCTexture; DrawSimple2DTexture(x0, y0, x1, y1, 0, 0, 1/pTexture->m_fXScale, 1/pTexture->m_fYScale, difColor, depth, 1); // return clamp type to original setting glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, iClampS); OPENGL_CHECK_ERRORS; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, iClampT); OPENGL_CHECK_ERRORS; } void CRender::LoadObjBG1CYC(uObjScaleBg &bg) { uint32 imageWidth = bg.imageW/4; uint32 imageHeight = bg.imageH/4; TxtrInfo gti; gti.Format = bg.imageFmt; gti.Size = bg.imageSiz; //uint8* img = (uint8*)(g_pRDRAMu8+RSPSegmentAddr(bg.imagePtr)); uchar *palAddr = (uchar *) &g_wRDPTlut[0]; gti.Address = RSPSegmentAddr(bg.imagePtr); gti.LeftToLoad = 0; gti.TopToLoad = 0; gti.WidthToCreate = imageWidth; gti.HeightToCreate = imageHeight; gti.clampS = gti.clampT = 1; gti.maskS = gti.maskT = 0; gti.Palette = bg.imagePal; gti.PalAddress = palAddr; gti.Pitch = imageWidth << gti.Size >> 1; gti.Pitch = (gti.Pitch>>3)<<3; // Align to 8 bytes if( gti.Address + gti.Pitch*gti.HeightToCreate > g_dwRamSize ) { TRACE0("Skip BG 1CYC loading, memory out of bound"); return; } gti.TLutFmt = TLUT_FMT_RGBA16; //RGBA16 gti.bSwapped = FALSE; gti.HeightToLoad = gti.HeightToCreate; gti.WidthToLoad = gti.WidthToCreate; gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address; gti.tileNo = -1; TxtrCacheEntry *pEntry = gTextureManager.GetTexture(>i, false,true,false); SetCurrentTexture(0,pEntry); DEBUGGER_IF_DUMP((pauseAtNext && (eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI||eventToPause == NEXT_OBJ_BG)), { TRACE0("Load Obj BG 1CYC:\n"); DebuggerAppendMsg("Addr=0x%08X, W=%d, H=%d, Left=%d, Top=%d\n", gti.Address, gti.WidthToCreate, gti.HeightToCreate, gti.LeftToLoad, gti.TopToLoad); DebuggerAppendMsg("Fmt=%s-%db, Pal=%d\n", pszImgFormat[gti.Format], pnImgSize[gti.Size], gti.Palette); } ); } void CRender::LoadObjSprite(uObjTxSprite &sprite, bool useTIAddr) { TxtrInfo gti; gti.Format = sprite.sprite.imageFmt; gti.Size = sprite.sprite.imageSiz; uchar *palAddr = (uchar *) &g_wRDPTlut[0]; gti.Address = RSPSegmentAddr(sprite.txtr.block.image); gti.Address += sprite.sprite.imageAdrs<<3; gti.LeftToLoad = 0; gti.TopToLoad = 0; gti.Palette = sprite.sprite.imagePal; gti.PalAddress = palAddr; if( sprite.txtr.block.type == S2DEX_OBJLT_TXTRBLOCK ) { gti.WidthToCreate = sprite.sprite.imageW/32; if( sprite.sprite.imageW >= 0x8000 ) { gti.WidthToCreate = (0x10000-sprite.sprite.imageW)/32; } gti.HeightToCreate = sprite.sprite.imageH/32; if( sprite.sprite.imageH >= 0x8000 ) { gti.HeightToCreate = (0x10000-sprite.sprite.imageH)/32; } gti.Pitch = (2047/(sprite.txtr.block.tline-1)) << 3; } else if( sprite.txtr.block.type == S2DEX_OBJLT_TXTRTILE ) { //#define GS_PIX2TMEM(pix, siz) ((pix)>>(4-(siz))) //#define GS_TT_TWIDTH(pix,siz) ((GS_PIX2TMEM((pix), (siz))<<2)-1) //#define GS_TT_THEIGHT(pix,siz) (((pix)<<2)-1) gti.WidthToCreate = ((sprite.txtr.tile.twidth+1)>>2)<<(4-gti.Size); gti.HeightToCreate = (sprite.txtr.tile.theight+1)>>2; if( gti.Size == TXT_SIZE_4b ) { gti.Pitch = gti.WidthToCreate >> 1; } else //gti.Pitch = (sprite.txtr.tile.twidth+1) << 3; gti.Pitch = gti.WidthToCreate << (gti.Size-1); } if( gti.Address + gti.Pitch*gti.HeightToCreate > g_dwRamSize ) { TRACE0("Skip Obj sprite loading, memory out of bound"); return; } gti.TLutFmt = TLUT_FMT_RGBA16; //RGBA16 gti.bSwapped = FALSE; gti.HeightToLoad = gti.HeightToCreate; gti.WidthToLoad = gti.WidthToCreate; gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address; gti.tileNo = -1; TxtrCacheEntry *pEntry = gTextureManager.GetTexture(>i, false); SetCurrentTexture(0,pEntry); } mupen64plus-video-rice-src-2.6.0/src/RenderTexture.cpp000066400000000000000000000041051464507324400226360ustar00rootroot00000000000000/* Copyright (C) 2005 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "Debugger.h" #include "FrameBuffer.h" #include "OGLTexture.h" #include "RenderTexture.h" #include "Texture.h" #include "TextureManager.h" #include "osal_opengl.h" // =========================================================================== COGLRenderTexture::COGLRenderTexture(int width, int height, RenderTextureInfo* pInfo, TextureUsage usage) : CRenderTexture(width, height, pInfo, usage), m_pOGLTexture(NULL) { if( usage == AS_BACK_BUFFER_SAVE ) { m_pTexture = m_pOGLTexture = new COGLTexture(width, height, usage); if( !m_pTexture ) { TRACE0("Error to create OGL render_texture"); SAFE_DELETE(m_pTexture); } } m_width = width; m_height = height; m_beingRendered = false; } COGLRenderTexture::~COGLRenderTexture() { if( m_beingRendered ) { g_pFrameBufferManager->CloseRenderTexture(false); SetAsRenderTarget(false); } ShutdownPBuffer(); SAFE_DELETE(m_pTexture); m_pOGLTexture = NULL; m_beingRendered = false; } bool COGLRenderTexture::InitPBuffer( void ) { return true; } void COGLRenderTexture::ShutdownPBuffer(void) { } bool COGLRenderTexture::SetAsRenderTarget(bool enable) { return true; } void COGLRenderTexture::LoadTexture(TxtrCacheEntry* pEntry) { } void COGLRenderTexture::StoreToRDRAM(int infoIdx) { } mupen64plus-video-rice-src-2.6.0/src/RenderTexture.h000066400000000000000000000056431464507324400223130ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _TEXTURE_BUFFER_H_ #define _TEXTURE_BUFFER_H_ #include #include "Texture.h" #include "TextureManager.h" #include "typedefs.h" class COGLTexture; class CRenderTexture; typedef struct { CRenderTexture *pRenderTexture; SetImgInfo CI_Info; uint32 bufferWidth; uint32 bufferHeight; uint32 N64Width; uint32 N64Height; float scaleX; float scaleY; int maxUsedHeight; uint32 updateAtFrame; uint32 updateAtUcodeCount; bool isUsed; uint32 knownHeight; uint32 crcInRDRAM; uint32 crcCheckedAtFrame; TxtrCacheEntry txtEntry; } RenderTextureInfo; class CRenderTexture { public: friend class CGraphicsContext; friend class CDXGraphicsContext; friend class FrameBufferManager; friend class DXFrameBufferManager; friend class OGLFrameBufferManager; CRenderTexture(int width, int height, RenderTextureInfo* pInfo, TextureUsage usage) { m_beingRendered = false; m_width = m_height = 0; m_pTexture = NULL; m_pInfo = pInfo; m_usage = usage; } virtual ~CRenderTexture() {} virtual bool SetAsRenderTarget(bool enable)=0; virtual void LoadTexture(TxtrCacheEntry* pEntry)=0; virtual void StoreToRDRAM(int infoIdx) {}; void GetDimension(int &width, int &height) { width = m_width; height = m_height; } bool IsBeingRendered() { return m_beingRendered; } TextureUsage GetUsage() {return m_usage;} protected: int m_width; int m_height; bool m_beingRendered; TextureUsage m_usage; CTexture* m_pTexture; RenderTextureInfo* m_pInfo; }; class COGLRenderTexture : public CRenderTexture { // Haven't implemented yet public: COGLRenderTexture(int width, int height, RenderTextureInfo* pInfo, TextureUsage usage); ~COGLRenderTexture(); bool SetAsRenderTarget(bool enable); void LoadTexture(TxtrCacheEntry* pEntry); void StoreToRDRAM(int infoIdx); protected: bool InitPBuffer(void); void ShutdownPBuffer(void); int m_widthCreated; int m_heightCreated; COGLTexture *m_pOGLTexture; }; #endif mupen64plus-video-rice-src-2.6.0/src/Texture.cpp000066400000000000000000000052451464507324400215040ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "Texture.h" #include "TextureManager.h" #include "typedefs.h" ////////////////////////////////////////// // Constructors / Deconstructors // Probably shouldn't need more than 4096 * 4096 CTexture::CTexture(uint32 dwWidth, uint32 dwHeight, TextureUsage usage) : m_dwWidth(dwWidth), m_dwHeight(dwHeight), m_dwCreatedTextureWidth(dwWidth), m_dwCreatedTextureHeight(dwHeight), m_fXScale(1.0f), m_fYScale(1.0f), m_bIsEnhancedTexture(false), m_Usage(usage), m_pTexture(NULL), m_dwTextureFmt(TEXTURE_FMT_A8R8G8B8) { // fix me, do something here } CTexture::~CTexture(void) { } TextureFmt CTexture::GetSurfaceFormat(void) { if (m_pTexture == NULL) return TEXTURE_FMT_UNKNOWN; else return m_dwTextureFmt; } uint32 CTexture::GetPixelSize() { if( m_dwTextureFmt == TEXTURE_FMT_A8R8G8B8 ) return 4; else return 2; } void CTexture::RestoreAlphaChannel(void) { DrawInfo di; if ( StartUpdate(&di) ) { uint32 *pSrc = (uint32 *)di.lpSurface; int lPitch = di.lPitch; for (uint32 y = 0; y < m_dwHeight; y++) { uint32 * dwSrc = (uint32 *)((uint8 *)pSrc + y*lPitch); for (uint32 x = 0; x < m_dwWidth; x++) { uint32 dw = dwSrc[x]; uint32 dwRed = (uint8)((dw & 0x00FF0000)>>16); uint32 dwGreen = (uint8)((dw & 0x0000FF00)>>8 ); uint32 dwBlue = (uint8)((dw & 0x000000FF) ); uint32 dwAlpha = (dwRed+dwGreen+dwBlue)/3; dw &= 0x00FFFFFF; dw |= (dwAlpha<<24); /* uint32 dw = dwSrc[x]; if( (dw&0x00FFFFFF) > 0 ) dw |= 0xFF000000; else dw &= 0x00FFFFFF; */ } } EndUpdate(&di); } else { //TRACE0("Cannot lock texture"); } } mupen64plus-video-rice-src-2.6.0/src/Texture.h000066400000000000000000000054461464507324400211540ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __SURFACEHANDLER_H__ #define __SURFACEHANDLER_H__ #include "typedefs.h" /////////////// Define a struct to use as /////////////// storage for all the surfaces /////////////// created so far. class CTexture; typedef struct { unsigned short int dwWidth; // Describes the width of the real texture area. Use lPitch to move between successive lines unsigned short int dwHeight; // Describes the height of the real texture area unsigned short int dwCreatedWidth; // Describes the width of the created texture area. Use lPitch to move between successive lines unsigned short int dwCreatedHeight; // Describes the height of the created texture area int lPitch; // Specifies the number of bytes on each row (not necessarily bitdepth*width/8) void *lpSurface; // Pointer to the top left pixel of the image } DrawInfo; enum TextureFmt { TEXTURE_FMT_A8R8G8B8, TEXTURE_FMT_A4R4G4B4, TEXTURE_FMT_UNKNOWN, }; enum TextureUsage { AS_NORMAL, AS_RENDER_TARGET, AS_BACK_BUFFER_SAVE, }; class CTexture { public: virtual ~CTexture(); uint32 m_dwWidth; // The requested Texture w/h uint32 m_dwHeight; unsigned int m_dwCreatedTextureWidth; // What was actually created unsigned int m_dwCreatedTextureHeight; float m_fXScale; // = m_dwCorrectedWidth/m_dwWidth float m_fYScale; // = m_dwCorrectedHeight/m_dwWidth bool m_bIsEnhancedTexture; TextureUsage m_Usage; virtual LPRICETEXTURE GetTexture() { return m_pTexture; } uint32 GetPixelSize(); TextureFmt GetSurfaceFormat(void); // Surface pixel format... // Provides access to "surface" virtual bool StartUpdate(DrawInfo *di)=0; virtual void EndUpdate(DrawInfo *di)=0; virtual void RestoreAlphaChannel(void); // Restore Alpha channel from RGB channel protected: CTexture(uint32 dwWidth, uint32 dwHeight, TextureUsage usage = AS_NORMAL); LPRICETEXTURE m_pTexture; TextureFmt m_dwTextureFmt; }; #endif mupen64plus-video-rice-src-2.6.0/src/TextureFilters.cpp000066400000000000000000002263741464507324400230450ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "CSortedList.h" #include "Debugger.h" #include "RSP_Parser.h" #include "RenderBase.h" #include "TextureManager.h" #include "liblinux/BMGImage.h" #include "liblinux/pngrw.h" #include "m64p_types.h" #include "osal_files.h" #include "osal_preproc.h" #define M64P_PLUGIN_PROTOTYPES 1 #include #include #include #include #include #include #include "ConvertImage.h" #include "DeviceBuilder.h" #include "Render.h" #include "TextureFilters.h" #include "Video.h" #include "liblinux/BMGDLL.h" #include "liblinux/BMGLibPNG.h" #include "m64p_plugin.h" #include "typedefs.h" #ifdef min #undef min #endif /************************************************************************/ /* 2X filters */ /************************************************************************/ // Basic 2x R8G8B8A8 filter with interpolation void Texture2x_32( DrawInfo &srcInfo, DrawInfo &destInfo) { uint32 *pDst1, *pDst2; uint32 *pSrc, *pSrc2; uint32 nWidth = srcInfo.dwWidth; uint32 nHeight = srcInfo.dwHeight; uint32 b1; uint32 g1; uint32 r1; uint32 a1; uint32 b2 = 0; uint32 g2 = 0; uint32 r2 = 0; uint32 a2 = 0; uint32 b3 = 0; uint32 g3 = 0; uint32 r3 = 0; uint32 a3 = 0; uint32 b4 = 0; uint32 g4 = 0; uint32 r4 = 0; uint32 a4 = 0; for (uint32 ySrc = 0; ySrc < nHeight; ySrc++) { pSrc = (uint32*)(((uint8*)srcInfo.lpSurface)+ySrc*srcInfo.lPitch); pSrc2 = (uint32*)(((uint8*)srcInfo.lpSurface)+(ySrc+1)*srcInfo.lPitch); pDst1 = (uint32*)(((uint8*)destInfo.lpSurface)+(ySrc*2)*destInfo.lPitch); pDst2 = (uint32*)(((uint8*)destInfo.lpSurface)+(ySrc*2+1)*destInfo.lPitch); for (uint32 xSrc = 0; xSrc < nWidth; xSrc++) { b1 = (pSrc[xSrc]>>0)&0xFF; g1 = (pSrc[xSrc]>>8)&0xFF; r1 = (pSrc[xSrc]>>16)&0xFF; a1 = (pSrc[xSrc]>>24)&0xFF; if( xSrc>0)&0xFF; g2 = (pSrc[xSrc+1]>>8)&0xFF; r2 = (pSrc[xSrc+1]>>16)&0xFF; a2 = (pSrc[xSrc+1]>>24)&0xFF; } if( ySrc>0)&0xFF; g3 = (pSrc2[xSrc]>>8)&0xFF; r3 = (pSrc2[xSrc]>>16)&0xFF; a3 = (pSrc2[xSrc]>>24)&0xFF; if( xSrc>0)&0xFF; g4 = (pSrc2[xSrc+1]>>8)&0xFF; r4 = (pSrc2[xSrc+1]>>16)&0xFF; a4 = (pSrc2[xSrc+1]>>24)&0xFF; } } // Pixel 1 pDst1[xSrc*2] = pSrc[xSrc]; // Pixel 2 if( xSrc> 0)&0xF; g1 = (pSrc[xSrc]>> 4)&0xF; r1 = (pSrc[xSrc]>> 8)&0xF; a1 = (pSrc[xSrc]>>12)&0xF; if( xSrc> 0)&0xF; g2 = (pSrc[xSrc+1]>> 4)&0xF; r2 = (pSrc[xSrc+1]>> 8)&0xF; a2 = (pSrc[xSrc+1]>>12)&0xF; } if( ySrc> 0)&0xF; g3 = (pSrc2[xSrc]>> 4)&0xF; r3 = (pSrc2[xSrc]>> 8)&0xF; a3 = (pSrc2[xSrc]>>12)&0xF; if( xSrc> 0)&0xF; g4 = (pSrc2[xSrc+1]>> 4)&0xF; r4 = (pSrc2[xSrc+1]>> 8)&0xF; a4 = (pSrc2[xSrc+1]>>12)&0xF; } } // Pixel 1 pDst1[xSrc*2] = pSrc[xSrc]; // Pixel 2 if( xSrc (t1+t3+t7+t9+t2+t4+t6+t8)*mul1 ) { val[z]= std::min((((t5*mul3) - (t1+t3+t7+t9+t2+t4+t6+t8)*mul1)>>shift4),0xFFU); } } dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24); } } delete [] pcopy; } void SharpenFilter_16(uint16 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter) { //return; // Sharpen does not make sense for 16 bits uint32 len=height*pitch; uint16 *pcopy = new uint16[len]; if( !pcopy ) return; memcpy(pcopy, pdata, len<<1); uint16 mul1, mul2, mul3, shift4; switch( filter ) { case TEXTURE_SHARPEN_MORE_ENHANCEMENT: mul1=1; mul2=8; mul3=12; shift4=2; break; case TEXTURE_SHARPEN_ENHANCEMENT: default: mul1=1; mul2=8; mul3=16; shift4=3; break; } uint32 x,y,z; uint16 *src1, *src2, *src3, *dest; uint16 val[4]; uint16 t1,t2,t3,t4,t5,t6,t7,t8,t9; for( y=1; y>1)))>>shift; t2 = (*((uint8*)(src1+x )+(z>>1)))>>shift; t3 = (*((uint8*)(src1+x+1)+(z>>1)))>>shift; t4 = (*((uint8*)(src2+x-1)+(z>>1)))>>shift; t5 = (*((uint8*)(src2+x )+(z>>1)))>>shift; t6 = (*((uint8*)(src2+x+1)+(z>>1)))>>shift; t7 = (*((uint8*)(src3+x-1)+(z>>1)))>>shift; t8 = (*((uint8*)(src3+x )+(z>>1)))>>shift; t9 = (*((uint8*)(src3+x+1)+(z>>1)))>>shift; val[z]=t5; if( (t5*mul2) > (t1+t3+t7+t9+t2+t4+t6+t8)*mul1 ) { val[z] = (((t5*mul3) - (t1+t3+t7+t9+t2+t4+t6+t8)*mul1)>>shift4); val[z]= std::min(val[z],(unsigned short)0xFU); } } dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12); } } delete [] pcopy; } /************************************************************************/ /* Smooth filters */ /************************************************************************/ void SmoothFilter_32(uint32 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter) { uint32 len=height*pitch; uint32 *pcopy = new uint32[len]; if( !pcopy ) return; memcpy(pcopy, pdata, len<<2); uint32 mul1, mul2, mul3, shift4; switch( filter ) { case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1: mul1=1; mul2=2; mul3=4; shift4=4; break; case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2: mul1=1; mul2=1; mul3=8; shift4=4; break; case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3: mul1=1; mul2=1; mul3=2; shift4=2; break; case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4: default: mul1=1; mul2=1; mul3=6; shift4=3; break; } uint32 x,y,z; uint32 *src1, *src2, *src3, *dest; uint32 val[4]; uint32 t1,t2,t3,t4,t5,t6,t7,t8,t9; if( filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3 || filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4 ) { for( y=1; y>shift4; } dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24); } } } else { for( y=0; y0 ) { src1 = pcopy+(y-1)*pitch; src2 = src1 + pitch; } else { src1 = src2 = pcopy; } src3 = src2; if( y>shift4; } dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24); } } } delete [] pcopy; } void SmoothFilter_16(uint16 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter) { uint32 len=height*pitch; uint16 *pcopy = new uint16[len]; if( !pcopy ) return; memcpy(pcopy, pdata, len<<1); uint16 mul1, mul2, mul3, shift4; switch( filter ) { case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1: mul1=1; mul2=2; mul3=4; shift4=4; break; case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2: mul1=1; mul2=1; mul3=8; shift4=4; break; case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3: mul1=1; mul2=1; mul3=2; shift4=2; break; case TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4: default: mul1=1; mul2=1; mul3=6; shift4=3; break; } uint32 x,y,z; uint16 *src1, *src2, *src3, *dest; uint16 val[4]; uint16 t1,t2,t3,t4,t5,t6,t7,t8,t9; if( filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3 || filter == TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4 ) { for( y=1; y>1)))>>shift; t5 = (*((uint8*)(src2+x )+(z>>1)))>>shift; t8 = (*((uint8*)(src3+x )+(z>>1)))>>shift; val[z] = ((t2+t8)*mul2+(t5*mul3))>>shift4; } dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12); } } } else { for( y=0; y0 ) { src1 = pcopy+(y-1)*pitch; src2 = src1 + pitch; } else { src1 = src2 = pcopy; } src3 = src2; if( y>1)))>>shift; t2 = (*((uint8*)(src1+x )+(z>>1)))>>shift; t3 = (*((uint8*)(src1+x+1)+(z>>1)))>>shift; t4 = (*((uint8*)(src2+x-1)+(z>>1)))>>shift; t5 = (*((uint8*)(src2+x )+(z>>1)))>>shift; t6 = (*((uint8*)(src2+x+1)+(z>>1)))>>shift; t7 = (*((uint8*)(src3+x-1)+(z>>1)))>>shift; t8 = (*((uint8*)(src3+x )+(z>>1)))>>shift; t9 = (*((uint8*)(src3+x+1)+(z>>1)))>>shift; val[z] = ((t1+t3+t7+t9)*mul1+((t2+t4+t6+t8)*mul2)+(t5*mul3))>>shift4; } dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12); } } } delete [] pcopy; } void EnhanceTexture(TxtrCacheEntry *pEntry) { if( pEntry->dwEnhancementFlag == options.textureEnhancement ) { // The texture has already been enhanced return; } else if( options.textureEnhancement == TEXTURE_NO_ENHANCEMENT ) { //Texture enhancement has being turned off //Delete any allocated memory for the enhanced texture SAFE_DELETE(pEntry->pEnhancedTexture); //Set the enhancement flag so the texture wont be processed again pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT; return; } if( status.primitiveType != PRIM_TEXTRECT && options.bTexRectOnly ) { return; } DrawInfo srcInfo; //Start the draw update if( pEntry->pTexture->StartUpdate(&srcInfo) == false ) { //If we get here we were unable to start the draw update //Delete any allocated memory for the enhanced texture SAFE_DELETE(pEntry->pEnhancedTexture); return; } uint32 realwidth = srcInfo.dwWidth; uint32 realheight = srcInfo.dwHeight; uint32 nWidth = srcInfo.dwCreatedWidth; uint32 nHeight = srcInfo.dwCreatedHeight; //Sharpen option is enabled, sharpen the texture if( options.textureEnhancement == TEXTURE_SHARPEN_ENHANCEMENT || options.textureEnhancement == TEXTURE_SHARPEN_MORE_ENHANCEMENT ) { if( pEntry->pTexture->GetPixelSize() == 4 ) SharpenFilter_32((uint32*)srcInfo.lpSurface, nWidth, nHeight, nWidth, options.textureEnhancement); else SharpenFilter_16((uint16*)srcInfo.lpSurface, nWidth, nHeight, nWidth, options.textureEnhancement); pEntry->dwEnhancementFlag = options.textureEnhancement; //End the draw update pEntry->pTexture->EndUpdate(&srcInfo); //Delete any allocated memory for the enhanced texture SAFE_DELETE(pEntry->pEnhancedTexture); return; } pEntry->dwEnhancementFlag = options.textureEnhancement; if( options.bSmallTextureOnly ) { if( nWidth + nHeight > 256 ) { //End the draw update pEntry->pTexture->EndUpdate(&srcInfo); //Delete any data allocated for the enhanced texture SAFE_DELETE(pEntry->pEnhancedTexture); //Set the enhancement flag so the texture wont be processed again pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT; return; } } CTexture* pSurfaceHandler = NULL; if( options.textureEnhancement == TEXTURE_HQ4X_ENHANCEMENT ) { if( nWidth + nHeight > 1024/4 ) { // Don't enhance for large textures pEntry->pTexture->EndUpdate(&srcInfo); SAFE_DELETE(pEntry->pEnhancedTexture); pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT; return; } pSurfaceHandler = CDeviceBuilder::GetBuilder()->CreateTexture(nWidth*4, nHeight*4); } else { if( nWidth + nHeight > 1024/2 ) { // Don't enhance for large textures pEntry->pTexture->EndUpdate(&srcInfo); SAFE_DELETE(pEntry->pEnhancedTexture); pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT; return; } pSurfaceHandler = CDeviceBuilder::GetBuilder()->CreateTexture(nWidth*2, nHeight*2); } DrawInfo destInfo; if(pSurfaceHandler) { if(pSurfaceHandler->StartUpdate(&destInfo)) { if( options.textureEnhancement == TEXTURE_2XSAI_ENHANCEMENT ) { if( pEntry->pTexture->GetPixelSize() == 4 ) Super2xSaI_32((uint32*)(srcInfo.lpSurface),(uint32*)(destInfo.lpSurface), nWidth, realheight, nWidth); else Super2xSaI_16((uint16*)(srcInfo.lpSurface),(uint16*)(destInfo.lpSurface), nWidth, realheight, nWidth); } else if( options.textureEnhancement == TEXTURE_HQ2X_ENHANCEMENT ) { if( pEntry->pTexture->GetPixelSize() == 4 ) { hq2x_init(32); hq2x_32((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight); } else { hq2x_init(16); hq2x_16((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight); } } else if( options.textureEnhancement == TEXTURE_LQ2X_ENHANCEMENT ) { if( pEntry->pTexture->GetPixelSize() == 4 ) { hq2x_init(32); lq2x_32((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight); } else { hq2x_init(16); lq2x_16((uint8*)(srcInfo.lpSurface), srcInfo.lPitch, (uint8*)(destInfo.lpSurface), destInfo.lPitch, nWidth, realheight); } } else if( options.textureEnhancement == TEXTURE_HQ4X_ENHANCEMENT ) { if( pEntry->pTexture->GetPixelSize() == 4 ) { hq4x_InitLUTs(); hq4x_32((uint8*)(srcInfo.lpSurface), (uint8*)(destInfo.lpSurface), realwidth, realheight, nWidth, destInfo.lPitch); } else { hq4x_InitLUTs(); hq4x_16((uint8*)(srcInfo.lpSurface), (uint8*)(destInfo.lpSurface), realwidth, realheight, nWidth, destInfo.lPitch); } } else { if( pEntry->pTexture->GetPixelSize() == 4 ) Texture2x_32( srcInfo, destInfo); else Texture2x_16( srcInfo, destInfo); } if( options.textureEnhancementControl >= TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1 ) { if( options.textureEnhancement != TEXTURE_HQ4X_ENHANCEMENT ) { if( pEntry->pTexture->GetPixelSize() == 4 ) SmoothFilter_32((uint32*)destInfo.lpSurface, realwidth<<1, realheight<<1, nWidth<<1, options.textureEnhancementControl); else SmoothFilter_16((uint16*)destInfo.lpSurface, realwidth<<1, realheight<<1, nWidth<<1, options.textureEnhancementControl); } else { if( pEntry->pTexture->GetPixelSize() == 4 ) SmoothFilter_32((uint32*)destInfo.lpSurface, realwidth<<2, realheight<<2, nWidth<<2, options.textureEnhancementControl); else SmoothFilter_16((uint16*)destInfo.lpSurface, realwidth<<2, realheight<<2, nWidth<<2, options.textureEnhancementControl); } } pSurfaceHandler->EndUpdate(&destInfo); } pSurfaceHandler->m_bIsEnhancedTexture = true; } pEntry->pTexture->EndUpdate(&srcInfo); pEntry->pEnhancedTexture = pSurfaceHandler; } /**** All code bellow, CLEAN ME ****/ enum TextureType { NO_TEXTURE, RGB_PNG, COLOR_INDEXED_BMP, RGB_WITH_ALPHA_TOGETHER_PNG, RGBA_PNG_FOR_CI, RGBA_PNG_FOR_ALL_CI, }; typedef struct { unsigned int width; unsigned int height; int fmt; int siz; int crc32; int pal_crc32; char *foldername; char *filename; char *filename_a; //char name[40]; TextureType type; bool bSeparatedAlpha; } ExtTxtrInfo; CSortedList gTxtrDumpInfos; CSortedList gHiresTxtrInfos; extern char * right(const char * src, int nchars); #define SURFFMT_P8 41 int GetImageInfoFromFile(char* pSrcFile, IMAGE_INFO *pSrcInfo) { unsigned char sig[8]; FILE *f; f = fopen(pSrcFile, "rb"); if (f == NULL) { DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile() error: couldn't open file '%s'", pSrcFile); return 1; } if (fread(sig, 1, 8, f) != 8) { DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile() error: couldn't read first 8 bytes of file '%s'", pSrcFile); fclose(f); return 1; } fclose(f); if(sig[0] == 'B' && sig[1] == 'M') // BMP { struct BMGImageStruct img; memset(&img, 0, sizeof(BMGImageStruct)); BMG_Error code = ReadBMP(pSrcFile, &img); if( code == BMG_OK ) { pSrcInfo->Width = img.width; pSrcInfo->Height = img.height; pSrcInfo->Depth = img.bits_per_pixel; pSrcInfo->MipLevels = 1; if(img.bits_per_pixel == 32) pSrcInfo->Format = SURFFMT_A8R8G8B8; else if(img.bits_per_pixel == 8) pSrcInfo->Format = SURFFMT_P8; // Resource and File Format ignored FreeBMGImage(&img); return 0; } DebugMessage(M64MSG_ERROR, "Couldn't read BMP file '%s'; error = %i", pSrcFile, code); return 1; } else if(sig[0] == 137 && sig[1] == 'P' && sig[2] == 'N' && sig[3] == 'G' && sig[4] == '\r' && sig[5] == '\n' && sig[6] == 26 && sig[7] == '\n') // PNG { struct BMGImageStruct img; memset(&img, 0, sizeof(BMGImageStruct)); BMG_Error code = ReadPNGInfo(pSrcFile, &img); if( code == BMG_OK ) { pSrcInfo->Width = img.width; pSrcInfo->Height = img.height; pSrcInfo->Depth = img.bits_per_pixel; pSrcInfo->MipLevels = 1; if(img.bits_per_pixel == 32) pSrcInfo->Format = SURFFMT_A8R8G8B8; else if(img.bits_per_pixel == 8) pSrcInfo->Format = SURFFMT_P8; // Resource and File Format ignored FreeBMGImage(&img); return 0; } DebugMessage(M64MSG_ERROR, "Couldn't read PNG file '%s'; error = %i", pSrcFile, code); return 1; } DebugMessage(M64MSG_ERROR, "GetImageInfoFromFile : unknown file format (%s)", pSrcFile); return 1; } BOOL PathFileExists(char* pszPath) { FILE *f; f = fopen(pszPath, "rb"); if(f != NULL) { fclose(f); return TRUE; } return FALSE; } /******************************************************************************************************************** * Truncates the current list with information about hires textures and scans the hires folder for hires textures and * creates a list with records of properties of the hires textures. * parameter: * foldername: the folder that should be scaned for valid hires textures. * infos: a pointer that will point to the list containing the records with the infos about the found hires textures. * In case of enabled caching, these records will also contain the actual textures. * extraCheck: ? * bRecursive: flag that indicates if also subfolders should be scanned for hires textures * bCacheTextures: flag that indicates if the identified hires textures should also be cached * bMainFolder: indicates if the folder is the main folder that will be scanned. That way, texture counting does not * start at 1 each time a subfolder is accessed. (microdev: I know that is not important but it really * bugged me ;-)) * return: * infos: the list with the records of the identified hires textures. Be aware that these records also contains the * actual textures if caching is enabled. ********************************************************************************************************************/ void FindAllTexturesFromFolder(char *foldername, CSortedList &infos, bool extraCheck, bool bRecursive) { // check if folder actually exists if (!osal_is_directory(foldername)) return; // the path of the texture char texturefilename[PATH_MAX]; // IMAGE_INFO imgInfo; // IMAGE_INFO imgInfo2; void *dir; dir = osal_search_dir_open(foldername); const char *foundfilename; int crc, palcrc32; unsigned int fmt, siz; char crcstr[16], crcstr2[16]; do { foundfilename = osal_search_dir_read_next(dir); // The array is empty, break the current operation if (foundfilename == NULL) break; // The current file is a hidden one if (foundfilename[0] == '.' ) // These files we don't need continue; // Get the folder name strcpy(texturefilename, foldername); // And append the file name strcat(texturefilename, foundfilename); // Check if the current file is a directory and if recursive scanning is enabled if (osal_is_directory(texturefilename) && bRecursive ) { // Add file-separator strcat(texturefilename, OSAL_DIR_SEPARATOR_STR); // Scan detected folder for hires textures (recursive call) FindAllTexturesFromFolder(texturefilename, infos, extraCheck, bRecursive); continue; } // well, the current file is actually no file (probably a directory & recursive scanning is not enabled) if( strstr(foundfilename,(const char*)g_curRomInfo.szGameName) == 0 ) // go on with the next one continue; TextureType type = NO_TEXTURE; bool bSeparatedAlpha = false; // Detect the texture type by it's extention // microdev: this is not the smartest way. Should be done by header analysis if possible if( strcasecmp(right(foundfilename,7), "_ci.bmp") == 0 ) { // Identify type if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0) { DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename); continue; } if( imgInfo.Format == SURFFMT_P8 ) // and store it to the record type = COLOR_INDEXED_BMP; else // Type is not supported, go on with the next one continue; } // Detect the texture type by its extention else if( strcasecmp(right(foundfilename,13), "_ciByRGBA.png") == 0 ) { // Identify type if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 ) { DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename); continue; } if( imgInfo.Format == SURFFMT_A8R8G8B8 ) // and store it to the record type = RGBA_PNG_FOR_CI; else // Type is not supported, go on with the next one continue; } // Detect the texture type by its extention else if( strcasecmp(right(foundfilename,16), "_allciByRGBA.png") == 0 ) { // Identify type if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 ) { DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename); continue; } if( imgInfo.Format == SURFFMT_A8R8G8B8 ) // and store it to the record type = RGBA_PNG_FOR_ALL_CI; else // Type not supported, go on with next one continue; } // Detect the texture type by its extention else if( strcasecmp(right(foundfilename,8), "_rgb.png") == 0 ) { // Identify type if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 ) { DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename); continue; } // Store type to the record type = RGB_PNG; char filename2[PATH_MAX]; // Assemble the file name for the separate alpha channel file strcpy(filename2,texturefilename); strcpy(filename2+strlen(filename2)-8,"_a.png"); // Check if the file actually exists if( PathFileExists(filename2) ) { // Check if the file with this name is actually a texture (well an alpha channel one) if( GetImageInfoFromFile(filename2, &imgInfo2) != 0 ) { // Nope, it isn't. => Go on with the next file DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", filename2); continue; } // Yes it is a texture file. Check if the size of the alpha channel is the same as the one of the texture if( extraCheck && (imgInfo2.Width != imgInfo.Width || imgInfo2.Height != imgInfo.Height) ) { // Nope, it isn't => go on with next file DebugMessage(M64MSG_WARNING, "RGB and alpha texture size mismatch: %s", filename2); continue; } bSeparatedAlpha = true; } } // Detect the texture type by its extention else if( strcasecmp(right(foundfilename,8), "_all.png") == 0 ) { // Check if texture is of expected type if( GetImageInfoFromFile(texturefilename, &imgInfo) != 0 ) { DebugMessage(M64MSG_WARNING, "Cannot get image info for file: %s", foundfilename); // Nope, continue with next file continue; } // Indicate file type type = RGB_WITH_ALPHA_TOGETHER_PNG; } // If a known texture format has been detected... if( type != NO_TEXTURE ) { /* Try to read image information here. (CASTLEVANIA2)#(58E2333F)#(2)#(0)#(D7A5C6D9)_ciByRGBA.png (------1-----)#(---2----)#(3)#(4)#(---5----)_ciByRGBA.png 1. Internal ROM name 2. The DRAM CRC 3. The image pixel size (8b=0, 16b=1, 24b=2, 32b=3) 4. The texture format (RGBA=0, YUV=1, CI=2, IA=3, I=4) 5. The palette CRC ##<24bit>##_ciByRGBA.png */ // Get the actual file name strcpy(texturefilename, foundfilename); // Place the pointer before the DRAM-CRC (first occurrence of '#') char *ptr = strchr(texturefilename,'#'); // Terminate the string ('0' means end of string - or in this case begin of string) *ptr++ = 0; if( type == RGBA_PNG_FOR_CI ) { // Extract the information from the file name; information is: // sscanf(ptr,"%8c#%d#%d#%8c", crcstr, &fmt, &siz,crcstr2); // Terminate the ascii represntation of the palette crc crcstr2[8] = 0; // Transform the ascii presentation of the hex value to an unsigned integer palcrc32 = strtoul(crcstr2,NULL,16); } else { // Extract the information from the file name - this file does not have a palette crc; information is: // // o gosh, commenting source code is really boring - but necessary!! Thus do it! (and don't use drugs ;-)) sscanf(ptr,"%8c#%d#%d", crcstr, &fmt, &siz); // Use dummy for palette crc - that way each texture can be handled in a heterogeneous way palcrc32 = 0xFFFFFFFF; } // Terminate the ascii represntation of the texture crc crcstr[8]=0; // Transform the ascii presentation of the hex value to an unsigned integer crc = strtoul(crcstr,NULL,16); // For the detection of an existing item int foundIdx = -1; for( int k=0; k uint64 crc64 = newinfo.crc32; crc64 <<= 32; if (options.bLoadHiResCRCOnly) crc64 |= newinfo.pal_crc32&0xFFFFFFFF; else crc64 |= (newinfo.pal_crc32&0xFFFFFF00)|(newinfo.fmt<<4)|newinfo.siz; // Add the new record to the list infos.add(crc64,newinfo); } } } while(foundfilename != NULL); osal_search_dir_close(dir); } /******************************************************************************************************************** * Checks if a folder is actually existant. If not, it tries to create this folder * parameter: * pathname: the name of the folder that should be checked or created if not existant * return: * return value: flag that indicates true if the folder is existant or could be created. If none was the case, * false will be returned ********************************************************************************************************************/ bool CheckAndCreateFolder(const char* pathname) { // Check if provided folder already exists if( !PathFileExists((char*)pathname) ) { // It didn't. Try creating it. if (osal_mkdirp(pathname, 0700) != 0) { // It didn't work (probably insufficient permissions or read-only media) ==> return false DebugMessage(M64MSG_WARNING, "Can not create new folder: %s", pathname); return false; } } // success return true; } // microdev: THIS HAS TO BE CLEANED UP... // Texture dumping filenaming // GameName_FrameCount_CRC_Fmt_Siz.bmp // File format: BMP // GameName: N64 game internal name // CRC: 32 bit, 8 hex digits // Fmt: 0 - 4 // Siz: 0 - 3 const char *subfolders[] = { "png_all", "png_by_rgb_a", "ci_bmp", "ci_bmp_with_pal_crc", "ci_by_png", }; void FindAllDumpedTextures(void) { char foldername[PATH_MAX + 64]; strncpy(foldername, ConfigGetUserDataPath(), PATH_MAX); foldername[PATH_MAX] = 0; if (foldername[strlen(foldername) - 1] != OSAL_DIR_SEPARATOR_CHAR) strcat(foldername, OSAL_DIR_SEPARATOR_STR); strcat(foldername,"texture_dump" OSAL_DIR_SEPARATOR_STR); CheckAndCreateFolder(foldername); strcat(foldername,(const char*)g_curRomInfo.szGameName); strcat(foldername, OSAL_DIR_SEPARATOR_STR); gTxtrDumpInfos.clear(); if( !PathFileExists(foldername) ) { CheckAndCreateFolder(foldername); char foldername2[PATH_MAX]; for( int i=0; i<5; i++) { strcpy(foldername2,foldername); strcat(foldername2,subfolders[i]); CheckAndCreateFolder(foldername2); } return; } else { gTxtrDumpInfos.clear(); FindAllTexturesFromFolder(foldername,gTxtrDumpInfos, false, true); char foldername2[PATH_MAX]; for( int i=0; i<5; i++) { strcpy(foldername2,foldername); strcat(foldername2,subfolders[i]); CheckAndCreateFolder(foldername2); } } } /******************************************************************************************************************** * Truncates the current list with information about hires textures and scans the hires folder for hires textures and * creates a list with records of properties of the hires textures. * parameter: * none * return: * none ********************************************************************************************************************/ void FindAllHiResTextures(void) { char foldername[PATH_MAX + 64]; strncpy(foldername, ConfigGetUserDataPath(), PATH_MAX); foldername[PATH_MAX] = 0; // Assure that a backslash exists at the end (should be handled by GetPluginDir()) if(foldername[strlen(foldername) - 1] != OSAL_DIR_SEPARATOR_CHAR) strcat(foldername, OSAL_DIR_SEPARATOR_STR); // Add the relative path to the hires folder strcat(foldername,"hires_texture" OSAL_DIR_SEPARATOR_STR); // It does not exist? => Create it CheckAndCreateFolder(foldername); // Add the path to a sub-folder corresponding to the rom name // HOOK IN: PACK SELECT strcat(foldername,(const char*)g_curRomInfo.szGameName); strcat(foldername, OSAL_DIR_SEPARATOR_STR); // Truncate the current list with the hires texture info gHiresTxtrInfos.clear(); if (!osal_is_directory(foldername)) { DebugMessage(M64MSG_WARNING, "Couldn't open hi-res texture directory: %s", foldername); return; } else { // Find all hires textures and also cache them if configured to do so FindAllTexturesFromFolder(foldername,gHiresTxtrInfos, true, true); } } void CloseHiresTextures(void) { for( int i=0; i= entry.ti.HeightToLoad*(1<= entry.ti.WidthToLoad*(1< &infos, TxtrCacheEntry &entry, int &indexa, int &scaleShift, bool bForDump = false) { if ((entry.ti.WidthToLoad != 0 && entry.ti.WidthToCreate / entry.ti.WidthToLoad > 2) || (entry.ti.HeightToLoad != 0 && entry.ti.HeightToCreate / entry.ti.HeightToLoad > 2 )) { //DebugMessage(M64MSG_WARNING, "Hires texture does not support extreme texture replication"); return -1; } // determine if texture is a color-indexed (CI) texture bool bCI = (gRDP.otherMode.text_tlut>=2 || entry.ti.Format == TXT_FMT_CI || entry.ti.Format == TXT_FMT_RGBA) && entry.ti.Size <= TXT_SIZE_8b; // generate two alternative ids uint64 crc64a = entry.dwCRC; crc64a <<= 32; uint64 crc64b = crc64a; if (options.bLoadHiResCRCOnly) { crc64a |= (0xFFFFFFFF); crc64b |= (entry.dwPalCRC&0xFFFFFFFF); } else { crc64a |= (0xFFFFFF00|(entry.ti.Format<<4)|entry.ti.Size); crc64b |= ((entry.dwPalCRC&0xFFFFFF00)|(entry.ti.Format<<4)|entry.ti.Size); } // infos is the list containing the references to the detected external textures // get the number of items contained in this list int infosize = infos.size(); int indexb=-1; // try to identify the external texture that // corresponds to the original texture indexa = infos.find(crc64a); // For CI without pal CRC, and for RGBA_PNG_FOR_ALL_CI if( bCI ) // and also for textures with separate alpha channel indexb = infos.find(crc64b); // For CI or PNG with pal CRC // did not found the ext. text. if( indexa >= infosize ) indexa = -1; // did not found the ext. text. w/ sep. alpha channel if( indexb >= infosize ) indexb = -1; scaleShift = -1; // found texture with sep. alpha channel if( indexb >= 0 ) { // determine the factor for scaling scaleShift = FindScaleFactor(infos[indexb], entry); // ok. the scale factor is supported. A valid replacement has been found if( scaleShift >= 0 ) return indexb; } // if texture is 4bit, should be dumped and there is no match in the list of external textures if( bForDump && bCI && indexb < 0) // than return that there is no replacement & therefore texture can be dumped (microdev: not sure about that...) return -1; // texture has no separate alpha channel, try to find it in the ext. text. list if( indexa >= 0 ) scaleShift = FindScaleFactor(infos[indexa], entry); // ok. the scale factor is supported. A valid replacement has been found // this is a texture without ext. alpha channel if( scaleShift >= 0 ) return indexa; // no luck at all. there is no valid replacement else return -1; } bool SaveCITextureToFile(TxtrCacheEntry &entry, char *filename, bool bShow, bool bWhole); void DumpCachedTexture( TxtrCacheEntry &entry ) { char cSep = '/'; CTexture *pSrcTexture = entry.pTexture; if( pSrcTexture ) { // Check the vector table int ciidx, scaleShift; if( CheckTextureInfos(gTxtrDumpInfos,entry,ciidx,scaleShift,true) >= 0 ) return; // This texture has been dumpped char filename1[PATH_MAX + 64]; char filename2[PATH_MAX + 64]; char filename3[PATH_MAX + 64]; char gamefolder[PATH_MAX + 64]; strncpy(gamefolder, ConfigGetUserDataPath(), PATH_MAX); gamefolder[PATH_MAX] = 0; strcat(gamefolder,"texture_dump" OSAL_DIR_SEPARATOR_STR); strcat(gamefolder,(const char*)g_curRomInfo.szGameName); strcat(gamefolder, OSAL_DIR_SEPARATOR_STR); //sprintf(filename1+strlen(filename1), "%08X#%d#%d", entry.dwCRC, entry.ti.Format, entry.ti.Size); sprintf(filename1, "%s%s#%08X#%d#%d", gamefolder, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size); if( (gRDP.otherMode.text_tlut>=2 || entry.ti.Format == TXT_FMT_CI || entry.ti.Format == TXT_FMT_RGBA) && entry.ti.Size <= TXT_SIZE_8b ) { if( ciidx < 0 ) { sprintf(filename1, "%sci_bmp%c%s#%08X#%d#%d_ci", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size); SaveCITextureToFile(entry, filename1, false, false); } sprintf(filename1, "%sci_bmp_with_pal_crc%c%s#%08X#%d#%d#%08X_ci", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size,entry.dwPalCRC); SaveCITextureToFile(entry, filename1, false, false); sprintf(filename1, "%sci_by_png%c%s#%08X#%d#%d#%08X_ciByRGBA", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size,entry.dwPalCRC); CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename1, TXT_RGBA, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad); } else { sprintf(filename1, "%spng_by_rgb_a%c%s#%08X#%d#%d_rgb", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size); sprintf(filename2, "%spng_by_rgb_a%c%s#%08X#%d#%d_a", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size); sprintf(filename3, "%spng_all%c%s#%08X#%d#%d_all", gamefolder, cSep, g_curRomInfo.szGameName, entry.dwCRC, entry.ti.Format, entry.ti.Size); CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename1, TXT_RGB, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad); CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename3, TXT_RGBA, false, false, entry.ti.WidthToLoad, entry.ti.HeightToLoad); if( entry.ti.Format != TXT_FMT_I ) { DrawInfo srcInfo; uint32 aFF = 0xFF; if( pSrcTexture->StartUpdate(&srcInfo) ) { // Copy RGB to buffer for( int i=entry.ti.HeightToLoad-1; i>=0; i--) { unsigned char *pSrc = (unsigned char*)srcInfo.lpSurface+srcInfo.lPitch * i; for( uint32 j=0; jEndUpdate(&srcInfo); } if( aFF != 0xFF) CRender::g_pRender->SaveTextureToFile(*pSrcTexture, filename2, TXT_ALPHA, false, false); } } ExtTxtrInfo newinfo; newinfo.width = entry.ti.WidthToLoad; newinfo.height = entry.ti.HeightToLoad; //strcpy(newinfo.name,g_curRomInfo.szGameName); newinfo.fmt = entry.ti.Format; newinfo.siz = entry.ti.Size; newinfo.crc32 = entry.dwCRC; newinfo.pal_crc32 = entry.dwPalCRC; newinfo.foldername = NULL; newinfo.filename = NULL; newinfo.filename_a = NULL; newinfo.type = NO_TEXTURE; newinfo.bSeparatedAlpha = false; uint64 crc64 = newinfo.crc32; crc64 <<= 32; if (options.bLoadHiResCRCOnly) crc64 |= newinfo.pal_crc32&0xFFFFFFFF; else crc64 |= (newinfo.pal_crc32&0xFFFFFF00)|(newinfo.fmt<<4)|newinfo.siz; gTxtrDumpInfos.add(crc64,newinfo); } } bool LoadRGBBufferFromPNGFile(char *filename, unsigned char **pbuf, int &width, int &height, int bits_per_pixel = 24 ) { struct BMGImageStruct img; memset(&img, 0, sizeof(BMGImageStruct)); if (!PathFileExists(filename)) { DebugMessage(M64MSG_ERROR, "File at '%s' doesn't exist in LoadRGBBufferFromPNGFile!", filename); return false; } BMG_Error code = ReadPNG( filename, &img ); if( code == BMG_OK ) { *pbuf = NULL; *pbuf = new unsigned char[img.width*img.height*bits_per_pixel/8]; if (*pbuf == NULL) { DebugMessage(M64MSG_ERROR, "new[] returned NULL for image width=%i height=%i bpp=%i", img.width, img.height, bits_per_pixel); return false; } if (img.bits_per_pixel == bits_per_pixel) { memcpy(*pbuf, img.bits, img.width*img.height*bits_per_pixel/8); } else if (img.bits_per_pixel == 24 && bits_per_pixel == 32) { unsigned char *pSrc = img.bits; unsigned char *pDst = *pbuf; for (int i = 0; i < (int)(img.width*img.height); i++) { *pDst++ = *pSrc++; *pDst++ = *pSrc++; *pDst++ = *pSrc++; *pDst++ = 0; } } // loaded image has alpha, needed image has to be without alpha channel else if (img.bits_per_pixel == 32 && bits_per_pixel == 24) { // pointer to source image data unsigned char *pSrc = img.bits; // buffer for destination image unsigned char *pDst = *pbuf; // copy data of the loaded image to the buffer by skipping the alpha byte for (int i = 0; i < (int)(img.width*img.height); i++) { // copy R *pDst++ = *pSrc++; // copy G *pDst++ = *pSrc++; // copy B *pDst++ = *pSrc++; // skip the alpha byte of the loaded image pSrc++; } } else if (img.bits_per_pixel == 8 && (bits_per_pixel == 24 || bits_per_pixel == 32)) { // do palette lookup and convert 8bpp to 24/32bpp int destBytePP = bits_per_pixel / 8; int paletteBytePP = img.bytes_per_palette_entry; unsigned char *pSrc = img.bits; unsigned char *pDst = *pbuf; // clear the destination image data (just to clear alpha if bpp=32) memset(*pbuf, 0, img.width*img.height*destBytePP); for (int i = 0; i < (int)(img.width*img.height); i++) { unsigned char clridx = *pSrc++; unsigned char *palcolor = img.palette + clridx * paletteBytePP; pDst[0] = palcolor[2]; // red pDst[1] = palcolor[1]; // green pDst[2] = palcolor[0]; // blue pDst += destBytePP; } } else { DebugMessage(M64MSG_ERROR, "PNG file '%s' is %i bpp but texture is %i bpp.", filename, img.bits_per_pixel, bits_per_pixel); delete [] *pbuf; *pbuf = NULL; } width = img.width; height = img.height; FreeBMGImage(&img); return true; } else { DebugMessage(M64MSG_ERROR, "ReadPNG() returned error for '%s' in LoadRGBBufferFromPNGFile!", filename); *pbuf = NULL; return false; } } bool LoadRGBABufferFromColorIndexedFile(char *filename, TxtrCacheEntry &entry, unsigned char **pbuf, int &width, int &height) { BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; FILE *f; f = fopen(filename, "rb"); if(f != NULL) { if (fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f) != 1 || fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f) != 1) { DebugMessage(M64MSG_ERROR, "Couldn't read BMP headers in file '%s'", filename); return false; } if( infoHeader.biBitCount != 4 && infoHeader.biBitCount != 8 ) { fclose(f); DebugMessage(M64MSG_ERROR, "Unsupported BMP file format: %s", filename); *pbuf = NULL; return false; } int tablesize = infoHeader.biBitCount == 4 ? 16 : 256; uint32 *pTable = new uint32[tablesize]; if (fread(pTable, tablesize*4, 1, f) != 1) { DebugMessage(M64MSG_ERROR, "Couldn't read BMP palette in file '%s'", filename); delete [] pTable; return false; } // Create the pallette table uint16 * pPal = (uint16 *)entry.ti.PalAddress; if( entry.ti.Size == TXT_SIZE_4b ) { // 4-bit table for( int i=0; i<16; i++ ) { pTable[i] = entry.ti.TLutFmt == TLUT_FMT_RGBA16 ? Convert555ToRGBA(pPal[i^1]) : ConvertIA16ToRGBA(pPal[i^1]); } } else { // 8-bit table for( int i=0; i<256; i++ ) { pTable[i] = entry.ti.TLutFmt == TLUT_FMT_RGBA16 ? Convert555ToRGBA(pPal[i^1]) : ConvertIA16ToRGBA(pPal[i^1]); } } *pbuf = new unsigned char[infoHeader.biWidth*infoHeader.biHeight*4]; if( *pbuf ) { unsigned char *colorIdxBuf = new unsigned char[infoHeader.biSizeImage]; if( colorIdxBuf ) { if (fread(colorIdxBuf, infoHeader.biSizeImage, 1, f) != 1) { DebugMessage(M64MSG_ERROR, "Couldn't read BMP image data in file '%s'", filename); } width = infoHeader.biWidth; height = infoHeader.biHeight; // Converting pallette texture to RGBA texture int idx = 0; uint32 *pbuf2 = (uint32*) *pbuf; for( int i=height-1; i>=0; i--) { for( int j=0; j>1]&0xF]; } else { // 0 *pbuf2++ = pTable[(colorIdxBuf[(idx++)>>1]>>4)&0xF]; } } else { // 8 bits *pbuf2++ = pTable[colorIdxBuf[idx++]]; } } if( entry.ti.Size == TXT_SIZE_4b ) { if( idx%8 ) idx = (idx/8+1)*8; } else { if( idx%4 ) idx = (idx/4+1)*4; } } delete [] colorIdxBuf; } else { TRACE0("Out of memory"); } delete [] pTable; return true; } else { fclose(f); delete [] pTable; return false; } } else { // Do something TRACE1("Fail to open file %s", filename); *pbuf = NULL; return false; } } bool LoadRGBBufferFromBMPFile(char *filename, unsigned char **pbuf, int &width, int &height) { BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; FILE *f; f = fopen(filename, "rb"); if(f != NULL) { if (fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f) != 1 || fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f) != 1) { DebugMessage(M64MSG_ERROR, "Couldn't read BMP headers in file '%s'", filename); return false; } if( infoHeader.biBitCount != 24 ) { fclose(f); DebugMessage(M64MSG_ERROR, "Unsupported BMP file 16 bits format: %s", filename); *pbuf = NULL; return false; } *pbuf = new unsigned char[infoHeader.biWidth*infoHeader.biHeight*3]; if( *pbuf ) { if (fread(*pbuf, infoHeader.biWidth*infoHeader.biHeight*3, 1, f) != 1) DebugMessage(M64MSG_ERROR, "Couldn't read RGB BMP image data in file '%s'", filename); fclose(f); width = infoHeader.biWidth; height = infoHeader.biHeight; return true; } else { fclose(f); return false; } } else { // Do something DebugMessage(M64MSG_WARNING, "Fail to open file %s", filename); *pbuf = NULL; return false; } } /******************************************************* * Loads the hires equivaltent of a texture * parameter: * TxtrCacheEntry: The original texture in the texture cache * return: * none *******************************************************/ void LoadHiresTexture( TxtrCacheEntry &entry ) { // check if the external texture has already been loaded if( entry.bExternalTxtrChecked ) return; // there is already an enhanced texture (e.g. a filtered one) if( entry.pEnhancedTexture ) { // delete it from memory before loading the external one SAFE_DELETE(entry.pEnhancedTexture); } int ciidx, scaleShift; // search the index of the appropriate hires replacement texture // in the list containing the infos of the external textures // ciidx is not needed here (just needed for dumping) int idx = CheckTextureInfos(gHiresTxtrInfos,entry,ciidx,scaleShift,false); if( idx < 0 ) { // there is no hires replacement => indicate that entry.bExternalTxtrChecked = true; return; } // Load the bitmap file char filename_rgb[PATH_MAX]; char filename_a[PATH_MAX]; strcpy(filename_rgb, gHiresTxtrInfos[idx].foldername); strcat(filename_rgb, gHiresTxtrInfos[idx].filename); if (gHiresTxtrInfos[idx].filename_a) { strcpy(filename_a, gHiresTxtrInfos[idx].foldername); strcat(filename_a, gHiresTxtrInfos[idx].filename_a); } else { strcpy(filename_a, ""); } // Load BMP image to buffer_rbg unsigned char *buf_rgba = NULL; unsigned char *buf_a = NULL; int width, height; bool bResRGBA=false, bResA=false; bool bCI = ((gRDP.otherMode.text_tlut>=2 || entry.ti.Format == TXT_FMT_CI || entry.ti.Format == TXT_FMT_RGBA) && entry.ti.Size <= TXT_SIZE_8b ); switch( gHiresTxtrInfos[idx].type ) { case RGB_PNG: if( bCI ) return; else { bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height); if( bResRGBA && gHiresTxtrInfos[idx].bSeparatedAlpha ) bResA = LoadRGBBufferFromPNGFile(filename_a, &buf_a, width, height); } break; case COLOR_INDEXED_BMP: if( bCI ) bResRGBA = LoadRGBABufferFromColorIndexedFile(filename_rgb, entry, &buf_rgba, width, height); else return; break; case RGBA_PNG_FOR_CI: case RGBA_PNG_FOR_ALL_CI: if( bCI ) bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height, 32); else return; break; case RGB_WITH_ALPHA_TOGETHER_PNG: if( bCI ) return; else bResRGBA = LoadRGBBufferFromPNGFile(filename_rgb, &buf_rgba, width, height, 32); break; default: return; } if( !bResRGBA || !buf_rgba ) { DebugMessage(M64MSG_ERROR, "RGBBuffer creation failed for file '%s'.", filename_rgb); return; } // check if the alpha channel has been loaded if the texture has a separate alpha channel else if( gHiresTxtrInfos[idx].bSeparatedAlpha && !bResA ) { DebugMessage(M64MSG_ERROR, "Alpha buffer creation failed for file '%s'.", filename_a); delete [] buf_rgba; return; } // calculate the texture size magnification by comparing the N64 texture size and the hi-res texture size int scale = 1 << scaleShift; int mirrorx = 1; int mirrory = 1; int input_height_shift = height - entry.ti.HeightToLoad * scale; int input_pitch_a = width; int input_pitch_rgb = width; width = entry.ti.WidthToLoad * scale; height = entry.ti.HeightToLoad * scale; if (entry.ti.WidthToCreate/entry.ti.WidthToLoad == 2) mirrorx = 2; if (entry.ti.HeightToCreate/entry.ti.HeightToLoad == 2) mirrory = 2; entry.pEnhancedTexture = CDeviceBuilder::GetBuilder()->CreateTexture(entry.ti.WidthToCreate*scale, entry.ti.HeightToCreate*scale); DrawInfo info; if( entry.pEnhancedTexture && entry.pEnhancedTexture->StartUpdate(&info) ) { if( gHiresTxtrInfos[idx].type == RGB_PNG ) { input_pitch_rgb *= 3; input_pitch_a *= 3; if (info.lPitch < width * 4) DebugMessage(M64MSG_ERROR, "Texture pitch %i less than width %i times 4", info.lPitch, width); if (height > info.dwHeight) DebugMessage(M64MSG_ERROR, "Texture source height %i greater than destination height %i", height, info.dwHeight); // Update the texture by using the buffer for( int i=0; i=0; i--) { uint32 *pRGB = (uint32*)(buf_rgba + (input_height_shift + i) * input_pitch_rgb); uint32 *pdst = (uint32*)((unsigned char*)info.lpSurface + (height - i - 1)*info.lPitch); for( int j=0; jm_dwCreatedTextureWidth, height, T_FLAG, 4 ); } if( entry.ti.WidthToCreate*scale < entry.pEnhancedTexture->m_dwCreatedTextureWidth ) { // Clamp gTextureManager.Clamp(info.lpSurface, width, entry.pEnhancedTexture->m_dwCreatedTextureWidth, entry.pEnhancedTexture->m_dwCreatedTextureWidth, height, S_FLAG, 4 ); } if( entry.ti.HeightToCreate*scale < entry.pEnhancedTexture->m_dwCreatedTextureHeight ) { // Clamp gTextureManager.Clamp(info.lpSurface, height, entry.pEnhancedTexture->m_dwCreatedTextureHeight, entry.pEnhancedTexture->m_dwCreatedTextureWidth, height, T_FLAG, 4 ); } entry.pEnhancedTexture->EndUpdate(&info); entry.pEnhancedTexture->m_bIsEnhancedTexture = true; entry.dwEnhancementFlag = TEXTURE_EXTERNAL; DebugMessage(M64MSG_VERBOSE, "Loaded hi-res texture: %s", filename_rgb); } else { DebugMessage(M64MSG_ERROR, "New texture creation failed."); TRACE0("Cannot create a new texture"); } if( buf_rgba ) { delete [] buf_rgba; } if( buf_a ) { delete [] buf_a; } } mupen64plus-video-rice-src-2.6.0/src/TextureFilters.h000066400000000000000000000062561464507324400225050ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __FILTERS_H__ #define __FILTERS_H__ #include "Config.h" #include "Texture.h" #include "TextureManager.h" #include "typedefs.h" #define DWORD_MAKE(r, g, b, a) ((uint32) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))) #define WORD_MAKE(r, g, b, a) ((uint16) (((a) << 12) | ((r) << 8) | ((g) << 4) | (b))) extern void InitExternalTextures(void); extern void CloseExternalTextures(void); void Texture2x_32( DrawInfo &srcInfo, DrawInfo &destInfo); void Texture2x_16( DrawInfo &srcInfo, DrawInfo &destInfo); void Texture2x_Interp_32( DrawInfo &srcInfo, DrawInfo &destInfo); void Texture2x_Interp_16( DrawInfo &srcInfo, DrawInfo &destInfo); void Super2xSaI_32( uint32 *srcPtr, uint32 *destPtr, uint32 width, uint32 height, uint32 pitch); void Super2xSaI_16( uint16 *srcPtr, uint16 *destPtr, uint32 width, uint32 height, uint32 pitch); void hq4x_16( unsigned char * pIn, unsigned char * pOut, int Xres, int Yres, int SrcPPL, int BpL ); void hq4x_32( unsigned char * pIn, unsigned char * pOut, int Xres, int Yres, int SrcPPL, int BpL ); void hq4x_InitLUTs(void); void SmoothFilter_32(uint32 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter=TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1); void SmoothFilter_16(uint16 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter=TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1); void SharpenFilter_32(uint32 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter=TEXTURE_SHARPEN_ENHANCEMENT); void SharpenFilter_16(uint16 *pdata, uint32 width, uint32 height, uint32 pitch, uint32 filter=TEXTURE_SHARPEN_ENHANCEMENT); void hq2x_init(unsigned bits_per_pixel); void hq2x_16(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height); void hq2x_32(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height); void lq2x_16(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height); void lq2x_32(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height); typedef enum _IMAGE_FILEFORMAT { XIFF_BMP = 0, XIFF_JPG = 1, XIFF_TGA = 2, XIFF_PNG = 3, XIFF_DDS = 4, XIFF_PPM = 5, XIFF_DIB = 6, XIFF_HDR = 7, XIFF_PFM = 8, XIFF_FORCE_DWORD = 0x7fffffff } IMAGE_FILEFORMAT; typedef struct _IMAGE_INFO { unsigned int Width; unsigned int Height; unsigned int Depth; unsigned int MipLevels; int Format; /* SURFFORMAT */ IMAGE_FILEFORMAT ImageFileFormat; } IMAGE_INFO; #endif mupen64plus-video-rice-src-2.6.0/src/TextureFilters_2xsai.cpp000066400000000000000000000325051464507324400241420ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "TextureFilters.h" #include "typedefs.h" /************************************************************************/ /* 2xSAI filters */ /************************************************************************/ static __inline int SAI_GetResult_32( uint32 A, uint32 B, uint32 C, uint32 D ) { int x = 0; int y = 0; int r = 0; if (A == C) x += 1; else if (B == C) y += 1; if (A == D) x += 1; else if (B == D) y += 1; if (x <= 1) r += 1; if (y <= 1) r -= 1; return r; } static __inline uint16 SAI_GetResult_16( uint16 A, uint16 B, uint16 C, uint16 D ) { uint16 x = 0; uint16 y = 0; uint16 r = 0; if (A == C) x += 1; else if (B == C) y += 1; if (A == D) x += 1; else if (B == D) y += 1; if (x <= 1) r += 1; if (y <= 1 && r>0 ) r -= 1; return r; } static __inline uint32 SAI_INTERPOLATE_32( uint32 A, uint32 B) { if (A != B) return ((A & 0xFEFEFEFE) >> 1) + (((B & 0xFEFEFEFE) >> 1) | (A & B & 0x01010101)); else return A; } static __inline uint16 SAI_INTERPOLATE_16( uint16 A, uint16 B) { if (A != B) return ((A & 0xFEFE) >> 1) + (((B & 0xFEFE) >> 1) | (A & B & 0x0101)); else return A; } static __inline uint32 SAI_Q_INTERPOLATE_32( uint32 A, uint32 B, uint32 C, uint32 D) { uint32 x = ((A & 0xFCFCFCFC) >> 2) + ((B & 0xFCFCFCFC) >> 2) + ((C & 0xFCFCFCFC) >> 2) + ((D & 0xFCFCFCFC) >> 2); uint32 y = (((A & 0x03030303) + (B & 0x03030303) + (C & 0x03030303) + (D & 0x03030303)) >> 2) & 0x03030303; return x | y; } static __inline uint16 SAI_Q_INTERPOLATE_16( uint16 A, uint16 B, uint16 C, uint16 D) { uint16 x = ((A & 0xFCFC) >> 2) + ((B & 0xFCFC) >> 2) + ((C & 0xFCFC) >> 2) + ((D & 0xFCFC) >> 2); uint16 y = (((A & 0x0303) + (B & 0x0303) + (C & 0x0303) + (D & 0x0303)) >> 2) & 0x0303; return x | y; } void Super2xSaI_32( uint32 *srcPtr, uint32 *destPtr, uint32 width, uint32 height, uint32 pitch) { uint32 destWidth = width << 1; //uint32 destHeight = height << 1; uint32 color4, color5, color6; uint32 color1, color2, color3; uint32 colorA0, colorA1, colorA2, colorA3; uint32 colorB0, colorB1, colorB2, colorB3; uint32 colorS1, colorS2; uint32 product1a, product1b, product2a, product2b; int row0, row1, row2, row3; int col0, col1, col2, col3; for (uint16 y = 0; y < height; y++) { if (y > 0) { row0 = width; row0 = -row0; } else row0 = 0; row1 = 0; if (y < height - 1) { row2 = width; if (y < height - 2) row3 = width << 1; else row3 = width; } else { row2 = 0; row3 = 0; } for (uint16 x = 0; x < width; x++) { //--------------------------------------- B0 B1 B2 B3 // 4 5 6 S2 // 1 2 3 S1 // A0 A1 A2 A3 if (x > 0) col0 = -1; else col0 = 0; col1 = 0; if (x < width - 1) { col2 = 1; if (x < width - 2) col3 = 2; else col3 = 1; } else { col2 = 0; col3 = 0; } colorB0 = *(srcPtr + col0 + row0); colorB1 = *(srcPtr + col1 + row0); colorB2 = *(srcPtr + col2 + row0); colorB3 = *(srcPtr + col3 + row0); color4 = *(srcPtr + col0 + row1); color5 = *(srcPtr + col1 + row1); color6 = *(srcPtr + col2 + row1); colorS2 = *(srcPtr + col3 + row1); color1 = *(srcPtr + col0 + row2); color2 = *(srcPtr + col1 + row2); color3 = *(srcPtr + col2 + row2); colorS1 = *(srcPtr + col3 + row2); colorA0 = *(srcPtr + col0 + row3); colorA1 = *(srcPtr + col1 + row3); colorA2 = *(srcPtr + col2 + row3); colorA3 = *(srcPtr + col3 + row3); //-------------------------------------- if (color2 == color6 && color5 != color3) product2b = product1b = color2; else if (color5 == color3 && color2 != color6) product2b = product1b = color5; else if (color5 == color3 && color2 == color6) { int r = 0; r += SAI_GetResult_32 (color6, color5, color1, colorA1); r += SAI_GetResult_32 (color6, color5, color4, colorB1); r += SAI_GetResult_32 (color6, color5, colorA2, colorS1); r += SAI_GetResult_32 (color6, color5, colorB2, colorS2); if (r > 0) product2b = product1b = color6; else if (r < 0) product2b = product1b = color5; else product2b = product1b = SAI_INTERPOLATE_32 (color5, color6); } else { if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0) product2b = SAI_Q_INTERPOLATE_32 (color3, color3, color3, color2); else if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3) product2b = SAI_Q_INTERPOLATE_32 (color2, color2, color2, color3); else product2b = SAI_INTERPOLATE_32 (color2, color3); if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0) product1b = SAI_Q_INTERPOLATE_32 (color6, color6, color6, color5); else if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3) product1b = SAI_Q_INTERPOLATE_32 (color6, color5, color5, color5); else product1b = SAI_INTERPOLATE_32 (color5, color6); } if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2) product2a = SAI_INTERPOLATE_32 (color2, color5); else if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0) product2a = SAI_INTERPOLATE_32(color2, color5); else product2a = color2; if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2) product1a = SAI_INTERPOLATE_32 (color2, color5); else if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0) product1a = SAI_INTERPOLATE_32(color2, color5); else product1a = color5; destPtr[0] = product1a; destPtr[1] = product1b; destPtr[destWidth] = product2a; destPtr[destWidth + 1] = product2b; srcPtr++; destPtr += 2; } srcPtr += (pitch-width); destPtr += (((pitch-width)<<1)+(pitch<<1)); } } void Super2xSaI_16( uint16 *srcPtr, uint16 *destPtr, uint32 width, uint32 height, uint32 pitch) { uint32 destWidth = width << 1; //uint32 destHeight = height << 1; uint16 color4, color5, color6; uint16 color1, color2, color3; uint16 colorA0, colorA1, colorA2, colorA3; uint16 colorB0, colorB1, colorB2, colorB3; uint16 colorS1, colorS2; uint16 product1a, product1b, product2a, product2b; int row0, row1, row2, row3; int col0, col1, col2, col3; for (uint16 y = 0; y < height; y++) { if (y > 0) { row0 = width; row0 = -row0; } else row0 = 0; row1 = 0; if (y < height - 1) { row2 = width; if (y < height - 2) row3 = width << 1; else row3 = width; } else { row2 = 0; row3 = 0; } for (uint16 x = 0; x < width; x++) { //--------------------------------------- B0 B1 B2 B3 // 4 5 6 S2 // 1 2 3 S1 // A0 A1 A2 A3 if (x > 0) col0 = -1; else col0 = 0; col1 = 0; if (x < width - 1) { col2 = 1; if (x < width - 2) col3 = 2; else col3 = 1; } else { col2 = 0; col3 = 0; } colorB0 = *(srcPtr + col0 + row0); colorB1 = *(srcPtr + col1 + row0); colorB2 = *(srcPtr + col2 + row0); colorB3 = *(srcPtr + col3 + row0); color4 = *(srcPtr + col0 + row1); color5 = *(srcPtr + col1 + row1); color6 = *(srcPtr + col2 + row1); colorS2 = *(srcPtr + col3 + row1); color1 = *(srcPtr + col0 + row2); color2 = *(srcPtr + col1 + row2); color3 = *(srcPtr + col2 + row2); colorS1 = *(srcPtr + col3 + row2); colorA0 = *(srcPtr + col0 + row3); colorA1 = *(srcPtr + col1 + row3); colorA2 = *(srcPtr + col2 + row3); colorA3 = *(srcPtr + col3 + row3); //-------------------------------------- if (color2 == color6 && color5 != color3) product2b = product1b = color2; else if (color5 == color3 && color2 != color6) product2b = product1b = color5; else if (color5 == color3 && color2 == color6) { int r = 0; r += SAI_GetResult_16 (color6, color5, color1, colorA1); r += SAI_GetResult_16 (color6, color5, color4, colorB1); r += SAI_GetResult_16 (color6, color5, colorA2, colorS1); r += SAI_GetResult_16 (color6, color5, colorB2, colorS2); if (r > 0) product2b = product1b = color6; else if (r < 0) product2b = product1b = color5; else product2b = product1b = SAI_INTERPOLATE_16 (color5, color6); } else { if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0) product2b = SAI_Q_INTERPOLATE_16 (color3, color3, color3, color2); else if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3) product2b = SAI_Q_INTERPOLATE_16 (color2, color2, color2, color3); else product2b = SAI_INTERPOLATE_16 (color2, color3); if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0) product1b = SAI_Q_INTERPOLATE_16 (color6, color6, color6, color5); else if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3) product1b = SAI_Q_INTERPOLATE_16 (color6, color5, color5, color5); else product1b = SAI_INTERPOLATE_16 (color5, color6); } if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2) product2a = SAI_INTERPOLATE_16 (color2, color5); else if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0) product2a = SAI_INTERPOLATE_16(color2, color5); else product2a = color2; if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2) product1a = SAI_INTERPOLATE_16 (color2, color5); else if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0) product1a = SAI_INTERPOLATE_16(color2, color5); else product1a = color5; destPtr[0] = product1a; destPtr[1] = product1b; destPtr[destWidth] = product2a; destPtr[destWidth + 1] = product2b; srcPtr++; destPtr += 2; } srcPtr += (pitch-width); destPtr += (((pitch-width)<<1)+(pitch<<1)); } } mupen64plus-video-rice-src-2.6.0/src/TextureFilters_hq2x.cpp000066400000000000000000000413161464507324400237760ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - TextureFilters_hq2x.cpp * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "typedefs.h" /************************************************************************/ /* hq2x filters */ /************************************************************************/ /***************************************************************************/ /* Basic types */ /***************************************************************************/ /* interpolation */ static unsigned interp_bits_per_pixel; #define INTERP_16_MASK_1_3(v) ((v)&0x0F0F) #define INTERP_16_MASK_SHIFT_2_4(v) (((v)&0xF0F0)>>4) #define INTERP_16_MASK_SHIFTBACK_2_4(v) ((INTERP_16_MASK_1_3(v))<<4) static inline uint16 hq2x_interp_16_521(uint16 p1, uint16 p2, uint16 p3) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*5 + INTERP_16_MASK_1_3(p2)*2 + INTERP_16_MASK_1_3(p3)*1) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*5 + INTERP_16_MASK_SHIFT_2_4(p2)*2 + INTERP_16_MASK_SHIFT_2_4(p3)*1) / 8); } static inline uint16 hq2x_interp_16_332(uint16 p1, uint16 p2, uint16 p3) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*3 + INTERP_16_MASK_1_3(p2)*3 + INTERP_16_MASK_1_3(p3)*2) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*3 + INTERP_16_MASK_SHIFT_2_4(p2)*3 + INTERP_16_MASK_SHIFT_2_4(p3)*2) / 8); } static inline uint16 hq2x_interp_16_611(uint16 p1, uint16 p2, uint16 p3) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*6 + INTERP_16_MASK_1_3(p2) + INTERP_16_MASK_1_3(p3)) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*6 + INTERP_16_MASK_SHIFT_2_4(p2) + INTERP_16_MASK_SHIFT_2_4(p3)) / 8); } static inline uint16 hq2x_interp_16_211(uint16 p1, uint16 p2, uint16 p3) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*2 + INTERP_16_MASK_1_3(p2) + INTERP_16_MASK_1_3(p3)) / 4) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*2 + INTERP_16_MASK_SHIFT_2_4(p2) + INTERP_16_MASK_SHIFT_2_4(p3)) / 4); } static inline uint16 hq2x_interp_16_31(uint16 p1, uint16 p2) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*3 + INTERP_16_MASK_1_3(p2)) / 4) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*3 + INTERP_16_MASK_SHIFT_2_4(p2)) / 4); } static inline uint16 hq2x_interp_16_1411(uint16 p1, uint16 p2, uint16 p3) { return INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*14 + INTERP_16_MASK_1_3(p2) + INTERP_16_MASK_1_3(p3)) / 16) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*14 + INTERP_16_MASK_SHIFT_2_4(p2) + INTERP_16_MASK_SHIFT_2_4(p3)) / 16); } #define INTERP_32_MASK_1_3(v) ((v)&0x00FF00FF) #define INTERP_32_MASK_SHIFT_2_4(v) (((v)&0xFF00FF00)>>8) #define INTERP_32_MASK_SHIFTBACK_2_4(v) (((INTERP_32_MASK_1_3(v))<<8)) /***************************************************************************/ /* diff */ #define INTERP_Y_LIMIT (0x30*4) #define INTERP_U_LIMIT (0x07*4) #define INTERP_V_LIMIT (0x06*8) static int hq2x_interp_16_diff(uint16 p1, uint16 p2) { int r, g, b; int y, u, v; if (p1 == p2) return 0; b = (int)((p1 & 0x000F) - (p2 & 0x000F)); g = (int)((p1 & 0x00F0) - (p2 & 0x00F0)) >> 4; r = (int)((p1 & 0x0F00) - (p2 & 0x0F00)) >> 8; y = r + g + b; u = r - b; v = -r + 2*g - b; if (y < -INTERP_Y_LIMIT || y > INTERP_Y_LIMIT) return 1; if (u < -INTERP_U_LIMIT || u > INTERP_U_LIMIT) return 1; if (v < -INTERP_V_LIMIT || v > INTERP_V_LIMIT) return 1; return 0; } static int hq2x_interp_32_diff(uint32 p1, uint32 p2) { int r, g, b; int y, u, v; if ((p1 & 0xF8F8F8) == (p2 & 0xF8F8F8)) return 0; b = (int)((p1 & 0xFF) - (p2 & 0xFF)); g = (int)((p1 & 0xFF00) - (p2 & 0xFF00)) >> 8; r = (int)((p1 & 0xFF0000) - (p2 & 0xFF0000)) >> 16; y = r + g + b; u = r - b; v = -r + 2*g - b; if (y < -INTERP_Y_LIMIT || y > INTERP_Y_LIMIT) return 1; if (u < -INTERP_U_LIMIT || u > INTERP_U_LIMIT) return 1; if (v < -INTERP_V_LIMIT || v > INTERP_V_LIMIT) return 1; return 0; } static void interp_set(unsigned bits_per_pixel) { interp_bits_per_pixel = bits_per_pixel; } static void hq2x_16_def(uint16* dst0, uint16* dst1, const uint16* src0, const uint16* src1, const uint16* src2, unsigned count) { unsigned i; for(i=0;i0) { c[0] = src0[-1]; c[3] = src1[-1]; c[6] = src2[-1]; } else { c[0] = c[1]; c[3] = c[4]; c[6] = c[7]; } if (i0) { c[0] = src0[-1]; c[3] = src1[-1]; c[6] = src2[-1]; } else { c[0] = src0[0]; c[3] = src1[0]; c[6] = src2[0]; } if (i0) { c[0] = src0[-1]; c[3] = src1[-1]; c[6] = src2[-1]; } else { c[0] = c[1]; c[3] = c[4]; c[6] = c[7]; } if (i0) { c[0] = src0[-1]; c[3] = src1[-1]; c[6] = src2[-1]; } else { c[0] = c[1]; c[3] = c[4]; c[6] = c[7]; } if (i> 1); uint16 *src0 = (uint16 *)srcPtr; uint16 *src1 = src0 + (srcPitch >> 1); uint16 *src2 = src1 + (srcPitch >> 1); hq2x_16_def(dst0, dst1, src0, src0, src1, width); if( height == 1 ) return; int count = height; count -= 2; while(count>0) { dst0 += dstPitch; dst1 += dstPitch; hq2x_16_def(dst0, dst1, src0, src1, src2, width); src0 = src1; src1 = src2; src2 += srcPitch >> 1; --count; } dst0 += dstPitch; dst1 += dstPitch; hq2x_16_def(dst0, dst1, src0, src1, src1, width); } void hq2x_32(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { uint32 *dst0 = (uint32 *)dstPtr; uint32 *dst1 = dst0 + (dstPitch >> 2); uint32 *src0 = (uint32 *)srcPtr; uint32 *src1 = src0 + (srcPitch >> 2); uint32 *src2 = src1 + (srcPitch >> 2); hq2x_32_def(dst0, dst1, src0, src0, src1, width); if( height == 1 ) return; int count = height; count -= 2; while(count>0) { dst0 += dstPitch >> 1; dst1 += dstPitch >> 1; hq2x_32_def(dst0, dst1, src0, src1, src2, width); src0 = src1; src1 = src2; src2 += srcPitch >> 2; --count; } dst0 += dstPitch >> 1; dst1 += dstPitch >> 1; hq2x_32_def(dst0, dst1, src0, src1, src1, width); } void lq2x_16(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { uint16 *dst0 = (uint16 *)dstPtr; uint16 *dst1 = dst0 + (dstPitch >> 1); uint16 *src0 = (uint16 *)srcPtr; uint16 *src1 = src0 + (srcPitch >> 1); uint16 *src2 = src1 + (srcPitch >> 1); lq2x_16_def(dst0, dst1, src0, src0, src1, width); if( height == 1 ) return; int count = height; count -= 2; while(count>0) { dst0 += dstPitch; dst1 += dstPitch; hq2x_16_def(dst0, dst1, src0, src1, src2, width); src0 = src1; src1 = src2; src2 += srcPitch >> 1; --count; } dst0 += dstPitch; dst1 += dstPitch; lq2x_16_def(dst0, dst1, src0, src1, src1, width); } void lq2x_32(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { uint32 *dst0 = (uint32 *)dstPtr; uint32 *dst1 = dst0 + (dstPitch >> 2); uint32 *src0 = (uint32 *)srcPtr; uint32 *src1 = src0 + (srcPitch >> 2); uint32 *src2 = src1 + (srcPitch >> 2); lq2x_32_def(dst0, dst1, src0, src0, src1, width); if( height == 1 ) return; int count = height; count -= 2; while(count>0) { dst0 += dstPitch >> 1; dst1 += dstPitch >> 1; hq2x_32_def(dst0, dst1, src0, src1, src2, width); src0 = src1; src1 = src2; src2 += srcPitch >> 2; --count; } dst0 += dstPitch >> 1; dst1 += dstPitch >> 1; lq2x_32_def(dst0, dst1, src0, src1, src1, width); } void hq2x_init(unsigned bits_per_pixel) { interp_set(bits_per_pixel); } /************************************************************************/ /* hq3x filters */ /************************************************************************/ /************************************************************************/ /* scale2x filters */ /************************************************************************/ /************************************************************************/ /* scale3x filters */ /************************************************************************/ mupen64plus-video-rice-src-2.6.0/src/TextureFilters_hq2x.h000066400000000000000000000645551464507324400234550ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - TextureFilters_hq2x.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2003 Rice1964 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ case 0 : case 1 : case 4 : case 5 : case 32 : case 33 : case 36 : case 37 : case 128 : case 129 : case 132 : case 133 : case 160 : case 161 : case 164 : case 165 : { P0 = I211(4, 1, 3); P1 = I211(4, 1, 5); P2 = I211(4, 3, 7); P3 = I211(4, 5, 7); } break; case 2 : case 34 : case 130 : case 162 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I211(4, 3, 7); P3 = I211(4, 5, 7); } break; case 3 : case 35 : case 131 : case 163 : { P0 = I31(4, 3); P1 = I31(4, 2); P2 = I211(4, 3, 7); P3 = I211(4, 5, 7); } break; case 6 : case 38 : case 134 : case 166 : { P0 = I31(4, 0); P1 = I31(4, 5); P2 = I211(4, 3, 7); P3 = I211(4, 5, 7); } break; case 7 : case 39 : case 135 : case 167 : { P0 = I31(4, 3); P1 = I31(4, 5); P2 = I211(4, 3, 7); P3 = I211(4, 5, 7); } break; case 8 : case 12 : case 136 : case 140 : { P0 = I31(4, 0); P1 = I211(4, 1, 5); P2 = I31(4, 6); P3 = I211(4, 5, 7); } break; case 9 : case 13 : case 137 : case 141 : { P0 = I31(4, 1); P1 = I211(4, 1, 5); P2 = I31(4, 6); P3 = I211(4, 5, 7); } break; case 10 : case 138 : { P1 = I31(4, 2); P2 = I31(4, 6); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I211(4, 1, 3); } } break; case 11 : case 139 : { P1 = I31(4, 2); P2 = I31(4, 6); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 14 : case 142 : { P2 = I31(4, 6); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = I31(4, 0); P1 = I31(4, 5); } else { P0 = I332(1, 3, 4); P1 = I521(4, 1, 5); } } break; case 15 : case 143 : { P2 = I31(4, 6); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = IC(4); P1 = I31(4, 5); } else { P0 = I332(1, 3, 4); P1 = I521(4, 1, 5); } } break; case 16 : case 17 : case 48 : case 49 : { P0 = I211(4, 1, 3); P1 = I31(4, 2); P2 = I211(4, 3, 7); P3 = I31(4, 8); } break; case 18 : case 50 : { P0 = I31(4, 0); P2 = I211(4, 3, 7); P3 = I31(4, 8); if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I211(4, 1, 5); } } break; case 19 : case 51 : { P2 = I211(4, 3, 7); P3 = I31(4, 8); if (HQ2X_MUR) { P0 = I31(4, 3); P1 = I31(4, 2); } else { P0 = I521(4, 1, 3); P1 = I332(1, 5, 4); } } break; case 20 : case 21 : case 52 : case 53 : { P0 = I211(4, 1, 3); P1 = I31(4, 1); P2 = I211(4, 3, 7); P3 = I31(4, 8); } break; case 22 : case 54 : { P0 = I31(4, 0); P2 = I211(4, 3, 7); P3 = I31(4, 8); if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 23 : case 55 : { P2 = I211(4, 3, 7); P3 = I31(4, 8); if (HQ2X_MUR) { P0 = I31(4, 3); P1 = IC(4); } else { P0 = I521(4, 1, 3); P1 = I332(1, 5, 4); } } break; case 24 : case 66 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 25 : { P0 = I31(4, 1); P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 26 : case 31 : case 95 : { P2 = I31(4, 6); P3 = I31(4, 8); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 27 : case 75 : { P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 8); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 28 : { P0 = I31(4, 0); P1 = I31(4, 1); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 29 : { P0 = I31(4, 1); P1 = I31(4, 1); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 30 : case 86 : { P0 = I31(4, 0); P2 = I31(4, 6); P3 = I31(4, 8); if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 40 : case 44 : case 168 : case 172 : { P0 = I31(4, 0); P1 = I211(4, 1, 5); P2 = I31(4, 7); P3 = I211(4, 5, 7); } break; case 41 : case 45 : case 169 : case 173 : { P0 = I31(4, 1); P1 = I211(4, 1, 5); P2 = I31(4, 7); P3 = I211(4, 5, 7); } break; case 42 : case 170 : { P1 = I31(4, 2); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = I31(4, 0); P2 = I31(4, 7); } else { P0 = I332(1, 3, 4); P2 = I521(4, 3, 7); } } break; case 43 : case 171 : { P1 = I31(4, 2); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = IC(4); P2 = I31(4, 7); } else { P0 = I332(1, 3, 4); P2 = I521(4, 3, 7); } } break; case 46 : case 174 : { P1 = I31(4, 5); P2 = I31(4, 7); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } } break; case 47 : case 175 : { P1 = I31(4, 5); P2 = I31(4, 7); P3 = I211(4, 5, 7); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } } break; case 56 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 7); P3 = I31(4, 8); } break; case 57 : { P0 = I31(4, 1); P1 = I31(4, 2); P2 = I31(4, 7); P3 = I31(4, 8); } break; case 58 : { P2 = I31(4, 7); P3 = I31(4, 8); if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 59 : { P2 = I31(4, 7); P3 = I31(4, 8); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 60 : { P0 = I31(4, 0); P1 = I31(4, 1); P2 = I31(4, 7); P3 = I31(4, 8); } break; case 61 : { P0 = I31(4, 1); P1 = I31(4, 1); P2 = I31(4, 7); P3 = I31(4, 8); } break; case 62 : { P0 = I31(4, 0); P2 = I31(4, 7); P3 = I31(4, 8); if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 63 : { P2 = I31(4, 7); P3 = I31(4, 8); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 64 : case 65 : case 68 : case 69 : { P0 = I211(4, 1, 3); P1 = I211(4, 1, 5); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 67 : { P0 = I31(4, 3); P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 70 : { P0 = I31(4, 0); P1 = I31(4, 5); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 71 : { P0 = I31(4, 3); P1 = I31(4, 5); P2 = I31(4, 6); P3 = I31(4, 8); } break; case 72 : case 76 : { P0 = I31(4, 0); P1 = I211(4, 1, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I211(4, 3, 7); } } break; case 73 : case 77 : { P1 = I211(4, 1, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P0 = I31(4, 1); P2 = I31(4, 6); } else { P0 = I521(4, 3, 1); P2 = I332(3, 7, 4); } } break; case 74 : case 107 : case 123 : { P1 = I31(4, 2); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 78 : { P1 = I31(4, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } } break; case 79 : { P1 = I31(4, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 80 : case 81 : { P0 = I211(4, 1, 3); P1 = I31(4, 2); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I211(4, 5, 7); } } break; case 82 : case 214 : case 222 : { P0 = I31(4, 0); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 83 : { P0 = I31(4, 3); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 84 : case 85 : { P0 = I211(4, 1, 3); P2 = I31(4, 6); if (HQ2X_MDR) { P1 = I31(4, 1); P3 = I31(4, 8); } else { P1 = I521(4, 5, 1); P3 = I332(5, 7, 4); } } break; case 87 : { P0 = I31(4, 3); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 88 : case 248 : case 250 : { P0 = I31(4, 0); P1 = I31(4, 2); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } } break; case 89 : { P0 = I31(4, 1); P1 = I31(4, 2); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } } break; case 90 : { if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 91 : { if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 92 : { P0 = I31(4, 0); P1 = I31(4, 1); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } } break; case 93 : { P0 = I31(4, 1); P1 = I31(4, 1); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } } break; case 94 : { if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 96 : case 97 : case 100 : case 101 : { P0 = I211(4, 1, 3); P1 = I211(4, 1, 5); P2 = I31(4, 3); P3 = I31(4, 8); } break; case 98 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 3); P3 = I31(4, 8); } break; case 99 : { P0 = I31(4, 3); P1 = I31(4, 2); P2 = I31(4, 3); P3 = I31(4, 8); } break; case 102 : { P0 = I31(4, 0); P1 = I31(4, 5); P2 = I31(4, 3); P3 = I31(4, 8); } break; case 103 : { P0 = I31(4, 3); P1 = I31(4, 5); P2 = I31(4, 3); P3 = I31(4, 8); } break; case 104 : case 108 : { P0 = I31(4, 0); P1 = I211(4, 1, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } } break; case 105 : case 109 : { P1 = I211(4, 1, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P0 = I31(4, 1); P2 = IC(4); } else { P0 = I521(4, 3, 1); P2 = I332(3, 7, 4); } } break; case 106 : case 120 : { P0 = I31(4, 0); P1 = I31(4, 2); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } } break; case 110 : { P0 = I31(4, 0); P1 = I31(4, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } } break; case 111 : { P1 = I31(4, 5); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } } break; case 112 : case 113 : { P0 = I211(4, 1, 3); P1 = I31(4, 2); if (HQ2X_MDR) { P2 = I31(4, 3); P3 = I31(4, 8); } else { P2 = I521(4, 7, 3); P3 = I332(5, 7, 4); } } break; case 114 : { P0 = I31(4, 0); P2 = I31(4, 3); if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 115 : { P0 = I31(4, 3); P2 = I31(4, 3); if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 116 : case 117 : { P0 = I211(4, 1, 3); P1 = I31(4, 1); P2 = I31(4, 3); if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } } break; case 118 : { P0 = I31(4, 0); P2 = I31(4, 3); P3 = I31(4, 8); if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 119 : { P2 = I31(4, 3); P3 = I31(4, 8); if (HQ2X_MUR) { P0 = I31(4, 3); P1 = IC(4); } else { P0 = I521(4, 1, 3); P1 = I332(1, 5, 4); } } break; case 121 : { P0 = I31(4, 1); P1 = I31(4, 2); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } } break; case 122 : { if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MDR) { P3 = I31(4, 8); } else { P3 = I611(4, 5, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 124 : { P0 = I31(4, 0); P1 = I31(4, 1); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } } break; case 125 : { P1 = I31(4, 1); P3 = I31(4, 8); if (HQ2X_MDL) { P0 = I31(4, 1); P2 = IC(4); } else { P0 = I521(4, 3, 1); P2 = I332(3, 7, 4); } } break; case 126 : { P0 = I31(4, 0); P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 127 : { P3 = I31(4, 8); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 144 : case 145 : case 176 : case 177 : { P0 = I211(4, 1, 3); P1 = I31(4, 2); P2 = I211(4, 3, 7); P3 = I31(4, 7); } break; case 146 : case 178 : { P0 = I31(4, 0); P2 = I211(4, 3, 7); if (HQ2X_MUR) { P1 = I31(4, 2); P3 = I31(4, 7); } else { P1 = I332(1, 5, 4); P3 = I521(4, 5, 7); } } break; case 147 : case 179 : { P0 = I31(4, 3); P2 = I211(4, 3, 7); P3 = I31(4, 7); if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 148 : case 149 : case 180 : case 181 : { P0 = I211(4, 1, 3); P1 = I31(4, 1); P2 = I211(4, 3, 7); P3 = I31(4, 7); } break; case 150 : case 182 : { P0 = I31(4, 0); P2 = I211(4, 3, 7); if (HQ2X_MUR) { P1 = IC(4); P3 = I31(4, 7); } else { P1 = I332(1, 5, 4); P3 = I521(4, 5, 7); } } break; case 151 : case 183 : { P0 = I31(4, 3); P2 = I211(4, 3, 7); P3 = I31(4, 7); if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 152 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 7); } break; case 153 : { P0 = I31(4, 1); P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 7); } break; case 154 : { P2 = I31(4, 6); P3 = I31(4, 7); if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 155 : { P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 7); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 156 : { P0 = I31(4, 0); P1 = I31(4, 1); P2 = I31(4, 6); P3 = I31(4, 7); } break; case 157 : { P0 = I31(4, 1); P1 = I31(4, 1); P2 = I31(4, 6); P3 = I31(4, 7); } break; case 158 : { P2 = I31(4, 6); P3 = I31(4, 7); if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 159 : { P2 = I31(4, 6); P3 = I31(4, 7); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 184 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 7); P3 = I31(4, 7); } break; case 185 : { P0 = I31(4, 1); P1 = I31(4, 2); P2 = I31(4, 7); P3 = I31(4, 7); } break; case 186 : { P2 = I31(4, 7); P3 = I31(4, 7); if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 187 : { P1 = I31(4, 2); P3 = I31(4, 7); if (HQ2X_MUL) { P0 = IC(4); P2 = I31(4, 7); } else { P0 = I332(1, 3, 4); P2 = I521(4, 3, 7); } } break; case 188 : { P0 = I31(4, 0); P1 = I31(4, 1); P2 = I31(4, 7); P3 = I31(4, 7); } break; case 189 : { P0 = I31(4, 1); P1 = I31(4, 1); P2 = I31(4, 7); P3 = I31(4, 7); } break; case 190 : { P0 = I31(4, 0); P2 = I31(4, 7); if (HQ2X_MUR) { P1 = IC(4); P3 = I31(4, 7); } else { P1 = I332(1, 5, 4); P3 = I521(4, 5, 7); } } break; case 191 : { P2 = I31(4, 7); P3 = I31(4, 7); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 192 : case 193 : case 196 : case 197 : { P0 = I211(4, 1, 3); P1 = I211(4, 1, 5); P2 = I31(4, 6); P3 = I31(4, 5); } break; case 194 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 5); } break; case 195 : { P0 = I31(4, 3); P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 5); } break; case 198 : { P0 = I31(4, 0); P1 = I31(4, 5); P2 = I31(4, 6); P3 = I31(4, 5); } break; case 199 : { P0 = I31(4, 3); P1 = I31(4, 5); P2 = I31(4, 6); P3 = I31(4, 5); } break; case 200 : case 204 : { P0 = I31(4, 0); P1 = I211(4, 1, 5); if (HQ2X_MDL) { P2 = I31(4, 6); P3 = I31(4, 5); } else { P2 = I332(3, 7, 4); P3 = I521(4, 7, 5); } } break; case 201 : case 205 : { P0 = I31(4, 1); P1 = I211(4, 1, 5); P3 = I31(4, 5); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } } break; case 202 : { P1 = I31(4, 2); P3 = I31(4, 5); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } } break; case 203 : { P1 = I31(4, 2); P2 = I31(4, 6); P3 = I31(4, 5); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 206 : { P1 = I31(4, 5); P3 = I31(4, 5); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } } break; case 207 : { P2 = I31(4, 6); P3 = I31(4, 5); if (HQ2X_MUL) { P0 = IC(4); P1 = I31(4, 5); } else { P0 = I332(1, 3, 4); P1 = I521(4, 1, 5); } } break; case 208 : case 209 : { P0 = I211(4, 1, 3); P1 = I31(4, 2); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } } break; case 210 : case 216 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } } break; case 211 : { P0 = I31(4, 3); P1 = I31(4, 2); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } } break; case 212 : case 213 : { P0 = I211(4, 1, 3); P2 = I31(4, 6); if (HQ2X_MDR) { P1 = I31(4, 1); P3 = IC(4); } else { P1 = I521(4, 5, 1); P3 = I332(5, 7, 4); } } break; case 215 : { P0 = I31(4, 3); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 217 : { P0 = I31(4, 1); P1 = I31(4, 2); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } } break; case 218 : { if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 219 : { P1 = I31(4, 2); P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 220 : { P0 = I31(4, 0); P1 = I31(4, 1); if (HQ2X_MDL) { P2 = I31(4, 6); } else { P2 = I611(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } } break; case 221 : { P0 = I31(4, 1); P2 = I31(4, 6); if (HQ2X_MDR) { P1 = I31(4, 1); P3 = IC(4); } else { P1 = I521(4, 5, 1); P3 = I332(5, 7, 4); } } break; case 223 : { P2 = I31(4, 6); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 224 : case 225 : case 228 : case 229 : { P0 = I211(4, 1, 3); P1 = I211(4, 1, 5); P2 = I31(4, 3); P3 = I31(4, 5); } break; case 226 : { P0 = I31(4, 0); P1 = I31(4, 2); P2 = I31(4, 3); P3 = I31(4, 5); } break; case 227 : { P0 = I31(4, 3); P1 = I31(4, 2); P2 = I31(4, 3); P3 = I31(4, 5); } break; case 230 : { P0 = I31(4, 0); P1 = I31(4, 5); P2 = I31(4, 3); P3 = I31(4, 5); } break; case 231 : { P0 = I31(4, 3); P1 = I31(4, 5); P2 = I31(4, 3); P3 = I31(4, 5); } break; case 232 : case 236 : { P0 = I31(4, 0); P1 = I211(4, 1, 5); if (HQ2X_MDL) { P2 = IC(4); P3 = I31(4, 5); } else { P2 = I332(3, 7, 4); P3 = I521(4, 7, 5); } } break; case 233 : case 237 : { P0 = I31(4, 1); P1 = I211(4, 1, 5); P3 = I31(4, 5); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } } break; case 234 : { P1 = I31(4, 2); P3 = I31(4, 5); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MUL) { P0 = I31(4, 0); } else { P0 = I611(4, 1, 3); } } break; case 235 : { P1 = I31(4, 2); P3 = I31(4, 5); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 238 : { P0 = I31(4, 0); P1 = I31(4, 5); if (HQ2X_MDL) { P2 = IC(4); P3 = I31(4, 5); } else { P2 = I332(3, 7, 4); P3 = I521(4, 7, 5); } } break; case 239 : { P1 = I31(4, 5); P3 = I31(4, 5); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } } break; case 240 : case 241 : { P0 = I211(4, 1, 3); P1 = I31(4, 2); if (HQ2X_MDR) { P2 = I31(4, 3); P3 = IC(4); } else { P2 = I521(4, 7, 3); P3 = I332(5, 7, 4); } } break; case 242 : { P0 = I31(4, 0); P2 = I31(4, 3); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUR) { P1 = I31(4, 2); } else { P1 = I611(4, 1, 5); } } break; case 243 : { P0 = I31(4, 3); P1 = I31(4, 2); if (HQ2X_MDR) { P2 = I31(4, 3); P3 = IC(4); } else { P2 = I521(4, 7, 3); P3 = I332(5, 7, 4); } } break; case 244 : case 245 : { P0 = I211(4, 1, 3); P1 = I31(4, 1); P2 = I31(4, 3); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } } break; case 246 : { P0 = I31(4, 0); P2 = I31(4, 3); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 247 : { P0 = I31(4, 3); P2 = I31(4, 3); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 249 : { P0 = I31(4, 1); P1 = I31(4, 2); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } } break; case 251 : { P1 = I31(4, 2); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 252 : { P0 = I31(4, 0); P1 = I31(4, 1); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } } break; case 253 : { P0 = I31(4, 1); P1 = I31(4, 1); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } } break; case 254 : { P0 = I31(4, 0); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 255 : { if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; mupen64plus-video-rice-src-2.6.0/src/TextureFilters_hq4x.cpp000066400000000000000000000557671464507324400240170ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - TextureFilters_hq4x.cpp * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "typedefs.h" static int RGBtoYUV[4096]; //#define RGB32toYUV(val) (RGBtoYUV[((val&0x00FF0000)>>20)+((val&0x0000FF00)>>12)+((val&0x000000FF)>>4)]) inline int RGB32toYUV(uint32 val) { int a,r,g,b,Y,u,v; //r = (val&0x00FF0000)>>16; //g = (val&0x0000FF00)>>8; //b = (val&0x000000FF); a = (val&0xFF000000); r = (val&0x00FF0000)>>16; g = (val&0x0000FF00)>>8; b = (val&0x000000FF); //r = (val&0x00F80000)>>16; //g = (val&0x0000FC00)>>8; //b = (val&0x000000F8); Y = (r + g + b) >> 2; u = 128 + ((r - b) >> 2); v = 128 + ((-r + 2*g -b)>>3); return a + (Y<<16) + (u<<8) + v; } #define RGB16toYUV(val) (RGBtoYUV[(val&0x0FFF)]) static int YUV1, YUV2; const int Amask = 0xFF000000; const int Ymask = 0x00FF0000; const int Umask = 0x0000FF00; const int Vmask = 0x000000FF; const int trA = 0x20000000; const int trY = 0x00300000; const int trU = 0x00000700; const int trV = 0x00000006; //const int trU = 0x00001800; //const int trV = 0x00000018; #define INTERP_16_MASK_1_3(v) ((v)&0x0F0F) #define INTERP_16_MASK_SHIFT_2_4(v) (((v)&0xF0F0)>>4) #define INTERP_16_MASK_SHIFTBACK_2_4(v) ((INTERP_16_MASK_1_3(v))<<4) inline void hq4x_Interp1_16(unsigned char * pc, uint16 p1, uint16 p2) { *((uint16*)pc) = INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*3 + INTERP_16_MASK_1_3(p2)) / 4) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*3 + INTERP_16_MASK_SHIFT_2_4(p2)) / 4 ); } inline void hq4x_Interp2_16(unsigned char * pc, uint16 p1, uint16 p2, uint16 p3) { *((uint16*)pc) = INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*2 + INTERP_16_MASK_1_3(p2) + INTERP_16_MASK_1_3(p3)) / 4) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*2 + INTERP_16_MASK_SHIFT_2_4(p2) + INTERP_16_MASK_SHIFT_2_4(p3)) / 4); } inline void hq4x_Interp3_16(unsigned char * pc, uint16 p1, uint16 p2) { *((uint16*)pc) = INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*7 + INTERP_16_MASK_1_3(p2)) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*7 + INTERP_16_MASK_SHIFT_2_4(p2)) / 8); } inline void hq4x_Interp5_16(unsigned char * pc, uint16 p1, uint16 p2) { *((uint16*)pc) = INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1) + INTERP_16_MASK_1_3(p2)) / 2) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1) + INTERP_16_MASK_SHIFT_2_4(p2)) / 2); } inline void hq4x_Interp6_16(unsigned char * pc, uint16 p1, uint16 p2, uint16 p3) { *((uint16*)pc) = INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*5 + INTERP_16_MASK_1_3(p2)*2 + INTERP_16_MASK_1_3(p3)*1) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*5 + INTERP_16_MASK_SHIFT_2_4(p2)*2 + INTERP_16_MASK_SHIFT_2_4(p3)*1) / 8); } inline void hq4x_Interp7_16(unsigned char * pc, uint16 p1, uint16 p2, uint16 p3) { *((uint16*)pc) = INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*6 + INTERP_16_MASK_1_3(p2) + INTERP_16_MASK_1_3(p3)) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*6 + INTERP_16_MASK_SHIFT_2_4(p2) + INTERP_16_MASK_SHIFT_2_4(p3)) / 8); } inline void hq4x_Interp8_16(unsigned char * pc, uint16 p1, uint16 p2) { //*((int*)pc) = (c1*5+c2*3)/8; *((uint16*)pc) = INTERP_16_MASK_1_3((INTERP_16_MASK_1_3(p1)*5 + INTERP_16_MASK_1_3(p2)*3) / 8) | INTERP_16_MASK_SHIFTBACK_2_4((INTERP_16_MASK_SHIFT_2_4(p1)*5 + INTERP_16_MASK_SHIFT_2_4(p2)*3) / 8); } #define INTERP_32_MASK_1_3(v) ((v)&0x00FF00FF) #define INTERP_32_MASK_SHIFT_2_4(v) (((v)&0xFF00FF00)>>8) #define INTERP_32_MASK_SHIFTBACK_2_4(v) (((INTERP_32_MASK_1_3(v))<<8)) inline void hq4x_Interp1_32(unsigned char * pc, uint32 p1, uint32 p2) { *((uint32*)pc) = INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*3 + INTERP_32_MASK_1_3(p2)) / 4) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*3 + INTERP_32_MASK_SHIFT_2_4(p2)) / 4 ); } inline void hq4x_Interp2_32(unsigned char * pc, uint32 p1, uint32 p2, uint32 p3) { *((uint32*)pc) = INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*2 + INTERP_32_MASK_1_3(p2) + INTERP_32_MASK_1_3(p3)) / 4) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*2 + INTERP_32_MASK_SHIFT_2_4(p2) + INTERP_32_MASK_SHIFT_2_4(p3)) / 4); } inline void hq4x_Interp3_32(unsigned char * pc, uint32 p1, uint32 p2) { *((uint32*)pc) = INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*7 + INTERP_32_MASK_1_3(p2)) / 8) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*7 + INTERP_32_MASK_SHIFT_2_4(p2)) / 8); } inline void hq4x_Interp5_32(unsigned char * pc, uint32 p1, uint32 p2) { *((uint32*)pc) = INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1) + INTERP_32_MASK_1_3(p2)) / 2) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1) + INTERP_32_MASK_SHIFT_2_4(p2)) / 2); } inline void hq4x_Interp6_32(unsigned char * pc, uint32 p1, uint32 p2, uint32 p3) { *((uint32*)pc) = INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*5 + INTERP_32_MASK_1_3(p2)*2 + INTERP_32_MASK_1_3(p3)*1) / 8) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*5 + INTERP_32_MASK_SHIFT_2_4(p2)*2 + INTERP_32_MASK_SHIFT_2_4(p3)*1) / 8); } inline void hq4x_Interp7_32(unsigned char * pc, uint32 p1, uint32 p2, uint32 p3) { *((uint32*)pc) = INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*6 + INTERP_32_MASK_1_3(p2) + INTERP_32_MASK_1_3(p3)) / 8) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*6 + INTERP_32_MASK_SHIFT_2_4(p2) + INTERP_32_MASK_SHIFT_2_4(p3)) / 8); } inline void hq4x_Interp8_32(unsigned char * pc, uint32 p1, uint32 p2) { //*((int*)pc) = (c1*5+c2*3)/8; *((uint32*)pc) = INTERP_32_MASK_1_3((INTERP_32_MASK_1_3(p1)*5 + INTERP_32_MASK_1_3(p2)*3) / 8) | INTERP_32_MASK_SHIFTBACK_2_4((INTERP_32_MASK_SHIFT_2_4(p1)*5 + INTERP_32_MASK_SHIFT_2_4(p2)*3) / 8); } #define PIXEL00_0 *((int*)(pOut)) = c[5]; #define PIXEL00_11 hq4x_Interp1(pOut, c[5], c[4]); #define PIXEL00_12 hq4x_Interp1(pOut, c[5], c[2]); #define PIXEL00_20 hq4x_Interp2(pOut, c[5], c[2], c[4]); #define PIXEL00_50 hq4x_Interp5(pOut, c[2], c[4]); #define PIXEL00_80 hq4x_Interp8(pOut, c[5], c[1]); #define PIXEL00_81 hq4x_Interp8(pOut, c[5], c[4]); #define PIXEL00_82 hq4x_Interp8(pOut, c[5], c[2]); #define PIXEL01_0 *((int*)(pOut+BPP)) = c[5]; #define PIXEL01_10 hq4x_Interp1(pOut+BPP, c[5], c[1]); #define PIXEL01_12 hq4x_Interp1(pOut+BPP, c[5], c[2]); #define PIXEL01_14 hq4x_Interp1(pOut+BPP, c[2], c[5]); #define PIXEL01_21 hq4x_Interp2(pOut+BPP, c[2], c[5], c[4]); #define PIXEL01_31 hq4x_Interp3(pOut+BPP, c[5], c[4]); #define PIXEL01_50 hq4x_Interp5(pOut+BPP, c[2], c[5]); #define PIXEL01_60 hq4x_Interp6(pOut+BPP, c[5], c[2], c[4]); #define PIXEL01_61 hq4x_Interp6(pOut+BPP, c[5], c[2], c[1]); #define PIXEL01_82 hq4x_Interp8(pOut+BPP, c[5], c[2]); #define PIXEL01_83 hq4x_Interp8(pOut+BPP, c[2], c[4]); #define PIXEL02_0 *((int*)(pOut+BPP2)) = c[5]; #define PIXEL02_10 hq4x_Interp1(pOut+BPP2, c[5], c[3]); #define PIXEL02_11 hq4x_Interp1(pOut+BPP2, c[5], c[2]); #define PIXEL02_13 hq4x_Interp1(pOut+BPP2, c[2], c[5]); #define PIXEL02_21 hq4x_Interp2(pOut+BPP2, c[2], c[5], c[6]); #define PIXEL02_32 hq4x_Interp3(pOut+BPP2, c[5], c[6]); #define PIXEL02_50 hq4x_Interp5(pOut+BPP2, c[2], c[5]); #define PIXEL02_60 hq4x_Interp6(pOut+BPP2, c[5], c[2], c[6]); #define PIXEL02_61 hq4x_Interp6(pOut+BPP2, c[5], c[2], c[3]); #define PIXEL02_81 hq4x_Interp8(pOut+BPP2, c[5], c[2]); #define PIXEL02_83 hq4x_Interp8(pOut+BPP2, c[2], c[6]); #define PIXEL03_0 *((int*)(pOut+BPP3)) = c[5]; #define PIXEL03_11 hq4x_Interp1(pOut+BPP3, c[5], c[2]); #define PIXEL03_12 hq4x_Interp1(pOut+BPP3, c[5], c[6]); #define PIXEL03_20 hq4x_Interp2(pOut+BPP3, c[5], c[2], c[6]); #define PIXEL03_50 hq4x_Interp5(pOut+BPP3, c[2], c[6]); #define PIXEL03_80 hq4x_Interp8(pOut+BPP3, c[5], c[3]); #define PIXEL03_81 hq4x_Interp8(pOut+BPP3, c[5], c[2]); #define PIXEL03_82 hq4x_Interp8(pOut+BPP3, c[5], c[6]); #define PIXEL10_0 *((int*)(pOut+BpL)) = c[5]; #define PIXEL10_10 hq4x_Interp1(pOut+BpL, c[5], c[1]); #define PIXEL10_11 hq4x_Interp1(pOut+BpL, c[5], c[4]); #define PIXEL10_13 hq4x_Interp1(pOut+BpL, c[4], c[5]); #define PIXEL10_21 hq4x_Interp2(pOut+BpL, c[4], c[5], c[2]); #define PIXEL10_32 hq4x_Interp3(pOut+BpL, c[5], c[2]); #define PIXEL10_50 hq4x_Interp5(pOut+BpL, c[4], c[5]); #define PIXEL10_60 hq4x_Interp6(pOut+BpL, c[5], c[4], c[2]); #define PIXEL10_61 hq4x_Interp6(pOut+BpL, c[5], c[4], c[1]); #define PIXEL10_81 hq4x_Interp8(pOut+BpL, c[5], c[4]); #define PIXEL10_83 hq4x_Interp8(pOut+BpL, c[4], c[2]); #define PIXEL11_0 *((int*)(pOut+BpL+BPP)) = c[5]; #define PIXEL11_30 hq4x_Interp3(pOut+BpL+BPP, c[5], c[1]); #define PIXEL11_31 hq4x_Interp3(pOut+BpL+BPP, c[5], c[4]); #define PIXEL11_32 hq4x_Interp3(pOut+BpL+BPP, c[5], c[2]); #define PIXEL11_70 hq4x_Interp7(pOut+BpL+BPP, c[5], c[4], c[2]); #define PIXEL12_0 *((int*)(pOut+BpL+BPP2)) = c[5]; #define PIXEL12_30 hq4x_Interp3(pOut+BpL+BPP2, c[5], c[3]); #define PIXEL12_31 hq4x_Interp3(pOut+BpL+BPP2, c[5], c[2]); #define PIXEL12_32 hq4x_Interp3(pOut+BpL+BPP2, c[5], c[6]); #define PIXEL12_70 hq4x_Interp7(pOut+BpL+BPP2, c[5], c[6], c[2]); #define PIXEL13_0 *((int*)(pOut+BpL+BPP3)) = c[5]; #define PIXEL13_10 hq4x_Interp1(pOut+BpL+BPP3, c[5], c[3]); #define PIXEL13_12 hq4x_Interp1(pOut+BpL+BPP3, c[5], c[6]); #define PIXEL13_14 hq4x_Interp1(pOut+BpL+BPP3, c[6], c[5]); #define PIXEL13_21 hq4x_Interp2(pOut+BpL+BPP3, c[6], c[5], c[2]); #define PIXEL13_31 hq4x_Interp3(pOut+BpL+BPP3, c[5], c[2]); #define PIXEL13_50 hq4x_Interp5(pOut+BpL+BPP3, c[6], c[5]); #define PIXEL13_60 hq4x_Interp6(pOut+BpL+BPP3, c[5], c[6], c[2]); #define PIXEL13_61 hq4x_Interp6(pOut+BpL+BPP3, c[5], c[6], c[3]); #define PIXEL13_82 hq4x_Interp8(pOut+BpL+BPP3, c[5], c[6]); #define PIXEL13_83 hq4x_Interp8(pOut+BpL+BPP3, c[6], c[2]); #define PIXEL20_0 *((int*)(pOut+BpL+BpL)) = c[5]; #define PIXEL20_10 hq4x_Interp1(pOut+BpL+BpL, c[5], c[7]); #define PIXEL20_12 hq4x_Interp1(pOut+BpL+BpL, c[5], c[4]); #define PIXEL20_14 hq4x_Interp1(pOut+BpL+BpL, c[4], c[5]); #define PIXEL20_21 hq4x_Interp2(pOut+BpL+BpL, c[4], c[5], c[8]); #define PIXEL20_31 hq4x_Interp3(pOut+BpL+BpL, c[5], c[8]); #define PIXEL20_50 hq4x_Interp5(pOut+BpL+BpL, c[4], c[5]); #define PIXEL20_60 hq4x_Interp6(pOut+BpL+BpL, c[5], c[4], c[8]); #define PIXEL20_61 hq4x_Interp6(pOut+BpL+BpL, c[5], c[4], c[7]); #define PIXEL20_82 hq4x_Interp8(pOut+BpL+BpL, c[5], c[4]); #define PIXEL20_83 hq4x_Interp8(pOut+BpL+BpL, c[4], c[8]); #define PIXEL21_0 *((int*)(pOut+BpL+BpL+BPP)) = c[5]; #define PIXEL21_30 hq4x_Interp3(pOut+BpL+BpL+BPP, c[5], c[7]); #define PIXEL21_31 hq4x_Interp3(pOut+BpL+BpL+BPP, c[5], c[8]); #define PIXEL21_32 hq4x_Interp3(pOut+BpL+BpL+BPP, c[5], c[4]); #define PIXEL21_70 hq4x_Interp7(pOut+BpL+BpL+BPP, c[5], c[4], c[8]); #define PIXEL22_0 *((int*)(pOut+BpL+BpL+BPP2)) = c[5]; #define PIXEL22_30 hq4x_Interp3(pOut+BpL+BpL+BPP2, c[5], c[9]); #define PIXEL22_31 hq4x_Interp3(pOut+BpL+BpL+BPP2, c[5], c[6]); #define PIXEL22_32 hq4x_Interp3(pOut+BpL+BpL+BPP2, c[5], c[8]); #define PIXEL22_70 hq4x_Interp7(pOut+BpL+BpL+BPP2, c[5], c[6], c[8]); #define PIXEL23_0 *((int*)(pOut+BpL+BpL+BPP3)) = c[5]; #define PIXEL23_10 hq4x_Interp1(pOut+BpL+BpL+BPP3, c[5], c[9]); #define PIXEL23_11 hq4x_Interp1(pOut+BpL+BpL+BPP3, c[5], c[6]); #define PIXEL23_13 hq4x_Interp1(pOut+BpL+BpL+BPP3, c[6], c[5]); #define PIXEL23_21 hq4x_Interp2(pOut+BpL+BpL+BPP3, c[6], c[5], c[8]); #define PIXEL23_32 hq4x_Interp3(pOut+BpL+BpL+BPP3, c[5], c[8]); #define PIXEL23_50 hq4x_Interp5(pOut+BpL+BpL+BPP3, c[6], c[5]); #define PIXEL23_60 hq4x_Interp6(pOut+BpL+BpL+BPP3, c[5], c[6], c[8]); #define PIXEL23_61 hq4x_Interp6(pOut+BpL+BpL+BPP3, c[5], c[6], c[9]); #define PIXEL23_81 hq4x_Interp8(pOut+BpL+BpL+BPP3, c[5], c[6]); #define PIXEL23_83 hq4x_Interp8(pOut+BpL+BpL+BPP3, c[6], c[8]); #define PIXEL30_0 *((int*)(pOut+BpL+BpL+BpL)) = c[5]; #define PIXEL30_11 hq4x_Interp1(pOut+BpL+BpL+BpL, c[5], c[8]); #define PIXEL30_12 hq4x_Interp1(pOut+BpL+BpL+BpL, c[5], c[4]); #define PIXEL30_20 hq4x_Interp2(pOut+BpL+BpL+BpL, c[5], c[8], c[4]); #define PIXEL30_50 hq4x_Interp5(pOut+BpL+BpL+BpL, c[8], c[4]); #define PIXEL30_80 hq4x_Interp8(pOut+BpL+BpL+BpL, c[5], c[7]); #define PIXEL30_81 hq4x_Interp8(pOut+BpL+BpL+BpL, c[5], c[8]); #define PIXEL30_82 hq4x_Interp8(pOut+BpL+BpL+BpL, c[5], c[4]); #define PIXEL31_0 *((int*)(pOut+BpL+BpL+BpL+BPP)) = c[5]; #define PIXEL31_10 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP, c[5], c[7]); #define PIXEL31_11 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP, c[5], c[8]); #define PIXEL31_13 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP, c[8], c[5]); #define PIXEL31_21 hq4x_Interp2(pOut+BpL+BpL+BpL+BPP, c[8], c[5], c[4]); #define PIXEL31_32 hq4x_Interp3(pOut+BpL+BpL+BpL+BPP, c[5], c[4]); #define PIXEL31_50 hq4x_Interp5(pOut+BpL+BpL+BpL+BPP, c[8], c[5]); #define PIXEL31_60 hq4x_Interp6(pOut+BpL+BpL+BpL+BPP, c[5], c[8], c[4]); #define PIXEL31_61 hq4x_Interp6(pOut+BpL+BpL+BpL+BPP, c[5], c[8], c[7]); #define PIXEL31_81 hq4x_Interp8(pOut+BpL+BpL+BpL+BPP, c[5], c[8]); #define PIXEL31_83 hq4x_Interp8(pOut+BpL+BpL+BpL+BPP, c[8], c[4]); #define PIXEL32_0 *((int*)(pOut+BpL+BpL+BpL+BPP2)) = c[5]; #define PIXEL32_10 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP2, c[5], c[9]); #define PIXEL32_12 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP2, c[5], c[8]); #define PIXEL32_14 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP2, c[8], c[5]); #define PIXEL32_21 hq4x_Interp2(pOut+BpL+BpL+BpL+BPP2, c[8], c[5], c[6]); #define PIXEL32_31 hq4x_Interp3(pOut+BpL+BpL+BpL+BPP2, c[5], c[6]); #define PIXEL32_50 hq4x_Interp5(pOut+BpL+BpL+BpL+BPP2, c[8], c[5]); #define PIXEL32_60 hq4x_Interp6(pOut+BpL+BpL+BpL+BPP2, c[5], c[8], c[6]); #define PIXEL32_61 hq4x_Interp6(pOut+BpL+BpL+BpL+BPP2, c[5], c[8], c[9]); #define PIXEL32_82 hq4x_Interp8(pOut+BpL+BpL+BpL+BPP2, c[5], c[8]); #define PIXEL32_83 hq4x_Interp8(pOut+BpL+BpL+BpL+BPP2, c[8], c[6]); #define PIXEL33_0 *((int*)(pOut+BpL+BpL+BpL+BPP3)) = c[5]; #define PIXEL33_11 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP3, c[5], c[6]); #define PIXEL33_12 hq4x_Interp1(pOut+BpL+BpL+BpL+BPP3, c[5], c[8]); #define PIXEL33_20 hq4x_Interp2(pOut+BpL+BpL+BpL+BPP3, c[5], c[8], c[6]); #define PIXEL33_50 hq4x_Interp5(pOut+BpL+BpL+BpL+BPP3, c[8], c[6]); #define PIXEL33_80 hq4x_Interp8(pOut+BpL+BpL+BpL+BPP3, c[5], c[9]); #define PIXEL33_81 hq4x_Interp8(pOut+BpL+BpL+BpL+BPP3, c[5], c[6]); #define PIXEL33_82 hq4x_Interp8(pOut+BpL+BpL+BpL+BPP3, c[5], c[8]); inline bool Diff_16(uint16 w1, uint16 w2) { YUV1 = RGB16toYUV(w1); YUV2 = RGB16toYUV(w2); return ( ( abs((YUV1 & Amask) - (YUV2 & Amask)) > trA ) || ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ); } inline bool Diff_32(uint32 w1, uint32 w2) { YUV1 = RGB32toYUV(w1); YUV2 = RGB32toYUV(w2); return ( ( abs((YUV1 & Amask) - (YUV2 & Amask)) > trA ) || ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ); } void hq4x_16( unsigned char * pIn, unsigned char * pOut, int Xres, int Yres, int SrcPPL, int BpL ) { #define hq4x_Interp1 hq4x_Interp1_16 #define hq4x_Interp2 hq4x_Interp2_16 #define hq4x_Interp3 hq4x_Interp3_16 #define hq4x_Interp4 hq4x_Interp4_16 #define hq4x_Interp5 hq4x_Interp5_16 #define hq4x_Interp6 hq4x_Interp6_16 #define hq4x_Interp7 hq4x_Interp7_16 #define hq4x_Interp8 hq4x_Interp8_16 #define Diff Diff_16 #define BPP 2 #define BPP2 4 #define BPP3 6 int i, j, k; int prevline, nextline; uint16 w[10]; uint16 c[10]; // +----+----+----+ // | | | | // | w1 | w2 | w3 | // +----+----+----+ // | | | | // | w4 | w5 | w6 | // +----+----+----+ // | | | | // | w7 | w8 | w9 | // +----+----+----+ for (j=0; j0) prevline = -SrcPPL*2; else prevline = 0; if (j0) { w[1] = *((uint16*)(pIn + prevline - 2)); w[4] = *((uint16*)(pIn - 2)); w[7] = *((uint16*)(pIn + nextline - 2)); } else { w[1] = w[2]; w[4] = w[5]; w[7] = w[8]; } if (i trA ) || ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ) pattern |= flag; } flag <<= 1; } for (k=1; k<=9; k++) c[k] = w[k]; #include "TextureFilters_hq4x.h" pIn+=2; pOut+=8; } pIn += 2*(SrcPPL-Xres); pOut+= 8*(SrcPPL-Xres); pOut+=BpL; pOut+=BpL; pOut+=BpL; } #undef BPP #undef BPP2 #undef BPP3 #undef Diff #undef hq4x_Interp1 #undef hq4x_Interp2 #undef hq4x_Interp3 #undef hq4x_Interp4 #undef hq4x_Interp5 #undef hq4x_Interp6 #undef hq4x_Interp7 #undef hq4x_Interp8 } void hq4x_32( unsigned char * pIn, unsigned char * pOut, int Xres, int Yres, int SrcPPL, int BpL ) { #define hq4x_Interp1 hq4x_Interp1_32 #define hq4x_Interp2 hq4x_Interp2_32 #define hq4x_Interp3 hq4x_Interp3_32 #define hq4x_Interp4 hq4x_Interp4_32 #define hq4x_Interp5 hq4x_Interp5_32 #define hq4x_Interp6 hq4x_Interp6_32 #define hq4x_Interp7 hq4x_Interp7_32 #define hq4x_Interp8 hq4x_Interp8_32 #define Diff Diff_32 #define BPP 4 #define BPP2 8 #define BPP3 12 int i, j, k; int prevline, nextline; uint32 w[10]; // +----+----+----+ // | | | | // | w1 | w2 | w3 | // +----+----+----+ // | | | | // | w4 | w5 | w6 | // +----+----+----+ // | | | | // | w7 | w8 | w9 | // +----+----+----+ for (j=0; j0) prevline = -SrcPPL*4; else prevline = 0; if (j0) { w[1] = *((uint32*)(pIn + prevline - 4)); w[4] = *((uint32*)(pIn - 4)); w[7] = *((uint32*)(pIn + nextline - 4)); } else { w[1] = w[2]; w[4] = w[5]; w[7] = w[8]; } if (i trA ) || ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ) pattern |= flag; } flag <<= 1; } pIn+=4; pOut+=16; } pIn += 4*(SrcPPL-Xres); pOut+= 16*(SrcPPL-Xres); pOut+=BpL; pOut+=BpL; pOut+=BpL; } #undef BPP #undef BPP2 #undef BPP3 #undef Diff #undef hq4x_Interp1 #undef hq4x_Interp2 #undef hq4x_Interp3 #undef hq4x_Interp4 #undef hq4x_Interp5 #undef hq4x_Interp6 #undef hq4x_Interp7 #undef hq4x_Interp8 } void hq4x_InitLUTs(void) { static bool done = false; int i, j, k, r, g, b, Y, u, v; if( !done ) { for (i=0; i<16; i++) { for (j=0; j<16; j++) { for (k=0; k<16; k++) { r = i << 4; g = j << 4; b = k << 4; Y = (r + g + b) >> 2; u = 128 + ((r - b) >> 2); v = 128 + ((-r + 2*g -b)>>3); RGBtoYUV[ (i << 8) + (j << 4) + k ] = (Y<<16) + (u<<8) + v; } } } done = true; } } mupen64plus-video-rice-src-2.6.0/src/TextureFilters_hq4x.h000066400000000000000000003213151464507324400234450ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - TextureFilters_hq4x.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ switch (pattern) { case 0: case 1: case 4: case 32: case 128: case 5: case 132: case 160: case 33: case 129: case 36: case 133: case 164: case 161: case 37: case 165: { PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; } case 2: case 34: case 130: case 162: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; } case 16: case 17: case 48: case 49: { PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; } case 64: case 65: case 68: case 69: { PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 8: case 12: case 136: case 140: { PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; } case 3: case 35: case 131: case 163: { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; } case 6: case 38: case 134: case 166: { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; } case 20: case 21: case 52: case 53: { PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; } case 144: case 145: case 176: case 177: { PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; } case 192: case 193: case 196: case 197: { PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; } case 96: case 97: case 100: case 101: { PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; } case 40: case 44: case 168: case 172: { PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; } case 9: case 13: case 137: case 141: { PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; } case 18: case 50: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_50 PIXEL03_50 PIXEL12_0 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; } case 80: case 81: { PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_61 PIXEL21_30 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 72: case 76: { PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_50 PIXEL21_0 PIXEL30_50 PIXEL31_50 } PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 10: case 138: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 PIXEL11_0 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; } case 66: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 24: { PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; } case 7: case 39: case 135: { PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; } case 148: case 149: case 180: { PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; } case 224: case 228: case 225: { PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; } case 41: case 169: case 45: { PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; } case 22: case 54: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; } case 208: case 209: { PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 104: case 108: { PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 11: case 139: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; } case 19: case 51: { if (Diff(w[2], w[6])) { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL00_12 PIXEL01_14 PIXEL02_83 PIXEL03_50 PIXEL12_70 PIXEL13_21 } PIXEL10_81 PIXEL11_31 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; } case 146: case 178: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 PIXEL23_32 PIXEL33_82 } else { PIXEL02_21 PIXEL03_50 PIXEL12_70 PIXEL13_83 PIXEL23_13 PIXEL33_11 } PIXEL10_61 PIXEL11_30 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 break; } case 84: case 85: { PIXEL00_20 PIXEL01_60 PIXEL02_81 if (Diff(w[6], w[8])) { PIXEL03_81 PIXEL13_31 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL03_12 PIXEL13_14 PIXEL22_70 PIXEL23_83 PIXEL32_21 PIXEL33_50 } PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL20_61 PIXEL21_30 PIXEL30_80 PIXEL31_10 break; } case 112: case 113: { PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_82 PIXEL21_32 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 } else { PIXEL22_70 PIXEL23_21 PIXEL30_11 PIXEL31_13 PIXEL32_83 PIXEL33_50 } break; } case 200: case 204: { PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 } else { PIXEL20_21 PIXEL21_70 PIXEL30_50 PIXEL31_83 PIXEL32_14 PIXEL33_12 } PIXEL22_31 PIXEL23_81 break; } case 73: case 77: { if (Diff(w[8], w[4])) { PIXEL00_82 PIXEL10_32 PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL00_11 PIXEL10_13 PIXEL20_83 PIXEL21_70 PIXEL30_50 PIXEL31_21 } PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 42: case 170: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 PIXEL20_31 PIXEL30_81 } else { PIXEL00_50 PIXEL01_21 PIXEL10_83 PIXEL11_70 PIXEL20_14 PIXEL30_12 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; } case 14: case 142: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_10 PIXEL11_30 } else { PIXEL00_50 PIXEL01_83 PIXEL02_13 PIXEL03_11 PIXEL10_21 PIXEL11_70 } PIXEL12_32 PIXEL13_82 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; } case 67: { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 70: { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 28: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; } case 152: { PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 194: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; } case 98: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; } case 56: { PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 25: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; } case 26: case 31: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL11_0 PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; } case 82: case 214: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 88: case 248: { PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } break; } case 74: case 107: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 27: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; } case 86: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 216: { PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 106: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_61 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 30: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; } case 210: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 120: { PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; } case 75: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 29: { PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_61 PIXEL32_61 PIXEL33_80 break; } case 198: { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; } case 184: { PIXEL00_80 PIXEL01_61 PIXEL02_61 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; } case 99: { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; } case 57: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 71: { PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_61 PIXEL21_30 PIXEL22_30 PIXEL23_61 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 156: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 226: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_61 PIXEL11_30 PIXEL12_30 PIXEL13_61 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; } case 60: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 195: { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; } case 102: { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; } case 153: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 58: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 83: { PIXEL00_81 PIXEL01_31 if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_81 PIXEL11_31 PIXEL20_61 PIXEL21_30 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_80 PIXEL31_10 break; } case 92: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 202: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_31 PIXEL23_81 PIXEL32_31 PIXEL33_81 break; } case 78: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_32 PIXEL03_82 PIXEL12_32 PIXEL13_82 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 154: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 114: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_61 PIXEL11_30 PIXEL20_82 PIXEL21_32 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_82 PIXEL31_32 break; } case 89: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 90: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 55: case 23: { if (Diff(w[2], w[6])) { PIXEL00_81 PIXEL01_31 PIXEL02_0 PIXEL03_0 PIXEL12_0 PIXEL13_0 } else { PIXEL00_12 PIXEL01_14 PIXEL02_83 PIXEL03_50 PIXEL12_70 PIXEL13_21 } PIXEL10_81 PIXEL11_31 PIXEL20_60 PIXEL21_70 PIXEL22_30 PIXEL23_10 PIXEL30_20 PIXEL31_60 PIXEL32_61 PIXEL33_80 break; } case 182: case 150: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL12_0 PIXEL13_0 PIXEL23_32 PIXEL33_82 } else { PIXEL02_21 PIXEL03_50 PIXEL12_70 PIXEL13_83 PIXEL23_13 PIXEL33_11 } PIXEL10_61 PIXEL11_30 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 break; } case 213: case 212: { PIXEL00_20 PIXEL01_60 PIXEL02_81 if (Diff(w[6], w[8])) { PIXEL03_81 PIXEL13_31 PIXEL22_0 PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL03_12 PIXEL13_14 PIXEL22_70 PIXEL23_83 PIXEL32_21 PIXEL33_50 } PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL20_61 PIXEL21_30 PIXEL30_80 PIXEL31_10 break; } case 241: case 240: { PIXEL00_20 PIXEL01_60 PIXEL02_61 PIXEL03_80 PIXEL10_60 PIXEL11_70 PIXEL12_30 PIXEL13_10 PIXEL20_82 PIXEL21_32 if (Diff(w[6], w[8])) { PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 PIXEL33_0 } else { PIXEL22_70 PIXEL23_21 PIXEL30_11 PIXEL31_13 PIXEL32_83 PIXEL33_50 } break; } case 236: case 232: { PIXEL00_80 PIXEL01_61 PIXEL02_60 PIXEL03_20 PIXEL10_10 PIXEL11_30 PIXEL12_70 PIXEL13_60 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL21_0 PIXEL30_0 PIXEL31_0 PIXEL32_31 PIXEL33_81 } else { PIXEL20_21 PIXEL21_70 PIXEL30_50 PIXEL31_83 PIXEL32_14 PIXEL33_12 } PIXEL22_31 PIXEL23_81 break; } case 109: case 105: { if (Diff(w[8], w[4])) { PIXEL00_82 PIXEL10_32 PIXEL20_0 PIXEL21_0 PIXEL30_0 PIXEL31_0 } else { PIXEL00_11 PIXEL10_13 PIXEL20_83 PIXEL21_70 PIXEL30_50 PIXEL31_21 } PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 171: case 43: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 PIXEL11_0 PIXEL20_31 PIXEL30_81 } else { PIXEL00_50 PIXEL01_21 PIXEL10_83 PIXEL11_70 PIXEL20_14 PIXEL30_12 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; } case 143: case 15: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 } else { PIXEL00_50 PIXEL01_83 PIXEL02_13 PIXEL03_11 PIXEL10_21 PIXEL11_70 } PIXEL12_32 PIXEL13_82 PIXEL20_10 PIXEL21_30 PIXEL22_70 PIXEL23_60 PIXEL30_80 PIXEL31_61 PIXEL32_60 PIXEL33_20 break; } case 124: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; } case 203: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 PIXEL20_10 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; } case 62: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 211: { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_10 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 118: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_10 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; } case 217: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 110: { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_10 PIXEL11_30 PIXEL12_32 PIXEL13_82 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 155: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 188: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; } case 185: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; } case 61: { PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 157: { PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 103: { PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_61 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; } case 227: { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_61 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; } case 230: { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_61 PIXEL11_30 PIXEL12_32 PIXEL13_82 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; } case 199: { PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_61 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; } case 220: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } break; } case 158: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 234: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_61 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_31 PIXEL23_81 PIXEL32_31 PIXEL33_81 break; } case 242: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_61 PIXEL11_30 PIXEL20_82 PIXEL21_32 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_82 PIXEL31_32 break; } case 59: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL11_0 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 121: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 87: { PIXEL00_81 PIXEL01_31 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_81 PIXEL11_31 PIXEL12_0 PIXEL20_61 PIXEL21_30 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_80 PIXEL31_10 break; } case 79: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_32 PIXEL03_82 PIXEL11_0 PIXEL12_32 PIXEL13_82 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 122: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 94: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL12_0 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 218: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } break; } case 91: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL11_0 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 229: { PIXEL00_20 PIXEL01_60 PIXEL02_60 PIXEL03_20 PIXEL10_60 PIXEL11_70 PIXEL12_70 PIXEL13_60 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; } case 167: { PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_60 PIXEL21_70 PIXEL22_70 PIXEL23_60 PIXEL30_20 PIXEL31_60 PIXEL32_60 PIXEL33_20 break; } case 173: { PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; } case 181: { PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; } case 186: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; } case 115: { PIXEL00_81 PIXEL01_31 if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_81 PIXEL11_31 PIXEL20_82 PIXEL21_32 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_82 PIXEL31_32 break; } case 93: { PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } break; } case 206: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_32 PIXEL03_82 PIXEL12_32 PIXEL13_82 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_31 PIXEL23_81 PIXEL32_31 PIXEL33_81 break; } case 205: case 201: { PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 if (Diff(w[8], w[4])) { PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 } else { PIXEL20_12 PIXEL21_0 PIXEL30_20 PIXEL31_11 } PIXEL22_31 PIXEL23_81 PIXEL32_31 PIXEL33_81 break; } case 174: case 46: { if (Diff(w[4], w[2])) { PIXEL00_80 PIXEL01_10 PIXEL10_10 PIXEL11_30 } else { PIXEL00_20 PIXEL01_12 PIXEL10_11 PIXEL11_0 } PIXEL02_32 PIXEL03_82 PIXEL12_32 PIXEL13_82 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; } case 179: case 147: { PIXEL00_81 PIXEL01_31 if (Diff(w[2], w[6])) { PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 } else { PIXEL02_11 PIXEL03_20 PIXEL12_0 PIXEL13_12 } PIXEL10_81 PIXEL11_31 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; } case 117: case 116: { PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_82 PIXEL21_32 if (Diff(w[6], w[8])) { PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 } else { PIXEL22_0 PIXEL23_11 PIXEL32_12 PIXEL33_20 } PIXEL30_82 PIXEL31_32 break; } case 189: { PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; } case 231: { PIXEL00_81 PIXEL01_31 PIXEL02_32 PIXEL03_82 PIXEL10_81 PIXEL11_31 PIXEL12_32 PIXEL13_82 PIXEL20_82 PIXEL21_32 PIXEL22_31 PIXEL23_81 PIXEL30_82 PIXEL31_32 PIXEL32_31 PIXEL33_81 break; } case 126: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; } case 219: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 125: { if (Diff(w[8], w[4])) { PIXEL00_82 PIXEL10_32 PIXEL20_0 PIXEL21_0 PIXEL30_0 PIXEL31_0 } else { PIXEL00_11 PIXEL10_13 PIXEL20_83 PIXEL21_70 PIXEL30_50 PIXEL31_21 } PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; } case 221: { PIXEL00_82 PIXEL01_82 PIXEL02_81 if (Diff(w[6], w[8])) { PIXEL03_81 PIXEL13_31 PIXEL22_0 PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL03_12 PIXEL13_14 PIXEL22_70 PIXEL23_83 PIXEL32_21 PIXEL33_50 } PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL20_10 PIXEL21_30 PIXEL30_80 PIXEL31_10 break; } case 207: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 } else { PIXEL00_50 PIXEL01_83 PIXEL02_13 PIXEL03_11 PIXEL10_21 PIXEL11_70 } PIXEL12_32 PIXEL13_82 PIXEL20_10 PIXEL21_30 PIXEL22_31 PIXEL23_81 PIXEL30_80 PIXEL31_10 PIXEL32_31 PIXEL33_81 break; } case 238: { PIXEL00_80 PIXEL01_10 PIXEL02_32 PIXEL03_82 PIXEL10_10 PIXEL11_30 PIXEL12_32 PIXEL13_82 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL21_0 PIXEL30_0 PIXEL31_0 PIXEL32_31 PIXEL33_81 } else { PIXEL20_21 PIXEL21_70 PIXEL30_50 PIXEL31_83 PIXEL32_14 PIXEL33_12 } PIXEL22_31 PIXEL23_81 break; } case 190: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL12_0 PIXEL13_0 PIXEL23_32 PIXEL33_82 } else { PIXEL02_21 PIXEL03_50 PIXEL12_70 PIXEL13_83 PIXEL23_13 PIXEL33_11 } PIXEL10_10 PIXEL11_30 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 break; } case 187: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 PIXEL11_0 PIXEL20_31 PIXEL30_81 } else { PIXEL00_50 PIXEL01_21 PIXEL10_83 PIXEL11_70 PIXEL20_14 PIXEL30_12 } PIXEL02_10 PIXEL03_80 PIXEL12_30 PIXEL13_10 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; } case 243: { PIXEL00_81 PIXEL01_31 PIXEL02_10 PIXEL03_80 PIXEL10_81 PIXEL11_31 PIXEL12_30 PIXEL13_10 PIXEL20_82 PIXEL21_32 if (Diff(w[6], w[8])) { PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 PIXEL33_0 } else { PIXEL22_70 PIXEL23_21 PIXEL30_11 PIXEL31_13 PIXEL32_83 PIXEL33_50 } break; } case 119: { if (Diff(w[2], w[6])) { PIXEL00_81 PIXEL01_31 PIXEL02_0 PIXEL03_0 PIXEL12_0 PIXEL13_0 } else { PIXEL00_12 PIXEL01_14 PIXEL02_83 PIXEL03_50 PIXEL12_70 PIXEL13_21 } PIXEL10_81 PIXEL11_31 PIXEL20_82 PIXEL21_32 PIXEL22_30 PIXEL23_10 PIXEL30_82 PIXEL31_32 PIXEL32_10 PIXEL33_80 break; } case 237: case 233: { PIXEL00_82 PIXEL01_82 PIXEL02_60 PIXEL03_20 PIXEL10_32 PIXEL11_32 PIXEL12_70 PIXEL13_60 PIXEL20_0 PIXEL21_0 PIXEL22_31 PIXEL23_81 if (Diff(w[8], w[4])) { PIXEL30_0 } else { PIXEL30_20 } PIXEL31_0 PIXEL32_31 PIXEL33_81 break; } case 175: case 47: { if (Diff(w[4], w[2])) { PIXEL00_0 } else { PIXEL00_20 } PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 PIXEL12_32 PIXEL13_82 PIXEL20_31 PIXEL21_31 PIXEL22_70 PIXEL23_60 PIXEL30_81 PIXEL31_81 PIXEL32_60 PIXEL33_20 break; } case 183: case 151: { PIXEL00_81 PIXEL01_31 PIXEL02_0 if (Diff(w[2], w[6])) { PIXEL03_0 } else { PIXEL03_20 } PIXEL10_81 PIXEL11_31 PIXEL12_0 PIXEL13_0 PIXEL20_60 PIXEL21_70 PIXEL22_32 PIXEL23_32 PIXEL30_20 PIXEL31_60 PIXEL32_82 PIXEL33_82 break; } case 245: case 244: { PIXEL00_20 PIXEL01_60 PIXEL02_81 PIXEL03_81 PIXEL10_60 PIXEL11_70 PIXEL12_31 PIXEL13_31 PIXEL20_82 PIXEL21_32 PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 if (Diff(w[6], w[8])) { PIXEL33_0 } else { PIXEL33_20 } break; } case 250: { PIXEL00_80 PIXEL01_10 PIXEL02_10 PIXEL03_80 PIXEL10_10 PIXEL11_30 PIXEL12_30 PIXEL13_10 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } break; } case 123: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; } case 95: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL11_0 PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_30 PIXEL23_10 PIXEL30_80 PIXEL31_10 PIXEL32_10 PIXEL33_80 break; } case 222: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 252: { PIXEL00_80 PIXEL01_61 PIXEL02_81 PIXEL03_81 PIXEL10_10 PIXEL11_30 PIXEL12_31 PIXEL13_31 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_0 PIXEL23_0 PIXEL32_0 if (Diff(w[6], w[8])) { PIXEL33_0 } else { PIXEL33_20 } break; } case 249: { PIXEL00_82 PIXEL01_82 PIXEL02_61 PIXEL03_80 PIXEL10_32 PIXEL11_32 PIXEL12_30 PIXEL13_10 PIXEL20_0 PIXEL21_0 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } if (Diff(w[8], w[4])) { PIXEL30_0 } else { PIXEL30_20 } PIXEL31_0 break; } case 235: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_61 PIXEL20_0 PIXEL21_0 PIXEL22_31 PIXEL23_81 if (Diff(w[8], w[4])) { PIXEL30_0 } else { PIXEL30_20 } PIXEL31_0 PIXEL32_31 PIXEL33_81 break; } case 111: { if (Diff(w[4], w[2])) { PIXEL00_0 } else { PIXEL00_20 } PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 PIXEL12_32 PIXEL13_82 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_61 PIXEL32_10 PIXEL33_80 break; } case 63: { if (Diff(w[4], w[2])) { PIXEL00_0 } else { PIXEL00_20 } PIXEL01_0 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_0 PIXEL11_0 PIXEL12_0 PIXEL20_31 PIXEL21_31 PIXEL22_30 PIXEL23_10 PIXEL30_81 PIXEL31_81 PIXEL32_61 PIXEL33_80 break; } case 159: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_0 if (Diff(w[2], w[6])) { PIXEL03_0 } else { PIXEL03_20 } PIXEL11_0 PIXEL12_0 PIXEL13_0 PIXEL20_10 PIXEL21_30 PIXEL22_32 PIXEL23_32 PIXEL30_80 PIXEL31_61 PIXEL32_82 PIXEL33_82 break; } case 215: { PIXEL00_81 PIXEL01_31 PIXEL02_0 if (Diff(w[2], w[6])) { PIXEL03_0 } else { PIXEL03_20 } PIXEL10_81 PIXEL11_31 PIXEL12_0 PIXEL13_0 PIXEL20_61 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 246: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_61 PIXEL11_30 PIXEL12_0 PIXEL20_82 PIXEL21_32 PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 if (Diff(w[6], w[8])) { PIXEL33_0 } else { PIXEL33_20 } break; } case 254: { PIXEL00_80 PIXEL01_10 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_10 PIXEL11_30 PIXEL12_0 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_0 PIXEL23_0 PIXEL32_0 if (Diff(w[6], w[8])) { PIXEL33_0 } else { PIXEL33_20 } break; } case 253: { PIXEL00_82 PIXEL01_82 PIXEL02_81 PIXEL03_81 PIXEL10_32 PIXEL11_32 PIXEL12_31 PIXEL13_31 PIXEL20_0 PIXEL21_0 PIXEL22_0 PIXEL23_0 if (Diff(w[8], w[4])) { PIXEL30_0 } else { PIXEL30_20 } PIXEL31_0 PIXEL32_0 if (Diff(w[6], w[8])) { PIXEL33_0 } else { PIXEL33_20 } break; } case 251: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_10 PIXEL03_80 PIXEL11_0 PIXEL12_30 PIXEL13_10 PIXEL20_0 PIXEL21_0 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } if (Diff(w[8], w[4])) { PIXEL30_0 } else { PIXEL30_20 } PIXEL31_0 break; } case 239: { if (Diff(w[4], w[2])) { PIXEL00_0 } else { PIXEL00_20 } PIXEL01_0 PIXEL02_32 PIXEL03_82 PIXEL10_0 PIXEL11_0 PIXEL12_32 PIXEL13_82 PIXEL20_0 PIXEL21_0 PIXEL22_31 PIXEL23_81 if (Diff(w[8], w[4])) { PIXEL30_0 } else { PIXEL30_20 } PIXEL31_0 PIXEL32_31 PIXEL33_81 break; } case 127: { if (Diff(w[4], w[2])) { PIXEL00_0 } else { PIXEL00_20 } PIXEL01_0 if (Diff(w[2], w[6])) { PIXEL02_0 PIXEL03_0 PIXEL13_0 } else { PIXEL02_50 PIXEL03_50 PIXEL13_50 } PIXEL10_0 PIXEL11_0 PIXEL12_0 if (Diff(w[8], w[4])) { PIXEL20_0 PIXEL30_0 PIXEL31_0 } else { PIXEL20_50 PIXEL30_50 PIXEL31_50 } PIXEL21_0 PIXEL22_30 PIXEL23_10 PIXEL32_10 PIXEL33_80 break; } case 191: { if (Diff(w[4], w[2])) { PIXEL00_0 } else { PIXEL00_20 } PIXEL01_0 PIXEL02_0 if (Diff(w[2], w[6])) { PIXEL03_0 } else { PIXEL03_20 } PIXEL10_0 PIXEL11_0 PIXEL12_0 PIXEL13_0 PIXEL20_31 PIXEL21_31 PIXEL22_32 PIXEL23_32 PIXEL30_81 PIXEL31_81 PIXEL32_82 PIXEL33_82 break; } case 223: { if (Diff(w[4], w[2])) { PIXEL00_0 PIXEL01_0 PIXEL10_0 } else { PIXEL00_50 PIXEL01_50 PIXEL10_50 } PIXEL02_0 if (Diff(w[2], w[6])) { PIXEL03_0 } else { PIXEL03_20 } PIXEL11_0 PIXEL12_0 PIXEL13_0 PIXEL20_10 PIXEL21_30 PIXEL22_0 if (Diff(w[6], w[8])) { PIXEL23_0 PIXEL32_0 PIXEL33_0 } else { PIXEL23_50 PIXEL32_50 PIXEL33_50 } PIXEL30_80 PIXEL31_10 break; } case 247: { PIXEL00_81 PIXEL01_31 PIXEL02_0 if (Diff(w[2], w[6])) { PIXEL03_0 } else { PIXEL03_20 } PIXEL10_81 PIXEL11_31 PIXEL12_0 PIXEL13_0 PIXEL20_82 PIXEL21_32 PIXEL22_0 PIXEL23_0 PIXEL30_82 PIXEL31_32 PIXEL32_0 if (Diff(w[6], w[8])) { PIXEL33_0 } else { PIXEL33_20 } break; } case 255: { if (Diff(w[4], w[2])) { PIXEL00_0 } else { PIXEL00_20 } PIXEL01_0 PIXEL02_0 if (Diff(w[2], w[6])) { PIXEL03_0 } else { PIXEL03_20 } PIXEL10_0 PIXEL11_0 PIXEL12_0 PIXEL13_0 PIXEL20_0 PIXEL21_0 PIXEL22_0 PIXEL23_0 if (Diff(w[8], w[4])) { PIXEL30_0 } else { PIXEL30_20 } PIXEL31_0 PIXEL32_0 if (Diff(w[6], w[8])) { PIXEL33_0 } else { PIXEL33_20 } break; } } mupen64plus-video-rice-src-2.6.0/src/TextureFilters_lq2x.h000066400000000000000000000432641464507324400234530ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - TextureFilters_lq2x.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ case 0 : case 2 : case 4 : case 6 : case 8 : case 12 : case 16 : case 20 : case 24 : case 28 : case 32 : case 34 : case 36 : case 38 : case 40 : case 44 : case 48 : case 52 : case 56 : case 60 : case 64 : case 66 : case 68 : case 70 : case 96 : case 98 : case 100 : case 102 : case 128 : case 130 : case 132 : case 134 : case 136 : case 140 : case 144 : case 148 : case 152 : case 156 : case 160 : case 162 : case 164 : case 166 : case 168 : case 172 : case 176 : case 180 : case 184 : case 188 : case 192 : case 194 : case 196 : case 198 : case 224 : case 226 : case 228 : case 230 : { P0 = IC(0); P1 = IC(0); P2 = IC(0); P3 = IC(0); } break; case 1 : case 5 : case 9 : case 13 : case 17 : case 21 : case 25 : case 29 : case 33 : case 37 : case 41 : case 45 : case 49 : case 53 : case 57 : case 61 : case 65 : case 69 : case 97 : case 101 : case 129 : case 133 : case 137 : case 141 : case 145 : case 149 : case 153 : case 157 : case 161 : case 165 : case 169 : case 173 : case 177 : case 181 : case 185 : case 189 : case 193 : case 197 : case 225 : case 229 : { P0 = IC(1); P1 = IC(1); P2 = IC(1); P3 = IC(1); } break; case 3 : case 35 : case 67 : case 99 : case 131 : case 163 : case 195 : case 227 : { P0 = IC(2); P1 = IC(2); P2 = IC(2); P3 = IC(2); } break; case 7 : case 39 : case 71 : case 103 : case 135 : case 167 : case 199 : case 231 : { P0 = IC(3); P1 = IC(3); P2 = IC(3); P3 = IC(3); } break; case 10 : case 138 : { P1 = IC(0); P2 = IC(0); P3 = IC(0); if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I211(0, 1, 3); } } break; case 11 : case 27 : case 75 : case 139 : case 155 : case 203 : { P1 = IC(2); P2 = IC(2); P3 = IC(2); if (HQ2X_MUL) { P0 = IC(2); } else { P0 = I211(2, 1, 3); } } break; case 14 : case 142 : { P2 = IC(0); P3 = IC(0); if (HQ2X_MUL) { P0 = IC(0); P1 = IC(0); } else { P0 = I332(1, 3, 0); P1 = I31(0, 1); } } break; case 15 : case 143 : case 207 : { P2 = IC(4); P3 = IC(4); if (HQ2X_MUL) { P0 = IC(4); P1 = IC(4); } else { P0 = I332(1, 3, 4); P1 = I31(4, 1); } } break; case 18 : case 22 : case 30 : case 50 : case 54 : case 62 : case 86 : case 118 : { P0 = IC(0); P2 = IC(0); P3 = IC(0); if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 19 : case 51 : { P2 = IC(2); P3 = IC(2); if (HQ2X_MUR) { P0 = IC(2); P1 = IC(2); } else { P0 = I31(2, 1); P1 = I332(1, 5, 2); } } break; case 23 : case 55 : case 119 : { P2 = IC(3); P3 = IC(3); if (HQ2X_MUR) { P0 = IC(3); P1 = IC(3); } else { P0 = I31(3, 1); P1 = I332(1, 5, 3); } } break; case 26 : { P2 = IC(0); P3 = IC(0); if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I211(0, 1, 3); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 31 : case 95 : { P2 = IC(4); P3 = IC(4); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 42 : case 170 : { P1 = IC(0); P3 = IC(0); if (HQ2X_MUL) { P0 = IC(0); P2 = IC(0); } else { P0 = I332(1, 3, 0); P2 = I31(0, 3); } } break; case 43 : case 171 : case 187 : { P1 = IC(2); P3 = IC(2); if (HQ2X_MUL) { P0 = IC(2); P2 = IC(2); } else { P0 = I332(1, 3, 2); P2 = I31(2, 3); } } break; case 46 : case 174 : { P1 = IC(0); P2 = IC(0); P3 = IC(0); if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } } break; case 47 : case 175 : { P1 = IC(4); P2 = IC(4); P3 = IC(4); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } } break; case 58 : case 154 : case 186 : { P2 = IC(0); P3 = IC(0); if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I611(0, 1, 5); } } break; case 59 : { P2 = IC(2); P3 = IC(2); if (HQ2X_MUL) { P0 = IC(2); } else { P0 = I211(2, 1, 3); } if (HQ2X_MUR) { P1 = IC(2); } else { P1 = I611(2, 1, 5); } } break; case 63 : { P2 = IC(4); P3 = IC(4); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 72 : case 76 : case 104 : case 106 : case 108 : case 110 : case 120 : case 124 : { P0 = IC(0); P1 = IC(0); P3 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } } break; case 73 : case 77 : case 105 : case 109 : case 125 : { P1 = IC(1); P3 = IC(1); if (HQ2X_MDL) { P0 = IC(1); P2 = IC(1); } else { P0 = I31(1, 3); P2 = I332(3, 7, 1); } } break; case 74 : { P1 = IC(0); P3 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I211(0, 1, 3); } } break; case 78 : case 202 : case 206 : { P1 = IC(0); P3 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I611(0, 3, 7); } if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } } break; case 79 : { P1 = IC(4); P3 = IC(4); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I611(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } } break; case 80 : case 208 : case 210 : case 216 : { P0 = IC(0); P1 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I211(0, 5, 7); } } break; case 81 : case 209 : case 217 : { P0 = IC(1); P1 = IC(1); P2 = IC(1); if (HQ2X_MDR) { P3 = IC(1); } else { P3 = I211(1, 5, 7); } } break; case 82 : case 214 : case 222 : { P0 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I211(0, 5, 7); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 83 : case 115 : { P0 = IC(2); P2 = IC(2); if (HQ2X_MDR) { P3 = IC(2); } else { P3 = I611(2, 5, 7); } if (HQ2X_MUR) { P1 = IC(2); } else { P1 = I611(2, 1, 5); } } break; case 84 : case 212 : { P0 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P1 = IC(0); P3 = IC(0); } else { P1 = I31(0, 5); P3 = I332(5, 7, 0); } } break; case 85 : case 213 : case 221 : { P0 = IC(1); P2 = IC(1); if (HQ2X_MDR) { P1 = IC(1); P3 = IC(1); } else { P1 = I31(1, 5); P3 = I332(5, 7, 1); } } break; case 87 : { P0 = IC(3); P2 = IC(3); if (HQ2X_MDR) { P3 = IC(3); } else { P3 = I611(3, 5, 7); } if (HQ2X_MUR) { P1 = IC(3); } else { P1 = I211(3, 1, 5); } } break; case 88 : case 248 : case 250 : { P0 = IC(0); P1 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I211(0, 5, 7); } } break; case 89 : case 93 : { P0 = IC(1); P1 = IC(1); if (HQ2X_MDL) { P2 = IC(1); } else { P2 = I611(1, 3, 7); } if (HQ2X_MDR) { P3 = IC(1); } else { P3 = I611(1, 5, 7); } } break; case 90 : { if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I611(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I611(0, 5, 7); } if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I611(0, 1, 5); } } break; case 91 : { if (HQ2X_MDL) { P2 = IC(2); } else { P2 = I611(2, 3, 7); } if (HQ2X_MDR) { P3 = IC(2); } else { P3 = I611(2, 5, 7); } if (HQ2X_MUL) { P0 = IC(2); } else { P0 = I211(2, 1, 3); } if (HQ2X_MUR) { P1 = IC(2); } else { P1 = I611(2, 1, 5); } } break; case 92 : { P0 = IC(0); P1 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I611(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I611(0, 5, 7); } } break; case 94 : { if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I611(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I611(0, 5, 7); } if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 107 : case 123 : { P1 = IC(2); P3 = IC(2); if (HQ2X_MDL) { P2 = IC(2); } else { P2 = I211(2, 3, 7); } if (HQ2X_MUL) { P0 = IC(2); } else { P0 = I211(2, 1, 3); } } break; case 111 : { P1 = IC(4); P3 = IC(4); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } } break; case 112 : case 240 : { P0 = IC(0); P1 = IC(0); if (HQ2X_MDR) { P2 = IC(0); P3 = IC(0); } else { P2 = I31(0, 7); P3 = I332(5, 7, 0); } } break; case 113 : case 241 : { P0 = IC(1); P1 = IC(1); if (HQ2X_MDR) { P2 = IC(1); P3 = IC(1); } else { P2 = I31(1, 7); P3 = I332(5, 7, 1); } } break; case 114 : { P0 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I611(0, 5, 7); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I611(0, 1, 5); } } break; case 116 : { P0 = IC(0); P1 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I611(0, 5, 7); } } break; case 117 : { P0 = IC(1); P1 = IC(1); P2 = IC(1); if (HQ2X_MDR) { P3 = IC(1); } else { P3 = I611(1, 5, 7); } } break; case 121 : { P0 = IC(1); P1 = IC(1); if (HQ2X_MDL) { P2 = IC(1); } else { P2 = I211(1, 3, 7); } if (HQ2X_MDR) { P3 = IC(1); } else { P3 = I611(1, 5, 7); } } break; case 122 : { if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I611(0, 5, 7); } if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I611(0, 1, 5); } } break; case 126 : { P0 = IC(0); P3 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 127 : { P3 = IC(4); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I211(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I211(4, 1, 5); } } break; case 146 : case 150 : case 178 : case 182 : case 190 : { P0 = IC(0); P2 = IC(0); if (HQ2X_MUR) { P1 = IC(0); P3 = IC(0); } else { P1 = I332(1, 5, 0); P3 = I31(0, 5); } } break; case 147 : case 179 : { P0 = IC(2); P2 = IC(2); P3 = IC(2); if (HQ2X_MUR) { P1 = IC(2); } else { P1 = I611(2, 1, 5); } } break; case 151 : case 183 : { P0 = IC(3); P2 = IC(3); P3 = IC(3); if (HQ2X_MUR) { P1 = IC(3); } else { P1 = I1411(3, 1, 5); } } break; case 158 : { P2 = IC(0); P3 = IC(0); if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 159 : { P2 = IC(4); P3 = IC(4); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 191 : { P2 = IC(4); P3 = IC(4); if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 200 : case 204 : case 232 : case 236 : case 238 : { P0 = IC(0); P1 = IC(0); if (HQ2X_MDL) { P2 = IC(0); P3 = IC(0); } else { P2 = I332(3, 7, 0); P3 = I31(0, 7); } } break; case 201 : case 205 : { P0 = IC(1); P1 = IC(1); P3 = IC(1); if (HQ2X_MDL) { P2 = IC(1); } else { P2 = I611(1, 3, 7); } } break; case 211 : { P0 = IC(2); P1 = IC(2); P2 = IC(2); if (HQ2X_MDR) { P3 = IC(2); } else { P3 = I211(2, 5, 7); } } break; case 215 : { P0 = IC(3); P2 = IC(3); if (HQ2X_MDR) { P3 = IC(3); } else { P3 = I211(3, 5, 7); } if (HQ2X_MUR) { P1 = IC(3); } else { P1 = I1411(3, 1, 5); } } break; case 218 : { if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I611(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I211(0, 5, 7); } if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I611(0, 1, 5); } } break; case 219 : { P1 = IC(2); P2 = IC(2); if (HQ2X_MDR) { P3 = IC(2); } else { P3 = I211(2, 5, 7); } if (HQ2X_MUL) { P0 = IC(2); } else { P0 = I211(2, 1, 3); } } break; case 220 : { P0 = IC(0); P1 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I611(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I211(0, 5, 7); } } break; case 223 : { P2 = IC(4); if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I211(4, 5, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I211(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; case 233 : case 237 : { P0 = IC(1); P1 = IC(1); P3 = IC(1); if (HQ2X_MDL) { P2 = IC(1); } else { P2 = I1411(1, 3, 7); } } break; case 234 : { P1 = IC(0); P3 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } if (HQ2X_MUL) { P0 = IC(0); } else { P0 = I611(0, 1, 3); } } break; case 235 : { P1 = IC(2); P3 = IC(2); if (HQ2X_MDL) { P2 = IC(2); } else { P2 = I1411(2, 3, 7); } if (HQ2X_MUL) { P0 = IC(2); } else { P0 = I211(2, 1, 3); } } break; case 239 : { P1 = IC(4); P3 = IC(4); if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } } break; case 242 : { P0 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I211(0, 5, 7); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I611(0, 1, 5); } } break; case 243 : { P0 = IC(2); P1 = IC(2); if (HQ2X_MDR) { P2 = IC(2); P3 = IC(2); } else { P2 = I31(2, 7); P3 = I332(5, 7, 2); } } break; case 244 : { P0 = IC(0); P1 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I1411(0, 5, 7); } } break; case 245 : { P0 = IC(1); P1 = IC(1); P2 = IC(1); if (HQ2X_MDR) { P3 = IC(1); } else { P3 = I1411(1, 5, 7); } } break; case 246 : { P0 = IC(0); P2 = IC(0); if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I1411(0, 5, 7); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 247 : { P0 = IC(3); P2 = IC(3); if (HQ2X_MDR) { P3 = IC(3); } else { P3 = I1411(3, 5, 7); } if (HQ2X_MUR) { P1 = IC(3); } else { P1 = I1411(3, 1, 5); } } break; case 249 : { P0 = IC(1); P1 = IC(1); if (HQ2X_MDL) { P2 = IC(1); } else { P2 = I1411(1, 3, 7); } if (HQ2X_MDR) { P3 = IC(1); } else { P3 = I211(1, 5, 7); } } break; case 251 : { P1 = IC(2); if (HQ2X_MDL) { P2 = IC(2); } else { P2 = I1411(2, 3, 7); } if (HQ2X_MDR) { P3 = IC(2); } else { P3 = I211(2, 5, 7); } if (HQ2X_MUL) { P0 = IC(2); } else { P0 = I211(2, 1, 3); } } break; case 252 : { P0 = IC(0); P1 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I1411(0, 5, 7); } } break; case 253 : { P0 = IC(1); P1 = IC(1); if (HQ2X_MDL) { P2 = IC(1); } else { P2 = I1411(1, 3, 7); } if (HQ2X_MDR) { P3 = IC(1); } else { P3 = I1411(1, 5, 7); } } break; case 254 : { P0 = IC(0); if (HQ2X_MDL) { P2 = IC(0); } else { P2 = I211(0, 3, 7); } if (HQ2X_MDR) { P3 = IC(0); } else { P3 = I1411(0, 5, 7); } if (HQ2X_MUR) { P1 = IC(0); } else { P1 = I211(0, 1, 5); } } break; case 255 : { if (HQ2X_MDL) { P2 = IC(4); } else { P2 = I1411(4, 3, 7); } if (HQ2X_MDR) { P3 = IC(4); } else { P3 = I1411(4, 5, 7); } if (HQ2X_MUL) { P0 = IC(4); } else { P0 = I1411(4, 1, 3); } if (HQ2X_MUR) { P1 = IC(4); } else { P1 = I1411(4, 1, 5); } } break; mupen64plus-video-rice-src-2.6.0/src/TextureManager.cpp000066400000000000000000001203021464507324400227670ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "CombinerDefs.h" #include "Config.h" #include "ConvertImage.h" #include "Debugger.h" #include "DeviceBuilder.h" #include "FrameBuffer.h" #include "RSP_Parser.h" #include "RenderBase.h" #include "RenderTexture.h" #include "TextureManager.h" CTextureManager gTextureManager; unsigned int g_maxTextureMemUsage = (5*1024*1024); unsigned int g_amountToFree = (512*1024); bool g_bUseSetTextureMem = false; // Returns the first prime greater than or equal to nFirst inline int GetNextPrime(int nFirst) { int nCurrent; nCurrent = nFirst; // Just make sure it's odd if ((nCurrent % 2) == 0) nCurrent++; for (;;) { int nSqrtCurrent; BOOL bIsComposite; // nSqrtCurrent = nCurrent^0.5 + 1 (round up) nSqrtCurrent = (int)sqrt((double)nCurrent) + 1; bIsComposite = FALSE; // Test all odd numbers from 3..nSqrtCurrent for (int i = 3; i <= nSqrtCurrent; i+=2) { if ((nCurrent % i) == 0) { bIsComposite = TRUE; break; } } if (!bIsComposite) { return nCurrent; } // Select next odd candidate... nCurrent += 2; } } /////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////// CTextureManager::CTextureManager() : m_pHead(NULL), m_pCacheTxtrList(NULL), m_numOfCachedTxtrList(809) { m_numOfCachedTxtrList = GetNextPrime(800); m_currentTextureMemUsage = 0; m_pYoungestTexture = NULL; m_pOldestTexture = NULL; m_pCacheTxtrList = new TxtrCacheEntry *[m_numOfCachedTxtrList]; SAFE_CHECK(m_pCacheTxtrList); for (uint32 i = 0; i < m_numOfCachedTxtrList; i++) m_pCacheTxtrList[i] = NULL; memset(&m_blackTextureEntry, 0, sizeof(TxtrCacheEntry)); } CTextureManager::~CTextureManager() { CleanUp(); delete []m_pCacheTxtrList; m_pCacheTxtrList = NULL; } // // Delete all textures. // bool CTextureManager::CleanUp() { RecycleAllTextures(); if (!g_bUseSetTextureMem) { while (m_pHead) { TxtrCacheEntry * pVictim = m_pHead; m_pHead = pVictim->pNext; delete pVictim; } } if( m_blackTextureEntry.pTexture ) delete m_blackTextureEntry.pTexture; memset(&m_blackTextureEntry, 0, sizeof(TxtrCacheEntry)); return true; } bool CTextureManager::TCacheEntryIsLoaded(TxtrCacheEntry *pEntry) { for (int i = 0; i < MAX_TEXTURES; i++) { if (g_textures[i].pTextureEntry == pEntry) return true; } return false; } // Purge any textures whos last usage was over 5 seconds ago void CTextureManager::PurgeOldTextures() { if (m_pCacheTxtrList == NULL) return; if (g_bUseSetTextureMem) return; static const uint32 dwFramesToKill = 5*30; // 5 secs at 30 fps static const uint32 dwFramesToDelete = 30*30; // 30 secs at 30 fps for ( uint32 i = 0; i < m_numOfCachedTxtrList; i++ ) { TxtrCacheEntry * pEntry; TxtrCacheEntry * pNext; pEntry = m_pCacheTxtrList[i]; while (pEntry) { pNext = pEntry->pNext; if ( status.gDlistCount - pEntry->FrameLastUsed > dwFramesToKill && !TCacheEntryIsLoaded(pEntry)) { RemoveTexture(pEntry); } pEntry = pNext; } } // Remove any old textures that haven't been recycled in 1 minute or so // Normally these would be reused TxtrCacheEntry * pPrev; TxtrCacheEntry * pCurr; TxtrCacheEntry * pNext; pPrev = NULL; pCurr = m_pHead; while (pCurr) { pNext = pCurr->pNext; if ( status.gDlistCount - pCurr->FrameLastUsed > dwFramesToDelete && !TCacheEntryIsLoaded(pCurr) ) { if (pPrev != NULL) pPrev->pNext = pCurr->pNext; else m_pHead = pCurr->pNext; delete pCurr; pCurr = pNext; } else { pPrev = pCurr; pCurr = pNext; } } } void CTextureManager::RecycleAllTextures() { if (m_pCacheTxtrList == NULL) return; uint32 dwCount = 0; uint32 dwTotalUses = 0; m_pYoungestTexture = NULL; m_pOldestTexture = NULL; for (uint32 i = 0; i < m_numOfCachedTxtrList; i++) { while (m_pCacheTxtrList[i]) { TxtrCacheEntry *pTVictim = m_pCacheTxtrList[i]; m_pCacheTxtrList[i] = pTVictim->pNext; dwTotalUses += pTVictim->dwUses; dwCount++; if (g_bUseSetTextureMem) delete pTVictim; else RecycleTexture(pTVictim); } } } void CTextureManager::RecheckHiresForAllTextures() { if (m_pCacheTxtrList == NULL) return; for (uint32 i = 0; i < m_numOfCachedTxtrList; i++) { while (m_pCacheTxtrList[i]) { TxtrCacheEntry *pTVictim = m_pCacheTxtrList[i]; m_pCacheTxtrList[i] = pTVictim->pNext; pTVictim->bExternalTxtrChecked = false; } } } // Add to the recycle list void CTextureManager::RecycleTexture(TxtrCacheEntry *pEntry) { if (g_bUseSetTextureMem) return; if( CDeviceBuilder::GetGeneralDeviceType() == OGL_DEVICE ) { // Fix me, why I can not reuse the texture in OpenGL, // how can I unload texture from video card memory for OpenGL delete pEntry; return; } if (pEntry->pTexture == NULL) { // No point in saving! delete pEntry; } else { // Add to the list pEntry->pNext = m_pHead; SAFE_DELETE(pEntry->pEnhancedTexture); m_pHead = pEntry; } } // Search for a texture of the specified dimensions to recycle TxtrCacheEntry * CTextureManager::ReviveTexture( uint32 width, uint32 height ) { if (g_bUseSetTextureMem) return NULL; TxtrCacheEntry * pPrev; TxtrCacheEntry * pCurr; pPrev = NULL; pCurr = m_pHead; while (pCurr) { if (pCurr->ti.WidthToCreate == width && pCurr->ti.HeightToCreate == height) { // Remove from list if (pPrev != NULL) pPrev->pNext = pCurr->pNext; else m_pHead = pCurr->pNext; return pCurr; } pPrev = pCurr; pCurr = pCurr->pNext; } return NULL; } uint32 CTextureManager::Hash(uint32 dwValue) { // Divide by four, because most textures will be on a 4 byte boundry, so bottom four // bits are null return (dwValue>>2) % m_numOfCachedTxtrList; } void CTextureManager::MakeTextureYoungest(TxtrCacheEntry *pEntry) { if (!g_bUseSetTextureMem) return; if (pEntry == m_pYoungestTexture) return; // if its the oldest, then change the oldest pointer if (pEntry == m_pOldestTexture) { m_pOldestTexture = pEntry->pNextYoungest; } // if its a not a new texture, close the gap in the age list // where pEntry use to reside if (pEntry->pNextYoungest != NULL || pEntry->pLastYoungest != NULL) { if (pEntry->pNextYoungest != NULL) { pEntry->pNextYoungest->pLastYoungest = pEntry->pLastYoungest; } if (pEntry->pLastYoungest != NULL) { pEntry->pLastYoungest->pNextYoungest = pEntry->pNextYoungest; } } // this texture is now the youngest, so place it on the end of the list if (m_pYoungestTexture != NULL) { m_pYoungestTexture->pNextYoungest = pEntry; } pEntry->pNextYoungest = NULL; pEntry->pLastYoungest = m_pYoungestTexture; m_pYoungestTexture = pEntry; // if this is the first texture in memory then its also the oldest if (m_pOldestTexture == NULL) { m_pOldestTexture = pEntry; } } void CTextureManager::AddTexture(TxtrCacheEntry *pEntry) { uint32 dwKey = Hash(pEntry->ti.Address); if (m_pCacheTxtrList == NULL) return; //TxtrCacheEntry **p = &m_pCacheTxtrList[dwKey]; // Add to head (not tail, for speed - new textures are more likely to be accessed next) pEntry->pNext = m_pCacheTxtrList[dwKey]; m_pCacheTxtrList[dwKey] = pEntry; // Move the texture to the top of the age list MakeTextureYoungest(pEntry); } TxtrCacheEntry * CTextureManager::GetTxtrCacheEntry(TxtrInfo * pti) { TxtrCacheEntry *pEntry; if (m_pCacheTxtrList == NULL) return NULL; // See if it is already in the hash table uint32 dwKey = Hash(pti->Address); for (pEntry = m_pCacheTxtrList[dwKey]; pEntry; pEntry = pEntry->pNext) { if ( pEntry->ti == *pti ) { MakeTextureYoungest(pEntry); return pEntry; } } return NULL; } void CTextureManager::RemoveTexture(TxtrCacheEntry * pEntry) { TxtrCacheEntry * pPrev; TxtrCacheEntry * pCurr; if (m_pCacheTxtrList == NULL) return; // See if it is already in the hash table uint32 dwKey = Hash(pEntry->ti.Address); pPrev = NULL; pCurr = m_pCacheTxtrList[dwKey]; while (pCurr) { // Check that the attributes match if ( pCurr->ti == pEntry->ti ) { if (pPrev != NULL) pPrev->pNext = pCurr->pNext; else m_pCacheTxtrList[dwKey] = pCurr->pNext; if (g_bUseSetTextureMem) { // remove the texture from the age list if (pEntry->pNextYoungest != NULL) { pEntry->pNextYoungest->pLastYoungest = pEntry->pLastYoungest; } if (pEntry->pLastYoungest != NULL) { pEntry->pLastYoungest->pNextYoungest = pEntry->pNextYoungest; } // decrease the mem usage counter m_currentTextureMemUsage -= (pEntry->pTexture->m_dwWidth * pEntry->pTexture->m_dwHeight * 4); delete pEntry; } else { RecycleTexture(pEntry); } break; } pPrev = pCurr; pCurr = pCurr->pNext; } } TxtrCacheEntry * CTextureManager::CreateNewCacheEntry(uint32 dwAddr, uint32 dwWidth, uint32 dwHeight) { TxtrCacheEntry * pEntry = NULL; if (g_bUseSetTextureMem) { uint32 widthToCreate = dwWidth; uint32 heightToCreate = dwHeight; unsigned int freeUpSize = (widthToCreate * heightToCreate * 4) + g_amountToFree; // make sure there is enough room for the new texture by deleting old textures while ((m_currentTextureMemUsage + freeUpSize) > g_maxTextureMemUsage && m_pOldestTexture != NULL) { TxtrCacheEntry *nextYoungest = m_pOldestTexture->pNextYoungest; RemoveTexture(m_pOldestTexture); m_pOldestTexture = nextYoungest; //printf("Freeing Texture\n"); } m_currentTextureMemUsage += widthToCreate * heightToCreate * 4; } else { // Find a used texture pEntry = ReviveTexture(dwWidth, dwHeight); } if (pEntry == NULL || g_bUseSetTextureMem) { // Couldn't find on - recreate! pEntry = new TxtrCacheEntry; if (pEntry == NULL) { _VIDEO_DisplayTemporaryMessage("Error to create an texture entry"); return NULL; } pEntry->pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(dwWidth, dwHeight); if (pEntry->pTexture == NULL || pEntry->pTexture->GetTexture() == NULL) { _VIDEO_DisplayTemporaryMessage("Error to create an texture"); TRACE2("Warning, unable to create %d x %d texture!", dwWidth, dwHeight); } } // Initialize pEntry->ti.Address = dwAddr; pEntry->pNext = NULL; pEntry->pNextYoungest = NULL; pEntry->pLastYoungest = NULL; pEntry->dwUses = 0; pEntry->dwTimeLastUsed = status.gRDPTime; pEntry->dwCRC = 0; pEntry->FrameLastUsed = status.gDlistCount; pEntry->lastEntry = NULL; pEntry->bExternalTxtrChecked = false; pEntry->maxCI = -1; // Add to the hash table AddTexture(pEntry); return pEntry; } // If already in table, return // Otherwise, create surfaces, and load texture into memory uint32 dwAsmHeight; uint32 dwAsmPitch; uint32 dwAsmdwBytesPerLine; uint32 dwAsmCRC; uint32 dwAsmCRC2; uint8* pAsmStart; TxtrCacheEntry *g_lastTextureEntry=NULL; bool lastEntryModified = false; TxtrCacheEntry * CTextureManager::GetTexture(TxtrInfo * pgti, bool fromTMEM, bool doCRCCheck, bool AutoExtendTexture) { TxtrCacheEntry *pEntry; if( g_curRomInfo.bDisableTextureCRC ) doCRCCheck = false; dwAsmCRC = 0; uint32 dwPalCRC = 0; pEntry = GetTxtrCacheEntry(pgti); bool loadFromTextureBuffer=false; int txtBufIdxToLoadFrom = -1; if( (frameBufferOptions.bCheckRenderTextures&&!frameBufferOptions.bWriteBackBufToRDRAM) || (frameBufferOptions.bCheckBackBufs&&!frameBufferOptions.bWriteBackBufToRDRAM) ) { txtBufIdxToLoadFrom = g_pFrameBufferManager->CheckAddrInRenderTextures(pgti->Address); if( txtBufIdxToLoadFrom >= 0 ) { loadFromTextureBuffer = true; // Check if it is the same size, RenderTextureInfo &info = gRenderTextureInfos[txtBufIdxToLoadFrom]; //if( info.pRenderTexture && info.CI_Info.dwAddr == pgti->Address && info.CI_Info.dwFormat == pgti->Format if( info.pRenderTexture && info.CI_Info.dwFormat == pgti->Format && info.CI_Info.dwSize == pgti->Size ) { info.txtEntry.ti = *pgti; return &info.txtEntry; } } } if( frameBufferOptions.bCheckBackBufs && g_pFrameBufferManager->CheckAddrInBackBuffers(pgti->Address, pgti->HeightToLoad*pgti->Pitch) >= 0 ) { if( !frameBufferOptions.bWriteBackBufToRDRAM ) { // Load the texture from recent back buffer txtBufIdxToLoadFrom = g_pFrameBufferManager->CheckAddrInRenderTextures(pgti->Address); if( txtBufIdxToLoadFrom >= 0 ) { loadFromTextureBuffer = true; // Check if it is the same size, RenderTextureInfo &info = gRenderTextureInfos[txtBufIdxToLoadFrom]; //if( info.pRenderTexture && info.CI_Info.dwAddr == pgti->Address && info.CI_Info.dwFormat == pgti->Format if( info.pRenderTexture && info.CI_Info.dwFormat == pgti->Format && info.CI_Info.dwSize == pgti->Size ) { info.txtEntry.ti = *pgti; return &info.txtEntry; } } } } if (pEntry && pEntry->dwTimeLastUsed == status.gRDPTime && status.gDlistCount != 0 && !status.bN64FrameBufferIsUsed ) // This is not good, Palatte may changes { // We've already calculated a CRC this frame! dwAsmCRC = pEntry->dwCRC; } else { if ( doCRCCheck ) { if( loadFromTextureBuffer ) dwAsmCRC = gRenderTextureInfos[txtBufIdxToLoadFrom].crcInRDRAM; else CalculateRDRAMCRC(pgti->pPhysicalAddress, pgti->LeftToLoad, pgti->TopToLoad, pgti->WidthToLoad, pgti->HeightToLoad, pgti->Size, pgti->Pitch); } } int maxCI = 0; if ( doCRCCheck && (pgti->Format == TXT_FMT_CI || (pgti->Format == TXT_FMT_RGBA && pgti->Size <= TXT_SIZE_8b ))) { //maxCI = pgti->Size == TXT_SIZE_8b ? 255 : 15; extern unsigned char CalculateMaxCI(void *pPhysicalAddress, uint32 left, uint32 top, uint32 width, uint32 height, uint32 size, uint32 pitchInBytes ); if( !pEntry || pEntry->dwCRC != dwAsmCRC || pEntry->maxCI < 0 ) { maxCI = CalculateMaxCI(pgti->pPhysicalAddress, pgti->LeftToLoad, pgti->TopToLoad, pgti->WidthToLoad, pgti->HeightToLoad, pgti->Size, pgti->Pitch); } else { maxCI = pEntry->maxCI; } //Check PAL CRC uint8 * pStart; uint32 dwPalSize = 16; uint32 dwOffset; if( pgti->Size == TXT_SIZE_8b ) { dwPalSize = 256; dwOffset = 0; } else { dwOffset = pgti->Palette << 4; } pStart = (uint8*)pgti->PalAddress+dwOffset*2; //uint32 y; //for (y = 0; y < dwPalSize*2; y+=4) //{ // dwPalCRC = (dwPalCRC + *(uint32*)&pStart[y]); //} uint32 dwAsmCRCSave = dwAsmCRC; //dwPalCRC = CalculateRDRAMCRC(pStart, 0, 0, dwPalSize, 1, TXT_SIZE_16b, dwPalSize*2); dwPalCRC = CalculateRDRAMCRC(pStart, 0, 0, maxCI+1, 1, TXT_SIZE_16b, dwPalSize*2); dwAsmCRC = dwAsmCRCSave; } if (pEntry && doCRCCheck ) { if(pEntry->dwCRC == dwAsmCRC && pEntry->dwPalCRC == dwPalCRC && (!loadFromTextureBuffer || gRenderTextureInfos[txtBufIdxToLoadFrom].updateAtFrame < pEntry->FrameLastUsed ) ) { // Tile is ok, return pEntry->dwUses++; pEntry->dwTimeLastUsed = status.gRDPTime; pEntry->FrameLastUsed = status.gDlistCount; LOG_TEXTURE(TRACE0(" Use current texture:\n")); pEntry->lastEntry = g_lastTextureEntry; g_lastTextureEntry = pEntry; lastEntryModified = false; DEBUGGER_IF_DUMP((pauseAtNext && loadFromTextureBuffer) , {DebuggerAppendMsg("Load cached texture from render_texture");} ); return pEntry; } else { //Do something } } if (pEntry == NULL) { // We need to create a new entry, and add it // to the hash table. pEntry = CreateNewCacheEntry(pgti->Address, pgti->WidthToCreate, pgti->HeightToCreate); if (pEntry == NULL) { g_lastTextureEntry = pEntry; _VIDEO_DisplayTemporaryMessage("Fail to create new texture entry"); return NULL; } } pEntry->ti = *pgti; pEntry->dwCRC = dwAsmCRC; pEntry->dwPalCRC = dwPalCRC; pEntry->bExternalTxtrChecked = false; pEntry->maxCI = maxCI; try { if (pEntry->pTexture != NULL) { if( pEntry->pTexture->m_dwCreatedTextureWidth < pgti->WidthToCreate ) { pEntry->ti.WidthToLoad = pEntry->pTexture->m_dwCreatedTextureWidth; } if( pEntry->pTexture->m_dwCreatedTextureHeight < pgti->HeightToCreate ) { pEntry->ti.HeightToLoad = pEntry->pTexture->m_dwCreatedTextureHeight; } TextureFmt dwType = pEntry->pTexture->GetSurfaceFormat(); SAFE_DELETE(pEntry->pEnhancedTexture); pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT; if (dwType != TEXTURE_FMT_UNKNOWN) { if( loadFromTextureBuffer ) { g_pFrameBufferManager->LoadTextureFromRenderTexture(pEntry, txtBufIdxToLoadFrom); DEBUGGER_IF_DUMP((pauseAtNext && loadFromTextureBuffer) , {DebuggerAppendMsg("Load texture from render_texture %d", txtBufIdxToLoadFrom);} ); extern void ConvertTextureRGBAtoI(TxtrCacheEntry* pEntry, bool alpha); if( g_pRenderTextureInfo->CI_Info.dwFormat == TXT_FMT_I ) { // Convert texture from RGBA to I ConvertTextureRGBAtoI(pEntry,false); } else if( g_pRenderTextureInfo->CI_Info.dwFormat == TXT_FMT_IA ) { // Convert texture from RGBA to IA ConvertTextureRGBAtoI(pEntry,true); } } else { LOG_TEXTURE(TRACE0(" Load new texture from RDRAM:\n")); if (dwType == TEXTURE_FMT_A8R8G8B8) ConvertTexture(pEntry, fromTMEM); else ConvertTexture_16(pEntry, fromTMEM); SAFE_DELETE(pEntry->pEnhancedTexture); pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT; } } pEntry->ti.WidthToLoad = pgti->WidthToLoad; pEntry->ti.HeightToLoad = pgti->HeightToLoad; if( AutoExtendTexture ) { ExpandTextureS(pEntry); ExpandTextureT(pEntry); } if( options.bDumpTexturesToFiles && !loadFromTextureBuffer ) { DumpCachedTexture(*pEntry); } #ifdef DEBUGGER if( pauseAtNext && eventToPause == NEXT_NEW_TEXTURE ) { CRender::g_pRender->SetCurrentTexture( 0, pEntry->pTexture, pEntry->ti.WidthToCreate, pEntry->ti.HeightToCreate, pEntry); CRender::g_pRender->DrawTexture(0); debuggerPause = true; TRACE0("Pause after loading a new texture"); if( pEntry->ti.Format == TXT_FMT_YUV ) { TRACE0("This is YUV texture"); } DebuggerAppendMsg("W:%d, H:%d, RealW:%d, RealH:%d, D3DW:%d, D3DH: %d", pEntry->ti.WidthToCreate, pEntry->ti.HeightToCreate, pEntry->ti.WidthToLoad, pEntry->ti.HeightToLoad, pEntry->pTexture->m_dwCreatedTextureWidth, pEntry->pTexture->m_dwCreatedTextureHeight); DebuggerPause(); CRender::g_pRender->SetCurrentTexture( 0, NULL, 64, 64, NULL); } #endif } } catch (...) { TRACE0("Exception in texture decompression"); g_lastTextureEntry = NULL; return NULL; } pEntry->lastEntry = g_lastTextureEntry; g_lastTextureEntry = pEntry; lastEntryModified = true; return pEntry; } const char *pszImgFormat[8] = {"RGBA", "YUV", "CI", "IA", "I", "?1", "?2", "?3"}; uint8 pnImgSize[4] = {4, 8, 16, 32}; const char *textlutname[4] = {"RGB16", "I16?", "RGBA16", "IA16"}; extern uint16 g_wRDPTlut[]; extern ConvertFunction gConvertFunctions_FullTMEM[ 8 ][ 4 ]; extern ConvertFunction gConvertFunctions[ 8 ][ 4 ]; extern ConvertFunction gConvertTlutFunctions[ 8 ][ 4 ]; extern ConvertFunction gConvertFunctions_16[ 8 ][ 4 ]; extern ConvertFunction gConvertFunctions_16_FullTMEM[ 8 ][ 4 ]; extern ConvertFunction gConvertTlutFunctions_16[ 8 ][ 4 ]; void CTextureManager::ConvertTexture(TxtrCacheEntry * pEntry, bool fromTMEM) { static uint32 dwCount = 0; // We first figure out which convert function to use in the various // function pointer arrays. ConvertFunction pF; if( options.bUseFullTMEM && fromTMEM && status.bAllowLoadFromTMEM ) { pF = gConvertFunctions_FullTMEM[ pEntry->ti.Format ][ pEntry->ti.Size ]; } else { if( gRDP.tiles[7].dwFormat == TXT_FMT_YUV ) { if( gRDP.otherMode.text_tlut>=2 ) pF = gConvertTlutFunctions[ TXT_FMT_YUV ][ pEntry->ti.Size ]; else pF = gConvertFunctions[ TXT_FMT_YUV ][ pEntry->ti.Size ]; } else { if( gRDP.otherMode.text_tlut>=2 ) pF = gConvertTlutFunctions[ pEntry->ti.Format ][ pEntry->ti.Size ]; else pF = gConvertFunctions[ pEntry->ti.Format ][ pEntry->ti.Size ]; } } // Once we found it we simply execute it on the texture. if( pF ) { pF( pEntry->pTexture, pEntry->ti ); LOG_TEXTURE( { DebuggerAppendMsg("Decompress 32bit Texture:\n\tFormat: %s\n\tImage Size:%d\n", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]); DebuggerAppendMsg("Palette Format: %s (%d)\n", textlutname[pEntry->ti.TLutFmt>>RSP_SETOTHERMODE_SHIFT_TEXTLUT], pEntry->ti.TLutFmt>>RSP_SETOTHERMODE_SHIFT_TEXTLUT); }); } else { TRACE2("ConvertTexture: Unable to decompress %s/%dbpp", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]); } dwCount++; } void CTextureManager::ConvertTexture_16(TxtrCacheEntry * pEntry, bool fromTMEM) { static uint32 dwCount = 0; ConvertFunction pF; if( options.bUseFullTMEM && fromTMEM && status.bAllowLoadFromTMEM ) { pF = gConvertFunctions_16_FullTMEM[ pEntry->ti.Format ][ pEntry->ti.Size ]; } else { if( gRDP.otherMode.text_tlut>=2 ) pF = gConvertTlutFunctions_16[ pEntry->ti.Format ][ pEntry->ti.Size ]; else pF = gConvertFunctions_16[ pEntry->ti.Format ][ pEntry->ti.Size ]; } if( pF ) { pF( pEntry->pTexture, pEntry->ti ); LOG_TEXTURE(TRACE2("Decompress 16bit Texture:\n\tFormat: %s\n\tImage Size:%d\n", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size])); } else { TRACE2("ConvertTexture: Unable to decompress %s/%dbpp", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]); } dwCount++; } void CTextureManager::ExpandTexture(TxtrCacheEntry * pEntry, uint32 sizeToLoad, uint32 sizeToCreate, uint32 sizeCreated, int arrayWidth, int flag, int mask, int mirror, int clamp, uint32 otherSize) { if( sizeToLoad >= sizeCreated ) return; uint32 maskWidth = (1<pTexture->GetPixelSize(); #ifdef DEBUGGER // Some checks if( sizeToLoad > sizeToCreate || sizeToCreate > sizeCreated ) TRACE0("Something is wrong, check me here in ExpandTextureS"); #endif // Doing Mirror And/Or Wrap in S direction // Image has been loaded with width=WidthToLoad, we need to enlarge the image // to width = pEntry->ti.WidthToCreate by doing mirroring or wrapping DrawInfo di; if( !(pEntry->pTexture->StartUpdate(&di)) ) { TRACE0("Cann't update the texture"); return; } if( mask == 0 ) { // Clamp Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, flag, size); pEntry->pTexture->EndUpdate(&di); return; } #ifdef DEBUGGER if( sizeToLoad > maskWidth ) { TRACE0("Something is wrong, check me here in ExpandTextureS"); pEntry->pTexture->EndUpdate(&di); return; } if( sizeToLoad == maskWidth && maskWidth == sizeToCreate && sizeToCreate != sizeCreated ) { TRACE0("Something is wrong, check me here in ExpandTextureS"); pEntry->pTexture->EndUpdate(&di); return; } #endif if( sizeToLoad == maskWidth ) { uint32 tempwidth = clamp ? sizeToCreate : sizeCreated; if( mirror ) { Mirror(di.lpSurface, sizeToLoad, mask, tempwidth, arrayWidth, otherSize, flag, size ); } else { Wrap(di.lpSurface, sizeToLoad, mask, tempwidth, arrayWidth, otherSize, flag, size ); } if( tempwidth < sizeCreated ) { Clamp(di.lpSurface, tempwidth, sizeCreated, arrayWidth, otherSize, flag, size ); } pEntry->pTexture->EndUpdate(&di); return; } if( sizeToLoad < sizeToCreate && sizeToCreate == maskWidth && maskWidth == sizeCreated ) { // widthToLoad < widthToCreate = maskWidth Wrap(di.lpSurface, sizeToLoad, mask, sizeCreated, arrayWidth, otherSize, flag, size ); pEntry->pTexture->EndUpdate(&di); return; } if( sizeToLoad == sizeToCreate && sizeToCreate < maskWidth ) { #ifdef DEBUGGER if( maskWidth < sizeToCreate ) TRACE0("Incorrect condition, check me"); #endif Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, flag, size ); pEntry->pTexture->EndUpdate(&di); return; } if( sizeToLoad < sizeToCreate && sizeToCreate < maskWidth ) { #ifdef DEBUGGER if( clamp ) TRACE0("Incorrect condition, check me"); if( maskWidth < sizeCreated ) TRACE0("Incorrect condition, check me"); #endif Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, flag, size ); pEntry->pTexture->EndUpdate(&di); return; } TRACE0("Check me, should not get here"); pEntry->pTexture->EndUpdate(&di); } void CTextureManager::ExpandTextureS(TxtrCacheEntry * pEntry) { TxtrInfo &ti = pEntry->ti; uint32 textureWidth = pEntry->pTexture->m_dwCreatedTextureWidth; ExpandTexture(pEntry, ti.WidthToLoad, ti.WidthToCreate, textureWidth, textureWidth, S_FLAG, ti.maskS, ti.mirrorS, ti.clampS, ti.HeightToLoad); } void CTextureManager::ExpandTextureT(TxtrCacheEntry * pEntry) { TxtrInfo &ti = pEntry->ti; uint32 textureHeight = pEntry->pTexture->m_dwCreatedTextureHeight; uint32 textureWidth = pEntry->pTexture->m_dwCreatedTextureWidth; ExpandTexture(pEntry, ti.HeightToLoad, ti.HeightToCreate, textureHeight, textureWidth, T_FLAG, ti.maskT, ti.mirrorT, ti.clampT, ti.WidthToLoad); } void CTextureManager::ClampS32(uint32 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows) { if ((int) width <= 0 || (int) towidth < 0) return; for( uint32 y = 0; ymaskval?y&maskval:y-height); uint32* linedst = array+arrayWidth*y;; for( uint32 x=0; xmaskval?y&maskval:y-height); uint16* linedst = array+arrayWidth*y;; for( uint32 x=0; xpNext) { if( size == tex ) return pEntry; else size++; } } } return NULL; } uint32 CTextureManager::GetNumOfCachedTexture() { uint32 size = 0; for( uint32 i=0; ipNext) { size++; } } } TRACE1("Totally %d texture cached", size); return size; } #endif TxtrCacheEntry * CTextureManager::GetBlackTexture(void) { if( m_blackTextureEntry.pTexture == NULL ) { m_blackTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4); m_blackTextureEntry.ti.WidthToCreate = 4; m_blackTextureEntry.ti.HeightToCreate = 4; updateColorTexture(m_blackTextureEntry.pTexture,0x00000000); } return &m_blackTextureEntry; } void CTextureManager::updateColorTexture(CTexture *ptexture, uint32 color) { DrawInfo di; if( !(ptexture->StartUpdate(&di)) ) { TRACE0("Cann't update the texture"); return; } int size = ptexture->GetPixelSize(); switch( size ) { case 2: // 16 bits { uint16 *buf = (uint16*)di.lpSurface; uint16 color16= (uint16)((color>>4)&0xF); color16 |= ((color>>12)&0xF)<<4; color16 |= ((color>>20)&0xF)<<8; color16 |= ((color>>28)&0xF)<<12; for( int i=0; i<16; i++ ) { buf[i] = color16; } } break; case 4: // 32 bits { uint32 *buf = (uint32*)di.lpSurface; for( int i=0; i<16; i++ ) { buf[i] = color; } } break; } ptexture->EndUpdate(&di); } void ConvertTextureRGBAtoI(TxtrCacheEntry* pEntry, bool alpha) { DrawInfo srcInfo; if( pEntry->pTexture->StartUpdate(&srcInfo) ) { uint32 *buf; uint32 val; uint32 r,g,b,a,i; for(int nY = 0; nY < srcInfo.dwCreatedHeight; nY++) { buf = (uint32*)((uint8*)srcInfo.lpSurface+nY*srcInfo.lPitch); for(int nX = 0; nX < srcInfo.dwCreatedWidth; nX++) { val = buf[nX]; b = (val>>0)&0xFF; g = (val>>8)&0xFF; r = (val>>16)&0xFF; i = (r+g+b)/3; a = alpha?(val&0xFF000000):(i<<24); buf[nX] = (a|(i<<16)|(i<<8)|i); } } pEntry->pTexture->EndUpdate(&srcInfo); } } mupen64plus-video-rice-src-2.6.0/src/TextureManager.h000066400000000000000000000172411464507324400224430ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __TEXTUREHANDLER_H__ #define __TEXTUREHANDLER_H__ #ifndef SAFE_DELETE #define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } #endif #ifndef SAFE_CHECK # define SAFE_CHECK(a) if( (a) == NULL ) {DebugMessage(M64MSG_ERROR, "Creater out of memory"); throw new std::exception();} #endif #include #include #include "Texture.h" #include "Video.h" #include "m64p_types.h" #include "osal_preproc.h" #include "typedefs.h" #define absi(x) ((x)>=0?(x):(-x)) #define S_FLAG 0 #define T_FLAG 1 class TxtrInfo { public: uint32 WidthToCreate; uint32 HeightToCreate; uint32 Address; void *pPhysicalAddress; uint32 Format; uint32 Size; int LeftToLoad; int TopToLoad; uint32 WidthToLoad; uint32 HeightToLoad; uint32 Pitch; uchar *PalAddress; uint32 TLutFmt; uint32 Palette; BOOL bSwapped; // if true: odd lines are WORD swapped uint32 maskS; uint32 maskT; BOOL clampS; BOOL clampT; BOOL mirrorS; BOOL mirrorT; int tileNo; inline TxtrInfo& operator = (const TxtrInfo& src) { memcpy(this, &src, sizeof( TxtrInfo )); return *this; } inline TxtrInfo& operator = (const Tile& tile) { Format = tile.dwFormat; Size = tile.dwSize; Palette = tile.dwPalette; maskS = tile.dwMaskS; maskT = tile.dwMaskT; mirrorS = tile.bMirrorS; mirrorT = tile.bMirrorT; clampS = tile.bClampS; clampT = tile.bClampT; return *this; } inline bool operator == ( const TxtrInfo& sec) { return ( Address == sec.Address && WidthToLoad == sec.WidthToLoad && HeightToLoad == sec.HeightToLoad && WidthToCreate == sec.WidthToCreate && HeightToCreate == sec.HeightToCreate && maskS == sec.maskS && maskT == sec.maskT && TLutFmt == sec.TLutFmt && PalAddress == sec.PalAddress && Palette == sec.Palette && LeftToLoad == sec.LeftToLoad && TopToLoad == sec.TopToLoad && Format == sec.Format && Size == sec.Size && Pitch == sec.Pitch && bSwapped == sec.bSwapped && mirrorS == sec.mirrorS && mirrorT == sec.mirrorT && clampS == sec.clampS && clampT == sec.clampT ); } } ; typedef struct TxtrCacheEntry { TxtrCacheEntry(): pTexture(NULL),pEnhancedTexture(NULL),txtrBufIdx(0) {} ~TxtrCacheEntry() { SAFE_DELETE(pTexture); SAFE_DELETE(pEnhancedTexture); } struct TxtrCacheEntry *pNext; // Must be first element! struct TxtrCacheEntry *pNextYoungest; struct TxtrCacheEntry *pLastYoungest; TxtrInfo ti; uint32 dwCRC; uint32 dwPalCRC; int maxCI; uint32 dwUses; // Total times used (for stats) uint32 dwTimeLastUsed; // timeGetTime of time of last usage uint32 FrameLastUsed; // Frame # that this was last used CTexture *pTexture; CTexture *pEnhancedTexture; uint32 dwEnhancementFlag; int txtrBufIdx; bool bExternalTxtrChecked; TxtrCacheEntry *lastEntry; } TxtrCacheEntry; //***************************************************************************** // Texture cache implementation //***************************************************************************** class CTextureManager { protected: TxtrCacheEntry * CreateNewCacheEntry(uint32 dwAddr, uint32 dwWidth, uint32 dwHeight); void AddTexture(TxtrCacheEntry *pEntry); void RemoveTexture(TxtrCacheEntry * pEntry); void RecycleTexture(TxtrCacheEntry *pEntry); TxtrCacheEntry * ReviveTexture( uint32 width, uint32 height ); TxtrCacheEntry * GetTxtrCacheEntry(TxtrInfo * pti); void ConvertTexture(TxtrCacheEntry * pEntry, bool fromTMEM); void ConvertTexture_16(TxtrCacheEntry * pEntry, bool fromTMEM); void ClampS32(uint32 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows); void ClampS16(uint16 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows); void ClampT32(uint32 *array, uint32 height, uint32 toheight, uint32 arrayWidth, uint32 cols); void ClampT16(uint16 *array, uint32 height, uint32 toheight, uint32 arrayWidth, uint32 cols); void MirrorS32(uint32 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows); void MirrorS16(uint16 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows); void MirrorT32(uint32 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols); void MirrorT16(uint16 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols); void WrapS32(uint32 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows); void WrapS16(uint16 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows); void WrapT32(uint32 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols); void WrapT16(uint16 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols); void ExpandTextureS(TxtrCacheEntry * pEntry); void ExpandTextureT(TxtrCacheEntry * pEntry); void ExpandTexture(TxtrCacheEntry * pEntry, uint32 sizeOfLoad, uint32 sizeToCreate, uint32 sizeCreated, int arrayWidth, int flag, int mask, int mirror, int clamp, uint32 otherSize); uint32 Hash(uint32 dwValue); bool TCacheEntryIsLoaded(TxtrCacheEntry *pEntry); void updateColorTexture(CTexture *ptexture, uint32 color); public: void Wrap(void *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size ); void Clamp(void *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size ); void Mirror(void *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size ); protected: TxtrCacheEntry * m_pHead; TxtrCacheEntry ** m_pCacheTxtrList; uint32 m_numOfCachedTxtrList; TxtrCacheEntry m_blackTextureEntry; void MakeTextureYoungest(TxtrCacheEntry *pEntry); unsigned int m_currentTextureMemUsage; TxtrCacheEntry *m_pYoungestTexture; TxtrCacheEntry *m_pOldestTexture; public: CTextureManager(); ~CTextureManager(); TxtrCacheEntry * GetBlackTexture(void); TxtrCacheEntry * GetTexture(TxtrInfo * pgti, bool fromTMEM, bool doCRCCheck=true, bool AutoExtendTexture = false); void PurgeOldTextures(); void RecycleAllTextures(); void RecheckHiresForAllTextures(); bool CleanUp(); #ifdef DEBUGGER TxtrCacheEntry * GetCachedTexture(uint32 tex); uint32 GetNumOfCachedTexture(); #endif }; extern CTextureManager gTextureManager; // The global instance of CTextureManager class extern void DumpCachedTexture(TxtrCacheEntry &entry); #endif mupen64plus-video-rice-src-2.6.0/src/Timing.h000066400000000000000000000111431464507324400207320ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _RSP_RDP_TIMING_H_ #define _RSP_RDP_TIMING_H_ enum { Timing_SP_Minimal = 10, Timing_SP_Minimal2 = 20, Timing_SP_Minimal4 = 40, Timing_SP_Minimal8 = 80, Timing_SP_Each_Triangle = 80, Timing_SP_Each_2_Triangle2 = 160, Timing_RSP_GBI1_SpNoop = Timing_SP_Minimal, Timing_RSP_GBI0_Mtx = Timing_SP_Minimal8, Timing_RSP_GBI1_Reserved = Timing_SP_Minimal2, Timing_RSP_GBI1_MoveMem = Timing_SP_Minimal2, // Fix me Timing_RSP_GBI1_Vtx = Timing_SP_Minimal4, // for each vertex Timing_RSP_GBI0_Vtx = Timing_SP_Minimal4, // for each vertex Timing_RSP_GBI0_DL = Timing_SP_Minimal*2, Timing_RSP_GBI1_Sprite2DBase = Timing_SP_Minimal8, Timing_RSP_GBI1_LoadUCode = 800, Timing_RSP_GBI1_BranchZ = Timing_SP_Minimal2, Timing_RSP_GBI1_Tri2 = Timing_SP_Each_2_Triangle2, Timing_RSP_GBI1_ModifyVtx = Timing_SP_Minimal4, Timing_RSP_GBI1_RDPHalf_2 = Timing_SP_Minimal, Timing_RSP_GBI1_RDPHalf_1 = Timing_SP_Minimal, Timing_RSP_GBI1_RDPHalf_Cont = Timing_SP_Minimal, Timing_RSP_GBI1_Line3D = Timing_SP_Each_Triangle, Timing_RSP_GBI1_ClearGeometryMode = Timing_SP_Minimal, Timing_RSP_GBI1_SetGeometryMode = Timing_SP_Minimal, Timing_RSP_GBI2_GeometryMode = Timing_SP_Minimal, Timing_RSP_GBI1_EndDL = Timing_SP_Minimal, Timing_RSP_GBI1_SetOtherModeL = Timing_SP_Minimal, Timing_RSP_GBI1_SetOtherModeH = Timing_SP_Minimal, Timing_RSP_GBI1_Texture = Timing_SP_Minimal2, Timing_RSP_GBI1_MoveWord = Timing_SP_Minimal2, Timing_RSP_GBI2_SubModule = Timing_SP_Minimal2, Timing_RSP_GBI1_PopMtx = Timing_SP_Minimal8, Timing_RSP_GBI1_CullDL = Timing_SP_Minimal2, Timing_RSP_GBI1_Tri1 = Timing_SP_Each_Triangle, Timing_RSP_GBI1_Noop = Timing_SP_Minimal, Timing_RSP_S2DEX_SPObjLoadTxtr_Ucode1 = Timing_SP_Minimal8, Timing_DP_Minimal = 10, Timing_DP_Minimal2 = 20, Timing_DP_Minimal4 = 40, Timing_DP_Minimal8 = 80, Timing_DP_Minimal16 = 160, Timing_DP_Each_Point = 1, Timing_RDP_TriFill = Timing_DP_Minimal8, Timing_RDP_TriFillZ = Timing_DP_Minimal8, Timing_RDP_TriTxtr = Timing_DP_Minimal8, Timing_RDP_TriTxtrZ = Timing_DP_Minimal8, Timing_RDP_TriShade = Timing_DP_Minimal8, Timing_RDP_TriShadeZ = Timing_DP_Minimal8, Timing_RDP_TriShadeTxtr = Timing_DP_Minimal8, Timing_RDP_TriShadeTxtrZ = Timing_DP_Minimal8, Timing_DLParser_TexRect = Timing_DP_Minimal8, Timing_DLParser_TexRectFlip = Timing_DP_Minimal8, Timing_DLParser_RDPLoadSync = Timing_DP_Minimal, Timing_DLParser_RDPPipeSync = Timing_DP_Minimal, Timing_DLParser_RDPTileSync = Timing_DP_Minimal, Timing_DLParser_RDPFullSync = Timing_DP_Minimal8, Timing_DLParser_SetKeyGB = Timing_DP_Minimal, Timing_DLParser_SetKeyR = Timing_DP_Minimal, Timing_DLParser_SetConvert = Timing_DP_Minimal2, Timing_DLParser_SetScissor = Timing_DP_Minimal2, Timing_DLParser_SetPrimDepth = Timing_DP_Minimal2, Timing_DLParser_RDPSetOtherMode = Timing_DP_Minimal, Timing_DLParser_LoadTLut = Timing_DP_Minimal16, Timing_RSP_RDP_Nothing = Timing_DP_Minimal, Timing_DLParser_SetTileSize = Timing_DP_Minimal4, Timing_DLParser_LoadBlock = Timing_DP_Minimal16, Timing_DLParser_LoadTile = Timing_DP_Minimal16, Timing_DLParser_SetTile = Timing_DP_Minimal8, Timing_DLParser_FillRect = Timing_DP_Minimal16, Timing_DLParser_SetFillColor = Timing_DP_Minimal, Timing_DLParser_SetFogColor = Timing_DP_Minimal, Timing_DLParser_SetBlendColor = Timing_DP_Minimal, Timing_DLParser_SetPrimColor = Timing_DP_Minimal, Timing_DLParser_SetEnvColor = Timing_DP_Minimal, Timing_DLParser_SetCombine = Timing_DP_Minimal, Timing_DLParser_SetTImg = Timing_DP_Minimal, Timing_DLParser_SetZImg = Timing_DP_Minimal, Timing_DLParser_SetCImg = Timing_DP_Minimal, }; #define DP_Timing(t) {status.DPCycleCount+=Timing_##t;} #define SP_Timing(t) {status.SPCycleCount+=Timing_##t;} #endif mupen64plus-video-rice-src-2.6.0/src/UcodeDefs.h000066400000000000000000000167041464507324400213540ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _UCODE_DEFS_H_ #define _UCODE_DEFS_H_ typedef struct { union { unsigned int w0; struct { unsigned int arg0:24; unsigned int cmd:8; }; }; unsigned int w1; } Gwords; typedef struct { unsigned int w0; unsigned int v2:8; unsigned int v1:8; unsigned int v0:8; unsigned int flag:8; } GGBI0_Tri1; typedef struct { unsigned int v0:8; unsigned int v1:8; unsigned int v2:8; unsigned int cmd:8; unsigned int pad:24; unsigned int flag:8; } GGBI2_Tri1; typedef struct { unsigned int :1; unsigned int v3:7; unsigned int :1; unsigned int v4:7; unsigned int :1; unsigned int v5:7; unsigned int cmd:8; unsigned int :1; unsigned int v0:7; unsigned int :1; unsigned int v1:7; unsigned int :1; unsigned int v2:7; unsigned int flag:8; } GGBI2_Tri2; typedef struct { unsigned int w0; unsigned int v2:8; unsigned int v1:8; unsigned int v0:8; unsigned int v3:8; } GGBI0_Ln3DTri2; typedef struct { unsigned int v5:8; unsigned int v4:8; unsigned int v3:8; unsigned int cmd:8; unsigned int v2:8; unsigned int v1:8; unsigned int v0:8; unsigned int flag:8; } GGBI1_Tri2; typedef struct { unsigned int v3:8; unsigned int v4:8; unsigned int v5:8; unsigned int cmd:8; unsigned int v0:8; unsigned int v1:8; unsigned int v2:8; unsigned int flag:8; } GGBI2_Line3D; typedef struct { unsigned int len:16; unsigned int v0:4; unsigned int n:4; unsigned int cmd:8; unsigned int addr; } GGBI0_Vtx; typedef struct { unsigned int len:10; unsigned int n:6; unsigned int :1; unsigned int v0:7; unsigned int cmd:8; unsigned int addr; } GGBI1_Vtx; typedef struct { unsigned int :1; unsigned int vend:7; unsigned int :4; unsigned int n:8; unsigned int :4; unsigned int cmd:8; unsigned int addr; } GGBI2_Vtx; typedef struct { unsigned int width:12; unsigned int :7; unsigned int siz:2; unsigned int fmt:3; unsigned int cmd:8; unsigned int addr; } GSetImg; typedef struct { unsigned int prim_level:8; unsigned int prim_min_level:8; unsigned int pad:8; unsigned int cmd:8; union { unsigned int color; struct { unsigned int fillcolor:16; unsigned int fillcolor2:16; }; struct { unsigned int a:8; unsigned int b:8; unsigned int g:8; unsigned int r:8; }; }; } GSetColor; typedef struct { unsigned int :16; unsigned int param:8; unsigned int cmd:8; unsigned int addr; } GGBI0_Dlist; typedef struct { unsigned int len:16; unsigned int projection:1; unsigned int load:1; unsigned int push:1; unsigned int :5; unsigned int cmd:8; unsigned int addr; } GGBI0_Matrix; typedef struct { unsigned int :24; unsigned int cmd:8; unsigned int projection:1; unsigned int :31; } GGBI0_PopMatrix; typedef struct { union { struct { unsigned int param:8; unsigned int len:16; unsigned int cmd:8; }; struct { unsigned int nopush:1; unsigned int load:1; unsigned int projection:1; unsigned int :5; unsigned int len2:16; unsigned int cmd2:8; }; }; unsigned int addr; } GGBI2_Matrix; typedef struct { unsigned int type:8; unsigned int offset:16; unsigned int cmd:8; unsigned int value; } GGBI0_MoveWord; typedef struct { unsigned int offset:16; unsigned int type:8; unsigned int cmd:8; unsigned int value; } GGBI2_MoveWord; typedef struct { unsigned int enable_gbi0:1; unsigned int enable_gbi2:1; unsigned int :6; unsigned int tile:3; unsigned int level:3; unsigned int :10; unsigned int cmd:8; unsigned int scaleT:16; unsigned int scaleS:16; } GTexture; typedef struct { unsigned int tl:12; unsigned int sl:12; unsigned int cmd:8; unsigned int th:12; unsigned int sh:12; unsigned int tile:3; unsigned int pad:5; } Gloadtile; typedef struct { unsigned int tmem:9; unsigned int line:9; unsigned int pad0:1; unsigned int siz:2; unsigned int fmt:3; unsigned int cmd:8; unsigned int shifts:4; unsigned int masks:4; unsigned int ms:1; unsigned int cs:1; unsigned int shiftt:4; unsigned int maskt:4; unsigned int mt:1; unsigned int ct:1; unsigned int palette:4; unsigned int tile:3; unsigned int pad1:5; } Gsettile; typedef union { Gwords words; GGBI0_Tri1 tri1; GGBI0_Ln3DTri2 ln3dtri2; GGBI1_Tri2 gbi1tri2; GGBI2_Tri1 gbi2tri1; GGBI2_Tri2 gbi2tri2; GGBI2_Line3D gbi2line3d; GGBI0_Vtx gbi0vtx; GGBI1_Vtx gbi1vtx; GGBI2_Vtx gbi2vtx; GSetImg setimg; GSetColor setcolor; GGBI0_Dlist gbi0dlist; GGBI0_Matrix gbi0matrix; GGBI0_PopMatrix gbi0popmatrix; GGBI2_Matrix gbi2matrix; GGBI0_MoveWord gbi0moveword; GGBI2_MoveWord gbi2moveword; GTexture texture; Gloadtile loadtile; Gsettile settile; /* Gdma dma; Gsegment segment; GsetothermodeH setothermodeH; GsetothermodeL setothermodeL; Gtexture texture; Gperspnorm perspnorm; Gsetcombine setcombine; Gfillrect fillrect; Gsettile settile; Gloadtile loadtile; Gsettilesize settilesize; Gloadtlut loadtlut; */ long long int force_structure_alignment; } Gfx; typedef union { struct { unsigned int w0; unsigned int w1; unsigned int w2; unsigned int w3; }; struct { unsigned int yl:12; /* Y coordinate of upper left */ unsigned int xl:12; /* X coordinate of upper left */ unsigned int cmd:8; /* command */ unsigned int yh:12; /* Y coordinate of lower right */ unsigned int xh:12; /* X coordinate of lower right */ unsigned int tile:3; /* Tile descriptor index */ unsigned int pad1:5; /* Padding */ unsigned int t:16; /* T texture coord at top left */ unsigned int s:16; /* S texture coord at top left */ unsigned int dtdy:16;/* Change in T per change in Y */ unsigned int dsdx:16;/* Change in S per change in X */ }; } Gtexrect; #endif mupen64plus-video-rice-src-2.6.0/src/VectorMath.cpp000066400000000000000000000171041464507324400221150ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - VectorMath.cpp * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Rice1964 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "VectorMath.h" //---------- XMATRIX XMATRIX::XMATRIX() { } XMATRIX::XMATRIX( const float *pIn ) { memcpy(m, pIn, 16*4); } XMATRIX::XMATRIX( const MATRIX &pIn ) { memcpy(m, pIn.m, 16*4); } XMATRIX::XMATRIX( float _11, float _12, float _13, float _14, float _21, float _22, float _23, float _24, float _31, float _32, float _33, float _34, float _41, float _42, float _43, float _44 ) { this->_11 = _11; this->_12 = _12; this->_13 = _13; this->_14 = _14; this->_21 = _21; this->_22 = _22; this->_23 = _23; this->_24 = _24; this->_31 = _31; this->_32 = _32; this->_33 = _33; this->_34 = _34; this->_41 = _41; this->_42 = _42; this->_43 = _43; this->_44 = _44; } float& XMATRIX::operator () ( unsigned int Row, unsigned int Col ) { return m[Row][Col]; } float XMATRIX::operator () ( unsigned int Row, unsigned int Col ) const { return m[Row][Col]; } XMATRIX::operator float* () { return (float*)m; } XMATRIX::operator const float* () const { return (float*)m; } XMATRIX& XMATRIX::operator *= ( const XMATRIX &pIn ) { XMATRIX mTemp(*this); *this = mTemp*pIn; return *this; } XMATRIX& XMATRIX::operator += ( const XMATRIX &pIn ) { XMATRIX mTemp(*this); *this = mTemp+pIn; return *this; } XMATRIX& XMATRIX::operator -= ( const XMATRIX &pIn ) { XMATRIX mTemp(*this); *this = mTemp-pIn; return *this; } XMATRIX& XMATRIX::operator *= ( float f) { for (int i=0; i<16; i++) { ((float*)m)[i] *= f; } return *this; } XMATRIX& XMATRIX::operator /= ( float f) { for (int i=0; i<16; i++) { ((float*)m)[i] /= f; } return *this; } XMATRIX XMATRIX::operator + () const { return *this; } XMATRIX XMATRIX::operator - () const { XMATRIX mTemp; for (int i=0; i<16; i++) { ((float*)mTemp.m)[i] = -((float*)m)[i]; } return mTemp; } XMATRIX XMATRIX::operator * ( const XMATRIX &pIn ) const { XMATRIX mTemp; for (int i=0; i<4; i++) { for (int j=0; j<4; j++) { mTemp.m[i][j] = m[i][0]*pIn.m[0][j] + m[i][1]*pIn.m[1][j] + m[i][2]*pIn.m[2][j] + m[i][3]*pIn.m[3][j]; } } return mTemp; } XMATRIX XMATRIX::operator + ( const XMATRIX &pIn ) const { XMATRIX mTemp; for (int i=0; i<16; i++) { ((float*)mTemp.m)[i] = ((float*)m)[i] + ((float*)pIn.m)[i]; } return mTemp; } XMATRIX XMATRIX::operator - ( const XMATRIX &pIn ) const { XMATRIX mTemp; for (int i=0; i<16; i++) { ((float*)mTemp.m)[i] = ((float*)m)[i] - ((float*)pIn.m)[i]; } return mTemp; } /* XMATRIX operator * ( float ) const; XMATRIX operator / ( float ) const; friend XMATRIX operator * ( float, const XMATRIX & ); bool operator == ( const XMATRIX & ) const; bool operator != ( const XMATRIX & ) const; */ //---------- VECTOR3 XVECTOR3::XVECTOR3() { } XVECTOR3::XVECTOR3( const float *f ) { x = f[0]; y = f[1]; z = f[2]; } XVECTOR3::XVECTOR3( const VECTOR3 &v ) { x = v.x; y = v.y; z = v.z; } XVECTOR3::XVECTOR3( float _x, float _y, float _z ) { x = _x; y = _y; z = _z; } /* // casting inline operator float* (); inline operator const float* () const; // assignment operators inline XVECTOR3& operator += ( const XVECTOR3 &op ); inline XVECTOR3& operator -= ( const XVECTOR3 &op ); inline XVECTOR3& operator *= ( float op ); inline XVECTOR3& operator /= ( float op ); // unary operators inline XVECTOR3 operator + () const; inline XVECTOR3 operator - () const; // binary operators inline XVECTOR3 operator + ( const XVECTOR3 &op ) const; inline XVECTOR3 operator - ( const XVECTOR3 &op ) const; inline XVECTOR3 operator * ( float op ) const; inline XVECTOR3 operator / ( float op ) const; friend XVECTOR3 operator * ( float, const XVECTOR3& ); inline bool operator == ( const XVECTOR3 &op ) const; inline bool operator != ( const XVECTOR3 &op ) const; */ //---------- XVECTOR4 XVECTOR4::XVECTOR4() { } /* XVECTOR4( const float *f ); XVECTOR4( const VECTOR4 &v ); XVECTOR4( float _x, float _y, float _z, float _w ); // casting inline operator float* (); inline operator const float* () const; // assignment operators inline XVECTOR4& operator += ( const XVECTOR4 &op ); inline XVECTOR4& operator -= ( const XVECTOR4 &op ); inline XVECTOR4& operator *= ( float op ); inline XVECTOR4& operator /= ( float op ); // unary operators inline XVECTOR4 operator + () const; inline XVECTOR4 operator - () const; // binary operators inline XVECTOR4 operator + ( const XVECTOR4 &op ) const; inline XVECTOR4 operator - ( const XVECTOR4 &op ) const; inline XVECTOR4 operator * ( float op ) const; inline XVECTOR4 operator / ( float op ) const; friend XVECTOR4 operator * ( float, const XVECTOR4& ); inline bool operator == ( const XVECTOR4 &op ) const; inline bool operator != ( const XVECTOR4 &op ) const; */ //---------- OTHER XMATRIX* MatrixTranspose( XMATRIX* pOut, const XMATRIX* pM ) { pOut->_11 = pM->_11; pOut->_12 = pM->_21; pOut->_13 = pM->_31; pOut->_14 = pM->_41; pOut->_21 = pM->_12; pOut->_22 = pM->_22; pOut->_23 = pM->_32; pOut->_24 = pM->_42; pOut->_31 = pM->_13; pOut->_32 = pM->_23; pOut->_33 = pM->_33; pOut->_34 = pM->_43; pOut->_41 = pM->_14; pOut->_42 = pM->_24; pOut->_43 = pM->_34; pOut->_44 = pM->_44; return pOut; } XVECTOR4 Vec3Transform( XVECTOR4 *pOut, const XVECTOR3 *pV, const XMATRIX *pM ) { pOut->x = pV->x*pM->_11 + pV->y*pM->_21 + pV->z*pM->_31 + pM->_41; pOut->y = pV->x*pM->_12 + pV->y*pM->_22 + pV->z*pM->_32 + pM->_42; pOut->z = pV->x*pM->_13 + pV->y*pM->_23 + pV->z*pM->_33 + pM->_43; pOut->w = pV->x*pM->_14 + pV->y*pM->_24 + pV->z*pM->_34 + pM->_44; return *pOut; } mupen64plus-video-rice-src-2.6.0/src/VectorMath.h000066400000000000000000000137311464507324400215640ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - VectorMath.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Rice1964 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef VECTORMATH_H #define VECTORMATH_H /****************************************************************************** * 4x4 matrix ******************************************************************************/ typedef struct _MATRIX { union { struct { float _11, _12, _13, _14; float _21, _22, _23, _24; float _31, _32, _33, _34; float _41, _42, _43, _44; }; float m[4][4]; }; } MATRIX; typedef struct XMATRIX : public MATRIX { public: XMATRIX(); XMATRIX( const float * ); XMATRIX( const MATRIX & ); XMATRIX( float _11, float _12, float _13, float _14, float _21, float _22, float _23, float _24, float _31, float _32, float _33, float _34, float _41, float _42, float _43, float _44 ); float& operator () ( unsigned int Row, unsigned int Col ); float operator () ( unsigned int Row, unsigned int Col ) const; operator float* (); operator const float* () const; // assignment operators XMATRIX& operator *= ( const XMATRIX & ); XMATRIX& operator += ( const XMATRIX & ); XMATRIX& operator -= ( const XMATRIX & ); XMATRIX& operator *= ( float ); XMATRIX& operator /= ( float ); // unary operators XMATRIX operator + () const; XMATRIX operator - () const; // binary operators XMATRIX operator * ( const XMATRIX & ) const; XMATRIX operator + ( const XMATRIX & ) const; XMATRIX operator - ( const XMATRIX & ) const; XMATRIX operator * ( float ) const; XMATRIX operator / ( float ) const; friend XMATRIX operator * ( float, const XMATRIX & ); bool operator == ( const XMATRIX & ) const; bool operator != ( const XMATRIX & ) const; } XMATRIX, *LPXMATRIX; /****************************************************************************** * 3d vector ******************************************************************************/ typedef struct _VECTOR3 { float x; float y; float z; } VECTOR3; class XVECTOR3 : public VECTOR3 { public: XVECTOR3(); XVECTOR3( const float *f ); XVECTOR3( const VECTOR3 &v ); XVECTOR3( float _x, float _y, float _z ); // casting inline operator float* (); inline operator const float* () const; // assignment operators inline XVECTOR3& operator += ( const XVECTOR3 &op ); inline XVECTOR3& operator -= ( const XVECTOR3 &op ); inline XVECTOR3& operator *= ( float op ); inline XVECTOR3& operator /= ( float op ); // unary operators inline XVECTOR3 operator + () const; inline XVECTOR3 operator - () const; // binary operators inline XVECTOR3 operator + ( const XVECTOR3 &op ) const; inline XVECTOR3 operator - ( const XVECTOR3 &op ) const; inline XVECTOR3 operator * ( float op ) const; inline XVECTOR3 operator / ( float op ) const; friend XVECTOR3 operator * ( float, const XVECTOR3& ); inline bool operator == ( const XVECTOR3 &op ) const; inline bool operator != ( const XVECTOR3 &op ) const; }; /****************************************************************************** * 4d vector ******************************************************************************/ typedef struct _VECTOR4 { float x; float y; float z; float w; } VECTOR4; class XVECTOR4 : public VECTOR4 { public: XVECTOR4(); XVECTOR4( const float *f ); XVECTOR4( const VECTOR4 &v ); XVECTOR4( float _x, float _y, float _z, float _w ); // casting inline operator float* (); inline operator const float* () const; // assignment operators inline XVECTOR4& operator += ( const XVECTOR4 &op ); inline XVECTOR4& operator -= ( const XVECTOR4 &op ); inline XVECTOR4& operator *= ( float op ); inline XVECTOR4& operator /= ( float op ); // unary operators inline XVECTOR4 operator + () const; inline XVECTOR4 operator - () const; // binary operators inline XVECTOR4 operator + ( const XVECTOR4 &op ) const; inline XVECTOR4 operator - ( const XVECTOR4 &op ) const; inline XVECTOR4 operator * ( float op ) const; inline XVECTOR4 operator / ( float op ) const; friend XVECTOR4 operator * ( float, const XVECTOR4& ); inline bool operator == ( const XVECTOR4 &op ) const; inline bool operator != ( const XVECTOR4 &op ) const; }; XVECTOR4 Vec3Transform(XVECTOR4 *pOut, const XVECTOR3 *pV, const XMATRIX *pM); XMATRIX* MatrixTranspose(XMATRIX* pOut, const XMATRIX* pM); #endif mupen64plus-video-rice-src-2.6.0/src/Video.cpp000066400000000000000000001110231464507324400211020ustar00rootroot00000000000000/* Copyright (C) 2002 Rice1964 Copyright (C) 2009-2011 Richard Goedeken This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include "CritSect.h" #include "RenderBase.h" #include "osal_opengl.h" #define M64P_PLUGIN_PROTOTYPES 1 #include "Config.h" #include "Debugger.h" #include "DeviceBuilder.h" #include "FrameBuffer.h" #include "GraphicsContext.h" #include "RSP_Parser.h" #include "Render.h" #include "TextureFilters.h" #include "TextureManager.h" #include "Video.h" #include "m64p_common.h" #include "m64p_plugin.h" #include "m64p_types.h" #include "osal_dynamiclib.h" #include "version.h" //======================================================= // local variables static void (*l_DebugCallback)(void *, int, const char *) = NULL; static void *l_DebugCallContext = NULL; static int l_PluginInit = 0; //======================================================= // global variables PluginStatus status; GFX_INFO g_GraphicsInfo; CCritSect g_CritialSection; unsigned int g_dwRamSize = 0x400000; unsigned int *g_pRDRAMu32 = NULL; signed char *g_pRDRAMs8 = NULL; unsigned char *g_pRDRAMu8 = NULL; RECT frameWriteByCPURect; std::vector frameWriteByCPURects; RECT frameWriteByCPURectArray[20][20]; bool frameWriteByCPURectFlag[20][20]; std::vector frameWriteRecord; void (*renderCallback)(int) = NULL; /* definitions of pointers to Core config functions */ ptr_ConfigOpenSection ConfigOpenSection = NULL; ptr_ConfigSetParameter ConfigSetParameter = NULL; ptr_ConfigSetParameterHelp ConfigSetParameterHelp = NULL; ptr_ConfigGetParameter ConfigGetParameter = NULL; ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL; ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL; ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat = NULL; ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL; ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL; ptr_ConfigGetParamInt ConfigGetParamInt = NULL; ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL; ptr_ConfigGetParamBool ConfigGetParamBool = NULL; ptr_ConfigGetParamString ConfigGetParamString = NULL; ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL; ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath = NULL; ptr_ConfigGetUserDataPath ConfigGetUserDataPath = NULL; ptr_ConfigGetUserCachePath ConfigGetUserCachePath = NULL; /* definitions of pointers to Core video extension functions */ ptr_VidExt_Init CoreVideo_Init = NULL; ptr_VidExt_Quit CoreVideo_Quit = NULL; ptr_VidExt_ListFullscreenModes CoreVideo_ListFullscreenModes = NULL; ptr_VidExt_SetVideoMode CoreVideo_SetVideoMode = NULL; ptr_VidExt_SetCaption CoreVideo_SetCaption = NULL; ptr_VidExt_ToggleFullScreen CoreVideo_ToggleFullScreen = NULL; ptr_VidExt_ResizeWindow CoreVideo_ResizeWindow = NULL; ptr_VidExt_GL_GetProcAddress CoreVideo_GL_GetProcAddress = NULL; ptr_VidExt_GL_SetAttribute CoreVideo_GL_SetAttribute = NULL; ptr_VidExt_GL_GetAttribute CoreVideo_GL_GetAttribute = NULL; ptr_VidExt_GL_SwapBuffers CoreVideo_GL_SwapBuffers = NULL; //--------------------------------------------------------------------------------------- // Forward function declarations extern "C" EXPORT void CALL RomClosed(void); //--------------------------------------------------------------------------------------- // Static (local) functions static void ChangeWindowStep2() { status.bDisableFPS = true; windowSetting.bDisplayFullscreen = !windowSetting.bDisplayFullscreen; g_CritialSection.Lock(); windowSetting.bDisplayFullscreen = CGraphicsContext::Get()->ToggleFullscreen(); CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); CGraphicsContext::Get()->UpdateFrame(); CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); CGraphicsContext::Get()->UpdateFrame(); CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); CGraphicsContext::Get()->UpdateFrame(); g_CritialSection.Unlock(); status.bDisableFPS = false; status.ToToggleFullScreen = FALSE; } static void ResizeStep2(void) { g_CritialSection.Lock(); // if we are in fullscreen mode then we cannot resize if (windowSetting.bDisplayFullscreen) { g_CritialSection.Unlock(); status.ToResize = false; return; } // Delete all OpenGL textures gTextureManager.CleanUp(); RDP_Cleanup(); // delete our opengl renderer CDeviceBuilder::GetBuilder()->DeleteRender(); // call video extension function with updated width, height (this creates a new OpenGL context) windowSetting.uDisplayWidth = status.gNewResizeWidth; windowSetting.uDisplayHeight = status.gNewResizeHeight; CoreVideo_ResizeWindow(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); // re-initialize our OpenGL graphics context state bool res = CGraphicsContext::Get()->ResizeInitialize(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, !windowSetting.bDisplayFullscreen); if (res) { // re-create the OpenGL renderer CDeviceBuilder::GetBuilder()->CreateRender(); CRender::GetRender()->Initialize(); DLParser_Init(); } g_CritialSection.Unlock(); status.ToResize = false; } static void UpdateScreenStep2 (void) { status.bVIOriginIsUpdated = false; if( status.ToToggleFullScreen && status.gDlistCount > 0 ) { ChangeWindowStep2(); return; } if (status.ToResize && status.gDlistCount > 0) { ResizeStep2(); return; } g_CritialSection.Lock(); if( status.bHandleN64RenderTexture ) g_pFrameBufferManager->CloseRenderTexture(true); g_pFrameBufferManager->SetAddrBeDisplayed(*g_GraphicsInfo.VI_ORIGIN_REG); if( status.gDlistCount == 0 ) { // CPU frame buffer update uint32 width = *g_GraphicsInfo.VI_WIDTH_REG; if( (*g_GraphicsInfo.VI_ORIGIN_REG & (g_dwRamSize-1) ) > width*2 && *g_GraphicsInfo.VI_H_START_REG != 0 && width != 0 ) { SetVIScales(); CRender::GetRender()->DrawFrameBuffer(true); CGraphicsContext::Get()->UpdateFrame(); } g_CritialSection.Unlock(); return; } TXTRBUF_DETAIL_DUMP(TRACE1("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG)); if( currentRomOptions.screenUpdateSetting == SCREEN_UPDATE_AT_VI_UPDATE ) { CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); g_CritialSection.Unlock(); return; } TXTRBUF_DETAIL_DUMP(TRACE1("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG)); if( currentRomOptions.screenUpdateSetting == SCREEN_UPDATE_AT_VI_UPDATE_AND_DRAWN ) { if( status.bScreenIsDrawn ) { CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); } else { DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Skip Screen Update: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); } DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); g_CritialSection.Unlock(); return; } if( currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_VI_CHANGE ) { if( *g_GraphicsInfo.VI_ORIGIN_REG != status.curVIOriginReg ) { if( *g_GraphicsInfo.VI_ORIGIN_REG < status.curDisplayBuffer || *g_GraphicsInfo.VI_ORIGIN_REG > status.curDisplayBuffer+0x2000 ) { status.curDisplayBuffer = *g_GraphicsInfo.VI_ORIGIN_REG; status.curVIOriginReg = status.curDisplayBuffer; //status.curRenderBuffer = NULL; CGraphicsContext::Get()->UpdateFrame(); DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); } else { status.curDisplayBuffer = *g_GraphicsInfo.VI_ORIGIN_REG; status.curVIOriginReg = status.curDisplayBuffer; DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("Skip Screen Update, closed to the display buffer, VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG);}); } } else { DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("Skip Screen Update, the same VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG);}); } g_CritialSection.Unlock(); return; } if( currentRomOptions.screenUpdateSetting >= SCREEN_UPDATE_AT_1ST_CI_CHANGE ) { status.bVIOriginIsUpdated=true; DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG);}); g_CritialSection.Unlock(); return; } DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("VI is updated, No screen update: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); g_CritialSection.Unlock(); } static void ProcessDListStep2(void) { g_CritialSection.Lock(); if( status.toShowCFB ) { CRender::GetRender()->DrawFrameBuffer(true); status.toShowCFB = false; } try { DLParser_Process((OSTask *)(g_GraphicsInfo.DMEM + 0x0FC0)); } catch (...) { TRACE0("Unknown Error in ProcessDList"); TriggerDPInterrupt(); TriggerSPInterrupt(); } g_CritialSection.Unlock(); } static bool StartVideo(void) { windowSetting.dps = windowSetting.fps = -1; windowSetting.lastSecDlistCount = windowSetting.lastSecFrameCount = 0xFFFFFFFF; g_CritialSection.Lock(); memcpy(&g_curRomInfo.romheader, g_GraphicsInfo.HEADER, sizeof(ROMHeader)); unsigned char *puc = (unsigned char *) &g_curRomInfo.romheader; unsigned int i; unsigned char temp; for (i = 0; i < sizeof(ROMHeader); i += 4) /* byte-swap the ROM header */ { temp = puc[i]; puc[i] = puc[i+3]; puc[i+3] = temp; temp = puc[i+1]; puc[i+1] = puc[i+2]; puc[i+2] = temp; } ROM_GetRomNameFromHeader(g_curRomInfo.szGameName, &g_curRomInfo.romheader); Ini_GetRomOptions(&g_curRomInfo); char *p = (char *) g_curRomInfo.szGameName + (strlen((char *) g_curRomInfo.szGameName) -1); // -1 to skip null while (p >= (char *) g_curRomInfo.szGameName) { if( *p == ':' || *p == '\\' || *p == '/' ) *p = '-'; p--; } GenerateCurrentRomOptions(); status.dwTvSystem = CountryCodeToTVSystem(g_curRomInfo.romheader.nCountryID); if( status.dwTvSystem == TV_SYSTEM_NTSC ) status.fRatio = 0.75f; else status.fRatio = 9/11.0f;; InitExternalTextures(); try { CDeviceBuilder::GetBuilder()->CreateGraphicsContext(); bool res = CGraphicsContext::Get()->Initialize(640, 480, !windowSetting.bDisplayFullscreen); if (!res) { g_CritialSection.Unlock(); return false; } CDeviceBuilder::GetBuilder()->CreateRender(); CRender::GetRender()->Initialize(); DLParser_Init(); status.bGameIsRunning = true; } catch(...) { DebugMessage(M64MSG_ERROR, "Exception caught while starting video renderer"); throw 0; } g_CritialSection.Unlock(); return true; } static void StopVideo() { g_CritialSection.Lock(); status.bGameIsRunning = false; try { CloseExternalTextures(); // Kill all textures? gTextureManager.RecycleAllTextures(); gTextureManager.CleanUp(); RDP_Cleanup(); CDeviceBuilder::GetBuilder()->DeleteRender(); CGraphicsContext::Get()->CleanUp(); CDeviceBuilder::GetBuilder()->DeleteGraphicsContext(); } catch(...) { TRACE0("Some exceptions during RomClosed"); } g_CritialSection.Unlock(); windowSetting.dps = windowSetting.fps = -1; windowSetting.lastSecDlistCount = windowSetting.lastSecFrameCount = 0xFFFFFFFF; status.gDlistCount = status.gFrameCount = 0; } //--------------------------------------------------------------------------------------- // Global functions, for use by other source files in this plugin void SetVIScales() { if( g_curRomInfo.VIHeight>0 && g_curRomInfo.VIWidth>0 ) { windowSetting.fViWidth = windowSetting.uViWidth = g_curRomInfo.VIWidth; windowSetting.fViHeight = windowSetting.uViHeight = g_curRomInfo.VIHeight; } else if( g_curRomInfo.UseCIWidthAndRatio && g_CI.dwWidth ) { windowSetting.fViWidth = windowSetting.uViWidth = g_CI.dwWidth; windowSetting.fViHeight = windowSetting.uViHeight = g_curRomInfo.UseCIWidthAndRatio == USE_CI_WIDTH_AND_RATIO_FOR_NTSC ? g_CI.dwWidth/4*3 : g_CI.dwWidth/11*9; } else { float xscale, yscale; uint32 val = *g_GraphicsInfo.VI_X_SCALE_REG & 0xFFF; xscale = (float)val / (1<<10); uint32 start = *g_GraphicsInfo.VI_H_START_REG >> 16; uint32 end = *g_GraphicsInfo.VI_H_START_REG&0xFFFF; uint32 width = *g_GraphicsInfo.VI_WIDTH_REG; windowSetting.fViWidth = (end-start)*xscale; if( abs((int)(windowSetting.fViWidth - width) ) < 8 ) { windowSetting.fViWidth = (float)width; } else { DebuggerAppendMsg("fViWidth = %f, Width Reg=%d", windowSetting.fViWidth, width); } val = (*g_GraphicsInfo.VI_Y_SCALE_REG & 0xFFF);// - ((*g_GraphicsInfo.VI_Y_SCALE_REG>>16) & 0xFFF); if( val == 0x3FF ) val = 0x400; yscale = (float)val / (1<<10); start = *g_GraphicsInfo.VI_V_START_REG >> 16; end = *g_GraphicsInfo.VI_V_START_REG&0xFFFF; windowSetting.fViHeight = (end-start)/2*yscale; if( yscale == 0 ) { windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio; } else { if( *g_GraphicsInfo.VI_WIDTH_REG > 0x300 ) windowSetting.fViHeight *= 2; if( windowSetting.fViWidth*status.fRatio > windowSetting.fViHeight && (*g_GraphicsInfo.VI_X_SCALE_REG & 0xFF) != 0 ) { if( abs(int(windowSetting.fViWidth*status.fRatio - windowSetting.fViHeight)) < 8 ) { windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio; } /* else { if( abs(windowSetting.fViWidth*status.fRatio-windowSetting.fViHeight) > windowSetting.fViWidth*0.1f ) { if( status.fRatio > 0.8 ) windowSetting.fViHeight = windowSetting.fViWidth*3/4; //windowSetting.fViHeight = (*g_GraphicsInfo.VI_V_SYNC_REG - 0x2C)/2; } } */ } if( windowSetting.fViHeight<100 || windowSetting.fViWidth<100 ) { //At sometime, value in VI_H_START_REG or VI_V_START_REG are 0 windowSetting.fViWidth = (float)*g_GraphicsInfo.VI_WIDTH_REG; windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio; } } windowSetting.uViWidth = (unsigned short)(windowSetting.fViWidth/4); windowSetting.fViWidth = windowSetting.uViWidth *= 4; windowSetting.uViHeight = (unsigned short)(windowSetting.fViHeight/4); windowSetting.fViHeight = windowSetting.uViHeight *= 4; uint16 optimizeHeight = (uint16)(windowSetting.uViWidth*status.fRatio); optimizeHeight &= ~3; uint16 optimizeHeight2 = (uint16)(windowSetting.uViWidth*3/4); optimizeHeight2 &= ~3; if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 ) { if( abs(windowSetting.uViHeight-optimizeHeight) <= 8 ) windowSetting.fViHeight = windowSetting.uViHeight = optimizeHeight; else if( abs(windowSetting.uViHeight-optimizeHeight2) <= 8 ) windowSetting.fViHeight = windowSetting.uViHeight = optimizeHeight2; } if( gRDP.scissor.left == 0 && gRDP.scissor.top == 0 && gRDP.scissor.right != 0 ) { if( (*g_GraphicsInfo.VI_X_SCALE_REG & 0xFF) != 0x0 && gRDP.scissor.right == windowSetting.uViWidth ) { // Mario Tennis if( abs(int( windowSetting.fViHeight - gRDP.scissor.bottom )) < 8 ) { windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom; } else if( windowSetting.fViHeight < gRDP.scissor.bottom ) { windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom; } windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom; } else if( gRDP.scissor.right == windowSetting.uViWidth - 1 && gRDP.scissor.bottom != 0 ) { if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 ) { if( status.fRatio != 0.75 && windowSetting.fViHeight > optimizeHeight/2 ) { windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom + gRDP.scissor.top + 1; } } } else if( gRDP.scissor.right == windowSetting.uViWidth && gRDP.scissor.bottom != 0 && status.fRatio != 0.75 ) { if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 ) { if( status.fRatio != 0.75 && windowSetting.fViHeight > optimizeHeight/2 ) { windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom + gRDP.scissor.top + 1; } } } } } SetScreenMult(windowSetting.uDisplayWidth/windowSetting.fViWidth, windowSetting.uDisplayHeight/windowSetting.fViHeight); } void TriggerDPInterrupt(void) { *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_DP; g_GraphicsInfo.CheckInterrupts(); } void TriggerSPInterrupt(void) { *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_SP; g_GraphicsInfo.CheckInterrupts(); } void _VIDEO_DisplayTemporaryMessage(const char *Message) { } void DebugMessage(int level, const char *message, ...) { char msgbuf[1024]; va_list args; if (l_DebugCallback == NULL) return; va_start(args, message); vsprintf(msgbuf, message, args); (*l_DebugCallback)(l_DebugCallContext, level, msgbuf); va_end(args); } //--------------------------------------------------------------------------------------- // Global functions, exported for use by the core library // since these functions are exported, they need to have C-style names #ifdef __cplusplus extern "C" { #endif /* Mupen64Plus plugin functions */ EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context, void (*DebugCallback)(void *, int, const char *)) { if (l_PluginInit) return M64ERR_ALREADY_INIT; /* first thing is to set the callback function for debug info */ l_DebugCallback = DebugCallback; l_DebugCallContext = Context; /* attach and call the CoreGetAPIVersions function, check Config and Video Extension API versions for compatibility */ ptr_CoreGetAPIVersions CoreAPIVersionFunc; CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions"); if (CoreAPIVersionFunc == NULL) { DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found."); return M64ERR_INCOMPATIBLE; } int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion; (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL); if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000)) { DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)", VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION)); return M64ERR_INCOMPATIBLE; } if ((VidextAPIVersion & 0xffff0000) != (VIDEXT_API_VERSION & 0xffff0000)) { DebugMessage(M64MSG_ERROR, "Emulator core Video Extension API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)", VERSION_PRINTF_SPLIT(VidextAPIVersion), VERSION_PRINTF_SPLIT(VIDEXT_API_VERSION)); return M64ERR_INCOMPATIBLE; } /* check Config API version to make sure ConfigSetParameterHelp is supported */ if (ConfigAPIVersion < 0x00020300) { DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) is too old. This plugin requires at least 2.3.0", VERSION_PRINTF_SPLIT(ConfigAPIVersion)); 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"); ConfigSetParameterHelp = (ptr_ConfigSetParameterHelp) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameterHelp"); ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter"); ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt"); ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat"); ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool"); ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString"); ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt"); ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat"); ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool"); ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString"); ConfigGetSharedDataFilepath = (ptr_ConfigGetSharedDataFilepath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetSharedDataFilepath"); ConfigGetUserConfigPath = (ptr_ConfigGetUserConfigPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserConfigPath"); ConfigGetUserDataPath = (ptr_ConfigGetUserDataPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserDataPath"); ConfigGetUserCachePath = (ptr_ConfigGetUserCachePath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserCachePath"); if (!ConfigOpenSection || !ConfigSetParameter || !ConfigSetParameterHelp || !ConfigGetParameter || !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString || !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString || !ConfigGetSharedDataFilepath || !ConfigGetUserConfigPath || !ConfigGetUserDataPath || !ConfigGetUserCachePath) { DebugMessage(M64MSG_ERROR, "Couldn't connect to Core configuration functions"); return M64ERR_INCOMPATIBLE; } /* Get the core Video Extension function pointers from the library handle */ CoreVideo_Init = (ptr_VidExt_Init) osal_dynlib_getproc(CoreLibHandle, "VidExt_Init"); CoreVideo_Quit = (ptr_VidExt_Quit) osal_dynlib_getproc(CoreLibHandle, "VidExt_Quit"); CoreVideo_ListFullscreenModes = (ptr_VidExt_ListFullscreenModes) osal_dynlib_getproc(CoreLibHandle, "VidExt_ListFullscreenModes"); CoreVideo_SetVideoMode = (ptr_VidExt_SetVideoMode) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetVideoMode"); CoreVideo_SetCaption = (ptr_VidExt_SetCaption) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetCaption"); CoreVideo_ToggleFullScreen = (ptr_VidExt_ToggleFullScreen) osal_dynlib_getproc(CoreLibHandle, "VidExt_ToggleFullScreen"); CoreVideo_ResizeWindow = (ptr_VidExt_ResizeWindow) osal_dynlib_getproc(CoreLibHandle, "VidExt_ResizeWindow"); CoreVideo_GL_GetProcAddress = (ptr_VidExt_GL_GetProcAddress) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_GetProcAddress"); CoreVideo_GL_SetAttribute = (ptr_VidExt_GL_SetAttribute) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SetAttribute"); CoreVideo_GL_GetAttribute = (ptr_VidExt_GL_GetAttribute) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_GetAttribute"); CoreVideo_GL_SwapBuffers = (ptr_VidExt_GL_SwapBuffers) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SwapBuffers"); if (!CoreVideo_Init || !CoreVideo_Quit || !CoreVideo_ListFullscreenModes || !CoreVideo_SetVideoMode || !CoreVideo_ResizeWindow || !CoreVideo_SetCaption || !CoreVideo_ToggleFullScreen || !CoreVideo_GL_GetProcAddress || !CoreVideo_GL_SetAttribute || !CoreVideo_GL_GetAttribute || !CoreVideo_GL_SwapBuffers) { DebugMessage(M64MSG_ERROR, "Couldn't connect to Core video extension functions"); return M64ERR_INCOMPATIBLE; } /* open config section handles and set parameter default values */ if (!InitConfiguration()) return M64ERR_INTERNAL; l_PluginInit = 1; return M64ERR_SUCCESS; } EXPORT m64p_error CALL PluginShutdown(void) { if (!l_PluginInit) return M64ERR_NOT_INIT; if( status.bGameIsRunning ) { RomClosed(); } if (bIniIsChanged) { WriteIniFile(); TRACE0("Write back INI file"); } /* reset some local variables */ l_DebugCallback = NULL; l_DebugCallContext = NULL; l_PluginInit = 0; return M64ERR_SUCCESS; } EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities) { /* set version info */ if (PluginType != NULL) *PluginType = M64PLUGIN_GFX; if (PluginVersion != NULL) *PluginVersion = PLUGIN_VERSION; if (APIVersion != NULL) *APIVersion = VIDEO_PLUGIN_API_VERSION; if (PluginNamePtr != NULL) *PluginNamePtr = PLUGIN_NAME; if (Capabilities != NULL) { *Capabilities = 0; } return M64ERR_SUCCESS; } //------------------------------------------------------------------------------------- EXPORT void CALL ChangeWindow (void) { if( status.ToToggleFullScreen ) status.ToToggleFullScreen = FALSE; else status.ToToggleFullScreen = TRUE; } //--------------------------------------------------------------------------------------- EXPORT void CALL MoveScreen (int xpos, int ypos) { } //--------------------------------------------------------------------------------------- EXPORT void CALL RomClosed(void) { TRACE0("To stop video"); Ini_StoreRomOptions(&g_curRomInfo); StopVideo(); TRACE0("Video is stopped"); } EXPORT int CALL RomOpen(void) { /* Read RiceVideoLinux.ini file, set up internal variables by reading values from core configuration API */ LoadConfiguration(); if( g_CritialSection.IsLocked() ) { g_CritialSection.Unlock(); TRACE0("g_CritialSection is locked when game is starting, unlock it now."); } status.bDisableFPS=false; g_dwRamSize = 0x800000; #ifdef DEBUGGER if( debuggerPause ) { debuggerPause = FALSE; usleep(100 * 1000); } #endif if (!StartVideo()) return 0; return 1; } //--------------------------------------------------------------------------------------- EXPORT void CALL UpdateScreen(void) { if(options.bShowFPS) { static unsigned int lastTick=0; static int frames=0; unsigned int nowTick = SDL_GetTicks(); frames++; if(lastTick + 5000 <= nowTick) { char caption[200]; sprintf(caption, "%s v%i.%i.%i - %.3f VI/S", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION), frames/5.0); CoreVideo_SetCaption(caption); frames = 0; lastTick = nowTick; } } UpdateScreenStep2(); } //--------------------------------------------------------------------------------------- EXPORT void CALL ViStatusChanged(void) { g_CritialSection.Lock(); SetVIScales(); CRender::g_pRender->UpdateClipRectangle(); g_CritialSection.Unlock(); } //--------------------------------------------------------------------------------------- EXPORT void CALL ViWidthChanged(void) { g_CritialSection.Lock(); SetVIScales(); CRender::g_pRender->UpdateClipRectangle(); g_CritialSection.Unlock(); } EXPORT int CALL InitiateGFX(GFX_INFO Gfx_Info) { memset(&status, 0, sizeof(status)); memcpy(&g_GraphicsInfo, &Gfx_Info, sizeof(GFX_INFO)); g_pRDRAMu8 = Gfx_Info.RDRAM; g_pRDRAMu32 = (uint32*)Gfx_Info.RDRAM; g_pRDRAMs8 = (signed char *)Gfx_Info.RDRAM; windowSetting.fViWidth = 320; windowSetting.fViHeight = 240; status.ToToggleFullScreen = FALSE; status.ToResize = false; status.bDisableFPS=false; if (!InitConfiguration()) { DebugMessage(M64MSG_ERROR, "Failed to read configuration data"); return FALSE; } return(TRUE); } EXPORT void CALL ResizeVideoOutput(int width, int height) { // save the new window resolution. actual resizing operation is asynchronous (it happens later) status.gNewResizeWidth = width; status.gNewResizeHeight = height; status.ToResize = true; } //--------------------------------------------------------------------------------------- EXPORT void CALL ProcessRDPList(void) { try { RDP_DLParser_Process(); } catch (...) { TRACE0("Unknown Error in ProcessRDPList"); TriggerDPInterrupt(); TriggerSPInterrupt(); } } EXPORT void CALL ProcessDList(void) { ProcessDListStep2(); } //--------------------------------------------------------------------------------------- /****************************************************************** Function: FrameBufferRead Purpose: This function is called to notify the dll that the frame buffer memory is beening read at the given address. DLL should copy content from its render buffer to the frame buffer in N64 RDRAM DLL is responsible to maintain its own frame buffer memory addr list DLL should copy 4KB block content back to RDRAM frame buffer. Emulator should not call this function again if other memory is read within the same 4KB range Since depth buffer is also being watched, the reported addr may belong to depth buffer input: addr rdram address val val size 1 = uint8, 2 = uint16, 4 = uint32 output: none *******************************************************************/ EXPORT void CALL FBRead(uint32 addr) { g_pFrameBufferManager->FrameBufferReadByCPU(addr); } /****************************************************************** Function: FrameBufferWrite Purpose: This function is called to notify the dll that the frame buffer has been modified by CPU at the given address. Since depth buffer is also being watched, the reported addr may belong to depth buffer input: addr rdram address val val size 1 = uint8, 2 = uint16, 4 = uint32 output: none *******************************************************************/ EXPORT void CALL FBWrite(uint32 addr, uint32 size) { g_pFrameBufferManager->FrameBufferWriteByCPU(addr, size); } /************************************************************************ Function: FBGetFrameBufferInfo Purpose: This function is called by the emulator core to retrieve frame buffer information from the video plugin in order to be able to notify the video plugin about CPU frame buffer read/write operations size: = 1 byte = 2 word (16 bit) <-- this is N64 default depth buffer format = 4 dword (32 bit) when frame buffer information is not available yet, set all values in the FrameBufferInfo structure to 0 input: FrameBufferInfo pinfo[6] pinfo is pointed to a FrameBufferInfo structure which to be filled in by this function output: Values are return in the FrameBufferInfo structure Plugin can return up to 6 frame buffer info ************************************************************************/ EXPORT void CALL FBGetFrameBufferInfo(void *p) { FrameBufferInfo * pinfo = (FrameBufferInfo *)p; memset(pinfo,0,sizeof(FrameBufferInfo)*6); //if( g_ZI.dwAddr == 0 ) //{ // memset(pinfo,0,sizeof(FrameBufferInfo)*6); //} //else { for (int i=0; i<5; i++ ) { if( status.gDlistCount-g_RecentCIInfo[i].lastUsedFrame > 30 || g_RecentCIInfo[i].lastUsedFrame == 0 ) { //memset(&pinfo[i],0,sizeof(FrameBufferInfo)); } else { pinfo[i].addr = g_RecentCIInfo[i].dwAddr; pinfo[i].size = 2; pinfo[i].width = g_RecentCIInfo[i].dwWidth; pinfo[i].height = g_RecentCIInfo[i].dwHeight; TXTRBUF_DETAIL_DUMP(TRACE3("Protect 0x%08X (%d,%d)", g_RecentCIInfo[i].dwAddr, g_RecentCIInfo[i].dwWidth, g_RecentCIInfo[i].dwHeight)); pinfo[5].width = g_RecentCIInfo[i].dwWidth; pinfo[5].height = g_RecentCIInfo[i].dwHeight; } } pinfo[5].addr = g_ZI.dwAddr; //pinfo->size = g_RecentCIInfo[5].dwSize; pinfo[5].size = 2; TXTRBUF_DETAIL_DUMP(TRACE3("Protect 0x%08X (%d,%d)", pinfo[5].addr, pinfo[5].width, pinfo[5].height)); } } // Plugin spec 1.3 functions EXPORT void CALL ShowCFB(void) { status.toShowCFB = true; } //void ReadScreen2( void *dest, int *width, int *height, int bFront ) EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int bFront) { if (width == NULL || height == NULL) return; *width = windowSetting.uDisplayWidth; *height = windowSetting.uDisplayHeight; if (dest == NULL) return; #ifndef USE_GLES GLint oldMode; glGetIntegerv( GL_READ_BUFFER, &oldMode ); if (bFront) glReadBuffer( GL_FRONT ); else glReadBuffer( GL_BACK ); glReadPixels( 0, 0, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, GL_RGB, GL_UNSIGNED_BYTE, dest ); glReadBuffer( oldMode ); #else unsigned char * line = (unsigned char *)dest; unsigned char *frameBuffer = (unsigned char *)malloc((*width)*(*height)*4); glReadPixels( 0, 0, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, GL_RGBA, GL_UNSIGNED_BYTE, frameBuffer ); //Convert RGBA to RGB for (Uint32 y=0; y #include #include #include #include "BMGImage.h" #include "BMGUtils.h" /* initializes a BMGImage to default values */ void InitBMGImage( struct BMGImageStruct *img ) { img->width = img->height = 0; img->bits_per_pixel = 0; img->palette_size = 0; img->bytes_per_palette_entry = 0; img->bits = NULL; img->palette = NULL; img->opt_for_bmp = 0; img->scan_width = 0; img->transparency_index = -1; } /* frees memory allocated to a BMGImage */ void FreeBMGImage( struct BMGImageStruct *img ) { if ( img->bits != NULL ) { free( img->bits ); img->bits = NULL; } if ( img->palette != NULL ) { free( img->palette ); img->palette = NULL; } img->bits_per_pixel = 0; img->palette_size = 0; img->bytes_per_palette_entry = 0; img->width = img->height = 0; img->opt_for_bmp = 0; img->scan_width = 0; img->transparency_index = -1; } /* allocates memory for the bits & palette. Assigned values to scan_line & bits_per_palette_entry as well. Assumes opt_for_bmp has been set before this function is called. Assumes that all images with bits_per_pixel <= 8 require a palette. */ BMGError AllocateBMGImage( struct BMGImageStruct *img ) { unsigned int mempal; SetLastBMGError( BMG_OK ); /* make sure that all REQUIRED parameters are valid */ if ( img->width * img->height <= 0 ) { SetLastBMGError(errInvalidSize); return errInvalidSize; } switch( img->bits_per_pixel ) { case 1: case 4: case 8: case 16: case 24: case 32: break; default: SetLastBMGError( errInvalidPixelFormat ); return errInvalidPixelFormat; } /* delete old memory */ if ( img->bits != NULL ) { free( img->bits ); img->bits = NULL; } if ( img->palette != NULL ) { free( img->palette ); img->palette = NULL; } /* allocate memory for the palette */ if ( img->bits_per_pixel <= 8 ) { if ( img->opt_for_bmp > 0 ) img->bytes_per_palette_entry = 4U; else { /* we only support 3-byte and 4-byte palettes */ if ( img->bytes_per_palette_entry <= 3U ) img->bytes_per_palette_entry = 3U; else img->bytes_per_palette_entry = 4U; } /* use bits_per_pixel to determine palette_size if none was specified */ if ( img->palette_size == 0 ) img->palette_size = (unsigned short)(1 << img->bits_per_pixel); mempal = img->bytes_per_palette_entry * img->palette_size; img->palette = (unsigned char *)calloc( mempal, sizeof(unsigned char) ); if ( img->palette == NULL ) { SetLastBMGError(errMemoryAllocation); return errMemoryAllocation; } } else { img->bytes_per_palette_entry = 0; img->palette_size = 0; } /* set the scan width. Bitmaps optimized for windows have scan widths that are evenly divisible by 4. */ img->scan_width = ( img->bits_per_pixel * img->width + 7 ) / 8; if ( img->opt_for_bmp && img->scan_width % 4 ) img->scan_width += 4 - img->scan_width % 4; /* allocate memory for the bits */ mempal = img->scan_width * img->height; if ( mempal > 0 ) { img->bits = (unsigned char *)calloc( mempal, sizeof( unsigned char) ); if ( img->bits == NULL ) { if ( img->palette != NULL ) { free( img->palette ); img->palette = NULL; } SetLastBMGError(errMemoryAllocation); return errMemoryAllocation; } } else { SetLastBMGError(errInvalidSize); return errInvalidSize; } return BMG_OK; } /******************************************************************************* A utility function for compressing paletted images. Will automatically convert 8-bit paletted images to 1-bit or 4-bit paletted images based upon palette_size. Assumes that indices in img->bits are valid. That is, 0 <= img->bits[i] <= 1 for all i if 1-bit compression is desired, and 0 <= img->bits[i] <= 15 for all i if 4-bit compression is desired Returns BMG_OK if successful, or an error code otherwise. *******************************************************************************/ BMGError CompressBMGImage( struct BMGImageStruct *img ) { unsigned char new_bits_per_pixel; unsigned int new_scan_width; unsigned char *new_bits = NULL; unsigned int new_bit_size; unsigned char *new_row, *old_row, *p, *q; unsigned char *end; unsigned short scale; SetLastBMGError( BMG_OK ); /* if we cannot compress it then do no harm and return "true" */ if ( img->palette == NULL || img->palette_size > 16 || img->bits_per_pixel != 8 ) { return BMG_OK; } /* calculate new dimensions */ new_bits_per_pixel = img->palette_size <= 2 ? 1U : 4U; new_scan_width = ( new_bits_per_pixel * img->width + 7 ) / 8; if ( img->opt_for_bmp > 0 && new_scan_width % 4 ) new_scan_width += 4 - new_scan_width % 4; new_bit_size = new_scan_width * img->height; /* allocate & test memory */ new_bits = (unsigned char *)calloc( new_bit_size, sizeof(unsigned char) ); if ( new_bits == NULL ) { SetLastBMGError( errMemoryAllocation ); return errMemoryAllocation; } old_row = img->bits; for ( new_row = new_bits; new_row < new_bits + new_bit_size; new_row += new_scan_width, old_row += img->scan_width ) { scale = 8 / new_bits_per_pixel; end = new_row + img->width / scale; p = old_row; if ( new_bits_per_pixel == 1 ) { for ( q = new_row; q < end; q++, p += scale ) { *q = (unsigned char)( (p[0] << 7) | (p[1] << 6) | (p[2] << 5) | (p[3] << 4) | (p[4] << 3) | (p[5] << 2) | (p[6] << 1) | p[7] ); } scale = img->width % scale; if ( scale-- > 0 ) { *q = (unsigned char)(p[0] << 7); if ( scale-- ) { *q |= (unsigned char)(p[1] << 6); if ( scale-- ) { *q |= (unsigned char)(p[2] << 5); if ( scale-- ) { *q |= (unsigned char)(p[3] << 4); if ( scale-- ) { *q |= (unsigned char)(p[4] << 3); if ( scale-- ) { *q |= (unsigned char)(p[5] << 2); if ( scale-- ) *q |= (unsigned char)(p[6] << 1); } } } } } } } else /* new_bits_per_pixel == 4 */ { for ( q = new_row; q < end; q++, p += scale ) { *q = (unsigned char)( (p[0] << 4) | (p[1] & 0x0F) ); } if ( img->width % scale ) *q = (unsigned char)(p[0] << 4); } } /* replace old values with new values */ free( img->bits ); img->bits = new_bits; img->scan_width = new_scan_width; img->bits_per_pixel = new_bits_per_pixel; return BMG_OK; } /* this function simply frees memory that was allocated by any function in the BMGLib. This was required because acces violations occurred when I tried to delete memory created by CreateRGBAArray in the demo applications */ void FreeBMGMemory( unsigned char *mem ) { if ( mem != NULL ) free( mem ); } /* converts a BGR to a gray scale // color[0] = blue, color[1] = green, color[2] = red */ static unsigned char CreateGrayScale( unsigned char *color ) { return (unsigned char)( 0.299f * color[2] + 0.587f * color[1] + 0.114f * color[0] + 0.5f ); } /* // converts a color image to a gray scale image. If img is a 16 or // 24-BPP image then it is converted to a 256 color grayscale bitmap. // If img is a 1, 4, or 8 BPP image, then it will have the same number // of grayscales as it has palette entries. If it is a 32-BPP bitmap then // it will remain a 32-BPP bitmap to preserve the alpha channel. // // This function returns BMG_OK if successfull, or an error state // otherwise. */ BMGError ConvertToGrayScale( struct BMGImageStruct *img ) { unsigned char *p, *q, *r, *end, gray; SetLastBMGError( BMG_OK ); /* if this is a paletted image then we simply need to convert the // palette entries */ switch ( img->bits_per_pixel ) { default: end = img->palette + img->palette_size * img->bytes_per_palette_entry; for ( p = img->palette; p < end; p += img->bytes_per_palette_entry ) { gray = CreateGrayScale( p ); memset( (void *)p, gray, 3 ); } break; /* 16 BPP image are converted to 24 BPP images */ case 16: { BMGError tmp = Convert16to24( img ); if ( tmp != BMG_OK ) { SetLastBMGError( tmp ); return tmp; } } case 24: { unsigned char *new_bits; unsigned char *s, *s_end; unsigned short i; /* calculate the new scan width */ unsigned int new_scan_width = img->width; if ( new_scan_width % 4 && img->opt_for_bmp ) new_scan_width += 4 - new_scan_width % 4; /* allocate memory for the new pixel values */ new_bits = (unsigned char *)calloc( new_scan_width * img->height, sizeof(unsigned char) ); if ( new_bits == NULL ) { SetLastBMGError( errMemoryAllocation ); return errMemoryAllocation; } /* allocate memory for a 256 gray scale palette */ img->bytes_per_palette_entry = img->opt_for_bmp == 1 ? 4 : 3; img->palette_size = 256; img->palette = (unsigned char *)calloc(img->bytes_per_palette_entry * img->palette_size, sizeof(unsigned char) ); if ( img->palette == NULL ) { free( new_bits ); img->bytes_per_palette_entry = 0; img->palette_size = 0; SetLastBMGError( errMemoryAllocation ); return errMemoryAllocation; } /* assign values to the gray scale palette */ for ( i = 0; i < 256; i++ ) { p = img->palette + i * img->bytes_per_palette_entry; memset( (void *)p, i, 3 ); if ( img->bytes_per_palette_entry == 4 ) p[3] = 0; } /* cycle through the pixels and convert them to gray scale values */ q = new_bits; end = img->bits + img->scan_width * img->height; for ( p = img->bits; p < end; p += img->scan_width, q += new_scan_width ) { s_end = p + 3 * img->width; r = q; for ( s = p; s < s_end; s += 3, r++ ) *r = CreateGrayScale( s ); } free( img->bits ); img->bits = new_bits; img->scan_width = new_scan_width; img->bits_per_pixel = 8; break; } case 32: end = img->bits + img->scan_width * img->height; for ( p = img->bits; p < end; p += img->scan_width ) { r = p + img->scan_width; for ( q = p; q < r; q += 4 ) { gray = CreateGrayScale( q ); memset( (void *)q, gray, 3 ); } } break; } return BMG_OK; } /* // converts a color image to a pseudo-gray scale image. This is a implementation // is based upon the code published by Rich Franzen // . I have "simplified" the 2 functions // he published into a single function. This implementation creates 1786 gray // scales from a 24-bit image. 16-BPP images are converted to 24-BPP images. 24 // and 32-BPP images will keep the same bitdepth. Paletted images and 16-BPP images // are not supported. // // This function returns BMK_OK if successfull, // errInvalidPixelFormat otherwise */ BMGError ConvertToPseudoGrayScale( struct BMGImageStruct *img ) { unsigned char *p, *p_end; unsigned char *q, *q_end; unsigned char gray; unsigned int bytes_per_pixel; SetLastBMGError( errMemoryAllocation ); if ( img->bits_per_pixel <= 16 ) { SetLastBMGError( errInvalidPixelFormat ); return errInvalidPixelFormat; } bytes_per_pixel = img->bits_per_pixel / 8; p_end = img->bits + img->scan_width * img->height; for ( p = img->bits; p < p_end; p += img->scan_width ) { q_end = p + bytes_per_pixel * img->width; for ( q = p; q < q_end; q += bytes_per_pixel ) { /* Rich's code has 1 function that converts an RGB triplet to a float // bounded by 0 and 1. He has a second function that converts a // float to a pseudo gray value. Pseudo gray values are RGB triplets // whose red, green and blue values differ by no more than 1. I have // combined these two functions into a single function that simply // looks for pseudo gray RGB triplets. If an RGB triplet meets this // criteria, I leave it unchanged; otherwise, I use the common intensity // conversion to create a grayscale value */ unsigned char cmin, cmax; cmin = q[0]; if ( q[1] < cmin ) cmin = q[1]; if ( q[2] < cmin ) cmin = q[2]; cmax = q[0]; if ( q[1] > cmax ) cmax = q[1]; if ( q[2] > cmax ) cmax = q[2]; if ( cmax - cmin > 2 ) { gray = CreateGrayScale( q ); memset( (void *)q, gray, 3 ); } } } return BMG_OK; } #ifdef _WIN32 /******************************************************************************* // extracts the dimensional information, pixel array, and color table from an // HBITMAP. // hBitmap can be a handle to a DIB or a DDB. This function assumes that DDBs // will not have a palette. If you create a DDB on a 256-color graphics card, // then the DDB will have a palette and this function will fail. // // returns BMK_OK if successfull, and error state otherwise. ********************************************************************************/ BMGError GetDataFromBitmap( HBITMAP hBitmap, struct BMGImageStruct *img, int remove_alpha ) { unsigned int DIBScanWidth; DIBSECTION DS; HWND hWnd = GetForegroundWindow(); HDC hDC = NULL; HDC hMemDC = NULL; unsigned char red, green, blue; int FreelpBits = 0; unsigned int numBytes; size_t soDIBSECTION = sizeof(DIBSECTION); size_t soBITMAP = sizeof(BITMAP); unsigned char *p, *q, *lpBits, alpha; jmp_buf err_jmp; int error; BMGError bmgerr; /* error handler */ error = setjmp( err_jmp ); if ( error != 0 ) { if ( hMemDC != NULL ) DeleteDC( hMemDC ); if ( hDC != NULL ) ReleaseDC( hWnd, hDC ); if ( FreelpBits ) free( lpBits ); FreeBMGImage( img ); SetLastBMGError( (BMGError)error ); return (BMGError)error; } SetLastBMGError( BMG_OK ); /* check for valid bitmap*/ if ( !hBitmap ) longjmp( err_jmp, (int)errInvalidBitmapHandle ); /* Extract DIBSECTION info from the HBITMAP. numBytes will equal // soDIBSECTION (84) if hBitmap is a handle to a DIBSECTION (DIB). // numBytes will equal soBITMAP (24) if hBitmap is a handle to a // BITMAP (DDB). */ numBytes = GetObject( hBitmap, sizeof(DIBSECTION), &DS ); if ( numBytes == 0 ) longjmp( err_jmp, (int)errWindowsAPI ); img->opt_for_bmp = 1; if ( numBytes == soDIBSECTION ) { img->width = DS.dsBmih.biWidth; img->height = DS.dsBmih.biHeight; img->bits_per_pixel = (unsigned char)DS.dsBmih.biBitCount; if ( img->bits_per_pixel <= 8 && DS.dsBmih.biClrUsed > 0 ) img->palette_size = (unsigned short)DS.dsBmih.biClrUsed; lpBits = (unsigned char *)DS.dsBm.bmBits; } /* this may be a DDB which must be handled differently */ else if ( numBytes == soBITMAP ) { BITMAP bm; BITMAPINFO bmi; if ( GetObject( hBitmap, sizeof(BITMAP), &bm ) == 0 ) longjmp( err_jmp, (int)errWindowsAPI ); /* DDB with a palette */ if ( bm.bmBitsPixel <= 8 ) longjmp( err_jmp, (int)errInvalidPixelFormat ); img->width = bm.bmWidth; img->height = bm.bmHeight; img->bits_per_pixel = (unsigned char)bm.bmBitsPixel; bmi = InternalCreateBMI( bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, BI_RGB ); lpBits = (unsigned char *)calloc( bm.bmHeight * bm.bmWidthBytes, sizeof(unsigned char) ); if ( lpBits == 0 ) longjmp( err_jmp, (int)errMemoryAllocation ); FreelpBits = 1; hDC = GetDC( hWnd ); if ( GetDIBits(hDC, hBitmap, 0, bm.bmHeight, (void *)lpBits, &bmi, DIB_RGB_COLORS ) == 0 ) longjmp( err_jmp, (int)errWindowsAPI ); ReleaseDC( hWnd, hDC ); hDC = NULL; } else /* I have no idea what this is */ longjmp( err_jmp, (int)errInvalidBitmapHandle ); /* allocate memory */ bmgerr = AllocateBMGImage( img ); if ( bmgerr != BMG_OK ) longjmp( err_jmp, (int)bmgerr ); /* dimensions */ DIBScanWidth = ( img->width * img->bits_per_pixel + 7 )/8; if ( DIBScanWidth % 4 ) DIBScanWidth += 4 - DIBScanWidth % 4; p = img->bits; for ( q = lpBits; q < lpBits + DIBScanWidth * img->height; p += img->scan_width, q += DIBScanWidth ) { memcpy( (void *)p, (void *)q, DIBScanWidth ); } /* "un-blend" the image if requested. NOTE: unblending only works with // bland backgrounds */ if ( remove_alpha > 0 && img->bits_per_pixel == 32 && numBytes == soDIBSECTION ) { unsigned char *color = GetBackgroundColor(); red = color[2]; green = color[1]; blue = color[0]; for ( p = img->bits; p < img->bits + img->scan_width * img->height; p += 4 ) { alpha = p[3]; p[2] = InverseAlphaComp( p[2], alpha, blue); p[1] = InverseAlphaComp( p[1], alpha, green); p[0] = InverseAlphaComp( p[0], alpha, red); } } /* 32-bit DDBs must have the alpha channel set to 0xFF before they are // saved to a file. This may not be true for all devices that generate // 32-bit DDBs. I have only created 32-bit DDBs using an Intense3D Wildcat // 4110 card. The alpha channel was always 0. */ if (img->bits_per_pixel == 32 && numBytes == soBITMAP ) { for ( p = img->bits + 3; p < img->bits + img->scan_width * img->height; p += 4 ) { *p = 0xFF; } } /* create palette if necessary */ if ( img->bits_per_pixel <= 8 ) { hDC = GetDC( hWnd ); hMemDC = CreateCompatibleDC( hDC ); SelectObject( hMemDC, hBitmap ); if ( !GetDIBColorTable( hMemDC, 0, img->palette_size, (RGBQUAD *)img->palette ) ) { longjmp( err_jmp, (int)errWindowsAPI ); } DeleteDC( hMemDC ); ReleaseDC( hWnd, hDC ); } if ( FreelpBits ) free( lpBits ); return BMG_OK; } /******************************************************************************* // this function creates a bitmap from raw data. Returns an HBITMAP if it // succeeds, otherwise NULL */ HBITMAP CreateBitmapFromData( struct BMGImageStruct img, int alpha_blend ) { HBITMAP hBitmap = NULL; HDC hMemDC = NULL; HWND hWnd = GetForegroundWindow(); HDC hDC = NULL; RGBQUAD *pColor = NULL; BITMAPINFO bmi; unsigned char *rbits; unsigned char *bits; unsigned char *lpBits; unsigned char alpha; unsigned int DIBScanWidth; int i; jmp_buf err_jmp; int error; /* error handler */ error = setjmp( err_jmp ); if ( error != 0 ) { if ( hMemDC != NULL ) DeleteDC( hMemDC ); if ( hDC != NULL ) ReleaseDC( hWnd, hDC ); if ( pColor != NULL && img.bytes_per_palette_entry == 3U ) free( pColor ); SetLastBMGError( (BMGError)error ); return 0; } SetLastBMGError( BMG_OK ); /* create the DIB section that will hold this bitmap */ bmi = InternalCreateBMI( (unsigned int)img.width, (unsigned int)img.height, (unsigned short)img.bits_per_pixel, BI_RGB ); bmi.bmiHeader.biClrUsed = bmi.bmiHeader.biClrImportant = img.palette_size; hDC = GetDC( hWnd ); hBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS, (void **)&lpBits, NULL, 0 ); if ( !hBitmap || !lpBits ) longjmp( err_jmp, (int)errWindowsAPI ); /* create a palette if needed */ if ( img.palette != NULL ) { /* copy pixel data to pColor */ if ( img.bytes_per_palette_entry == 4U ) pColor = (RGBQUAD *)img.palette; else /* bytes_per_palette_entry === 3 */ { pColor = (RGBQUAD *)calloc(img.palette_size, sizeof(RGBQUAD) ); if ( pColor == NULL ) longjmp( err_jmp, (int)errMemoryAllocation ); bits = img.palette; for ( i = 0; i < (int)bmi.bmiHeader.biClrUsed; i++, bits += 3 ) { pColor[i].rgbRed = bits[0]; pColor[i].rgbGreen = bits[1]; pColor[i].rgbBlue = bits[2]; } } if ( img.transparency_index > -1 ) { unsigned char *color = GetBackgroundColor(); rbits = img.palette + img.bytes_per_palette_entry * img.transparency_index; rbits[0] = color[2]; rbits[1] = color[1]; rbits[2] = color[0]; } /* save color table in bitmap */ hMemDC = CreateCompatibleDC( hDC ); SelectObject( hMemDC, hBitmap ); if ( !SetDIBColorTable( hMemDC, 0, img.palette_size, pColor ) ) longjmp( err_jmp, (int)errWindowsAPI ); DeleteDC( hMemDC ); hMemDC = NULL; if ( img.bytes_per_palette_entry == 3U ) free( pColor ); pColor = NULL; } /* calculate the scan line width */ DIBScanWidth = img.scan_width; if ( DIBScanWidth % 4 ) DIBScanWidth += 4 - DIBScanWidth % 4; if ( img.opt_for_bmp == 0 ) { /* store bits into hBitmap */ rbits = img.bits; for ( bits = lpBits; bits < lpBits + img.height * DIBScanWidth; bits += DIBScanWidth, rbits += img.scan_width ) { memcpy( (void *)bits, (void *)rbits, img.scan_width ); } } else memcpy( (void *)lpBits, (void *)img.bits, img.scan_width * img.height ); /* blend the image with the window background if alpha pixels // are present */ if ( img.bits_per_pixel == 32 ) { /* blend with a bland background */ if ( alpha_blend == 1 ) { unsigned char *color = GetBackgroundColor(); unsigned char red = color[2]; unsigned char green = color[1]; unsigned char blue = color[0]; for ( rbits = lpBits; rbits < lpBits + img.height*DIBScanWidth; rbits += DIBScanWidth ) { for ( bits = rbits; bits < rbits + DIBScanWidth; bits += 4 ) { alpha = bits[3]; bits[2] = AlphaComp( bits[2], alpha, blue ); bits[1] = AlphaComp( bits[1], alpha, green ); bits[0] = AlphaComp( bits[0], alpha, red ); } } } /* blend with a background image */ else if ( alpha_blend == 2 ) { unsigned char *bg_bits; unsigned char *bg_bits_2; unsigned int bg_bytes_per_pixel; struct BMGImageStruct *bg = GetBackgroundImage(); /* make sure we can blend with a background image // I assume that the background image is invalid if it does not // have a valid width */ if ( bg->width <= 0 || bg->height <= 0 ) longjmp( err_jmp, (int)errUndefinedBGImage ); /* I cannot blend a foreground image with a background image that // is smaller than it */ if ( bg->width < img.width || bg->height < img.height ) longjmp( err_jmp, (int)errBGImageTooSmall ); /* the background image was forced to be a 24 or 32-BPP image; // therefore, we can safely divide by 8 to determined the // bytes per pixel*/ bg_bytes_per_pixel = bg->bits_per_pixel / 8; /* I will assume that the upper left corner of the input image // must be aligned with the upper left corner of the background // image. This allows me to have background images that are bigger // than the input image. */ bg_bits = bg->bits; for ( rbits = lpBits; rbits < lpBits + img.height*DIBScanWidth; rbits += DIBScanWidth, bg_bits += bg->scan_width ) { bg_bits_2 = bg_bits; for ( bits = rbits; bits < rbits + DIBScanWidth; bits += 4, bg_bits_2 += bg_bytes_per_pixel ) { alpha = bits[3]; bits[2] = AlphaComp( bits[2], alpha, bg_bits_2[2] ); bits[1] = AlphaComp( bits[1], alpha, bg_bits_2[1] ); bits[0] = AlphaComp( bits[0], alpha, bg_bits_2[0] ); } } } } ReleaseDC( hWnd, hDC ); return hBitmap; } #endif // _WIN32 /****************************************************************************** // ConvertPaletteToRGB converts paletted and 16-BPP images that do not have // transparent pixels to 24-BPP images. Paletted images with transparent pixels // are converted to 32-BPP images. 24-BPP and 32-BPP images are simply copied // to the output structure // // INPUTS: // img_in // OUTPUTS: // img_out // // returns BMG_OK if no errors occur, an error code otherwise ******************************************************************************/ BMGError ConvertPaletteToRGB( struct BMGImageStruct img_in, struct BMGImageStruct *img_out ) { jmp_buf err_jmp; int error; /* error handler */ error = setjmp( err_jmp ); if ( error != 0 ) { FreeBMGImage( img_out ); SetLastBMGError( (BMGError)error ); return (BMGError)error; } SetLastBMGError( BMG_OK ); if ( img_in.height == 0 || img_in.width == 0 ) longjmp( err_jmp, (int)errInvalidSize ); InitBMGImage( img_out ); // copy 16, 24, and 32-BPP images into the output image if ( img_in.bits_per_pixel > 8 ) { BMGError out; img_out->bits_per_pixel = img_in.bits_per_pixel; out = CopyBMGImage( img_in, img_out ); if ( out != BMG_OK ) longjmp( err_jmp, (int)out ); // 16-BPP are converted to 24-BPP images if ( img_out->bits_per_pixel == 16 ) { out = Convert16to24( img_out ); if ( out != BMG_OK ) longjmp( err_jmp, (int)out ); } } else // convert paletted images to 24-BPP BGR or 32-BPP BGRA images { BMGError out; unsigned char *buf; unsigned int scan_width; int dealloc; unsigned char *q0, *q1, *p0, *p1; unsigned int bpp; // allocate memory for the 24-BPP output image img_out->width = img_in.width; img_out->height = img_in.height; img_out->opt_for_bmp = img_in.opt_for_bmp; img_out->bits_per_pixel = img_in.transparency_index > -1 ? 32 : 24; out = AllocateBMGImage( img_out ); if ( out != BMG_OK ) longjmp( err_jmp, (int)out ); // 1-BPP and 4-BPP images are packed, so we need to unpack them if ( img_in.bits_per_pixel < 8 ) { dealloc = 1; scan_width = img_in.width; buf = (unsigned char *)malloc(scan_width * img_in.height); if ( buf == NULL ) longjmp( err_jmp, (int)errMemoryAllocation ); if ( img_in.bits_per_pixel == 1 ) Convert1to8( img_in, buf ); else Convert4to8( img_in, buf ); } else // simply point to the bits array if we have a 8-BPP image { dealloc = 0; buf = img_in.bits; scan_width = img_in.scan_width; } // convert palette indices to BGR pixels bpp = img_out->bits_per_pixel / 8; q0 = img_out->bits; for ( p0 = buf; p0 < buf + scan_width * img_in.height; p0 += scan_width, q0 += img_out->scan_width ) { q1 = q0; for ( p1 = p0; p1 < p0 + img_in.width; p1++, q1 += bpp ) { memcpy( (void *)q1, (void *)(img_in.palette + *p1 * img_in.bytes_per_palette_entry), 3 ); if ( bpp == 4 ) { q1[3] = *p1 == img_in.transparency_index ? 0 : 0xFF; } } } if ( dealloc == 1 ) free( buf ); } return BMG_OK; } /****************************************************************************** // CopyBMG copies the contents of img_in into img_out. // // CopyBMG returns BMG_OK if successful, otherwise, it returns an error code ******************************************************************************/ BMGError CopyBMGImage( struct BMGImageStruct img_in, struct BMGImageStruct *img_out ) { BMGError out = BMG_OK; SetLastBMGError( out ); FreeBMGImage( img_out ); img_out->height = img_in.height; img_out->width = img_in.width; img_out->bits_per_pixel = img_in.bits_per_pixel; img_out->palette_size = img_in.palette_size; img_out->opt_for_bmp = img_in.opt_for_bmp; if ( img_in.width > 0 && img_in.height > 0 ) { out = AllocateBMGImage( img_out ); if ( out == BMG_OK ) { memcpy( (void *)img_out->bits, (void *)img_in.bits, img_in.scan_width * img_in.height ); if ( img_in.palette_size > 0 ) memcpy( (void *)img_out->palette, (void *)img_in.palette, img_in.palette_size * img_in.bytes_per_palette_entry ); } } return out; } /* sets the background color for alpha blending color points to an array of 4 unsigned chars color[0] = blue, color[1] = green, color[2] = red, color[3] = unused */ void SetBMGBackgroundColor( unsigned char *color ) { memcpy( (void *)GetBackgroundColor(), (void *)color, 4*sizeof(unsigned char) ); } #ifdef _WIN32 /* defines the background bitmap that is used for alpha blending & transparent pixels */ BMGError SetBMGBackgroundBitmap( HBITMAP hBitmap ) { BMGError out; struct BMGImageStruct tmp; InitBMGImage( &tmp ); /* first we extract the data from the HBITMAP */ out = GetDataFromBitmap( hBitmap, &tmp, 0 ); if ( out == BMG_OK ) { /* clean up the old background image */ FreeBMGImage( GetBackgroundImage() ); /* next, we convert paletted & 16-BPP images to 24 or 32-BPP images. // this will simplify the alpha blending. */ out = ConvertPaletteToRGB( tmp, GetBackgroundImage() ); } return out; } #endif // _WIN32 /* defines the background image that is used for alpha blending & transparent pixels */ BMGError SetBMGBackgroundImage( struct BMGImageStruct img ) { /* clean up the old background image */ FreeBMGImage( GetBackgroundImage() ); /* convert paletted and 16-BPP images to 24-BPP or 32-BPP images. This // will simplify the alpha blending logic*/ return ConvertPaletteToRGB( img, GetBackgroundImage() ); } mupen64plus-video-rice-src-2.6.0/src/liblinux/BMGImage.h000066400000000000000000000122221464507324400227000ustar00rootroot00000000000000#ifndef _BMG_IMAGE_H_ #define _BMG_IMAGE_H_ /* // header file for the BMGImage functions // // Copyright 2000, 2001 M. Scott Heiman // // You may use the software for any purpose you see fit. You may modify // it, incorporate it in a commercial application, use it for school, // even turn it in as homework. You must keep the Copyright in the // header and source files. This software is not in the "Public Domain". // You may use this software at your own risk. I have made a reasonable // effort to verify that this software works in the manner I expect it to; // however,... // // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "../osal_preproc.h" #if !defined(WIN32) typedef struct tagRGBQUAD { unsigned char rgbBlue; unsigned char rgbGreen; unsigned char rgbRed; unsigned char rgbReserved; } RGBQUAD; #endif enum BMG_Error { BMG_OK = 0, errLib = 1, errInvalidPixelFormat = 2, errMemoryAllocation = 3, errInvalidSize = 4, errInvalidBitmapHandle = 5, errWindowsAPI = 6, errFileOpen = 7, errUnsupportedFileFormat = 8, errInvalidBMGImage = 9, errInvalidFileExtension = 10, errFileRead = 11, errFileWrite = 12, errInvalidGeoTIFFPointer = 13, errUndefinedBGImage = 14, errBGImageTooSmall = 15, errCorruptFile = 16 }; typedef enum BMG_Error BMGError; #pragma pack(push,1) struct BMGImageStruct { unsigned int width; unsigned int height; unsigned char bits_per_pixel; unsigned char *bits; unsigned short palette_size; unsigned char bytes_per_palette_entry; unsigned char *palette; unsigned int scan_width; int opt_for_bmp; /*= 1 if memory has been sized for HBITMAP, 0 otherwise*/ short transparency_index; }; #pragma pack(pop) #if defined(__cplusplus) extern "C" { #endif /* initializes a BMGImage to default values */ extern void InitBMGImage(struct BMGImageStruct *img ); /* frees memory allocated to a BMGImage */ extern void FreeBMGImage( struct BMGImageStruct *img ); /* allocates memory (bits & palette) for a BMGImage. returns 1 if successfull, 0 otherwise. width, height, bits_per_pixel, palette_size, & opt_for_bmp must have valid values before this function is called. Assumes that all images with bits_per_pixel <= 8 requires a palette. will set bits_per_palette_entry, scan_width, bits, & palette */ extern BMGError AllocateBMGImage( struct BMGImageStruct *img ); /* compresses 8 BPP paletted images to 1 BPP or 4 BPP paletted images if possible */ extern BMGError CompressBMGImage( struct BMGImageStruct *img ); /* a utility function for freeing memory created in BMGLib */ extern void FreeBMGMemory( unsigned char *mem ); /* converts a color image to a gray scale image */ extern BMGError ConvertToGrayScale( struct BMGImageStruct *img ); /* converts a color image to a pseudo-gray scale image */ extern BMGError ConvertToPseudoGrayScale( struct BMGImageStruct *img ); /* stores the contents of a bitmap into a BMGImageStruct */ extern BMGError GetDataFromBitmap( HBITMAP hBitmap, struct BMGImageStruct *img, int remove_alpha ); /* creates an HBITMAP from a BMGImageStruct */ extern HBITMAP CreateBitmapFromData( struct BMGImageStruct img, int alpha_blend ); /* sets the background color for alpha blending color points to an array of 4 unsigned chars color[0] = blue, color[1] = green, color[2] = red, color[3] = unused */ extern void SetBMGBackgroundColor( unsigned char *color ); /* defines the background bitmap that is used for alpha blending & transparent pixels */ extern BMGError SetBMGBackgroundBitmap( HBITMAP hBitmap ); /* defines the background image that is used for alpha blending & transparent pixels */ extern BMGError SetBMGBackgroundImage( struct BMGImageStruct img ); /* Converts paletted images and 16-BPP images to 24-BPP images */ extern BMGError ConvertPaletteToRGB( struct BMGImageStruct img_in, struct BMGImageStruct *img_out ); /* copies the contents of the input image into the output image */ extern BMGError CopyBMGImage( struct BMGImageStruct img_in, struct BMGImageStruct *img_out ); /* returns the last error state */ extern BMGError GetLastBMGError(); /* gets the error message */ extern void GetLastBMGErrorMessage( const char **msg ); #if defined(__cplusplus) } #endif #endif mupen64plus-video-rice-src-2.6.0/src/liblinux/BMGLibPNG.h000066400000000000000000000047411464507324400227400ustar00rootroot00000000000000#ifndef _BMG_LIBPNG_H_ #define _BMG_LIBPNG_H_ /* // header file for the BMGLibPNG functions // // Copyright 2000, 2001 M. Scott Heiman // All Rights Reserved // libPNG is Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. // (libpng versions 0.5, May 1995, through 0.89c, May 1996) // Copyright (c) 1996, 1997 Andreas Dilger // (libpng versions 0.90, December 1996, through 0.96, May 1997) // Copyright (c) 1998, 1999 Glenn Randers-Pehrson // (libpng versions 0.97, January 1998, through 1.0.5, October 15, 1999) // // You may use the software for any purpose you see fit. You may modify // it, incorporate it in a commercial application, use it for school, // even turn it in as homework. You must keep the Copyright in the // header and source files. This software is not in the "Public Domain". // You may use this software at your own risk. I have made a reasonable // effort to verify that this software works in the manner I expect it to; // however,... // // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "pngrw.h" #if defined(__cplusplus) extern "C" { #endif //#pragma message ("Exporting BMGLibPNG functions") /* saves the contents of an HBITMAP to a file. The extension of the file name // determines the file type. returns 1 if successfull, 0 otherwise */ extern BMGError SaveBitmapToPNGFile( HBITMAP hBitmap, /* bitmap to be saved */ const char *filename); /* name of output file */ /* Creates an HBITMAP to an image file. The extension of the file name // determines the file type. returns an HBITMAP if successfull, NULL // otherwise */ extern HBITMAP CreateBitmapFromPNGFile( const char *filename, int blend ); #if defined(__cplusplus) } #endif #endif mupen64plus-video-rice-src-2.6.0/src/liblinux/BMGUtils.c000066400000000000000000000261521464507324400227600ustar00rootroot00000000000000/* // source code for the BMGLib Utility functions // // Copyright (C) 2001 M. Scott Heiman // All Rights Reserved // // You may use the software for any purpose you see fit. You may modify // it, incorporate it in a commercial application, use it for school, // even turn it in as homework. You must keep the Copyright in the // header and source files. This software is not in the "Public Domain". // You may use this software at your own risk. I have made a reasonable // effort to verify that this software works in the manner I expect it to; // however,... // // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include "BMGUtils.h" #include "../osal_preproc.h" #include "BMGImage.h" #ifndef _WIN32 #include #endif // _WIN32 /* error strings for all BMG errors */ static char BMGErrorStrings[17][128] = { "No Error", "Corrupted file or invalid file format", "Invalid bits per pixel for this file format", "Memory allocation error", "Invalid requested image size", "Invalid bitmap handle", "Windows API Error", /* this will be overwritten */ "Unable to open file", "Unsupported file format option", "Invalid pointer to a BMG image", "Unsupported file extension", "Error reading file", "Error writing to the output file", "Invalid pointer to a GeoTIFF structure", "The background image is undefined", "The background image is too small", "Corrupt File" }; /* stores last BMG error */ static BMGError LastBMGError; /* sets the last BMG error */ void SetLastBMGError( BMGError err ) { LastBMGError = err; } /* returns the last error state */ BMGError GetLastBMGError(void) { return LastBMGError; } /* gets the error message */ void GetLastBMGErrorMessage( const char **msg ) { if ( LastBMGError == errWindowsAPI ) { char* lpMsgBuf = "Erreur BMG\n"; /* copy the string. */ strcpy( BMGErrorStrings[(int)LastBMGError], (char *)lpMsgBuf ); } *msg = BMGErrorStrings[(int)LastBMGError]; } /* Global background color variables */ static unsigned char BackgroundColor[4]; static struct BMGImageStruct BackgroundImage; /* this function simply initializes the background info. It is called from the DllEntryPoint function */ void InitBackground(void) { memset( (void *)BackgroundColor, 0xFF, 3 ); /* white */ BackgroundColor[3] = 0; /* ignored */ InitBMGImage( &BackgroundImage ); } unsigned char *GetBackgroundColor(void) { return &BackgroundColor[0]; } struct BMGImageStruct *GetBackgroundImage(void) { return &BackgroundImage; } /* converts an array of 1-bit scanlines to 8-bit scanlines */ void Convert1to8( struct BMGImageStruct img, unsigned char *out ) { unsigned char *p, *q, *r, *s, *end; int i; q = out; for ( s = img.bits; s < img.bits + img.scan_width * img.height; s += img.scan_width, q += img.width ) { i = img.width % 8; end = q + img.width - i; p = s; for ( r = q; r < end; p++ ) { *r++ = (unsigned char)((*p & 0x80) ? 1 : 0); *r++ = (unsigned char)((*p & 0x40) ? 1 : 0); *r++ = (unsigned char)((*p & 0x20) ? 1 : 0); *r++ = (unsigned char)((*p & 0x10) ? 1 : 0); *r++ = (unsigned char)((*p & 0x08) ? 1 : 0); *r++ = (unsigned char)((*p & 0x04) ? 1 : 0); *r++ = (unsigned char)((*p & 0x02) ? 1 : 0); *r++ = (unsigned char)(*p & 0x01); } if ( i-- ) { *r++ = (unsigned char)((*p & 0x80) ? 1 : 0); if ( i-- ) { *r++ = (unsigned char)((*p & 0x40) ? 1 : 0); if ( i-- ) { *r++ = (unsigned char)((*p & 0x20) ? 1 : 0); if ( i-- ) { *r++ = (unsigned char)((*p & 0x10) ? 1 : 0); if ( i-- ) { *r++ = (unsigned char)((*p & 0x08) ? 1 : 0); if ( i-- ) { *r++ = (unsigned char)((*p & 0x04) ? 1 : 0); if ( i ) *r = (unsigned char)((*p & 0x02) ? 1:0); } } } } } } } } /* converts an array of 4-bit scanlines to 8-bit scanlines */ void Convert4to8( struct BMGImageStruct img, unsigned char *out ) { unsigned char *p, *q, *r, *s, *end; int i; q = out; for ( s = img.bits; s < img.bits + img.scan_width * img.height; s += img.scan_width, q += img.width ) { i = img.width % 2; end = q + img.width - i; p = s; for ( r = q; r < end; p++ ) { *r++ = (unsigned char)((*p >> 4) & 0x0F); *r++ = (unsigned char)(*p & 0x0F); } if ( i ) *r = (unsigned char)((*p >> 4) & 0x0F); } } /****************************************************************************/ /* this function performs alpha blending. It is a variation of a function that I found in the PNG example code */ unsigned char AlphaComp( unsigned char fg, unsigned char alpha, unsigned char bg ) { unsigned char out; unsigned short temp; switch ( alpha ) { case 0: out = bg; break; case 255: out = fg; break; default: temp = ((unsigned short)(fg)*(unsigned short)(alpha) + (unsigned short)(bg)*(unsigned short)(255 - (unsigned short)(alpha)) + (unsigned short)128); out = (unsigned char)((temp + (temp >> 8)) >> 8); break; } return out; } /**************************************************************************** // Converts a 16 BPP image to a 24 BPP image // returns 1 if successfull, 0 otherwise */ BMGError Convert16to24( struct BMGImageStruct *img ) { unsigned int i; unsigned int new_scan_width; unsigned char *new_bits; /* this function will only work with 16 BBP images */ if ( img->bits_per_pixel != 16 ) return errInvalidPixelFormat; /* calculate the new scan width */ new_scan_width = 3 * img->width; if ( new_scan_width % 4 && img->opt_for_bmp ) new_scan_width += 4 - new_scan_width % 4; /* allocate memory for the new pixel values */ new_bits = (unsigned char *)calloc( new_scan_width * img->height, sizeof(unsigned char) ); if ( new_bits == NULL ) return errMemoryAllocation; /* convert the 16 BPP pixel values to the equivalent 24 BPP values */ for ( i = 0; i < img->height; i++ ) { unsigned char *p24; unsigned short *p16 = (unsigned short *)(img->bits + i * img->scan_width); unsigned char *start = new_bits + i * new_scan_width; unsigned char *end = start + new_scan_width; for ( p24 = start; p24 < end; p24 += 3, p16++ ) { p24[0] = (unsigned char)( (*p16 & 0x001F) << 3 ); p24[1] = (unsigned char)( (*p16 & 0x03E0) >> 2 ); p24[2] = (unsigned char)( (*p16 & 0x7C00) >> 7 ); } } free( img->bits ); img->bits = new_bits; img->scan_width = new_scan_width; img->bits_per_pixel = 24; return BMG_OK; } /****************************************************************************/ /* this function undoes alpha blending - kind-a-sort-of ;-) */ unsigned char InverseAlphaComp( unsigned char fg, unsigned char alpha, unsigned char bg ) { unsigned char out; short temp; switch ( alpha ) { case 0: out = bg; break; case 255: out = fg; break; default: temp = (255*fg - bg*(255-alpha))/alpha; if ( temp < 0 ) temp = 0; out = (unsigned char)temp; break; } return out; } /****************************************************************************/ /* // Creates a BITMAPINFOHEADER for the given width, height, bit count, and // compression. Compression must = BI_RGB, BI_BITFIELDS, BI_RLE4, or BI_RLE8. */ BITMAPINFO InternalCreateBMI( unsigned int dwWidth, /* width */ unsigned int dwHeight, /* height */ unsigned short wBitCount, /* bit count */ int compression ) /* compression type */ { BITMAPINFO bi; /* bitmap header */ unsigned int dwBytesPerLine; /* Number of bytes per scanline */ /* clear the bitmapinfo structure */ memset(&bi, 0, sizeof(BITMAPINFO)); /* Make sure bits per pixel is valid */ if (wBitCount <= 1) wBitCount = 1; else if (wBitCount <= 4) wBitCount = 4; else if (wBitCount <= 8) wBitCount = 8; else if (wBitCount <= 16) wBitCount = 16; else if (wBitCount <= 24) wBitCount = 24; else if (wBitCount <= 32) wBitCount = 32; else wBitCount = 8; /* set default value to 8 if parameter is bogus */ dwBytesPerLine = (((wBitCount * dwWidth) + 31) / 32 * 4); /* initialize BITMAPINFO */ bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth = dwWidth; bi.bmiHeader.biHeight = dwHeight; bi.bmiHeader.biPlanes = 1; /* must be 1 */ bi.bmiHeader.biBitCount = wBitCount; bi.bmiHeader.biCompression = compression; bi.bmiHeader.biSizeImage = dwBytesPerLine*dwHeight; bi.bmiHeader.biXPelsPerMeter = 0; bi.bmiHeader.biYPelsPerMeter = 0; bi.bmiHeader.biClrUsed = wBitCount <= 8 ? 1U << wBitCount : 0; bi.bmiHeader.biClrImportant = bi.bmiHeader.biClrUsed; return bi; } short SwapShort( short in ) { char sin[2]; char sout[2]; memcpy( (char *)sin, (char *)&in, 2 ); sout[0] = sin[1]; sout[1] = sin[0]; return *((short *)sout); } unsigned short SwapUShort( unsigned short in ) { char sin[2]; char sout[2]; memcpy( (char *)sin, (char *)&in, 2 ); sout[0] = sin[1]; sout[1] = sin[0]; return *((unsigned short *)sout); } int SwapLong( int in ) { char sin[4]; char sout[4]; memcpy( (char *)sin, (char *)&in, 4 ); sout[0] = sin[3]; sout[1] = sin[2]; sout[2] = sin[1]; sout[3] = sin[0]; return *((int *)sout); } unsigned int SwapULong( unsigned int in ) { char sin[4]; char sout[4]; memcpy( (char *)sin, (char *)&in, 4 ); sout[0] = sin[3]; sout[1] = sin[2]; sout[2] = sin[1]; sout[3] = sin[0]; return *((unsigned int *)sout); } mupen64plus-video-rice-src-2.6.0/src/liblinux/BMGUtils.h000066400000000000000000000032441464507324400227620ustar00rootroot00000000000000#ifndef _BMG_UTILS_H_ #define _BMG_UTILS_H_ /* some handy utilities used in several units Copyright 2001 M. Scott Heiman All Rights Reserved */ #include "../osal_preproc.h" #include "BMGImage.h" /* the following 3 functions are used to access the background color // and the background image */ void InitBackground(void); unsigned char *GetBackgroundColor(void); struct BMGImageStruct *GetBackgroundImage(void); /* creates a 24 bpp image from a 16 bpp image */ BMGError Convert16to24( struct BMGImageStruct *img ); /* converts an array of 1-bit scanlines to 8-bit scanlines */ void Convert1to8( struct BMGImageStruct img, unsigned char *out ); /* converts an array of 4-bit scanlines to 8-bit scanlines */ void Convert4to8( struct BMGImageStruct img, unsigned char *out ); unsigned char AlphaComp( unsigned char fg, unsigned char alpha, unsigned char bg ); unsigned char InverseAlphaComp( unsigned char fg, unsigned char alpha, unsigned char bg ); BITMAPINFO InternalCreateBMI( unsigned int dwWidth, /* width */ unsigned int dwHeight, /* height */ unsigned short wBitCount, /* bit count */ int compression ); /* compression type */ void SetLastBMGError( BMGError err ); /* the following 4 functions are for dealing with file formats that store data in big endian format */ short SwapShort( short in ); unsigned short SwapUShort( unsigned short in ); int SwapLong( int in ); unsigned int SwapULong( unsigned int in ); #endif mupen64plus-video-rice-src-2.6.0/src/liblinux/bmp.c000066400000000000000000000410651464507324400221100ustar00rootroot00000000000000/* // source code for the ImageLib BMP functions // // Copyright (C) 2001 M. Scott Heiman // All Rights Reserved // // You may use the software for any purpose you see fit. You may modify // it, incorporate it in a commercial application, use it for school, // even turn it in as homework. You must keep the Copyright in the // header and source files. This software is not in the "Public Domain". // You may use this software at your own risk. I have made a reasonable // effort to verify that this software works in the manner I expect it to; // however,... // // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "../osal_preproc.h" #include "BMGDLL.h" #include "BMGImage.h" #include "BMGUtils.h" #ifndef _WIN32 #include #endif // _WIN32 static const unsigned short BMP_ID = 0x4D42; /* ReadBMP - reads the image data from a BMP files and stores it in a BMGImageStruct. Inputs: filename - the name of the file to be opened Outputs: img - the BMGImageStruct containing the image data Returns: BMGError - if the file could not be read or a resource error occurred BMG_OK - if the file was read and the data was stored in img Limitations: will not read BMP files using BI_RLE8, BI_RLE4, or BI_BITFIELDS */ BMGError ReadBMP( const char *filename, struct BMGImageStruct *img ) { FILE *file = NULL; int error; BMGError tmp; unsigned char *p, *q; /*, *q_end; */ /* unsigned int cnt; */ int i; /* int EOBMP; */ BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmih; /* unsigned int mask[3]; */ unsigned int DIBScanWidth; unsigned int bit_size, rawbit_size; unsigned char *rawbits = NULL; SetLastBMGError( BMG_OK ); if ( img == NULL ) { error = (int) errInvalidBMGImage; goto err_jmp; } file = fopen( filename, "rb" ); if ( file == NULL ) { error = (int) errFileOpen; goto err_jmp; } /* read the file header */ if ( fread( (void *)&bmfh, sizeof(BITMAPFILEHEADER), 1, file ) != 1 ) { error = (int) errFileRead; goto err_jmp; } /* confirm that this is a BMP file */ if ( bmfh.bfType != BMP_ID ) { error = (int) errUnsupportedFileFormat; goto err_jmp; } /* read the bitmap info header */ if ( fread( (void *)&bmih, sizeof(BITMAPINFOHEADER), 1, file ) != 1 ) { error = (int) errFileRead; goto err_jmp; } /* abort if this is an unsupported format */ if ( bmih.biCompression != BI_RGB ) { printf("planes: %i bits: %i type: %i ", bmih.biPlanes, bmih.biBitCount, bmih.biCompression); error = (int) errUnsupportedFileFormat; goto err_jmp; } img->bits_per_pixel = (unsigned char)bmih.biBitCount; img->width = bmih.biWidth; img->height = bmih.biHeight; if ( img->bits_per_pixel <= 8 ) { img->palette_size = (unsigned short)bmih.biClrUsed; img->bytes_per_palette_entry = 4U; } tmp = AllocateBMGImage( img ); if ( tmp != BMG_OK ) { error = (int) tmp; goto err_jmp; } /* read palette if necessary */ if ( img->bits_per_pixel <= 8 ) { if ( fread( (void *)img->palette, sizeof(RGBQUAD), img->palette_size, file ) != (unsigned int)img->palette_size ) { error = (int) errFileRead; goto err_jmp; } } /* dimensions */ DIBScanWidth = ( img->bits_per_pixel * img->width + 7 ) / 8; if ( DIBScanWidth %4 ) DIBScanWidth += 4 - DIBScanWidth % 4; bit_size = img->scan_width * img->height; /* allocate memory for the raw bits */ if ( bmih.biCompression != BI_RGB ) rawbit_size = bmfh.bfSize - bmfh.bfOffBits; else rawbit_size = DIBScanWidth * img->height; rawbits = (unsigned char *)calloc( rawbit_size, 1 ); if ( rawbits == NULL ) { error = (int) errMemoryAllocation; goto err_jmp; } if ( fread( (void *)rawbits, sizeof(unsigned char), rawbit_size, file ) != rawbit_size ) { error = (int) errFileRead; goto err_jmp; } if ( bmih.biCompression == BI_RGB ) { p = rawbits; for ( q = img->bits; q < img->bits + bit_size; q += img->scan_width, p += DIBScanWidth ) { memcpy( (void *)q, (void *)p, img->scan_width ); } } /* swap rows if necessary */ if ( bmih.biHeight < 0 ) { for ( i = 0; i < (int)(img->height) / 2; i++ ) { p = img->bits + i * img->scan_width; q = img->bits + ((img->height) - i - 1 ) * img->scan_width; memcpy( (void *)rawbits, (void *)p, img->scan_width ); memcpy( (void *)p, (void *)q, img->scan_width ); memcpy( (void *)q, (void *)rawbits, img->scan_width ); } } fclose( file ); free( rawbits ); return BMG_OK; /* error handler */ err_jmp: if ( file != NULL ) fclose( file ); if ( rawbits != NULL ) free( rawbits ); FreeBMGImage( img ); SetLastBMGError( (BMGError)error ); return (BMGError)error; } /* WriteBMP - writes the contents of an BMGImageStruct to a bmp file. Inputs: filename - the name of the file to be opened img - the BMGImageStruct containing the image data Returns: BMGError - if a write error or a resource error occurred BMG_OK - if the data was successfilly stored in filename Limitations: will not write BMP files using BI_RLE8, BI_RLE4, or BI_BITFIELDS */ BMGError WriteBMP( const char *filename, struct BMGImageStruct img ) { FILE * volatile file = NULL; jmp_buf err_jmp; int error; unsigned char * volatile bits = NULL; unsigned int DIBScanWidth; unsigned int BitsPerPixel; unsigned int bit_size; /*, new_bit_size; */ /* unsigned int rawbit_size; */ unsigned char *p, *q, *r, *t; /* unsigned int cnt; */ unsigned char * volatile pColor = NULL; BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmih; SetLastBMGError( BMG_OK ); /* error handler */ error = setjmp(err_jmp); if (error != 0) { if (file != NULL) fclose(file); if (bits != NULL) free(bits); if (pColor != NULL) free(pColor); SetLastBMGError((BMGError)error); return (BMGError) error; } if ( img.bits == NULL ) longjmp( err_jmp, (int)errInvalidBMGImage ); file = fopen( filename, "wb" ); if ( file == NULL ) longjmp( err_jmp, (int)errFileOpen ); /* abort if we do not support the data */ if ( img.palette != NULL && img.bytes_per_palette_entry < 3 ) longjmp( err_jmp, (int)errInvalidBMGImage ); /* calculate dimensions */ BitsPerPixel = img.bits_per_pixel < 32 ? img.bits_per_pixel : 24U; DIBScanWidth = ( BitsPerPixel * img.width + 7 ) / 8; if ( DIBScanWidth % 4 ) DIBScanWidth += 4 - DIBScanWidth % 4; bit_size = DIBScanWidth * img.height; /* rawbit_size = BITScanWidth * img.height; */ /* allocate memory for bit array - assume that compression will // actually compress the bitmap */ bits = (unsigned char *)calloc( bit_size, 1 ); if ( bits == NULL ) longjmp( err_jmp, (int)errMemoryAllocation ); /* some initialization */ memset( (void *)&bmih, 0, sizeof(BITMAPINFOHEADER) ); bmih.biSize = sizeof(BITMAPINFOHEADER); bmih.biWidth = img.width; bmih.biHeight = img.height; bmih.biPlanes = 1; /* 32-bit images will be stored as 24-bit images to save space. The BMP format does not use the high word and I do not want to store alpha components in an image format that does not recognize it */ bmih.biBitCount = BitsPerPixel; bmih.biCompression = BI_RGB; // assumed bmih.biSizeImage = bit_size; // assumed bmih.biClrUsed = img.palette == NULL ? 0 : img.palette_size; bmih.biClrImportant = img.palette == NULL ? 0 : img.palette_size; /* if we are not compressed then copy the raw bits to bits */ if ( bmih.biCompression == BI_RGB ) { p = img.bits; /* simple memcpy's for images containing < 32-bits per pixel */ if ( img.bits_per_pixel < 32 ) { for ( q = bits; q < bits + bit_size; q += DIBScanWidth, p += img.scan_width ) { memcpy( (void *)q, (void *)p, img.scan_width ); } } /* store 32-bit images as 24-bit images to save space. alpha terms are lost */ else { DIBScanWidth = 3 * img.width; if ( DIBScanWidth % 4 ) DIBScanWidth += 4 - DIBScanWidth % 4; for ( q = bits; q < bits + bit_size; q += DIBScanWidth, p += img.scan_width ) { t = p; for ( r = q; r < q + DIBScanWidth; r += 3, t += 4 ) memcpy( (void *)r, (void *)t, 3 ); } } } /* create the palette if necessary */ if ( img.palette != NULL ) { pColor = (unsigned char *)calloc( img.palette_size, sizeof(RGBQUAD) ); if ( pColor == NULL ) longjmp( err_jmp, (int)errMemoryAllocation ); if ( img.bytes_per_palette_entry == 3 ) { p = img.palette; for ( q = pColor + 1; q < pColor +img.palette_size*sizeof(RGBQUAD); q += sizeof(RGBQUAD), p += 3 ) { memcpy( (void *)pColor, (void *)p, 3 ); } } else /* img.bytes_per_palette_entry == 4 */ { memcpy( (void *)pColor, (void *)img.palette, img.palette_size * sizeof(RGBQUAD) ); } } /* now that we know how big everything is let's write the file */ memset( (void *)&bmfh, 0, sizeof(BITMAPFILEHEADER) ); bmfh.bfType = BMP_ID; bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + img.palette_size * sizeof(RGBQUAD); bmfh.bfSize = bmfh.bfOffBits + bit_size; if ( fwrite( (void *)&bmfh, sizeof(BITMAPFILEHEADER), 1, file ) != 1 ) longjmp( err_jmp, (int)errFileWrite ); if ( fwrite( (void *)&bmih, sizeof(BITMAPINFOHEADER), 1, file ) != 1 ) longjmp( err_jmp, (int)errFileWrite ); if ( pColor != NULL ) { if ( fwrite( (void *)pColor, sizeof(RGBQUAD), img.palette_size, file ) != (unsigned int)img.palette_size ) { longjmp( err_jmp, (int)errFileWrite ); } } if ( fwrite( (void *)bits, sizeof(unsigned char), bit_size, file ) != bit_size ) { longjmp( err_jmp, (int)errFileWrite ); } fclose( file ); free( bits ); if ( pColor != NULL ) free( pColor ); return BMG_OK; } #ifdef _NEVER_DEFINE_THIS_DEF_ /* following code is not tested. I keep it here in case I ever find a BMP file that is compressed and I want to test it */ else if ( bmih.biCompression == BI_RLE8 ) { bmih.biCompression = BI_RGB; bmih.biSizeImage = DIBScanWidth * img.height; p = rawbits; q = img.bits; EOBMP = 1; while ( q < img.bits + bit_size && p < rawbits + rawbit_size && EOBMP ) { cnt = (unsigned int)*p; p++; /* encoded mode */ if ( cnt == 0 ) { cnt = (unsigned int)*p; if ( cnt < 3U ) { p++; /* EOL */ if ( *p == 0 ) p++; /* end of bitmap */ else if ( *p == 1 ) EOBMP = 0; /* delta */ else if ( *p == 2 ) { p++; q += *p; /* columns */ p++; q += (*p)*BITScanWidth; /* rows */ p++; } } /* copy *p duplicates of *(p++) into the bit array */ else { cnt = (unsigned int)*p; p++; q_end = q + cnt; while ( q < q_end ) *q++ = *p; p++; } } /* absolute mode */ else { q_end = q + cnt; while ( q < q_end ) *q++ = *p++; } } } /* if compression is desired && possible then attempt compression. The // following logic will try to compress the data. If the compressed data // requires more space than the uncompressed data then the bits will be // stored in an uncompressed format */ if ( try_compression != 0 && img.bits_per_pixel == 8 ) { p = rawbits; r = bits; new_bit_size = 0; cnt = 0; while ( p < rawbits + rawbit_size && new_bit_size < bit_size ) { q = p; while ( q < p + BITScanWidth ) { t = q; while ( t < q + 255 && t < p + BITScanWidth ) { /* look for non-repeats - absolute mode */ if ( *t != *(t+1) ) { while ( *t != *(t+1) && cnt < 255 && t < p + BITScanWidth ) { t++; cnt++; } cnt++; *r++ = (unsigned char)cnt; memcpy( (void *)r, (void *)q, cnt ); r += cnt; q += cnt; new_bit_size += 1 + cnt; cnt = 0; } /* else look for repeats */ else { while ( *t == *(t+1) && cnt < 255 && t < p + BITScanWidth ) { t++; cnt++; } cnt++; if ( cnt > 2 ) { *r++ = 0; *r++ = (unsigned char)cnt; *r++ = *(t-1); new_bit_size += 3; q = t; cnt = 0; } /* use absolute mode if we have reached the EOL && // cnt <= 2 */ else if ( t >= p + BITScanWidth ) { *r++ = (unsigned char)cnt; memcpy( (void *)r, (void *)q, cnt ); r += cnt; q += cnt; new_bit_size += 1 + cnt; cnt = 0; } } } /* put an EOL marker here */ *r++ = 0; *r++ = 0; new_bit_size += 2; cnt = 0; } p += BITScanWidth; } /* put the EOB marker here */ if ( new_bit_size < bit_size - 2 ) { *r++ = 0; *r = 1; new_bit_size += 2; } else new_bit_size = bit_size + 1; /* if the compressed image will take less space then use it */ if ( new_bit_size < bit_size ) { bmih.biCompression = BI_RLE8; bmih.biSizeImage = bit_size = new_bit_size; } } #endif mupen64plus-video-rice-src-2.6.0/src/liblinux/jpegrw.h000066400000000000000000000021021464507324400226220ustar00rootroot00000000000000#ifndef _JPEG_RW_H_ #define _JPEG_RW_H_ /* // header file for the BMGLib JPEG functions // // Copyright 2000, 2001 M. Scott Heiman // All Rights Reserved // libJPEG is Copyright (C) 1991-1998, Thomas G. Lane and is part of the // Independent JPEG Group's software. // // We are releasing this software for both noncommercial and commercial use. // Companies are welcome to use it as the basis for JPEG-related products. // We do not ask a royalty, although we do ask for an acknowledgement in // product literature (see the README file in the distribution for details). // We hope to make this software industrial-quality --- although, as with // anything that's free, we offer no warranty and accept no liability. */ #include "BMGImage.h" #if defined(__cplusplus) extern "C" { #endif extern BMGError ReadJPEG( const char *filename, struct BMGImageStruct *img ); extern BMGError WriteJPEG( const char *filename, struct BMGImageStruct img, int quality ); #if defined(__cplusplus) } #endif #endif mupen64plus-video-rice-src-2.6.0/src/liblinux/pngrw.c000066400000000000000000000521701464507324400224660ustar00rootroot00000000000000/* // source code for the ImageLib PNG functions // // Copyright (C) 2001 M. Scott Heiman // All Rights Reserved // // You may use the software for any purpose you see fit. You may modify // it, incorporate it in a commercial application, use it for school, // even turn it in as homework. You must keep the Copyright in the // header and source files. This software is not in the "Public Domain". // You may use this software at your own risk. I have made a reasonable // effort to verify that this software works in the manner I expect it to; // however,... // // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include "BMGImage.h" #include "BMGUtils.h" #ifdef _BMG_LIBPNG_STANDALONE #include "BMGLibPNG.h" #else #include "pngrw.h" #endif #include #ifndef png_jmpbuf # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) #endif /* this stuff is necessary because the normal png_init_io() method crashes in Win32 */ static void user_read_data(png_structp png_read, png_bytep data, png_size_t length) { FILE *fPtr = (FILE *) png_get_io_ptr(png_read); if (fread(data, 1, length, fPtr) != length) fprintf(stderr, "Failed to read %i bytes from PNG file.\n", (int) length); } static void user_write_data(png_structp png_write, png_bytep data, png_size_t length) { FILE *fPtr = (FILE *) png_get_io_ptr(png_write); if (fwrite(data, 1, length, fPtr) != length) fprintf(stderr, "Failed to write %i bytes to PNG file.\n", (int) length); } static void user_flush_data(png_structp png_read) { FILE *fPtr = (FILE *) png_get_io_ptr(png_read); fflush(fPtr); } /* ReadPNG - Reads the contents of a PNG file and stores the contents into BMGImageStruct Inputs: filename - the name of the file to be opened Outputs: img - the BMGImageStruct containing the image data Returns: BMGError - if the file could not be read or a resource error occurred BMG_OK - if the file was read and the data was stored in img Limitations: None. Comments: 2-bit images are converted to 4-bit images. 16-bit images are converted to 8-bit images. gray scale images with alpha components are converted to 32-bit images */ BMGError ReadPNG( const char *filename, struct BMGImageStruct * volatile img ) { jmp_buf err_jmp; int error; FILE * volatile file = NULL; int BitDepth; int ColorType; int InterlaceType; unsigned char signature[8]; png_structp volatile png_ptr = NULL; png_infop volatile info_ptr = NULL; png_infop volatile end_info = NULL; png_color_16 *ImageBackground = NULL; png_bytep trns = NULL; int NumTrans = 0; int i, k; png_color_16p TransColors = NULL; png_uint_32 Width, Height; unsigned char *bits; unsigned char** volatile rows = NULL; BMGError tmp; /* error handler */ error = setjmp( err_jmp ); if (error != 0) { if (end_info != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); else if (info_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL); else if (png_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL); if (rows) { if (rows[0]) free(rows[0]); free(rows); } if (img) FreeBMGImage(img); if (file) fclose(file); SetLastBMGError((BMGError) error); return (BMGError) error; } if ( img == NULL ) longjmp ( err_jmp, (int)errInvalidBMGImage ); file = fopen( filename, "rb" ); if ( !file || fread( signature, 1, 8, file ) != 8) longjmp ( err_jmp, (int)errFileOpen ); /* check the signature */ if ( png_sig_cmp( signature, 0, 8 ) != 0 ) longjmp( err_jmp, (int)errUnsupportedFileFormat ); /* create a pointer to the png read structure */ png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if ( !png_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png info structure */ info_ptr = png_create_info_struct( png_ptr ); if ( !info_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png end-info structure */ end_info = png_create_info_struct(png_ptr); if (!end_info) longjmp( err_jmp, (int)errMemoryAllocation ); /* bamboozle the PNG longjmp buffer */ /*generic PNG error handler*/ /* error will always == 1 which == errLib */ // error = png_setjmp(png_ptr); error = setjmp( png_jmpbuf( png_ptr ) ); if ( error > 0 ) longjmp( err_jmp, error ); /* set function pointers in the PNG library, for read callbacks */ png_set_read_fn(png_ptr, (png_voidp) file, user_read_data); /*let the read functions know that we have already read the 1st 8 bytes */ png_set_sig_bytes( png_ptr, 8 ); /* read all PNG data up to the image data */ png_read_info( png_ptr, info_ptr ); /* extract the data we need to form the HBITMAP from the PNG header */ png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType, &InterlaceType, NULL, NULL); img->width = (unsigned int) Width; img->height = (unsigned int) Height; img->bits_per_pixel = (unsigned char)32; img->scan_width = Width * 4; /* convert 16-bit images to 8-bit images */ if (BitDepth == 16) png_set_strip_16(png_ptr); /* These are not really required per Rice format spec, * but is done just in case someone uses them. */ /* convert palette color to rgb color */ if (ColorType == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); ColorType = PNG_COLOR_TYPE_RGB; } /* expand 1,2,4 bit gray scale to 8 bit gray scale */ if (ColorType == PNG_COLOR_TYPE_GRAY && BitDepth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); /* convert gray scale or gray scale + alpha to rgb color */ if (ColorType == PNG_COLOR_TYPE_GRAY || ColorType == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); ColorType = PNG_COLOR_TYPE_RGB; } /* add alpha channel if any */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); ColorType = PNG_COLOR_TYPE_RGB_ALPHA; } /* convert rgb to rgba */ if (ColorType == PNG_COLOR_TYPE_RGB) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); ColorType = PNG_COLOR_TYPE_RGB_ALPHA; } png_set_bgr(png_ptr); /* set the background color if one is found */ if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD) ) png_get_bKGD(png_ptr, info_ptr, &ImageBackground); /* get the transparent color if one is there */ if ( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) ) png_get_tRNS( png_ptr, info_ptr, &trns, &NumTrans, &TransColors ); img->palette_size = (unsigned short)0; img->bytes_per_palette_entry = 4U; tmp = AllocateBMGImage( img ); if ( tmp != BMG_OK ) longjmp( err_jmp, (int)tmp ); png_read_update_info( png_ptr, info_ptr ); /* create buffer to read data to */ rows = (unsigned char **)malloc(Height*sizeof(unsigned char *)); if ( !rows ) longjmp( err_jmp, (int)errMemoryAllocation ); k = png_get_rowbytes( png_ptr, info_ptr ); rows[0] = (unsigned char *)malloc( Height*k*sizeof(char)); if ( !rows[0] ) longjmp( err_jmp, (int)errMemoryAllocation ); for ( i = 1; i < (int)Height; i++ ) rows[i] = rows[i-1] + k; /* read the entire image into rows */ png_read_image( png_ptr, rows ); bits = img->bits + (Height - 1) * img->scan_width; for ( i = 0; i < (int)Height; i++ ) { memcpy(bits, rows[i], 4*Width); bits -= img->scan_width; } free( rows[0] ); free( rows ); png_read_end( png_ptr, info_ptr ); png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); fclose( file ); return BMG_OK; } BMGError ReadPNGInfo( const char *filename, struct BMGImageStruct * volatile img ) { jmp_buf err_jmp; int error; FILE * volatile file = NULL; int BitDepth; int ColorType; int InterlaceType; unsigned char signature[8]; png_structp volatile png_ptr = NULL; png_infop volatile info_ptr = NULL; png_infop volatile end_info = NULL; png_uint_32 Width, Height; /* error handler */ error = setjmp( err_jmp ); if (error != 0) { if (end_info != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); else if (info_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL); else if (png_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL); if (img) FreeBMGImage(img); if (file) fclose(file); SetLastBMGError((BMGError) error); return (BMGError) error; } if ( img == NULL ) longjmp ( err_jmp, (int)errInvalidBMGImage ); file = fopen( filename, "rb" ); if ( !file || fread( signature, 1, 8, file ) != 8) longjmp ( err_jmp, (int)errFileOpen ); /* check the signature */ if ( png_sig_cmp( signature, 0, 8 ) != 0 ) longjmp( err_jmp, (int)errUnsupportedFileFormat ); /* create a pointer to the png read structure */ png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if ( !png_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png info structure */ info_ptr = png_create_info_struct( png_ptr ); if ( !info_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png end-info structure */ end_info = png_create_info_struct(png_ptr); if (!end_info) longjmp( err_jmp, (int)errMemoryAllocation ); /* bamboozle the PNG longjmp buffer */ /*generic PNG error handler*/ /* error will always == 1 which == errLib */ // error = png_setjmp(png_ptr); error = setjmp( png_jmpbuf( png_ptr ) ); if ( error > 0 ) longjmp( err_jmp, error ); /* set function pointers in the PNG library, for read callbacks */ png_set_read_fn(png_ptr, (png_voidp) file, user_read_data); /*let the read functions know that we have already read the 1st 8 bytes */ png_set_sig_bytes( png_ptr, 8 ); /* read all PNG data up to the image data */ png_read_info( png_ptr, info_ptr ); /* extract the data we need to form the HBITMAP from the PNG header */ png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType, &InterlaceType, NULL, NULL); img->width = (unsigned int) Width; img->height = (unsigned int) Height; img->bits_per_pixel = (unsigned char)32; img->scan_width = Width * 4; img->palette_size = (unsigned short)0; img->bytes_per_palette_entry = 4U; img->bits = NULL; png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); fclose( file ); return BMG_OK; } /* WritePNG - writes the contents of a BMGImageStruct to a PNG file. Inputs: filename - the name of the file to be opened img - the BMGImageStruct containing the image data Returns: 0 - if the file could not be written or a resource error occurred 1 - if the file was written Comments: 16-BPP BMG Images are converted to 24-BPP images Limitations: Color Type is limited to PNG_COLOR_TYPE_GRAY, PNG_COLOR_TYPE_RGB_ALPHA, PNG_COLOR_TYPE_RGB, & PNG_COLOR_TYPE_PALETTE; */ BMGError WritePNG( const char *filename, struct BMGImageStruct img ) { jmp_buf err_jmp; int error = 0; int BitDepth = 0; int ColorType = 0; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_colorp PNGPalette = NULL; unsigned char *bits, *p, *q; unsigned char **rows = NULL; volatile int GrayScale, NumColors; // mark as volatile so GCC won't throw warning with -Wclobbered int DIBScanWidth; FILE *outfile = NULL; int i; BMGError tmp; /* error handler */ error = setjmp( err_jmp ); fprintf(stderr,"Writing PNG file %s.\n", filename); if ( error != 0 ) { if ( png_ptr != NULL ) png_destroy_write_struct( &png_ptr, NULL ); if ( rows ) { if ( rows[0] ) { free( rows[0] ); } free( rows ); } if ( PNGPalette ) free( PNGPalette ); if (outfile) { fclose( outfile ); } SetLastBMGError( (BMGError)error ); return (BMGError)error; } SetLastBMGError( BMG_OK ); /* open the file */ if ((outfile = fopen(filename, "wb")) == NULL) { fprintf(stderr, "Error opening %s for reading.\n", filename); longjmp( err_jmp, (int)errFileOpen ); } /* 16 BPP DIBS do not have palettes. libPNG expects 16 BPP images to have a palette. To correct this situation we must convert 16 BPP images to 24 BPP images before saving the data to the file */ if ( img.bits_per_pixel == 16 ) { tmp = Convert16to24( &img ); if ( tmp != BMG_OK ) longjmp( err_jmp, (int)tmp ); } GrayScale = 0; NumColors = 0; if (img.bits_per_pixel <= 8) // has palette { NumColors = img.palette_size; /* if this is a grayscale image then set the flag and delete the palette*/ i = 0; bits = img.palette; while ( i < NumColors && bits[0] == bits[1] && bits[0] == bits[2] ) { i++; bits += img.bytes_per_palette_entry; } GrayScale = (i == NumColors); } /* dimensions */ DIBScanWidth = ( img.width * img.bits_per_pixel + 7 ) / 8; /* create the png pointer */ png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if ( !png_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create the info pointer */ info_ptr = png_create_info_struct( png_ptr ); if ( !info_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* bamboozle the png error handler */ /* error will always == 1 which equals errLib */ // error = png_setjmp(png_ptr); error = setjmp( png_jmpbuf( png_ptr ) ); if ( error > 0 ) longjmp( err_jmp, error ); /* set function pointers in the PNG library, for write callbacks */ png_set_write_fn(png_ptr, (png_voidp) outfile, user_write_data, user_flush_data); /* prepare variables needed to create PNG header */ BitDepth = img.bits_per_pixel < 8 ? img.bits_per_pixel : 8; /* determine color type */ if ( GrayScale ) ColorType = PNG_COLOR_TYPE_GRAY; else if ( img.bits_per_pixel == 32 ) ColorType = PNG_COLOR_TYPE_RGB_ALPHA; else if ( img.bits_per_pixel == 24 ) ColorType = PNG_COLOR_TYPE_RGB; else ColorType = PNG_COLOR_TYPE_PALETTE; /* create the PNG header */ png_set_IHDR( png_ptr, info_ptr, img.width, img.height, BitDepth, ColorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE ); /* store the palette information if there is any */ if ( img.palette != NULL && !GrayScale ) { PNGPalette = (png_colorp)png_malloc( png_ptr, NumColors*sizeof(png_color)); if ( PNGPalette ) { bits = img.palette; for ( i = 0; i < NumColors; i++, bits += img.bytes_per_palette_entry ) { PNGPalette[i].red = bits[2]; PNGPalette[i].green = bits[1]; PNGPalette[i].blue = bits[0]; } png_set_PLTE( png_ptr, info_ptr, PNGPalette, NumColors ); } else longjmp( err_jmp, (int)errMemoryAllocation ); } /* write the file header information */ png_write_info( png_ptr, info_ptr ); /* create array to store data in */ rows = (unsigned char **)malloc(sizeof(unsigned char*)); if ( !rows ) longjmp( err_jmp, (int)errMemoryAllocation ); rows[0] = (unsigned char *)malloc( DIBScanWidth * sizeof(unsigned char)); if ( !rows[0] ) longjmp( err_jmp, (int)errMemoryAllocation ); /* point to the bottom row of the DIB data. DIBs are stored bottom-to-top, PNGs are stored top-to-bottom. */ bits = img.bits + (img.height - 1) * img.scan_width; /* store bits */ for ( i = 0; i < (int)img.height; i++ ) { switch ( img.bits_per_pixel ) { case 1: case 4: case 8: memcpy( (void *)rows[0], (void *)bits, DIBScanWidth ); break; case 24: q = bits; for ( p = rows[0]; p < rows[0] + DIBScanWidth; p += 3, q += 3 ) { p[0] = q[2]; p[1] = q[1]; p[2] = q[0]; } break; case 32: q = bits; for ( p = rows[0]; p < rows[0] + DIBScanWidth; p += 4, q += 4 ) { p[3] = q[3]; p[0] = q[2]; p[1] = q[1]; p[2] = q[0]; } break; } png_write_rows( png_ptr, rows, 1 ); bits -= img.scan_width; } /* finish writing the rest of the file */ png_write_end( png_ptr, info_ptr ); /* clean up and exit */ if ( PNGPalette ) free( PNGPalette ); free( rows[0] ); free( rows ); png_destroy_write_struct( &png_ptr, NULL ); fclose( outfile ); return BMG_OK; } #ifdef _BMG_LIBPNG_STANDALONE #pragma message ("Creating BMGLibPNG functions") #ifdef _WIN32 /* saves the contents of an HBITMAP to a file. returns 1 if successfull, // 0 otherwise */ BMGError SaveBitmapToPNGFile( HBITMAP hBitmap, /* bitmap to be saved */ const char *filename) /* name of output file */ { struct BMGImageStruct img; char msg[256], ext[4], *period; BMGError out = BMG_OK; InitBMGImage( &img ); /* determine the file type by using the extension */ strcpy( msg, filename ); period = strrchr( msg, '.' ); if ( period != NULL ) { period++; strcpy( ext, period ); ext[0] = toupper( ext[0] ); ext[1] = toupper( ext[1] ); ext[2] = toupper( ext[2] ); ext[3] = 0; } else { strcat( msg, ".PNG" ); strcpy( ext, "PNG" ); } if ( strcmp( ext, "PNG" ) == 0 ) { /* extract data from the bitmap. We assume that 32 bit images have been // blended with the background (unless this is a DDB - see GetDataFromBitmap // for more details) */ out = GetDataFromBitmap( hBitmap, &img, 1 ); if ( out == BMG_OK ) { out = WritePNG( msg, img ); } FreeBMGImage( &img ); } else { out = errInvalidFileExtension; } SetLastBMGError( out ); return out; } #endif // _WIN32 /* Creates an HBITMAP to an image file. returns an HBITMAP if successfull, // NULL otherwise */ HBITMAP CreateBitmapFromPNGFile( const char *filename, int blend ) { char ext[4], msg[256]; char *period; BMGError out = BMG_OK; struct BMGImageStruct img; HBITMAP hBitmap = NULL; InitBMGImage( &img ); img.opt_for_bmp = 1; strcpy( msg, filename ); period = strrchr( msg, '.' ); if ( period != NULL ) { period++; strncpy( ext, period, 3 ); ext[0] = toupper( ext[0] ); ext[1] = toupper( ext[1] ); ext[2] = toupper( ext[2] ); ext[3] = 0; } else { strcat( msg, ".PNG" ); strcpy( ext, "PNG" ); } if ( strcmp( ext, "PNG" ) == 0 ) { out = ReadPNG( msg, &img ); if ( out == BMG_OK ) { hBitmap = CreateBitmapFromData( img, blend ); } FreeBMGImage( &img ); } else { out = errInvalidFileExtension; } SetLastBMGError( out ); return hBitmap; } #endif mupen64plus-video-rice-src-2.6.0/src/liblinux/pngrw.h000066400000000000000000000041551464507324400224730ustar00rootroot00000000000000#ifndef _PNG_RW_H_ #define _PNG_RW_H_ /* // header file for the BMGLib PNG functions // // Copyright 2000, 2001 M. Scott Heiman // All Rights Reserved // libPNG is Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. // (libpng versions 0.5, May 1995, through 0.89c, May 1996) // Copyright (c) 1996, 1997 Andreas Dilger // (libpng versions 0.90, December 1996, through 0.96, May 1997) // Copyright (c) 1998, 1999 Glenn Randers-Pehrson // (libpng versions 0.97, January 1998, through 1.0.5, October 15, 1999) // // You may use the software for any purpose you see fit. You may modify // it, incorporate it in a commercial application, use it for school, // even turn it in as homework. You must keep the Copyright in the // header and source files. This software is not in the "Public Domain". // You may use this software at your own risk. I have made a reasonable // effort to verify that this software works in the manner I expect it to; // however,... // // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "BMGImage.h" #if defined(__cplusplus) extern "C" { #endif extern BMGError ReadPNG( const char *filename, struct BMGImageStruct * volatile img ); extern BMGError ReadPNGInfo( const char *filename, struct BMGImageStruct * volatile img ); extern BMGError WritePNG( const char *filename, struct BMGImageStruct img ); #if defined(__cplusplus) } #endif #endif mupen64plus-video-rice-src-2.6.0/src/liblinux/tiffrw.h000066400000000000000000000050541464507324400226360ustar00rootroot00000000000000#ifndef _TIFF_RW_H_ #define _TIFF_RW_H_ /* // header file defining BMGLib libTIFF structures and functions // // Copyright 2000, 2001 Scott Heiman // libTIFF is Copyright Sam Leffler and SGI // zLib Copyright (C) 1995-1998 Jean-loup Gailly. // // Permission to use, copy, modify, distribute, and sell this software and // its documentation for any purpose is hereby granted without fee, provided // that (i) the above copyright notices and this permission notice appear in // all copies of the software and related documentation, and (ii) the names of // Sam Leffler and Silicon Graphics may not be used in any advertising or // publicity relating to the software without the specific, prior written // permission of Sam Leffler and Silicon Graphics. // // THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, // EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY // WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. // // IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR // ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, // OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, // WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF // LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE // OF THIS SOFTWARE. */ #include "BMGImage.h" /* enumeration types that support libTIFF */ enum TiffCompressionEnum { NONE, CCITTRLE, CCITTFAX3, CCITTFAX4, LZW, JPEG6, JPEG_DCT, NeXT, CCITTRLEW, MACINTOSH, THUNDERSCAN, PIXARFILM, PIXARLOG, ZIP, KODAK, JBIG }; enum TiffPhotometricEnum { MINISWHITE, MINISBLACK, RGB, PALETTE, MASK, SEPARATED, YCBCR, CIELAB, CIE_LOGL, CIE_LOGLUV }; enum TiffOrientationEnum { TOPLEFT, BOTTOMLEFT }; typedef enum TiffCompressionEnum TiffCompression; typedef enum TiffPhotometricEnum TiffPhotometric; typedef enum TiffOrientationEnum TiffOrientation; #pragma pack(push,1) struct TIFFInfoStruct { TiffCompression compression; TiffPhotometric photometric; TiffOrientation orientation; unsigned short predictor; }; #pragma pack(pop) #if defined(__cplusplus) extern "C" { #endif extern BMGError ReadTIFF( const char *filename, struct BMGImageStruct *img, struct TIFFInfoStruct *info ); extern BMGError WriteTIFF( const char *filename, struct BMGImageStruct img, struct TIFFInfoStruct *info ); #if defined(__cplusplus) } #endif #endif mupen64plus-video-rice-src-2.6.0/src/osal_dynamiclib.h000066400000000000000000000034441464507324400226410ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal/dynamiclib.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if !defined(OSAL_DYNAMICLIB_H) #define OSAL_DYNAMICLIB_H #ifdef __cplusplus extern "C" { #endif #include "m64p_types.h" void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName); #ifdef __cplusplus } #endif #endif /* #define OSAL_DYNAMICLIB_H */ mupen64plus-video-rice-src-2.6.0/src/osal_dynamiclib_unix.c000066400000000000000000000034731464507324400237010ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal/dynamiclib_unix.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include "m64p_types.h" #include "osal_dynamiclib.h" void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName) { if (pccProcedureName == NULL) return NULL; return dlsym(LibHandle, pccProcedureName); } mupen64plus-video-rice-src-2.6.0/src/osal_dynamiclib_win32.c000066400000000000000000000060551464507324400236570ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-ui-console - osal_dynamiclib_win32.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include "m64p_types.h" #include "osal_dynamiclib.h" m64p_error osal_dynlib_open(m64p_dynlib_handle *pLibHandle, const char *pccLibraryPath) { if (pLibHandle == NULL || pccLibraryPath == NULL) return M64ERR_INPUT_ASSERT; *pLibHandle = LoadLibrary(pccLibraryPath); if (*pLibHandle == NULL) { char *pchErrMsg; DWORD dwErr = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL); fprintf(stderr, "LoadLibrary('%s') error: %s\n", pccLibraryPath, pchErrMsg); LocalFree(pchErrMsg); return M64ERR_INPUT_NOT_FOUND; } return M64ERR_SUCCESS; } void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName) { if (pccProcedureName == NULL) return NULL; return GetProcAddress(LibHandle, pccProcedureName); } m64p_error osal_dynlib_close(m64p_dynlib_handle LibHandle) { int rval = FreeLibrary(LibHandle); if (rval == 0) { char *pchErrMsg; DWORD dwErr = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL); fprintf(stderr, "FreeLibrary() error: %s\n", pchErrMsg); LocalFree(pchErrMsg); return M64ERR_INTERNAL; } return M64ERR_SUCCESS; } mupen64plus-video-rice-src-2.6.0/src/osal_files.h000066400000000000000000000046441464507324400216330ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-ui-console - osal_files.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This header file is for all kinds of system-dependent file handling * */ #if !defined(OSAL_FILES_H) #define OSAL_FILES_H #ifdef __cplusplus extern "C" { #endif #include "m64p_types.h" #if defined(WIN32) #define PATH_MAX _MAX_PATH #define OSAL_DIR_SEPARATOR_STR "\\" #define OSAL_DIR_SEPARATOR_CHAR '\\' #define strdup _strdup #else /* Not WIN32 */ #include // for PATH_MAX #define OSAL_DIR_SEPARATOR_STR "/" #define OSAL_DIR_SEPARATOR_CHAR '/' /* PATH_MAX only may be defined by limits.h */ #ifndef PATH_MAX #define PATH_MAX 4096 #endif #endif int osal_is_directory(const char* name); int osal_mkdirp(const char *dirpath, int mode); void * osal_search_dir_open(const char *pathname); const char *osal_search_dir_read_next(void * dir_handle); void osal_search_dir_close(void * dir_handle); #ifdef __cplusplus } #endif #endif /* #define OSAL_FILES_H */ mupen64plus-video-rice-src-2.6.0/src/osal_files_unix.c000066400000000000000000000070711464507324400226660ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal_files_unix.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the definitions for the unix-specific file handling * functions */ #include #include #include #include #include #include #include #include "osal_files.h" /* global functions */ int osal_is_directory(const char* name) { DIR* dir; dir = opendir(name); if(dir != NULL) { closedir(dir); return 1; } return 0; } int osal_mkdirp(const char *dirpath, int mode) { struct stat fileinfo; int dirpathlen = strlen(dirpath); char *currpath = strdup(dirpath); /* first, break the path into pieces by replacing all of the slashes wil NULL chars */ while (strlen(currpath) > 1) { char *lastslash = strrchr(currpath, '/'); if (lastslash == NULL) break; *lastslash = 0; } /* then re-assemble the path from left to right until we get to a directory that doesn't exist */ while (strlen(currpath) < dirpathlen) { if (strlen(currpath) > 0 && stat(currpath, &fileinfo) != 0) break; currpath[strlen(currpath)] = '/'; } /* then walk up the path chain, creating directories along the way */ do { if (stat(currpath, &fileinfo) != 0) { if (mkdir(currpath, mode) != 0) { free(currpath); return 1; /* mkdir failed */ } } if (strlen(currpath) == dirpathlen) break; else currpath[strlen(currpath)] = '/'; } while (1); free(currpath); return 0; } void * osal_search_dir_open(const char *pathname) { DIR *dir; dir = opendir(pathname); return dir; } const char *osal_search_dir_read_next(void * dir_handle) { DIR *dir = (DIR *) dir_handle; struct dirent *entry; entry = readdir(dir); if (entry == NULL) return NULL; return entry->d_name; } void osal_search_dir_close(void * dir_handle) { closedir((DIR *) dir_handle); } mupen64plus-video-rice-src-2.6.0/src/osal_files_win32.c000066400000000000000000000113371464507324400226450ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal_files_win32.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the definitions for the unix-specific file handling * functions */ #include #include #include #include #include #include #include #include "osal_files.h" /* global functions */ int osal_is_directory(const char* name) { char DirName[MAX_PATH + 1]; int namelen = 0; /* we must remove any trailing backslash on the end of the pathname, or this will fail */ strncpy(DirName, name, MAX_PATH); DirName[MAX_PATH] = 0; namelen = strlen(DirName); if (namelen > 0 && DirName[namelen-1] == '\\') DirName[namelen-1] = 0; return (GetFileAttributes(DirName) & FILE_ATTRIBUTE_DIRECTORY); } int osal_mkdirp(const char *dirpath, int mode) { struct _stat fileinfo; size_t dirpathlen = strlen(dirpath); char *currpath = _strdup(dirpath); /* first, remove sub-dirs on the end (by replacing slashes with NULL chars) until we find an existing directory */ while (strlen(currpath) > 1 && _stat(currpath, &fileinfo) != 0) { char *lastslash = strrchr(currpath, '\\'); if (lastslash == NULL) { free(currpath); return 1; /* error: we never found an existing directory, this path is bad */ } *lastslash = 0; } /* then walk up the path chain, creating directories along the way */ do { if (currpath[strlen(currpath)-1] != '\\' && _stat(currpath, &fileinfo) != 0) { if (_mkdir(currpath) != 0) { free(currpath); return 2; /* mkdir failed */ } } if (strlen(currpath) == dirpathlen) break; else currpath[strlen(currpath)] = '\\'; } while (1); free(currpath); return 0; } typedef struct { HANDLE hFind; WIN32_FIND_DATA find_data; } dir_search_info; void * osal_search_dir_open(const char *pathname) { char SearchString[MAX_PATH + 1]; dir_search_info *pInfo = malloc(sizeof(dir_search_info)); if (pInfo == NULL) return NULL; pInfo->hFind = INVALID_HANDLE_VALUE; pInfo->find_data.cFileName[0] = 0; if (pathname[strlen(pathname)-1] == '\\') _snprintf(SearchString, MAX_PATH, "%s*", pathname); else _snprintf(SearchString, MAX_PATH, "%s\\*", pathname); SearchString[MAX_PATH] = 0; pInfo->hFind = FindFirstFile(SearchString, &pInfo->find_data); return (void *) pInfo; } const char *osal_search_dir_read_next(void * search_info) { static char last_filename[_MAX_PATH]; dir_search_info *pInfo = (dir_search_info *) search_info; if (pInfo == NULL || pInfo->hFind == INVALID_HANDLE_VALUE || pInfo->find_data.cFileName[0] == 0) return NULL; strcpy(last_filename, pInfo->find_data.cFileName); if (FindNextFile(pInfo->hFind, &pInfo->find_data) == 0) { pInfo->find_data.cFileName[0] = 0; } return last_filename; } void osal_search_dir_close(void * search_info) { dir_search_info *pInfo = (dir_search_info *) search_info; if (pInfo != NULL) { if (pInfo->hFind != INVALID_HANDLE_VALUE) FindClose(pInfo->hFind); free(pInfo); } } mupen64plus-video-rice-src-2.6.0/src/osal_opengl.h000066400000000000000000000057601464507324400220150ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - osal_opengl.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2013 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if !defined(OSAL_OPENGL_H) #define OSAL_OPENGL_H #include // Vertex shader params #define VS_POSITION 0 #define VS_COLOR 1 #define VS_TEXCOORD0 2 #define VS_TEXCOORD1 3 #define VS_FOG 4 #ifdef USE_GLES #ifndef SDL_VIDEO_OPENGL_ES2 #error SDL is not build with OpenGL ES2 support. Try USE_GLES=0 #endif #include #define GLSL_VERSION "100" // SDL_opengles2.h define GL_APIENTRYP instead of APIENTRYP #define APIENTRYP GL_APIENTRYP // Constant substitutions #define GL_CLAMP GL_CLAMP_TO_EDGE #define GL_MIRRORED_REPEAT_ARB GL_MIRRORED_REPEAT #define GL_ADD 0x0104 #define GL_MODULATE 0x2100 #define GL_INTERPOLATE 0x8575 #define GL_CONSTANT 0x8576 #define GL_PREVIOUS 0x8578 // Function substitutions #define glClearDepth glClearDepthf #define glDepthRange glDepthRangef // No-op substitutions (unavailable in GLES2) #define glLoadIdentity() #define glReadBuffer(x) #define glTexEnvi(x,y,z) #else // !USE_GLES #ifndef SDL_VIDEO_OPENGL #error SDL is not build with OpenGL support. Try USE_GLES=1 #endif #if defined(__APPLE__) #include #include #define APIENTRY #endif #if defined(WIN32) #include #include #include #else #include #endif #define GLSL_VERSION "120" #endif // !USE_GLES #endif // OSAL_OPENGL_H mupen64plus-video-rice-src-2.6.0/src/osal_preproc.h000066400000000000000000000060321464507324400221740ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - osal_preproc.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* this header file is for system-dependent #defines, #includes, and typedefs */ #if !defined(OSAL_PREPROC_H) #define OSAL_PREPROC_H #if defined(WIN32) #include #if defined(__MINGW32__) #define ALIGN(BYTES,DATA) DATA __attribute__((aligned(BYTES))); #else #define ALIGN(BYTES,DATA) __declspec(align(BYTES)) DATA; #define strncasecmp _strnicmp #define strcasecmp _stricmp #endif #else #define ALIGN(BYTES,DATA) DATA __attribute__((aligned(BYTES))); typedef unsigned int BOOL; typedef void* HBITMAP; typedef struct { int top; int bottom; int right; int left; } RECT; #define __cdecl #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif typedef struct tagBITMAPINFOHEADER { unsigned int biSize; int biWidth; int biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned int biCompression; unsigned int biSizeImage; int biXPelsPerMeter; int biYPelsPerMeter; unsigned int biClrUsed; unsigned int biClrImportant; } __attribute__ ((packed)) BITMAPINFOHEADER; typedef struct tagBITMAPINFO { BITMAPINFOHEADER bmiHeader; unsigned int unused; } BITMAPINFO; typedef struct tagBITMAPFILEHEADER { unsigned short bfType; unsigned int bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned int bfOffBits; } __attribute__ ((packed)) BITMAPFILEHEADER; #define BI_RGB 0 #endif // WIN32 #endif // OSAL_PREPROC_H mupen64plus-video-rice-src-2.6.0/src/typedefs.h000066400000000000000000000204571464507324400213360ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _TYPEDEFS_H_ #define _TYPEDEFS_H_ #include "VectorMath.h" #include "osal_preproc.h" #define uchar unsigned char #define uint16 unsigned short #define uint32 unsigned int #define uint64 unsigned long long typedef unsigned char uint8; typedef signed char s8; typedef int s32; typedef unsigned int u32; typedef unsigned char u8; typedef unsigned int COLOR; typedef struct _COORDRECT { int x1,y1; int x2,y2; } COORDRECT; // convert rgba values (0-255 per channel) to a DWORD in A8R8G8B8 order #define COLOR_RGBA(r,g,b,a) ((r&0xFF)<<16 | (g&0xFF)<<8 | (b&0xFF)<<0 | (a&0xFF)<<24) // convert DWORD R8G8B8A8 order to A8R8G8B8 #define RGBA_TO_ARGB(rgba) ((rgba&0x000000FF)<<24 | (rgba&0xFF000000)>>8 | (rgba&0x00FF0000)>>8 | (rgba&0x0000FF00)>>8) #define SURFFMT_A8R8G8B8 21 #define RGBA_GETALPHA(rgb) ((rgb) >> 24) #define RGBA_GETRED(rgb) (((rgb) >> 16) & 0xff) #define RGBA_GETGREEN(rgb) (((rgb) >> 8) & 0xff) #define RGBA_GETBLUE(rgb) ((rgb) & 0xff) typedef XMATRIX Matrix; typedef void* LPRICETEXTURE ; typedef struct { uint32 dwRGBA, dwRGBACopy; char x,y,z; // Direction uint8 pad; } N64Light; typedef struct { unsigned int dwFormat:3; unsigned int dwSize:2; unsigned int dwWidth:10; uint32 dwAddr; uint32 bpl; } SetImgInfo; typedef struct { // Set by RDP_SetTile unsigned int dwFormat :3; // e.g. RGBA, YUV etc unsigned int dwSize :2; // e.g 4/8/16/32bpp unsigned int dwLine :9; // Ummm... unsigned int dwPalette :4; // 0..15 - a palette index? uint32 dwTMem; // Texture memory location unsigned int bClampS :1; unsigned int bClampT :1; unsigned int bMirrorS :1; unsigned int bMirrorT :1; unsigned int dwMaskS :4; unsigned int dwMaskT :4; unsigned int dwShiftS :4; unsigned int dwShiftT :4; // Set by RDP_SetTileSize int sl; // Upper left S - 8:3 int tl; // Upper Left T - 8:3 int sh; // Lower Right S int th; // Lower Right T int hilite_sl; int hilite_tl; int hilite_sh; int hilite_th; float fsl; // Upper left S - 8:3 float ftl; // Upper Left T - 8:3 float fsh; // Lower Right S float fth; // Lower Right T float fhilite_sl; float fhilite_tl; float fhilite_sh; float fhilite_th; uint32 dwDXT; uint32 dwPitch; uint32 dwWidth; uint32 dwHeight; float fShiftScaleS; float fShiftScaleT; uint32 lastTileCmd; bool bSizeIsValid; bool bForceWrapS; bool bForceWrapT; bool bForceClampS; bool bForceClampT; } Tile; typedef struct { float u; float v; } TexCord; typedef struct VECTOR2 { float x; float y; VECTOR2( float newx, float newy ) {x=newx; y=newy;} VECTOR2() {x=0; y=0;} } VECTOR2; typedef struct { short x; short y; } IVector2; typedef struct { short x; short y; short z; } IVector3; typedef struct { float x,y,z; float rhw; union { COLOR dcDiffuse; struct { uint8 b; uint8 g; uint8 r; uint8 a; }; }; TexCord tcord[2]; } TLITVERTEX, *LPTLITVERTEX; typedef struct { float x,y,z; float rhw; union { COLOR dcDiffuse; struct { uint8 b; uint8 g; uint8 r; uint8 a; }; }; } LITVERTEX, *LPLITVERTEX; typedef struct { float x,y,z; float rhw; COLOR dcDiffuse; } FILLRECTVERTEX, *LPFILLRECTVERTEX; #include "COLOR.h" typedef struct { float x,y,z; float nx,ny,nz; union { COLOR dcDiffuse; struct { uint8 b; uint8 g; uint8 r; uint8 a; }; }; float u,v; }EXTERNAL_VERTEX, *LPSHADERVERTEX; typedef struct { union { struct { float x; float y; float z; float range; // Range == 0 for directional light // Range != 0 for point light, Zelda MM }; }; union { struct { uint8 r; uint8 g; uint8 b; uint8 a; }; uint32 col; }; union { struct { float fr; float fg; float fb; float fa; }; float fcolors[4]; }; union { struct { float tx; float ty; float tz; float tdummy; }; }; union { struct { float ox; float oy; float oz; float odummy; }; }; } Light; typedef struct { short y; short x; short flag; short z; short tv; short tu; union { struct { uint8 a; uint8 b; uint8 g; uint8 r; } rgba; struct { char na; char nz; // b char ny; //g char nx; //r } norma; }; } FiddledVtx; typedef struct { short y; short x; uint8 a; uint8 b; short z; uint8 g; uint8 r; } FiddledVtxDKR; typedef struct { short y; short x; uint16 cidx; short z; short t; short s; } N64VtxPD; class CTexture; class COGLTexture; class CDirectXTexture; struct TxtrCacheEntry; typedef struct { LPRICETEXTURE m_lpsTexturePtr; union { CTexture * m_pCTexture; CDirectXTexture * m_pCDirectXTexture; COGLTexture * m_pCOGLTexture; }; uint32 m_dwTileWidth; uint32 m_dwTileHeight; float m_fTexWidth; float m_fTexHeight; // Float to avoid converts when processing verts TxtrCacheEntry *pTextureEntry; } RenderTexture; typedef struct { unsigned int dwFormat; unsigned int dwSize; unsigned int dwWidth; unsigned int dwAddr; unsigned int dwLastWidth; unsigned int dwLastHeight; unsigned int dwHeight; unsigned int dwMemSize; bool bCopied; unsigned int dwCopiedAtFrame; unsigned int dwCRC; unsigned int lastUsedFrame; unsigned int bUsedByVIAtFrame; unsigned int lastSetAtUcode; } RecentCIInfo; typedef struct { uint32 addr; uint32 FrameCount; } RecentViOriginInfo; typedef enum { SHADE_DISABLED, SHADE_FLAT, SHADE_SMOOTH, } RenderShadeMode; typedef enum { TEXTURE_UV_FLAG_WRAP, TEXTURE_UV_FLAG_MIRROR, TEXTURE_UV_FLAG_CLAMP, } TextureUVFlag; typedef struct { TextureUVFlag N64flag; uint32 realFlag; } UVFlagMap; typedef enum { FILTER_POINT, FILTER_LINEAR, } TextureFilter; typedef struct { TextureFilter N64filter; uint32 realFilter; } TextureFilterMap; typedef struct { const char* description; int number; uint32 setting; } BufferSettingInfo; typedef struct { const char* description; uint32 setting; } SettingInfo; typedef union { uint8 g_Tmem8bit[0x1000]; short g_Tmem16bit[0x800]; uint32 g_Tmem32bit[0x300]; uint64 g_Tmem64bit[0x200]; } TmemType; typedef struct { uint32 dwFormat; uint32 dwSize; BOOL bSetBy; uint32 dwLoadAddress; uint32 dwTotalWords; uint32 dxt; BOOL bSwapped; uint32 dwWidth; uint32 dwLine; int sl; int sh; int tl; int th; uint32 dwTmem; } TMEMLoadMapInfo; #endif mupen64plus-video-rice-src-2.6.0/src/ucode.h000066400000000000000000001104001464507324400205760ustar00rootroot00000000000000/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "UcodeDefs.h" #ifndef _UCODE_H_ #define _UCODE_H_ //typedef void (*RDPInstruction)(Gfx *gfx); typedef void (*RDPInstruction)(Gfx*); extern RDPInstruction *currentUcodeMap; typedef RDPInstruction UcodeMap[256] ; //#define UcodeFunc(name) void name(uint32, uint32) #define UcodeFunc(name) void name(Gfx*) UcodeFunc(RSP_RDP_Nothing); UcodeFunc(RSP_GBI0_Mtx); UcodeFunc(RSP_Mtx_DKR); UcodeFunc(RSP_GBI0_DL); UcodeFunc(RSP_DL_In_MEM_DKR); UcodeFunc(RSP_GBI0_Vtx); UcodeFunc(RSP_Vtx_DKR); UcodeFunc(RSP_Vtx_WRUS); UcodeFunc(RSP_Vtx_ShadowOfEmpire); UcodeFunc(RSP_GBI0_Tri4); UcodeFunc(RSP_DMA_Tri_DKR); UcodeFunc(DLParser_Set_Addr_Ucode6); UcodeFunc(RSP_MoveWord_DKR); UcodeFunc(RSP_Vtx_PD); UcodeFunc(RSP_Set_Vtx_CI_PD); UcodeFunc(RSP_Tri4_PD); UcodeFunc(RSP_GBI0_Sprite2DBase); UcodeFunc(RSP_GBI0_Sprite2DDraw); UcodeFunc(RSP_GBI1_Sprite2DBase); UcodeFunc(RSP_GBI1_Sprite2DScaleFlip); UcodeFunc(RSP_GBI1_Sprite2DDraw); UcodeFunc(RSP_GBI_Sprite2DBase); UcodeFunc(RSP_GBI_Sprite2D_PuzzleMaster64); UcodeFunc(RSP_GBI1_SpNoop); UcodeFunc(RSP_GBI1_Reserved); UcodeFunc(RSP_GBI1_Vtx); UcodeFunc(RSP_GBI1_MoveMem); UcodeFunc(RSP_GBI1_RDPHalf_Cont); UcodeFunc(RSP_GBI1_RDPHalf_2); UcodeFunc(RSP_GBI1_RDPHalf_1); UcodeFunc(RSP_GBI1_Line3D); UcodeFunc(RSP_GBI1_ClearGeometryMode); UcodeFunc(RSP_GBI1_SetGeometryMode); UcodeFunc(RSP_GBI1_EndDL); UcodeFunc(RSP_GBI1_SetOtherModeL); UcodeFunc(RSP_GBI1_SetOtherModeH); UcodeFunc(RSP_GBI1_Texture); UcodeFunc(RSP_GBI1_MoveWord); UcodeFunc(RSP_GBI1_PopMtx); UcodeFunc(RSP_GBI1_CullDL); UcodeFunc(RSP_GBI1_Tri1); UcodeFunc(RSP_GBI1_Tri2); UcodeFunc(RSP_GBI1_Noop); UcodeFunc(RSP_GBI1_ModifyVtx); UcodeFunc(RSP_GBI1_BranchZ); UcodeFunc(RSP_GBI1_LoadUCode); UcodeFunc(DLParser_TexRect); UcodeFunc(DLParser_TexRectFlip); UcodeFunc(DLParser_RDPLoadSync); UcodeFunc(DLParser_RDPPipeSync); UcodeFunc(DLParser_RDPTileSync); UcodeFunc(DLParser_RDPFullSync); UcodeFunc(DLParser_SetKeyGB); UcodeFunc(DLParser_SetKeyR); UcodeFunc(DLParser_SetConvert); UcodeFunc(DLParser_SetScissor); UcodeFunc(DLParser_SetPrimDepth); UcodeFunc(DLParser_RDPSetOtherMode); UcodeFunc(DLParser_LoadTLut); UcodeFunc(DLParser_SetTileSize); UcodeFunc(DLParser_LoadBlock); UcodeFunc(DLParser_LoadTile); UcodeFunc(DLParser_SetTile); UcodeFunc(DLParser_FillRect); UcodeFunc(DLParser_SetFillColor); UcodeFunc(DLParser_SetFogColor); UcodeFunc(DLParser_SetBlendColor); UcodeFunc(DLParser_SetPrimColor); UcodeFunc(DLParser_SetEnvColor); UcodeFunc(DLParser_SetCombine); UcodeFunc(DLParser_SetTImg); UcodeFunc(DLParser_SetZImg); UcodeFunc(DLParser_SetCImg); UcodeFunc(RSP_GBI2_DL); UcodeFunc(RSP_GBI2_CullDL); UcodeFunc(RSP_GBI2_EndDL); UcodeFunc(RSP_GBI2_MoveWord); UcodeFunc(RSP_GBI2_Texture); UcodeFunc(RSP_GBI2_GeometryMode); UcodeFunc(RSP_GBI2_SetOtherModeL); UcodeFunc(RSP_GBI2_SetOtherModeH); UcodeFunc(RSP_GBI2_MoveMem); UcodeFunc(RSP_GBI2_Mtx); UcodeFunc(RSP_GBI2_PopMtx); UcodeFunc(RSP_GBI2_Vtx); UcodeFunc(RSP_GBI2_Tri1); UcodeFunc(RSP_GBI2_Tri2); UcodeFunc(RSP_GBI2_Line3D); UcodeFunc(RSP_GBI2_DL_Count); UcodeFunc(RSP_GBI2_SubModule); UcodeFunc(RSP_GBI2_0x8); UcodeFunc(DLParser_Bomberman2TextRect); UcodeFunc(RSP_S2DEX_BG_1CYC_2); UcodeFunc(RSP_S2DEX_OBJ_RENDERMODE_2); UcodeFunc(RSP_S2DEX_SPObjLoadTxtr_Ucode1); UcodeFunc( RSP_S2DEX_BG_1CYC); UcodeFunc( RSP_S2DEX_BG_COPY); UcodeFunc( RSP_S2DEX_OBJ_RECTANGLE); UcodeFunc( RSP_S2DEX_OBJ_SPRITE); UcodeFunc( RSP_S2DEX_OBJ_MOVEMEM); UcodeFunc( RSP_S2DEX_SELECT_DL); UcodeFunc( RSP_S2DEX_OBJ_RENDERMODE); UcodeFunc( RSP_S2DEX_OBJ_RECTANGLE_R); UcodeFunc( RSP_S2DEX_SPObjLoadTxtr); UcodeFunc( RSP_S2DEX_SPObjLoadTxSprite); UcodeFunc( RSP_S2DEX_SPObjLoadTxRect); UcodeFunc( RSP_S2DEX_SPObjLoadTxRectR); UcodeFunc( RSP_S2DEX_RDPHALF_0); UcodeFunc( RSP_S2DEX_Yoshi_Unknown); UcodeFunc( RSP_RDP_InsertMatrix ); UcodeFunc( RSP_S2DEX_SPObjLoadTxtr ); UcodeFunc(RDP_TriFill); UcodeFunc(RDP_TriFillZ); UcodeFunc(RDP_TriTxtr); UcodeFunc(RDP_TriTxtrZ); UcodeFunc(RDP_TriShade); UcodeFunc(RDP_TriShadeZ); UcodeFunc(RDP_TriShadeTxtr); UcodeFunc(RDP_TriShadeTxtrZ); #ifdef DEBUGGER const char* ucodeNames_GBI1[256] = { "RSP_SPNOOP", "RSP_MTX", "Reserved0", "RSP_MOVEMEM", "RSP_VTX", "Reserved1", "RSP_DL", "Reserved2", "RSP_RESERVED3", "RSP_SPRITE2D", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //10 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //20 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //30 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //40 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //50 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //60 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //70 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //80 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //90 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //A0 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "RSP_LOAD_UCODE", //B0 "RSP_BRANCH_Z", "RSP_TRI2", "G_MODIFY_VERTEX", "RSP_RDPHALF_2", "RSP_RDPHALF_1", "RSP_LINE3D", "RSP_CLEARGEOMETRYMODE", "RSP_SETGEOMETRYMODE", "RSP_ENDDL", "RSP_SETOTHERMODE_L", "RSP_SETOTHERMODE_H", "RSP_TEXTURE", "RSP_MOVEWORD", "RSP_POPMTX", "RSP_CULLDL", "RSP_TRI1", //C0 "RDP_NOOP", "G_NOTHING", "G_YS_UNK1", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "RDP_TriFill", "RDP_TriFillZ", "RDP_TriTxtr", "RDP_TriTxtrZ", "RDP_TriShade", "RDP_TriShadeZ", "RDP_TriShadeTxtr", "RDP_TriShadeTxtrZ", //D0 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", //E0 "G_NOTHING", "G_NOTHING", "G_NOTHING", "G_NOTHING", "RDP_TEXRECT", "RDP_TEXRECT_FLIP", "RDP_LOADSYNC", "RDP_PIPESYNC", "RDP_TILESYNC", "RDP_FULLSYNC", "RDP_SETKEYGB", "RDP_SETKEYR", "RDP_SETCONVERT", "RDP_SETSCISSOR", "RDP_SETPRIMDEPTH", "RDP_RDPSETOTHERMODE", //F0 "RDP_LOADTLUT", "G_NOTHING", "RDP_SETTILESIZE", "RDP_LOADBLOCK", "RDP_LOADTILE", "RDP_SETTILE", "RDP_FILLRECT", "RDP_SETFILLCOLOR", "RDP_SETFOGCOLOR", "RDP_SETBLENDCOLOR", "RDP_SETPRIMCOLOR", "RDP_SETENVCOLOR", "RDP_SETCOMBINE", "RDP_SETTIMG", "RDP_SETZIMG", "RDP_SETCIMG" }; const char* ucodeNames_GBI2[256] = { "NOOP", "GBI2_Vtx", "ModifyVtx", "GBI2_CullDL", "BranchZ", "GBI2_Tri1", "GBI2_Tri2","GBI2_Line3D", "Nothing", "ObjBG1CYC", "ObjBGCopy", "OBJ_RenderMode", "Nothing", "Nothing", "Nothing", "Nothing", //10 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //20 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //30 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //40 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //50 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //60 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //70 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //80 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //90 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", //a0 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Load_Ucode", //b0 "BranchZ", "Tri2_Goldeneye", "ModifyVtx", "RDPHalf_2", "RDPHalf_1", "Line3D", "ClearGeometryMode", "SetGeometryMode", "EndDL", "SetOtherMode_L", "SetOtherMode_H", "Texture", "MoveWord", "PopMtx", "CullDL", "Tri1", //c0 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "RDP_TriFill", "RDP_TriFillZ", "RDP_TriTxtr", "RDP_TriTxtrZ", "RDP_TriShade", "RDP_TriShadeZ", "RDP_TriShadeTxtr", "RDP_TriShadeTxtrZ", //d0 "Nothing", "Nothing", "Nothing", "Nothing", "Nothing", "GBI2_DL_N", "GBI2_SubModule", "GBI2_Texture", "GBI2_PopMtx", "GBI2_SetGeometryMode", "GBI2_Mtx", "GBI2_MoveWord", "GBI2_MoveMem", "Load_Ucode", "GBI2_DL", "GBI2_EndDL", //e0 "SPNOOP", "RDPHalf_1", "GBI2_SetOtherMode_L", "GBI2_SetOtherMode_H", "TexRect", "TexRectFlip", "RDPLoadSync", "RDPPipeSync", "RDPTileSync", "RDPFullSync", "SetKeyGB", "SetKeyR", "SetConvert", "SetScissor", "SetPrimDepth", "RDPSetOtherMode", //f0 "LoadTLut", "Nothing", "SetTileSize", "LoadBlock", "LoadTile", "SetTile", "FillRect", "SetFillColor", "SetFogColor", "SetBlendColor", "SetPrimColor", "SetEnvColor", "SetCombine", "SetTImg", "SetZImg", "SetCImg", }; #endif typedef RDPInstruction UcodeMap[256] ; // Ucode: F3DEX, for most games UcodeMap ucodeMap1 = { RSP_GBI1_SpNoop, RSP_GBI0_Mtx, RSP_GBI1_Reserved, RSP_GBI1_MoveMem, RSP_GBI1_Vtx, RSP_GBI1_Reserved, RSP_GBI0_DL, RSP_GBI1_Reserved, RSP_GBI1_Reserved, RSP_GBI1_Sprite2DBase, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //10 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //20 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //30 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //40 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //50 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //60 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //70 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //80 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //90 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //a0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_GBI1_LoadUCode, //b0 RSP_GBI1_BranchZ, RSP_GBI1_Tri2, RSP_GBI1_ModifyVtx, RSP_GBI1_RDPHalf_2, RSP_GBI1_RDPHalf_1, RSP_GBI1_Line3D, RSP_GBI1_ClearGeometryMode, RSP_GBI1_SetGeometryMode, RSP_GBI1_EndDL, RSP_GBI1_SetOtherModeL, RSP_GBI1_SetOtherModeH, RSP_GBI1_Texture, RSP_GBI1_MoveWord, RSP_GBI1_PopMtx, RSP_GBI1_CullDL, RSP_GBI1_Tri1, //c0 RSP_GBI1_Noop, RSP_S2DEX_SPObjLoadTxtr_Ucode1, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RDP_TriFill, RDP_TriFillZ, RDP_TriTxtr, RDP_TriTxtrZ, RDP_TriShade, RDP_TriShadeZ, RDP_TriShadeTxtr, RDP_TriShadeTxtrZ, //d0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //e0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, DLParser_TexRect, DLParser_TexRectFlip, DLParser_RDPLoadSync, DLParser_RDPPipeSync, DLParser_RDPTileSync, DLParser_RDPFullSync, DLParser_SetKeyGB, DLParser_SetKeyR, DLParser_SetConvert, DLParser_SetScissor, DLParser_SetPrimDepth, DLParser_RDPSetOtherMode, //f0 DLParser_LoadTLut, RSP_RDP_Nothing, DLParser_SetTileSize, DLParser_LoadBlock, DLParser_LoadTile, DLParser_SetTile, DLParser_FillRect, DLParser_SetFillColor, DLParser_SetFogColor, DLParser_SetBlendColor, DLParser_SetPrimColor, DLParser_SetEnvColor, DLParser_SetCombine, DLParser_SetTImg, DLParser_SetZImg, DLParser_SetCImg }; UcodeMap ucodeMap0= { RSP_GBI1_SpNoop, RSP_GBI0_Mtx, RSP_GBI1_Reserved, RSP_GBI1_MoveMem, RSP_GBI0_Vtx, RSP_GBI1_Reserved, RSP_GBI0_DL, RSP_GBI1_Reserved, RSP_GBI1_Reserved, RSP_GBI0_Sprite2DBase, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //10 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //20 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //30 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //40 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //50 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //60 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //70 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //80 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //90 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //a0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //b0 RSP_RDP_Nothing, RSP_GBI0_Tri4, RSP_GBI1_RDPHalf_Cont, RSP_GBI1_RDPHalf_2, RSP_GBI1_RDPHalf_1, RSP_GBI1_Line3D, RSP_GBI1_ClearGeometryMode, RSP_GBI1_SetGeometryMode, RSP_GBI1_EndDL, RSP_GBI1_SetOtherModeL, RSP_GBI1_SetOtherModeH, RSP_GBI1_Texture, RSP_GBI1_MoveWord, RSP_GBI1_PopMtx, RSP_GBI1_CullDL, RSP_GBI1_Tri1, //c0 RSP_GBI1_Noop, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RDP_TriFill, RDP_TriFillZ, RDP_TriTxtr, RDP_TriTxtrZ, RDP_TriShade, RDP_TriShadeZ, RDP_TriShadeTxtr, RDP_TriShadeTxtrZ, //d0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //e0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, DLParser_TexRect, DLParser_TexRectFlip, DLParser_RDPLoadSync, DLParser_RDPPipeSync, DLParser_RDPTileSync, DLParser_RDPFullSync, DLParser_SetKeyGB, DLParser_SetKeyR, DLParser_SetConvert, DLParser_SetScissor, DLParser_SetPrimDepth, DLParser_RDPSetOtherMode, //f0 DLParser_LoadTLut, RSP_RDP_Nothing, DLParser_SetTileSize, DLParser_LoadBlock, DLParser_LoadTile, DLParser_SetTile, DLParser_FillRect, DLParser_SetFillColor, DLParser_SetFogColor, DLParser_SetBlendColor, DLParser_SetPrimColor, DLParser_SetEnvColor, DLParser_SetCombine, DLParser_SetTImg, DLParser_SetZImg, DLParser_SetCImg }; // Zelda and new games, F3DEX_GBI_2 UcodeMap ucodeMap5= { RSP_GBI1_Noop, RSP_GBI2_Vtx, RSP_GBI1_ModifyVtx, RSP_GBI2_CullDL, RSP_GBI1_BranchZ, RSP_GBI2_Tri1, RSP_GBI2_Tri2, RSP_GBI2_Line3D, RSP_GBI2_0x8, RSP_S2DEX_BG_1CYC, RSP_S2DEX_BG_COPY, RSP_S2DEX_OBJ_RENDERMODE, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //10 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //20 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //30 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //40 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //50 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //60 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //70 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //80 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //90 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //a0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_GBI1_LoadUCode, //b0 RSP_GBI1_BranchZ, RSP_GBI0_Tri4, RSP_GBI1_ModifyVtx, RSP_GBI1_RDPHalf_2, RSP_GBI1_RDPHalf_1, RSP_GBI1_Line3D, RSP_GBI1_ClearGeometryMode, RSP_GBI1_SetGeometryMode, RSP_GBI1_EndDL, RSP_GBI1_SetOtherModeL, RSP_GBI1_SetOtherModeH, RSP_GBI1_Texture, RSP_GBI1_MoveWord, RSP_GBI1_PopMtx, RSP_GBI1_CullDL, RSP_GBI1_Tri1, //c0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RDP_TriFill, RDP_TriFillZ, RDP_TriTxtr, RDP_TriTxtrZ, RDP_TriShade, RDP_TriShadeZ, RDP_TriShadeTxtr, RDP_TriShadeTxtrZ, //d0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_GBI2_DL_Count, RSP_GBI2_SubModule, RSP_GBI2_Texture, RSP_GBI2_PopMtx, RSP_GBI2_GeometryMode, RSP_GBI2_Mtx, RSP_GBI2_MoveWord, RSP_GBI2_MoveMem, RSP_GBI1_LoadUCode, RSP_GBI2_DL, RSP_GBI2_EndDL, //e0 RSP_GBI1_SpNoop, RSP_GBI1_RDPHalf_1, RSP_GBI2_SetOtherModeL, RSP_GBI2_SetOtherModeH, DLParser_TexRect, DLParser_TexRectFlip, DLParser_RDPLoadSync, DLParser_RDPPipeSync, DLParser_RDPTileSync, DLParser_RDPFullSync, DLParser_SetKeyGB, DLParser_SetKeyR, DLParser_SetConvert, DLParser_SetScissor, DLParser_SetPrimDepth, DLParser_RDPSetOtherMode, //f0 DLParser_LoadTLut, RSP_RDP_Nothing, DLParser_SetTileSize, DLParser_LoadBlock, DLParser_LoadTile, DLParser_SetTile, DLParser_FillRect, DLParser_SetFillColor, DLParser_SetFogColor, DLParser_SetBlendColor, DLParser_SetPrimColor, DLParser_SetEnvColor, DLParser_SetCombine, DLParser_SetTImg, DLParser_SetZImg, DLParser_SetCImg }; // S2DEX 1.-- UcodeMap ucodeMap7= { RSP_GBI1_SpNoop, RSP_S2DEX_BG_1CYC_2, RSP_S2DEX_BG_COPY, RSP_S2DEX_OBJ_RECTANGLE, RSP_S2DEX_OBJ_SPRITE, RSP_S2DEX_OBJ_MOVEMEM, RSP_GBI0_DL, RSP_GBI1_Reserved, RSP_GBI1_Reserved, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //10 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //20 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //30 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //40 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //50 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //60 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //70 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //80 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //90 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //a0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_GBI1_LoadUCode, //b0 RSP_S2DEX_SELECT_DL, RSP_S2DEX_OBJ_RENDERMODE_2, RSP_S2DEX_OBJ_RECTANGLE_R, RSP_GBI1_RDPHalf_2, RSP_GBI1_RDPHalf_1, RSP_GBI1_Line3D, RSP_GBI1_ClearGeometryMode, RSP_GBI1_SetGeometryMode, RSP_GBI1_EndDL, RSP_GBI1_SetOtherModeL, RSP_GBI1_SetOtherModeH, RSP_GBI1_Texture, RSP_GBI1_MoveWord, RSP_GBI1_PopMtx, RSP_GBI1_CullDL, RSP_GBI1_Tri1, //c0 RSP_GBI1_Noop, RSP_S2DEX_SPObjLoadTxtr, RSP_S2DEX_SPObjLoadTxSprite, RSP_S2DEX_SPObjLoadTxRect, RSP_S2DEX_SPObjLoadTxRectR, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RDP_TriFill, RDP_TriFillZ, RDP_TriTxtr, RDP_TriTxtrZ, RDP_TriShade, RDP_TriShadeZ, RDP_TriShadeTxtr, RDP_TriShadeTxtrZ, //d0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //e0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_S2DEX_RDPHALF_0, DLParser_TexRectFlip, DLParser_RDPLoadSync, DLParser_RDPPipeSync, DLParser_RDPTileSync, DLParser_RDPFullSync, DLParser_SetKeyGB, DLParser_SetKeyR, DLParser_SetConvert, DLParser_SetScissor, DLParser_SetPrimDepth, DLParser_RDPSetOtherMode, //f0 DLParser_LoadTLut, RSP_RDP_Nothing, DLParser_SetTileSize, DLParser_LoadBlock, DLParser_LoadTile, DLParser_SetTile, DLParser_FillRect, DLParser_SetFillColor, DLParser_SetFogColor, DLParser_SetBlendColor, DLParser_SetPrimColor, DLParser_SetEnvColor, DLParser_SetCombine, DLParser_SetTImg, DLParser_SetZImg, DLParser_SetCImg }; // Ucode 3 - S2DEX GBI2 UcodeMap ucodeMap3= { RSP_GBI1_Noop, RSP_S2DEX_OBJ_RECTANGLE, RSP_S2DEX_OBJ_SPRITE, RSP_GBI2_CullDL, RSP_S2DEX_SELECT_DL, RSP_S2DEX_SPObjLoadTxtr, RSP_S2DEX_SPObjLoadTxSprite, RSP_S2DEX_SPObjLoadTxRect, RSP_S2DEX_SPObjLoadTxRectR, RSP_S2DEX_BG_1CYC, RSP_S2DEX_BG_COPY, RSP_S2DEX_OBJ_RENDERMODE, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //10 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //20 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //30 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //40 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //50 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //60 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //70 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //80 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //90 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, //a0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_GBI1_LoadUCode, //b0 RSP_GBI1_BranchZ, RSP_GBI0_Tri4, RSP_GBI1_ModifyVtx, RSP_GBI1_RDPHalf_2, RSP_GBI1_RDPHalf_1, RSP_GBI1_Line3D, RSP_GBI1_ClearGeometryMode, RSP_GBI1_SetGeometryMode, RSP_GBI1_EndDL, RSP_GBI1_SetOtherModeL, RSP_GBI1_SetOtherModeH, RSP_GBI1_Texture, RSP_GBI1_MoveWord, RSP_GBI1_PopMtx, RSP_GBI1_CullDL, RSP_GBI1_Tri1, //c0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RDP_TriFill, RDP_TriFillZ, RDP_TriTxtr, RDP_TriTxtrZ, RDP_TriShade, RDP_TriShadeZ, RDP_TriShadeTxtr, RDP_TriShadeTxtrZ, //d0 RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_RDP_Nothing, RSP_GBI2_DL_Count, RSP_GBI2_SubModule, RSP_GBI2_Texture, RSP_GBI2_PopMtx, RSP_GBI2_GeometryMode, RSP_GBI2_Mtx, RSP_GBI2_MoveWord, RSP_GBI2_MoveMem, RSP_GBI1_LoadUCode, RSP_GBI2_DL, RSP_GBI2_EndDL, //e0 RSP_GBI1_SpNoop, RSP_GBI1_RDPHalf_1, RSP_GBI2_SetOtherModeL, RSP_GBI2_SetOtherModeH, DLParser_TexRect, DLParser_TexRectFlip, DLParser_RDPLoadSync, DLParser_RDPPipeSync, DLParser_RDPTileSync, DLParser_RDPFullSync, DLParser_SetKeyGB, DLParser_SetKeyR, DLParser_SetConvert, DLParser_SetScissor, DLParser_SetPrimDepth, DLParser_RDPSetOtherMode, //f0 DLParser_LoadTLut, RSP_RDP_Nothing, DLParser_SetTileSize, DLParser_LoadBlock, DLParser_LoadTile, DLParser_SetTile, DLParser_FillRect, DLParser_SetFillColor, DLParser_SetFogColor, DLParser_SetBlendColor, DLParser_SetPrimColor, DLParser_SetEnvColor, DLParser_SetCombine, DLParser_SetTImg, DLParser_SetZImg, DLParser_SetCImg }; RDPInstruction *currentUcodeMap = ucodeMap1; #endif mupen64plus-video-rice-src-2.6.0/src/version.h000066400000000000000000000037201464507324400211720ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-video-rice - version.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009-2011 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This header file is for versioning information * */ #if !defined(VERSION_H) #define VERSION_H #define PLUGIN_NAME "Mupen64Plus OpenGL Video Plugin by Rice" #define PLUGIN_VERSION 0x020600 #define VIDEO_PLUGIN_API_VERSION 0x020200 #define CONFIG_API_VERSION 0x020300 #define VIDEXT_API_VERSION 0x030000 #define VERSION_PRINTF_SPLIT(x) (((x) >> 16) & 0xffff), (((x) >> 8) & 0xff), ((x) & 0xff) #endif /* #define VERSION_H */ mupen64plus-video-rice-src-2.6.0/src/video_api_export.ver000066400000000000000000000004661464507324400234160ustar00rootroot00000000000000{ global: PluginStartup; PluginShutdown; PluginGetVersion; ChangeWindow; InitiateGFX; MoveScreen; ProcessDList; ProcessRDPList; RomClosed; RomOpen; ShowCFB; UpdateScreen; ViStatusChanged; ViWidthChanged; ReadScreen2; SetRenderingCallback; ResizeVideoOutput; FBRead; FBWrite; FBGetFrameBufferInfo; local: *; };