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